From 9f4bd5dde81b5cb94e4f52f2f05825aa0422f1ff Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Sun, 1 Oct 2006 10:48:04 +0100 Subject: [ALSA] snd-emu10k1: Added support for emu1010, including E-Mu 1212m and E-Mu 1820m Signed-off-by: James Courtier-Dutton Signed-off-by: Jaroslav Kysela --- sound/pci/emu10k1/emu10k1_main.c | 540 ++++++++++++++++++++++++++++++--------- sound/pci/emu10k1/emu10k1x.c | 6 +- sound/pci/emu10k1/emufx.c | 102 +++++++- sound/pci/emu10k1/emumixer.c | 325 ++++++++++++++++++++++- sound/pci/emu10k1/emupcm.c | 127 ++++++--- sound/pci/emu10k1/emuproc.c | 34 ++- sound/pci/emu10k1/io.c | 45 ++++ sound/pci/emu10k1/p16v.c | 12 +- sound/pci/emu10k1/voice.c | 2 +- 9 files changed, 1015 insertions(+), 178 deletions(-) (limited to 'sound') diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 972ec40d816..891172f2b1d 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -3,8 +3,10 @@ * Creative Labs, Inc. * Routines for control of EMU10K1 chips * - * Copyright (c) by James Courtier-Dutton + * Copyright (c) by James Courtier-Dutton * Added support for Audigy 2 Value. + * Added EMU 1010 support. + * General bug fixes and enhancements. * * * BUGS: @@ -41,6 +43,7 @@ #include #include +#include #include "p16v.h" #include "tina2.h" @@ -211,7 +214,7 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) int size, n; size = ARRAY_SIZE(spi_dac_init); - for (n=0; n < size; n++) + for (n = 0; n < size; n++) snd_emu10k1_spi_write(emu, spi_dac_init[n]); snd_emu10k1_ptr20_write(emu, 0x60, 0, 0x10); @@ -239,6 +242,10 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) snd_emu10k1_ptr_write(emu, MAPB, ch, silent_page); } + if (emu->card_capabilities->emu1010) { + outl(HCFG_AUTOMUTE_ASYNC | + HCFG_EMU32_SLAVE | + HCFG_AUDIOENABLE, emu->port + HCFG); /* * Hokay, setup HCFG * Mute Disable Audio = 0 @@ -246,7 +253,7 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) * Lock Sound Memory = 0 * Auto Mute = 1 */ - if (emu->audigy) { + } else if (emu->audigy) { if (emu->revision == 4) /* audigy2 */ outl(HCFG_AUDIOENABLE | HCFG_AC3ENABLE_CDSPDIF | @@ -265,8 +272,8 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) outl(HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE | HCFG_JOYENABLE, emu->port + HCFG); if (enable_ir) { /* enable IR for SB Live */ - if ( emu->card_capabilities->emu1212m) { - ; /* Disable all access to A_IOCFG for the emu1212m */ + if (emu->card_capabilities->emu1010) { + ; /* Disable all access to A_IOCFG for the emu1010 */ } else if (emu->audigy) { unsigned int reg = inl(emu->port + A_IOCFG); outl(reg | A_IOCFG_GPOUT2, emu->port + A_IOCFG); @@ -284,8 +291,8 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) } } - if ( emu->card_capabilities->emu1212m) { - ; /* Disable all access to A_IOCFG for the emu1212m */ + if (emu->card_capabilities->emu1010) { + ; /* Disable all access to A_IOCFG for the emu1010 */ } else if (emu->audigy) { /* enable analog output */ unsigned int reg = inl(emu->port + A_IOCFG); outl(reg | A_IOCFG_GPOUT0, emu->port + A_IOCFG); @@ -302,8 +309,8 @@ static void snd_emu10k1_audio_enable(struct snd_emu10k1 *emu) outl(inl(emu->port + HCFG) | HCFG_AUDIOENABLE, emu->port + HCFG); /* Enable analog/digital outs on audigy */ - if ( emu->card_capabilities->emu1212m) { - ; /* Disable all access to A_IOCFG for the emu1212m */ + if (emu->card_capabilities->emu1010) { + ; /* Disable all access to A_IOCFG for the emu1010 */ } else if (emu->audigy) { outl(inl(emu->port + A_IOCFG) & ~0x44, emu->port + A_IOCFG); @@ -596,133 +603,417 @@ static int snd_emu10k1_cardbus_init(struct snd_emu10k1 * emu) return 0; } -static int snd_emu1212m_fpga_write(struct snd_emu10k1 * emu, int reg, int value) -{ - if (reg<0 || reg>0x3f) - return 1; - reg+=0x40; /* 0x40 upwards are registers. */ - if (value<0 || value>0x3f) /* 0 to 0x3f are values */ - return 1; - outl(reg, emu->port + A_IOCFG); - outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */ - outl(value, emu->port + A_IOCFG); - outl(value | 0x80 , emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */ - - return 0; -} - -static int snd_emu1212m_fpga_read(struct snd_emu10k1 * emu, int reg, int *value) +static int snd_emu1010_load_firmware(struct snd_emu10k1 * emu, const char * filename) { - if (reg<0 || reg>0x3f) - return 1; - reg+=0x40; /* 0x40 upwards are registers. */ - outl(reg, emu->port + A_IOCFG); - outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */ - *value = inl(emu->port + A_IOCFG); - - return 0; -} + int err; + int n, i; + int reg; + int value; + const struct firmware *fw_entry; + + if ((err = request_firmware(&fw_entry, filename, &emu->pci->dev)) != 0) { + snd_printk(KERN_ERR "firmware: %s not found. Err=%d\n",filename, err); + return err; + } + snd_printk(KERN_INFO "firmware size=0x%x\n",fw_entry->size); + if (fw_entry->size != 0x133a4) { + snd_printk(KERN_ERR "firmware: %s wrong size.\n",filename); + return -EINVAL; + } -static int snd_emu1212m_fpga_netlist_write(struct snd_emu10k1 * emu, int reg, int value) -{ - snd_emu1212m_fpga_write(emu, 0x00, ((reg >> 8) & 0x3f) ); - snd_emu1212m_fpga_write(emu, 0x01, (reg & 0x3f) ); - snd_emu1212m_fpga_write(emu, 0x02, ((value >> 8) & 0x3f) ); - snd_emu1212m_fpga_write(emu, 0x03, (value & 0x3f) ); + /* The FPGA is a Xilinx Spartan IIE XC2S50E */ + /* GPIO7 -> FPGA PGMN + * GPIO6 -> FPGA CCLK + * GPIO5 -> FPGA DIN + * FPGA CONFIG OFF -> FPGA PGMN + */ + outl(0x00, emu->port + A_IOCFG); /* Set PGMN low for 1uS. */ + udelay(1); + outl(0x80, emu->port + A_IOCFG); /* Leave bit 7 set during netlist setup. */ + udelay(100); /* Allow FPGA memory to clean */ + for(n = 0; n < fw_entry->size; n++) { + value=fw_entry->data[n]; + for(i = 0; i < 8; i++) { + reg = 0x80; + if (value & 0x1) + reg = reg | 0x20; + value = value >> 1; + outl(reg, emu->port + A_IOCFG); + outl(reg | 0x40, emu->port + A_IOCFG); + } + } + /* After programming, set GPIO bit 4 high again. */ + outl(0x10, emu->port + A_IOCFG); + + release_firmware(fw_entry); return 0; } -static int snd_emu10k1_emu1212m_init(struct snd_emu10k1 * emu) +static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu) { unsigned int i; - int tmp; - - snd_printk(KERN_ERR "emu1212m: Special config.\n"); + int tmp,tmp2; + int reg; + int err; + const char *hana_filename = "emu/hana.fw"; + const char *dock_filename = "emu/audio_dock.fw"; + + snd_printk(KERN_INFO "emu1010: Special config.\n"); + /* AC97 2.1, Any 16Meg of 4Gig address, Auto-Mute, EMU32 Slave, + * Lock Sound Memory Cache, Lock Tank Memory Cache, + * Mute all codecs. + */ outl(0x0005a00c, emu->port + HCFG); - outl(0x0005a004, emu->port + HCFG); + /* AC97 2.1, Any 16Meg of 4Gig address, Auto-Mute, EMU32 Slave, + * Lock Tank Memory Cache, + * Mute all codecs. + */ + outl(0x0005a004, emu->port + HCFG); + /* AC97 2.1, Any 16Meg of 4Gig address, Auto-Mute, EMU32 Slave, + * Mute all codecs. + */ outl(0x0005a000, emu->port + HCFG); + /* AC97 2.1, Any 16Meg of 4Gig address, Auto-Mute, EMU32 Slave, + * Mute all codecs. + */ outl(0x0005a000, emu->port + HCFG); - snd_emu1212m_fpga_read(emu, 0x22, &tmp ); - snd_emu1212m_fpga_read(emu, 0x23, &tmp ); - snd_emu1212m_fpga_read(emu, 0x24, &tmp ); - snd_emu1212m_fpga_write(emu, 0x04, 0x01 ); - snd_emu1212m_fpga_read(emu, 0x0b, &tmp ); - snd_emu1212m_fpga_write(emu, 0x0b, 0x01 ); - snd_emu1212m_fpga_read(emu, 0x10, &tmp ); - snd_emu1212m_fpga_write(emu, 0x10, 0x00 ); - snd_emu1212m_fpga_read(emu, 0x11, &tmp ); - snd_emu1212m_fpga_write(emu, 0x11, 0x30 ); - snd_emu1212m_fpga_read(emu, 0x13, &tmp ); - snd_emu1212m_fpga_write(emu, 0x13, 0x0f ); - snd_emu1212m_fpga_read(emu, 0x11, &tmp ); - snd_emu1212m_fpga_write(emu, 0x11, 0x30 ); - snd_emu1212m_fpga_read(emu, 0x0a, &tmp ); - snd_emu1212m_fpga_write(emu, 0x0a, 0x10 ); - snd_emu1212m_fpga_write(emu, 0x0c, 0x19 ); - snd_emu1212m_fpga_write(emu, 0x12, 0x0c ); - snd_emu1212m_fpga_write(emu, 0x09, 0x0f ); - snd_emu1212m_fpga_write(emu, 0x06, 0x00 ); - snd_emu1212m_fpga_write(emu, 0x05, 0x00 ); - snd_emu1212m_fpga_write(emu, 0x0e, 0x12 ); - snd_emu1212m_fpga_netlist_write(emu, 0x0000, 0x0200); - snd_emu1212m_fpga_netlist_write(emu, 0x0001, 0x0201); - snd_emu1212m_fpga_netlist_write(emu, 0x0002, 0x0500); - snd_emu1212m_fpga_netlist_write(emu, 0x0003, 0x0501); - snd_emu1212m_fpga_netlist_write(emu, 0x0004, 0x0400); - snd_emu1212m_fpga_netlist_write(emu, 0x0005, 0x0401); - snd_emu1212m_fpga_netlist_write(emu, 0x0006, 0x0402); - snd_emu1212m_fpga_netlist_write(emu, 0x0007, 0x0403); - snd_emu1212m_fpga_netlist_write(emu, 0x0008, 0x0404); - snd_emu1212m_fpga_netlist_write(emu, 0x0009, 0x0405); - snd_emu1212m_fpga_netlist_write(emu, 0x000a, 0x0406); - snd_emu1212m_fpga_netlist_write(emu, 0x000b, 0x0407); - snd_emu1212m_fpga_netlist_write(emu, 0x000c, 0x0100); - snd_emu1212m_fpga_netlist_write(emu, 0x000d, 0x0104); - snd_emu1212m_fpga_netlist_write(emu, 0x000e, 0x0200); - snd_emu1212m_fpga_netlist_write(emu, 0x000f, 0x0201); - for (i=0;i < 0x20;i++) { - snd_emu1212m_fpga_netlist_write(emu, 0x0100+i, 0x0000); + /* Disable 48Volt power to Audio Dock */ + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0 ); + + /* ID, should read & 0x7f = 0x55. (Bit 7 is the IRQ bit) */ + snd_emu1010_fpga_read(emu, EMU_HANA_ID, ® ); + snd_printdd("reg1=0x%x\n",reg); + if (reg == 0x55) { + /* FPGA netlist already present so clear it */ + /* Return to programming mode */ + + snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0x02 ); } - for (i=0;i < 4;i++) { - snd_emu1212m_fpga_netlist_write(emu, 0x0200+i, 0x0000); + snd_emu1010_fpga_read(emu, EMU_HANA_ID, ® ); + snd_printdd("reg2=0x%x\n",reg); + if (reg == 0x55) { + /* FPGA failed to return to programming mode */ + return -ENODEV; } - for (i=0;i < 7;i++) { - snd_emu1212m_fpga_netlist_write(emu, 0x0300+i, 0x0000); + snd_printk(KERN_INFO "emu1010: EMU_HANA_ID=0x%x\n",reg); + if ((err = snd_emu1010_load_firmware(emu, hana_filename)) != 0) { + snd_printk(KERN_INFO "emu1010: Loading Hana Firmware file %s failed\n", hana_filename); + return err; } - for (i=0;i < 7;i++) { - snd_emu1212m_fpga_netlist_write(emu, 0x0400+i, 0x0000); + + /* ID, should read & 0x7f = 0x55 when FPGA programmed. */ + snd_emu1010_fpga_read(emu, EMU_HANA_ID, ® ); + if (reg != 0x55) { + /* FPGA failed to be programmed */ + snd_printk(KERN_INFO "emu1010: Loading Hana Firmware file failed, reg=0x%x\n", reg); + return -ENODEV; } - snd_emu1212m_fpga_netlist_write(emu, 0x0500, 0x0108); - snd_emu1212m_fpga_netlist_write(emu, 0x0501, 0x010c); - snd_emu1212m_fpga_netlist_write(emu, 0x0600, 0x0110); - snd_emu1212m_fpga_netlist_write(emu, 0x0601, 0x0114); - snd_emu1212m_fpga_netlist_write(emu, 0x0700, 0x0118); - snd_emu1212m_fpga_netlist_write(emu, 0x0701, 0x011c); - snd_emu1212m_fpga_write(emu, 0x07, 0x01 ); - snd_emu1212m_fpga_read(emu, 0x21, &tmp ); + snd_printk(KERN_INFO "emu1010: Hana Firmware loaded\n"); + snd_emu1010_fpga_read(emu, EMU_HANA_MAJOR_REV, &tmp ); + snd_emu1010_fpga_read(emu, EMU_HANA_MINOR_REV, &tmp2 ); + snd_printk("Hana ver:%d.%d\n",tmp ,tmp2); + /* Enable 48Volt power to Audio Dock */ + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, EMU_HANA_DOCK_PWR_ON ); + + snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ® ); + snd_printk(KERN_INFO "emu1010: Card options=0x%x\n",reg); + snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ® ); + snd_printk(KERN_INFO "emu1010: Card options=0x%x\n",reg); + snd_emu1010_fpga_read(emu, EMU_HANA_OPTICAL_TYPE, &tmp ); + /* ADAT input. */ + snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, 0x01 ); + snd_emu1010_fpga_read(emu, EMU_HANA_DOCK_PADS, &tmp ); + /* Set no attenuation on Audio Dock pads. */ + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PADS, 0x00 ); + snd_emu1010_fpga_read(emu, EMU_HANA_DOCK_MISC, &tmp ); + /* Unmute Audio dock DACs, Headphone source DAC-4. */ + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_MISC, 0x30 ); + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12 ); + snd_emu1010_fpga_read(emu, EMU_HANA_UNKNOWN13, &tmp ); + /* Unknown. */ + snd_emu1010_fpga_write(emu, EMU_HANA_UNKNOWN13, 0x0f ); + snd_emu1010_fpga_read(emu, EMU_HANA_DOCK_MISC, &tmp ); + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_MISC, 0x30 ); + snd_emu1010_fpga_read(emu, EMU_HANA_SPDIF_MODE, &tmp ); + /* SPDIF Format. Set Consumer mode, 24bit, copy enable */ + snd_emu1010_fpga_write(emu, EMU_HANA_SPDIF_MODE, 0x10 ); + /* MIDI routing */ + snd_emu1010_fpga_write(emu, EMU_HANA_MIDI, 0x19 ); + /* Unknown. */ + snd_emu1010_fpga_write(emu, EMU_HANA_UNKNOWN12, 0x0c ); + /* snd_emu1010_fpga_write(emu, 0x09, 0x0f ); // IRQ Enable: All on */ + /* IRQ Enable: All off */ + snd_emu1010_fpga_write(emu, EMU_HANA_IRQ_ENABLE, 0x00 ); + + snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ® ); + snd_printk(KERN_INFO "emu1010: Card options3=0x%x\n",reg); + /* Default WCLK set to 48kHz. */ + snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, 0x00 ); + /* Word Clock source, Internal 48kHz x1 */ + snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K ); + //snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_4X ); + /* Audio Dock LEDs. */ + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12 ); - outl(0x0000a000, emu->port + HCFG); +#if 0 + /* For 96kHz */ + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_0, EMU_SRC_HAMOA_ADC_LEFT1); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_1, EMU_SRC_HAMOA_ADC_RIGHT1); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_4, EMU_SRC_HAMOA_ADC_LEFT2); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_5, EMU_SRC_HAMOA_ADC_RIGHT2); +#endif +#if 0 + /* For 192kHz */ + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_0, EMU_SRC_HAMOA_ADC_LEFT1); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_1, EMU_SRC_HAMOA_ADC_RIGHT1); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_2, EMU_SRC_HAMOA_ADC_LEFT2); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_3, EMU_SRC_HAMOA_ADC_RIGHT2); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_4, EMU_SRC_HAMOA_ADC_LEFT3); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_5, EMU_SRC_HAMOA_ADC_RIGHT3); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_6, EMU_SRC_HAMOA_ADC_LEFT4); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_7, EMU_SRC_HAMOA_ADC_RIGHT4); +#endif +#if 1 + /* For 48kHz */ + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_0, EMU_SRC_DOCK_MIC_A1); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_1, EMU_SRC_DOCK_MIC_B1); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_2, EMU_SRC_HAMOA_ADC_LEFT2); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_3, EMU_SRC_HAMOA_ADC_LEFT2); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_4, EMU_SRC_DOCK_ADC1_LEFT1); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_5, EMU_SRC_DOCK_ADC1_RIGHT1); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_6, EMU_SRC_DOCK_ADC2_LEFT1); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_7, EMU_SRC_DOCK_ADC2_RIGHT1); +#endif +#if 0 + /* Original */ + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_4, EMU_SRC_HANA_ADAT); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_5, EMU_SRC_HANA_ADAT + 1); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_6, EMU_SRC_HANA_ADAT + 2); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_7, EMU_SRC_HANA_ADAT + 3); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_8, EMU_SRC_HANA_ADAT + 4); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_9, EMU_SRC_HANA_ADAT + 5); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_A, EMU_SRC_HANA_ADAT + 6); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_B, EMU_SRC_HANA_ADAT + 7); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_C, EMU_SRC_DOCK_MIC_A1); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_D, EMU_SRC_DOCK_MIC_B1); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_E, EMU_SRC_HAMOA_ADC_LEFT2); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_F, EMU_SRC_HAMOA_ADC_LEFT2); +#endif + for (i = 0;i < 0x20; i++ ) { + /* AudioDock Elink <- Silence */ + snd_emu1010_fpga_link_dst_src_write(emu, 0x0100+i, EMU_SRC_SILENCE); + } + for (i = 0;i < 4; i++) { + /* Hana SPDIF Out <- Silence */ + snd_emu1010_fpga_link_dst_src_write(emu, 0x0200+i, EMU_SRC_SILENCE); + } + for (i = 0;i < 7; i++) { + /* Hamoa DAC <- Silence */ + snd_emu1010_fpga_link_dst_src_write(emu, 0x0300+i, EMU_SRC_SILENCE); + } + for (i = 0;i < 7; i++) { + /* Hana ADAT Out <- Silence */ + snd_emu1010_fpga_link_dst_src_write(emu, EMU_DST_HANA_ADAT + i, EMU_SRC_SILENCE); + } + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE_I2S0_LEFT, EMU_SRC_DOCK_ADC1_LEFT1); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE_I2S0_RIGHT, EMU_SRC_DOCK_ADC1_RIGHT1); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE_I2S1_LEFT, EMU_SRC_DOCK_ADC2_LEFT1); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE_I2S1_RIGHT, EMU_SRC_DOCK_ADC2_RIGHT1); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE_I2S2_LEFT, EMU_SRC_DOCK_ADC3_LEFT1); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE_I2S2_RIGHT, EMU_SRC_DOCK_ADC3_RIGHT1); + snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, 0x01 ); // Unmute all + + snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &tmp ); + + /* AC97 1.03, Any 32Meg of 2Gig address, Auto-Mute, EMU32 Slave, + * Lock Sound Memory Cache, Lock Tank Memory Cache, + * Mute all codecs. + */ + outl(0x0000a000, emu->port + HCFG); + /* AC97 1.03, Any 32Meg of 2Gig address, Auto-Mute, EMU32 Slave, + * Lock Sound Memory Cache, Lock Tank Memory Cache, + * Un-Mute all codecs. + */ outl(0x0000a001, emu->port + HCFG); + /* Initial boot complete. Now patches */ - snd_emu1212m_fpga_read(emu, 0x21, &tmp ); - snd_emu1212m_fpga_write(emu, 0x0c, 0x19 ); - snd_emu1212m_fpga_write(emu, 0x12, 0x0c ); - snd_emu1212m_fpga_write(emu, 0x0c, 0x19 ); - snd_emu1212m_fpga_write(emu, 0x12, 0x0c ); - snd_emu1212m_fpga_read(emu, 0x0a, &tmp ); - snd_emu1212m_fpga_write(emu, 0x0a, 0x10 ); - - snd_emu1212m_fpga_read(emu, 0x20, &tmp ); - snd_emu1212m_fpga_read(emu, 0x21, &tmp ); - - snd_emu1212m_fpga_netlist_write(emu, 0x0300, 0x0312); - snd_emu1212m_fpga_netlist_write(emu, 0x0301, 0x0313); - snd_emu1212m_fpga_netlist_write(emu, 0x0200, 0x0302); - snd_emu1212m_fpga_netlist_write(emu, 0x0201, 0x0303); + snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &tmp ); + snd_emu1010_fpga_write(emu, EMU_HANA_MIDI, 0x19 ); /* MIDI Route */ + snd_emu1010_fpga_write(emu, EMU_HANA_UNKNOWN12, 0x0c ); /* Unknown */ + snd_emu1010_fpga_write(emu, EMU_HANA_MIDI, 0x19 ); /* MIDI Route */ + snd_emu1010_fpga_write(emu, EMU_HANA_UNKNOWN12, 0x0c ); /* Unknown */ + snd_emu1010_fpga_read(emu, EMU_HANA_SPDIF_MODE, &tmp ); + snd_emu1010_fpga_write(emu, EMU_HANA_SPDIF_MODE, 0x10 ); /* SPDIF Format spdif (or 0x11 for aes/ebu) */ + + /* Delay to allow Audio Dock to settle */ + msleep(100); + snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &tmp ); /* IRQ Status */ + snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ® ); /* OPTIONS: Which cards are attached to the EMU */ + /* FIXME: The loading of this should be able to happen any time, + * as the user can plug/unplug it at any time + */ + if (reg & (EMU_HANA_OPTION_DOCK_ONLINE | EMU_HANA_OPTION_DOCK_OFFLINE) ) { + /* Audio Dock attached */ + /* Return to Audio Dock programming mode */ + snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware\n"); + snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, EMU_HANA_FPGA_CONFIG_AUDIODOCK ); + if ((err = snd_emu1010_load_firmware(emu, dock_filename)) != 0) { + return err; + } + snd_printk(KERN_INFO "emu1010: Audio Dock Firmware loaded\n"); + snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0 ); + snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, ® ); + snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_IRQ_STATUS=0x%x\n",reg); + /* ID, should read & 0x7f = 0x55 when FPGA programmed. */ + snd_emu1010_fpga_read(emu, EMU_HANA_ID, ® ); + snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_ID=0x%x\n",reg); + if (reg != 0x55) { + /* FPGA failed to be programmed */ + snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware file failed, reg=0x%x\n", reg); + return 0; + return -ENODEV; + } + } +#if 0 + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_HAMOA_DAC_LEFT1, EMU_SRC_ALICE_EMU32B + 2); /* ALICE2 bus 0xa2 */ + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_HAMOA_DAC_RIGHT1, EMU_SRC_ALICE_EMU32B + 3); /* ALICE2 bus 0xa3 */ + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_HANA_SPDIF_LEFT1, EMU_SRC_ALICE_EMU32A + 2); /* ALICE2 bus 0xb2 */ + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_HANA_SPDIF_RIGHT1, EMU_SRC_ALICE_EMU32A + 3); /* ALICE2 bus 0xb3 */ +#endif + /* Default outputs */ + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_DOCK_DAC1_LEFT1, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */ + emu->emu1010.output_source[0] = 21; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_DOCK_DAC1_RIGHT1, EMU_SRC_ALICE_EMU32A + 1); + emu->emu1010.output_source[1] = 22; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_DOCK_DAC2_LEFT1, EMU_SRC_ALICE_EMU32A + 2); + emu->emu1010.output_source[2] = 23; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_DOCK_DAC2_RIGHT1, EMU_SRC_ALICE_EMU32A + 3); + emu->emu1010.output_source[3] = 24; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_DOCK_DAC3_LEFT1, EMU_SRC_ALICE_EMU32A + 4); + emu->emu1010.output_source[4] = 25; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_DOCK_DAC3_RIGHT1, EMU_SRC_ALICE_EMU32A + 5); + emu->emu1010.output_source[5] = 26; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_DOCK_DAC4_LEFT1, EMU_SRC_ALICE_EMU32A + 6); + emu->emu1010.output_source[6] = 27; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_DOCK_DAC4_RIGHT1, EMU_SRC_ALICE_EMU32A + 7); + emu->emu1010.output_source[7] = 28; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_DOCK_PHONES_LEFT1, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */ + emu->emu1010.output_source[8] = 21; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_DOCK_PHONES_RIGHT1, EMU_SRC_ALICE_EMU32A + 1); + emu->emu1010.output_source[9] = 22; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_DOCK_SPDIF_LEFT1, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */ + emu->emu1010.output_source[10] = 21; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_DOCK_SPDIF_RIGHT1, EMU_SRC_ALICE_EMU32A + 1); + emu->emu1010.output_source[11] = 22; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_HANA_SPDIF_LEFT1, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */ + emu->emu1010.output_source[12] = 21; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_HANA_SPDIF_RIGHT1, EMU_SRC_ALICE_EMU32A + 1); + emu->emu1010.output_source[13] = 22; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_HAMOA_DAC_LEFT1, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */ + emu->emu1010.output_source[14] = 21; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_HAMOA_DAC_RIGHT1, EMU_SRC_ALICE_EMU32A + 1); + emu->emu1010.output_source[15] = 22; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_HANA_ADAT, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */ + emu->emu1010.output_source[16] = 21; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_HANA_ADAT + 1, EMU_SRC_ALICE_EMU32A + 1); + emu->emu1010.output_source[17] = 22; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_HANA_ADAT + 2, EMU_SRC_ALICE_EMU32A + 2); + emu->emu1010.output_source[18] = 23; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_HANA_ADAT + 3, EMU_SRC_ALICE_EMU32A + 3); + emu->emu1010.output_source[19] = 24; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_HANA_ADAT + 4, EMU_SRC_ALICE_EMU32A + 4); + emu->emu1010.output_source[20] = 25; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_HANA_ADAT + 5, EMU_SRC_ALICE_EMU32A + 5); + emu->emu1010.output_source[21] = 26; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_HANA_ADAT + 6, EMU_SRC_ALICE_EMU32A + 6); + emu->emu1010.output_source[22] = 27; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_HANA_ADAT + 7, EMU_SRC_ALICE_EMU32A + 7); + emu->emu1010.output_source[23] = 28; + + /* TEMP: Select SPDIF in/out */ + snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, 0x0); /* Output spdif */ + + /* TEMP: Select 48kHz SPDIF out */ + snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, 0x0); /* Mute all */ + snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, 0x0); /* Default fallback clock 48kHz */ + /* Word Clock source, Internal 48kHz x1 */ + snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K ); + //snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_4X ); + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12);/* Set LEDs on Audio Dock */ + snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, 0x1); /* Unmute all */ + //snd_emu1010_fpga_write(emu, 0x7, 0x0); /* Mute all */ + //snd_emu1010_fpga_write(emu, 0x7, 0x1); /* Unmute all */ + //snd_emu1010_fpga_write(emu, 0xe, 0x12); /* Set LEDs on Audio Dock */ return 0; } @@ -747,6 +1038,10 @@ static int snd_emu10k1_free(struct snd_emu10k1 *emu) } snd_emu10k1_free_efx(emu); } + if (emu->card_capabilities->emu1010) { + /* Disable 48Volt power to Audio Dock */ + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0 ); + } if (emu->memhdr) snd_util_memhdr_free(emu->memhdr); if (emu->silent_page.area) @@ -865,11 +1160,12 @@ static struct snd_emu_chip_details emu_chip_details[] = { .ac97_chip = 1} , /* Tested by James@superbug.co.uk 8th July 2005. No sound available yet. */ {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x40011102, - .driver = "Audigy2", .name = "E-mu 1212m [4001]", - .id = "EMU1212m", + .driver = "Audigy2", .name = "E-mu 1010 [4001]", + .id = "EMU1010", .emu10k2_chip = 1, .ca0102_chip = 1, - .emu1212m = 1} , + .spk71 = 1, + .emu1010 = 1} , /* Tested by James@superbug.co.uk 3rd July 2005 */ {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20071102, .driver = "Audigy2", .name = "Audigy 4 PRO [SB0380]", @@ -1297,8 +1593,8 @@ int __devinit snd_emu10k1_create(struct snd_card *card, } else if (emu->card_capabilities->ca_cardbus_chip) { if ((err = snd_emu10k1_cardbus_init(emu)) < 0) goto error; - } else if (emu->card_capabilities->emu1212m) { - if ((err = snd_emu10k1_emu1212m_init(emu)) < 0) { + } else if (emu->card_capabilities->emu1010) { + if ((err = snd_emu10k1_emu1010_init(emu)) < 0) { snd_emu10k1_free(emu); return err; } @@ -1446,8 +1742,8 @@ void snd_emu10k1_resume_init(struct snd_emu10k1 *emu) snd_emu10k1_ecard_init(emu); else if (emu->card_capabilities->ca_cardbus_chip) snd_emu10k1_cardbus_init(emu); - else if (emu->card_capabilities->emu1212m) - snd_emu10k1_emu1212m_init(emu); + else if (emu->card_capabilities->emu1010) + snd_emu10k1_emu1010_init(emu); else snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE); snd_emu10k1_init(emu, emu->enable_ir, 1); diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c index 2199b42a601..bb0fec7f7e1 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c @@ -460,7 +460,7 @@ static int snd_emu10k1x_pcm_prepare(struct snd_pcm_substream *substream) u32 period_size_bytes = frames_to_bytes(runtime, runtime->period_size); int i; - for(i=0; i < runtime->periods; i++) { + for(i = 0; i < runtime->periods; i++) { *table_base++=runtime->dma_addr+(i*period_size_bytes); *table_base++=period_size_bytes<<16; } @@ -1042,8 +1042,8 @@ static void snd_emu10k1x_proc_reg_write(struct snd_info_entry *entry, if (sscanf(line, "%x %x %x", ®, &channel_id, &val) != 3) continue; - if ((reg < 0x49) && (reg >=0) && (val <= 0xffffffff) - && (channel_id >=0) && (channel_id <= 2) ) + if ((reg < 0x49) && (reg >= 0) && (val <= 0xffffffff) + && (channel_id >= 0) && (channel_id <= 2) ) snd_emu10k1x_ptr_write(emu, reg, channel_id, val); } } diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c index 13cd6ce8981..d8e8db89535 100644 --- a/sound/pci/emu10k1/emufx.c +++ b/sound/pci/emu10k1/emufx.c @@ -3,6 +3,9 @@ * Creative Labs, Inc. * Routines for effect processor FX8010 * + * Copyright (c) by James Courtier-Dutton + * Added EMU 1010 support. + * * BUGS: * -- * @@ -1069,6 +1072,21 @@ snd_emu10k1_init_stereo_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl ctl->translation = EMU10K1_GPR_TRANSLATION_ONOFF; } +static int snd_emu10k1_audigy_dsp_convert_32_to_2x16( + struct snd_emu10k1_fx8010_code *icode, + u32 *ptr, int tmp, int bit_shifter16, + int reg_in, int reg_out) +{ + A_OP(icode, ptr, iACC3, A_GPR(tmp + 1), reg_in, A_C_00000000, A_C_00000000); + A_OP(icode, ptr, iANDXOR, A_GPR(tmp), A_GPR(tmp + 1), A_GPR(bit_shifter16 - 1), A_C_00000000); + A_OP(icode, ptr, iTSTNEG, A_GPR(tmp + 2), A_GPR(tmp), A_C_80000000, A_GPR(bit_shifter16 - 2)); + A_OP(icode, ptr, iANDXOR, A_GPR(tmp + 2), A_GPR(tmp + 2), A_C_80000000, A_C_00000000); + A_OP(icode, ptr, iANDXOR, A_GPR(tmp), A_GPR(tmp), A_GPR(bit_shifter16 - 3), A_C_00000000); + A_OP(icode, ptr, iMACINT0, A_GPR(tmp), A_C_00000000, A_GPR(tmp), A_C_00010000); + A_OP(icode, ptr, iANDXOR, reg_out, A_GPR(tmp), A_C_ffffffff, A_GPR(tmp + 2)); + A_OP(icode, ptr, iACC3, reg_out + 1, A_GPR(tmp + 1), A_C_00000000, A_C_00000000); + return 1; +} /* * initial DSP configuration for Audigy @@ -1077,6 +1095,7 @@ snd_emu10k1_init_stereo_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl static int __devinit _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu) { int err, i, z, gpr, nctl; + int bit_shifter16; const int playback = 10; const int capture = playback + (SND_EMU10K1_PLAYBACK_CHANNELS * 2); /* we reserve 10 voices */ const int stereo_mix = capture + 2; @@ -1114,17 +1133,14 @@ static int __devinit _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu) ptr = 0; nctl = 0; gpr = stereo_mix + 10; + gpr_map[gpr++] = 0x00007fff; + gpr_map[gpr++] = 0x00008000; + gpr_map[gpr++] = 0x0000ffff; + bit_shifter16 = gpr; /* stop FX processor */ snd_emu10k1_ptr_write(emu, A_DBG, 0, (emu->fx8010.dbg = 0) | A_DBG_SINGLE_STEP); -#if 0 - /* FIX: jcd test */ - for (z = 0; z < 80; z=z+2) { - A_OP(icode, &ptr, iACC3, A_EXTOUT(z), A_FXBUS(FXBUS_PCM_LEFT_FRONT), A_C_00000000, A_C_00000000); /* left */ - A_OP(icode, &ptr, iACC3, A_EXTOUT(z+1), A_FXBUS(FXBUS_PCM_RIGHT_FRONT), A_C_00000000, A_C_00000000); /* right */ - } -#endif /* jcd test */ #if 1 /* PCM front Playback Volume (independent from stereo mix) */ A_OP(icode, &ptr, iMAC0, A_GPR(playback), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_FRONT)); @@ -1182,13 +1198,20 @@ static int __devinit _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu) A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+1), A_FXBUS(FXBUS_MIDI_RIGHT)); snd_emu10k1_init_stereo_control(&controls[nctl++], "Synth Capture Volume", gpr, 0); gpr += 2; - + /* * inputs */ #define A_ADD_VOLUME_IN(var,vol,input) \ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) + /* emu1212 DSP 0 and DSP 1 Capture */ + if (emu->card_capabilities->emu1010) { + A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_GPR(capture+0), A_GPR(gpr), A_P16VIN(0x0)); + A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+1), A_P16VIN(0x1)); + snd_emu10k1_init_stereo_control(&controls[nctl++], "EMU Capture Volume", gpr, 0); + gpr += 2; + } /* AC'97 Playback Volume - used only for mic (renamed later) */ A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_AC97_L); A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_AC97_R); @@ -1429,6 +1452,13 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) /* digital outputs */ /* A_PUT_STEREO_OUTPUT(A_EXTOUT_FRONT_L, A_EXTOUT_FRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS); */ + if (emu->card_capabilities->emu1010) { + /* EMU1010 Outputs from PCM Front, Rear, Center, LFE, Side */ + snd_printk("EMU outputs on\n"); + for (z = 0; z < 8; z++) { + A_OP(icode, &ptr, iACC3, A_EMU32OUTL(z), A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), A_C_00000000, A_C_00000000); + } + } /* IEC958 Optical Raw Playback Switch */ gpr_map[gpr++] = 0; @@ -1466,9 +1496,57 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) A_PUT_OUTPUT(A_EXTOUT_ADC_CAP_R, capture+1); #endif - /* EFX capture - capture the 16 EXTINs */ - for (z = 0; z < 16; z++) { - A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_EXTIN(z)); + if (emu->card_capabilities->emu1010) { + snd_printk("EMU inputs on\n"); + /* Capture 8 channels of S32_LE sound */ + + /* printk("emufx.c: gpr=0x%x, tmp=0x%x\n",gpr, tmp); */ + /* For the EMU1010: How to get 32bit values from the DSP. High 16bits into L, low 16bits into R. */ + /* A_P16VIN(0) is delayed by one sample, + * so all other A_P16VIN channels will need to also be delayed + */ + /* Left ADC in. 1 of 2 */ + snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_P16VIN(0x0), A_FXBUS2(0) ); + /* Right ADC in 1 of 2 */ + gpr_map[gpr++] = 0x00000000; + snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(2) ); + A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x1), A_C_00000000, A_C_00000000); + gpr_map[gpr++] = 0x00000000; + snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(4) ); + A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x2), A_C_00000000, A_C_00000000); + gpr_map[gpr++] = 0x00000000; + snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(6) ); + A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x3), A_C_00000000, A_C_00000000); + /* For 96kHz mode */ + /* Left ADC in. 2 of 2 */ + gpr_map[gpr++] = 0x00000000; + snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0x8) ); + A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x4), A_C_00000000, A_C_00000000); + /* Right ADC in 2 of 2 */ + gpr_map[gpr++] = 0x00000000; + snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xa) ); + A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x5), A_C_00000000, A_C_00000000); + gpr_map[gpr++] = 0x00000000; + snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xc) ); + A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x6), A_C_00000000, A_C_00000000); + gpr_map[gpr++] = 0x00000000; + snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xe) ); + A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x7), A_C_00000000, A_C_00000000); + +#if 0 + for (z = 4; z < 8; z++) { + A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_C_00000000); + } + for (z = 0xc; z < 0x10; z++) { + A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_C_00000000); + } +#endif + } else { + /* EFX capture - capture the 16 EXTINs */ + /* Capture 16 channels of S16_LE sound */ + for (z = 0; z < 16; z++) { + A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_EXTIN(z)); + } } #endif /* JCD test */ @@ -2138,7 +2216,7 @@ void snd_emu10k1_free_efx(struct snd_emu10k1 *emu) snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg = EMU10K1_DBG_SINGLE_STEP); } -#if 0 // FIXME: who use them? +#if 0 /* FIXME: who use them? */ int snd_emu10k1_fx8010_tone_control_activate(struct snd_emu10k1 *emu, int output) { if (output < 0 || output >= 6) diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index c31f3d0877f..c8176dc8142 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c @@ -5,6 +5,9 @@ * Routines for control of EMU10K1 chips / mixer routines * Multichannel PCM support Copyright (c) Lee Revell * + * Copyright (c) by James Courtier-Dutton + * Added EMU 1010 support. + * * BUGS: * -- * @@ -68,6 +71,311 @@ static int snd_emu10k1_spdif_get_mask(struct snd_kcontrol *kcontrol, return 0; } +static char *emu1010_src_texts[] = { + "Silence", + "Dock Mic A", + "Dock Mic B", + "Dock ADC1 Left", + "Dock ADC1 Right", + "Dock ADC2 Left", + "Dock ADC2 Right", + "Dock ADC3 Left", + "Dock ADC3 Right", + "0202 ADC Left", + "0202 ADC Right", + "0202 SPDIF Left", + "0202 SPDIF Right", + "ADAT 0", + "ADAT 1", + "ADAT 2", + "ADAT 3", + "ADAT 4", + "ADAT 5", + "ADAT 6", + "ADAT 7", + "DSP 0", + "DSP 1", + "DSP 2", + "DSP 3", + "DSP 4", + "DSP 5", + "DSP 6", + "DSP 7", + "DSP 8", + "DSP 9", + "DSP 10", + "DSP 11", + "DSP 12", + "DSP 13", + "DSP 14", + "DSP 15", + "DSP 16", + "DSP 17", + "DSP 18", + "DSP 19", + "DSP 20", + "DSP 21", + "DSP 22", + "DSP 23", + "DSP 24", + "DSP 25", + "DSP 26", + "DSP 27", + "DSP 28", + "DSP 29", + "DSP 30", + "DSP 31", +}; + +static unsigned int emu1010_src_regs[] = { + EMU_SRC_SILENCE,/* 0 */ + EMU_SRC_DOCK_MIC_A1, /* 1 */ + EMU_SRC_DOCK_MIC_B1, /* 2 */ + EMU_SRC_DOCK_ADC1_LEFT1, /* 3 */ + EMU_SRC_DOCK_ADC1_RIGHT1, /* 4 */ + EMU_SRC_DOCK_ADC2_LEFT1, /* 5 */ + EMU_SRC_DOCK_ADC2_RIGHT1, /* 6 */ + EMU_SRC_DOCK_ADC3_LEFT1, /* 7 */ + EMU_SRC_DOCK_ADC3_RIGHT1, /* 8 */ + EMU_SRC_HAMOA_ADC_LEFT1, /* 9 */ + EMU_SRC_HAMOA_ADC_RIGHT1, /* 10 */ + EMU_SRC_HANA_SPDIF_LEFT1, /* 11 */ + EMU_SRC_HANA_SPDIF_RIGHT1, /* 12 */ + EMU_SRC_HANA_ADAT, /* 13 */ + EMU_SRC_HANA_ADAT+1, /* 14 */ + EMU_SRC_HANA_ADAT+2, /* 15 */ + EMU_SRC_HANA_ADAT+3, /* 16 */ + EMU_SRC_HANA_ADAT+4, /* 17 */ + EMU_SRC_HANA_ADAT+5, /* 18 */ + EMU_SRC_HANA_ADAT+6, /* 19 */ + EMU_SRC_HANA_ADAT+7, /* 20 */ + EMU_SRC_ALICE_EMU32A, /* 21 */ + EMU_SRC_ALICE_EMU32A+1, /* 22 */ + EMU_SRC_ALICE_EMU32A+2, /* 23 */ + EMU_SRC_ALICE_EMU32A+3, /* 24 */ + EMU_SRC_ALICE_EMU32A+4, /* 25 */ + EMU_SRC_ALICE_EMU32A+5, /* 26 */ + EMU_SRC_ALICE_EMU32A+6, /* 27 */ + EMU_SRC_ALICE_EMU32A+7, /* 28 */ + EMU_SRC_ALICE_EMU32A+8, /* 29 */ + EMU_SRC_ALICE_EMU32A+9, /* 30 */ + EMU_SRC_ALICE_EMU32A+0xa, /* 31 */ + EMU_SRC_ALICE_EMU32A+0xb, /* 32 */ + EMU_SRC_ALICE_EMU32A+0xc, /* 33 */ + EMU_SRC_ALICE_EMU32A+0xd, /* 34 */ + EMU_SRC_ALICE_EMU32A+0xe, /* 35 */ + EMU_SRC_ALICE_EMU32A+0xf, /* 36 */ + EMU_SRC_ALICE_EMU32B, /* 37 */ + EMU_SRC_ALICE_EMU32B+1, /* 38 */ + EMU_SRC_ALICE_EMU32B+2, /* 39 */ + EMU_SRC_ALICE_EMU32B+3, /* 40 */ + EMU_SRC_ALICE_EMU32B+4, /* 41 */ + EMU_SRC_ALICE_EMU32B+5, /* 42 */ + EMU_SRC_ALICE_EMU32B+6, /* 43 */ + EMU_SRC_ALICE_EMU32B+7, /* 44 */ + EMU_SRC_ALICE_EMU32B+8, /* 45 */ + EMU_SRC_ALICE_EMU32B+9, /* 46 */ + EMU_SRC_ALICE_EMU32B+0xa, /* 47 */ + EMU_SRC_ALICE_EMU32B+0xb, /* 48 */ + EMU_SRC_ALICE_EMU32B+0xc, /* 49 */ + EMU_SRC_ALICE_EMU32B+0xd, /* 50 */ + EMU_SRC_ALICE_EMU32B+0xe, /* 51 */ + EMU_SRC_ALICE_EMU32B+0xf, /* 52 */ +}; + +static unsigned int emu1010_output_dst[] = { + EMU_DST_DOCK_DAC1_LEFT1, /* 0 */ + EMU_DST_DOCK_DAC1_RIGHT1, /* 1 */ + EMU_DST_DOCK_DAC2_LEFT1, /* 2 */ + EMU_DST_DOCK_DAC2_RIGHT1, /* 3 */ + EMU_DST_DOCK_DAC3_LEFT1, /* 4 */ + EMU_DST_DOCK_DAC3_RIGHT1, /* 5 */ + EMU_DST_DOCK_DAC4_LEFT1, /* 6 */ + EMU_DST_DOCK_DAC4_RIGHT1, /* 7 */ + EMU_DST_DOCK_PHONES_LEFT1, /* 8 */ + EMU_DST_DOCK_PHONES_RIGHT1, /* 9 */ + EMU_DST_DOCK_SPDIF_LEFT1, /* 10 */ + EMU_DST_DOCK_SPDIF_RIGHT1, /* 11 */ + EMU_DST_HANA_SPDIF_LEFT1, /* 12 */ + EMU_DST_HANA_SPDIF_RIGHT1, /* 13 */ + EMU_DST_HAMOA_DAC_LEFT1, /* 14 */ + EMU_DST_HAMOA_DAC_RIGHT1, /* 15 */ + EMU_DST_HANA_ADAT, /* 16 */ + EMU_DST_HANA_ADAT+1, /* 17 */ + EMU_DST_HANA_ADAT+2, /* 18 */ + EMU_DST_HANA_ADAT+3, /* 19 */ + EMU_DST_HANA_ADAT+4, /* 20 */ + EMU_DST_HANA_ADAT+5, /* 21 */ + EMU_DST_HANA_ADAT+6, /* 22 */ + EMU_DST_HANA_ADAT+7, /* 23 */ +}; + +static unsigned int emu1010_input_dst[] = { + EMU_DST_ALICE2_EMU32_0, + EMU_DST_ALICE2_EMU32_1, + EMU_DST_ALICE2_EMU32_2, + EMU_DST_ALICE2_EMU32_3, + EMU_DST_ALICE2_EMU32_4, + EMU_DST_ALICE2_EMU32_5, + EMU_DST_ALICE2_EMU32_6, + EMU_DST_ALICE2_EMU32_7, + EMU_DST_ALICE2_EMU32_8, + EMU_DST_ALICE2_EMU32_9, + EMU_DST_ALICE2_EMU32_A, + EMU_DST_ALICE2_EMU32_B, + EMU_DST_ALICE2_EMU32_C, + EMU_DST_ALICE2_EMU32_D, + EMU_DST_ALICE2_EMU32_E, + EMU_DST_ALICE2_EMU32_F, + EMU_DST_ALICE_I2S0_LEFT, + EMU_DST_ALICE_I2S0_RIGHT, + EMU_DST_ALICE_I2S1_LEFT, + EMU_DST_ALICE_I2S1_RIGHT, + EMU_DST_ALICE_I2S2_LEFT, + EMU_DST_ALICE_I2S2_RIGHT, +}; + +static int snd_emu1010_input_output_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 53; + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, emu1010_src_texts[uinfo->value.enumerated.item]); + return 0; +} + +static int snd_emu1010_output_source_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); + int channel; + + channel = (kcontrol->private_value) & 0xff; + ucontrol->value.enumerated.item[0] = emu->emu1010.output_source[channel]; + return 0; +} + +static int snd_emu1010_output_source_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); + int change = 0; + unsigned int val; + int channel; + + channel = (kcontrol->private_value) & 0xff; + if (emu->emu1010.output_source[channel] != ucontrol->value.enumerated.item[0]) { + val = emu->emu1010.output_source[channel] = ucontrol->value.enumerated.item[0]; + change = 1; + snd_emu1010_fpga_link_dst_src_write(emu, + emu1010_output_dst[channel], emu1010_src_regs[val]); + } + return change; +} + +static int snd_emu1010_input_source_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); + int channel; + + channel = (kcontrol->private_value) & 0xff; + ucontrol->value.enumerated.item[0] = emu->emu1010.input_source[channel]; + return 0; +} + +static int snd_emu1010_input_source_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); + int change = 0; + unsigned int val; + int channel; + + channel = (kcontrol->private_value) & 0xff; + if (emu->emu1010.input_source[channel] != ucontrol->value.enumerated.item[0]) { + val = emu->emu1010.input_source[channel] = ucontrol->value.enumerated.item[0]; + change = 1; + snd_emu1010_fpga_link_dst_src_write(emu, + emu1010_input_dst[channel], emu1010_src_regs[val]); + } + return change; +} + +#define EMU1010_SOURCE_OUTPUT(xname,chid) \ +{ \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ + .info = snd_emu1010_input_output_source_info, \ + .get = snd_emu1010_output_source_get, \ + .put = snd_emu1010_output_source_put, \ + .private_value = chid \ +} + +static struct snd_kcontrol_new snd_emu1010_output_enum_ctls[] __devinitdata = { + EMU1010_SOURCE_OUTPUT("Playback Dock DAC1 Left", 0), + EMU1010_SOURCE_OUTPUT("Playback Dock DAC1 Right", 1), + EMU1010_SOURCE_OUTPUT("Playback Dock DAC2 Left", 2), + EMU1010_SOURCE_OUTPUT("Playback Dock DAC2 Right", 3), + EMU1010_SOURCE_OUTPUT("Playback Dock DAC3 Left", 4), + EMU1010_SOURCE_OUTPUT("Playback Dock DAC3 Right", 5), + EMU1010_SOURCE_OUTPUT("Playback Dock DAC4 Left", 6), + EMU1010_SOURCE_OUTPUT("Playback Dock DAC4 Right", 7), + EMU1010_SOURCE_OUTPUT("Playback Dock Phones Left", 8), + EMU1010_SOURCE_OUTPUT("Playback Dock Phones Right", 9), + EMU1010_SOURCE_OUTPUT("Playback Dock SPDIF Left", 0xa), + EMU1010_SOURCE_OUTPUT("Playback Dock SPDIF Right", 0xb), + EMU1010_SOURCE_OUTPUT("Playback 1010 SPDIF Left", 0xc), + EMU1010_SOURCE_OUTPUT("Playback 1010 SPDIF Right", 0xd), + EMU1010_SOURCE_OUTPUT("Playback 0202 DAC Left", 0xe), + EMU1010_SOURCE_OUTPUT("Playback 0202 DAC Right", 0xf), + EMU1010_SOURCE_OUTPUT("Playback 1010 ADAT 0", 0x10), + EMU1010_SOURCE_OUTPUT("Playback 1010 ADAT 1", 0x11), + EMU1010_SOURCE_OUTPUT("Playback 1010 ADAT 2", 0x12), + EMU1010_SOURCE_OUTPUT("Playback 1010 ADAT 3", 0x13), + EMU1010_SOURCE_OUTPUT("Playback 1010 ADAT 4", 0x14), + EMU1010_SOURCE_OUTPUT("Playback 1010 ADAT 5", 0x15), + EMU1010_SOURCE_OUTPUT("Playback 1010 ADAT 6", 0x16), + EMU1010_SOURCE_OUTPUT("Playback 1010 ADAT 7", 0x17), +}; + +#define EMU1010_SOURCE_INPUT(xname,chid) \ +{ \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ + .info = snd_emu1010_input_output_source_info, \ + .get = snd_emu1010_input_source_get, \ + .put = snd_emu1010_input_source_put, \ + .private_value = chid \ +} + +static struct snd_kcontrol_new snd_emu1010_input_enum_ctls[] __devinitdata = { + EMU1010_SOURCE_INPUT("DSP 0 CAPTURE ENUM", 0), + EMU1010_SOURCE_INPUT("DSP 1 CAPTURE ENUM", 1), + EMU1010_SOURCE_INPUT("DSP 2 CAPTURE ENUM", 2), + EMU1010_SOURCE_INPUT("DSP 3 CAPTURE ENUM", 3), + EMU1010_SOURCE_INPUT("DSP 4 CAPTURE ENUM", 4), + EMU1010_SOURCE_INPUT("DSP 5 CAPTURE ENUM", 5), + EMU1010_SOURCE_INPUT("DSP 6 CAPTURE ENUM", 6), + EMU1010_SOURCE_INPUT("DSP 7 CAPTURE ENUM", 7), + EMU1010_SOURCE_INPUT("DSP 8 CAPTURE ENUM", 8), + EMU1010_SOURCE_INPUT("DSP 9 CAPTURE ENUM", 9), + EMU1010_SOURCE_INPUT("DSP A CAPTURE ENUM", 0xa), + EMU1010_SOURCE_INPUT("DSP B CAPTURE ENUM", 0xb), + EMU1010_SOURCE_INPUT("DSP C CAPTURE ENUM", 0xc), + EMU1010_SOURCE_INPUT("DSP D CAPTURE ENUM", 0xd), + EMU1010_SOURCE_INPUT("DSP E CAPTURE ENUM", 0xe), + EMU1010_SOURCE_INPUT("DSP F CAPTURE ENUM", 0xf), + EMU1010_SOURCE_INPUT("DSP 10 CAPTURE ENUM", 0x10), + EMU1010_SOURCE_INPUT("DSP 11 CAPTURE ENUM", 0x11), + EMU1010_SOURCE_INPUT("DSP 12 CAPTURE ENUM", 0x12), + EMU1010_SOURCE_INPUT("DSP 13 CAPTURE ENUM", 0x13), + EMU1010_SOURCE_INPUT("DSP 14 CAPTURE ENUM", 0x14), + EMU1010_SOURCE_INPUT("DSP 15 CAPTURE ENUM", 0x15), +}; + #if 0 static int snd_audigy_spdif_output_rate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -1021,7 +1329,7 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, return err; } - if ( emu->card_capabilities->emu1212m) { + if ( emu->card_capabilities->emu1010) { ; /* Disable the snd_audigy_spdif_shared_spdif */ } else if (emu->audigy) { if ((kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu)) == NULL) @@ -1045,6 +1353,21 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, if ((err = snd_p16v_mixer(emu))) return err; } + + if ( emu->card_capabilities->emu1010) { + int i; + + for (i = 0; i < ARRAY_SIZE(snd_emu1010_output_enum_ctls); i++) { + err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_output_enum_ctls[i], emu)); + if (err < 0) + return err; + } + for (i = 0; i < ARRAY_SIZE(snd_emu1010_input_enum_ctls); i++) { + err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_input_enum_ctls[i], emu)); + if (err < 0) + return err; + } + } return 0; } diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index 717e92ec9e0..44d098ac86d 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c @@ -147,7 +147,7 @@ static int snd_emu10k1_pcm_channel_alloc(struct snd_emu10k1_pcm * epcm, int voic 1, &epcm->extra); if (err < 0) { - // printk("pcm_channel_alloc: failed extra: voices=%d, frame=%d\n", voices, frame); + /* printk("pcm_channel_alloc: failed extra: voices=%d, frame=%d\n", voices, frame); */ for (i = 0; i < voices; i++) { snd_emu10k1_voice_free(epcm->emu, epcm->voices[i]); epcm->voices[i] = NULL; @@ -339,7 +339,7 @@ static void snd_emu10k1_pcm_init_voice(struct snd_emu10k1 *emu, } } - // setup routing + /* setup routing */ if (emu->audigy) { snd_emu10k1_ptr_write(emu, A_FXRT1, voice, snd_emu10k1_compose_audigy_fxrt1(send_routing)); @@ -353,8 +353,8 @@ static void snd_emu10k1_pcm_init_voice(struct snd_emu10k1 *emu, } else snd_emu10k1_ptr_write(emu, FXRT, voice, snd_emu10k1_compose_send_routing(send_routing)); - // Stop CA - // Assumption that PT is already 0 so no harm overwriting + /* Stop CA */ + /* Assumption that PT is already 0 so no harm overwriting */ snd_emu10k1_ptr_write(emu, PTRX, voice, (send_amount[0] << 8) | send_amount[1]); snd_emu10k1_ptr_write(emu, DSL, voice, end_addr | (send_amount[3] << 24)); snd_emu10k1_ptr_write(emu, PSST, voice, start_addr | (send_amount[2] << 24)); @@ -367,14 +367,14 @@ static void snd_emu10k1_pcm_init_voice(struct snd_emu10k1 *emu, snd_emu10k1_ptr_write(emu, CCCA, voice, (start_addr + ccis) | emu10k1_select_interprom(pitch_target) | (w_16 ? 0 : CCCA_8BITSELECT)); - // Clear filter delay memory + /* Clear filter delay memory */ snd_emu10k1_ptr_write(emu, Z1, voice, 0); snd_emu10k1_ptr_write(emu, Z2, voice, 0); - // invalidate maps + /* invalidate maps */ silent_page = ((unsigned int)emu->silent_page.addr << 1) | MAP_PTI_MASK; snd_emu10k1_ptr_write(emu, MAPA, voice, silent_page); snd_emu10k1_ptr_write(emu, MAPB, voice, silent_page); - // modulation envelope + /* modulation envelope */ snd_emu10k1_ptr_write(emu, CVCF, voice, 0xffff); snd_emu10k1_ptr_write(emu, VTFT, voice, 0xffff); snd_emu10k1_ptr_write(emu, ATKHLDM, voice, 0); @@ -385,12 +385,12 @@ static void snd_emu10k1_pcm_init_voice(struct snd_emu10k1 *emu, snd_emu10k1_ptr_write(emu, TREMFRQ, voice, 0); snd_emu10k1_ptr_write(emu, FM2FRQ2, voice, 0); snd_emu10k1_ptr_write(emu, ENVVAL, voice, 0x8000); - // volume envelope + /* volume envelope */ snd_emu10k1_ptr_write(emu, ATKHLDV, voice, 0x7f7f); snd_emu10k1_ptr_write(emu, ENVVOL, voice, 0x0000); - // filter envelope + /* filter envelope */ snd_emu10k1_ptr_write(emu, PEFE_FILTERAMOUNT, voice, 0x7f); - // pitch envelope + /* pitch envelope */ snd_emu10k1_ptr_write(emu, PEFE_PITCHAMOUNT, voice, 0); spin_unlock_irqrestore(&emu->reg_lock, flags); @@ -468,7 +468,7 @@ static int snd_emu10k1_efx_playback_hw_free(struct snd_pcm_substream *substream) snd_emu10k1_voice_free(epcm->emu, epcm->extra); epcm->extra = NULL; } - for (i=0; i < NUM_EFX_PLAYBACK; i++) { + for (i = 0; i < NUM_EFX_PLAYBACK; i++) { if (epcm->voices[i]) { snd_emu10k1_voice_free(epcm->emu, epcm->voices[i]); epcm->voices[i] = NULL; @@ -637,7 +637,7 @@ static void snd_emu10k1_playback_invalidate_cache(struct snd_emu10k1 *emu, int e stereo = (!extra && runtime->channels == 2); sample = snd_pcm_format_width(runtime->format) == 16 ? 0 : 0x80808080; ccis = emu10k1_ccis(stereo, sample == 0); - // set cs to 2 * number of cache registers beside the invalidated + /* set cs to 2 * number of cache registers beside the invalidated */ cs = (sample == 0) ? (32-ccis) : (64-ccis+1) >> 1; if (cs > 16) cs = 16; for (i = 0; i < cs; i++) { @@ -646,14 +646,14 @@ static void snd_emu10k1_playback_invalidate_cache(struct snd_emu10k1 *emu, int e snd_emu10k1_ptr_write(emu, CD0 + i, voice + 1, sample); } } - // reset cache + /* reset cache */ snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice, 0); snd_emu10k1_ptr_write(emu, CCR_READADDRESS, voice, cra); if (stereo) { snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice + 1, 0); snd_emu10k1_ptr_write(emu, CCR_READADDRESS, voice + 1, cra); } - // fill cache + /* fill cache */ snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice, ccis); if (stereo) { snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice+1, ccis); @@ -732,7 +732,7 @@ static int snd_emu10k1_playback_trigger(struct snd_pcm_substream *substream, struct snd_emu10k1_pcm_mixer *mix; int result = 0; - // printk("trigger - emu10k1 = 0x%x, cmd = %i, pointer = %i\n", (int)emu, cmd, substream->ops->pointer(substream)); + /* printk("trigger - emu10k1 = 0x%x, cmd = %i, pointer = %i\n", (int)emu, cmd, substream->ops->pointer(substream)); */ spin_lock(&emu->reg_lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -778,10 +778,10 @@ static int snd_emu10k1_capture_trigger(struct snd_pcm_substream *substream, switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: - // hmm this should cause full and half full interrupt to be raised? + /* hmm this should cause full and half full interrupt to be raised? */ outl(epcm->capture_ipr, emu->port + IPR); snd_emu10k1_intr_enable(emu, epcm->capture_inte); - // printk("adccr = 0x%x, adcbs = 0x%x\n", epcm->adccr, epcm->adcbs); + /* printk("adccr = 0x%x, adcbs = 0x%x\n", epcm->adccr, epcm->adcbs); */ switch (epcm->type) { case CAPTURE_AC97ADC: snd_emu10k1_ptr_write(emu, ADCCR, 0, epcm->capture_cr_val); @@ -790,6 +790,7 @@ static int snd_emu10k1_capture_trigger(struct snd_pcm_substream *substream, if (emu->audigy) { snd_emu10k1_ptr_write(emu, A_FXWC1, 0, epcm->capture_cr_val); snd_emu10k1_ptr_write(emu, A_FXWC2, 0, epcm->capture_cr_val2); + snd_printdd("cr_val=0x%x, cr_val2=0x%x\n", epcm->capture_cr_val, epcm->capture_cr_val2); } else snd_emu10k1_ptr_write(emu, FXWC, 0, epcm->capture_cr_val); break; @@ -851,7 +852,7 @@ static snd_pcm_uframes_t snd_emu10k1_playback_pointer(struct snd_pcm_substream * ptr -= runtime->buffer_size; } #endif - // printk("ptr = 0x%x, buffer_size = 0x%x, period_size = 0x%x\n", ptr, runtime->buffer_size, runtime->period_size); + /* printk("ptr = 0x%x, buffer_size = 0x%x, period_size = 0x%x\n", ptr, runtime->buffer_size, runtime->period_size); */ return ptr; } @@ -868,7 +869,7 @@ static int snd_emu10k1_efx_playback_trigger(struct snd_pcm_substream *substream, spin_lock(&emu->reg_lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: - // prepare voices + /* prepare voices */ for (i = 0; i < NUM_EFX_PLAYBACK; i++) { snd_emu10k1_playback_invalidate_cache(emu, 0, epcm->voices[i]); } @@ -917,7 +918,7 @@ static snd_pcm_uframes_t snd_emu10k1_capture_pointer(struct snd_pcm_substream *s if (!epcm->running) return 0; if (epcm->first_ptr) { - udelay(50); // hack, it takes awhile until capture is started + udelay(50); /* hack, it takes awhile until capture is started */ epcm->first_ptr = 0; } ptr = snd_emu10k1_ptr_read(emu, epcm->capture_idx_reg, 0) & 0x0000ffff; @@ -972,6 +973,28 @@ static struct snd_pcm_hardware snd_emu10k1_capture = .fifo_size = 0, }; +static struct snd_pcm_hardware snd_emu10k1_capture_efx = +{ + .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_RESUME | + SNDRV_PCM_INFO_MMAP_VALID), + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000, + .rate_min = 44100, + .rate_max = 192000, + .channels_min = 8, + .channels_max = 8, + .buffer_bytes_max = (64*1024), + .period_bytes_min = 384, + .period_bytes_max = (64*1024), + .periods_min = 2, + .periods_max = 2, + .fifo_size = 0, +}; + /* * */ @@ -1016,7 +1039,7 @@ static int snd_emu10k1_efx_playback_close(struct snd_pcm_substream *substream) struct snd_emu10k1_pcm_mixer *mix; int i; - for (i=0; i < NUM_EFX_PLAYBACK; i++) { + for (i = 0; i < NUM_EFX_PLAYBACK; i++) { mix = &emu->efx_pcm_mixer[i]; mix->epcm = NULL; snd_emu10k1_pcm_efx_mixer_notify(emu, i, 0); @@ -1045,7 +1068,7 @@ static int snd_emu10k1_efx_playback_open(struct snd_pcm_substream *substream) runtime->private_free = snd_emu10k1_pcm_free_substream; runtime->hw = snd_emu10k1_efx_playback; - for (i=0; i < NUM_EFX_PLAYBACK; i++) { + for (i = 0; i < NUM_EFX_PLAYBACK; i++) { mix = &emu->efx_pcm_mixer[i]; mix->send_routing[0][0] = i; memset(&mix->send_volume, 0, sizeof(mix->send_volume)); @@ -1199,15 +1222,59 @@ static int snd_emu10k1_capture_efx_open(struct snd_pcm_substream *substream) epcm->capture_idx_reg = FXIDX; substream->runtime->private_data = epcm; substream->runtime->private_free = snd_emu10k1_pcm_free_substream; - runtime->hw = snd_emu10k1_capture; + runtime->hw = snd_emu10k1_capture_efx; runtime->hw.rates = SNDRV_PCM_RATE_48000; runtime->hw.rate_min = runtime->hw.rate_max = 48000; spin_lock_irq(&emu->reg_lock); - runtime->hw.channels_min = runtime->hw.channels_max = 0; - for (idx = 0; idx < nefx; idx++) { - if (emu->efx_voices_mask[idx/32] & (1 << (idx%32))) { - runtime->hw.channels_min++; - runtime->hw.channels_max++; + if (emu->card_capabilities->emu1010) { + /* TODO + * SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE + * SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | + * SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | + * SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000 + * rate_min = 44100, + * rate_max = 192000, + * channels_min = 8, + * channels_max = 8, + * Need to add mixer control to fix sample rate + * + * There are 16 mono channels of 16bits each. + * 24bit Audio uses 2x channels over 16bit + * 96kHz uses 2x channels over 48kHz + * 192kHz uses 4x channels over 48kHz + * So, for 48kHz 24bit, one has 8 channels + * for 96kHz 24bit, one has 4 channels + * for 192kHz 24bit, one has 2 channels + */ +#if 1 + /* For 48kHz */ + runtime->hw.rates = SNDRV_PCM_RATE_48000; + runtime->hw.rate_min = runtime->hw.rate_max = 48000; + runtime->hw.channels_min = runtime->hw.channels_max = 8; +#endif +#if 0 + /* For 96kHz */ + runtime->hw.rates = SNDRV_PCM_RATE_96000; + runtime->hw.rate_min = runtime->hw.rate_max = 96000; + runtime->hw.channels_min = runtime->hw.channels_max = 4; +#endif +#if 0 + /* For 192kHz */ + runtime->hw.rates = SNDRV_PCM_RATE_192000; + runtime->hw.rate_min = runtime->hw.rate_max = 192000; + runtime->hw.channels_min = runtime->hw.channels_max = 2; +#endif + runtime->hw.formats = SNDRV_PCM_FMTBIT_S32_LE; + /* efx_voices_mask[0] is expected to be zero + * efx_voices_mask[1] is expected to have 16bits set + */ + } else { + runtime->hw.channels_min = runtime->hw.channels_max = 0; + for (idx = 0; idx < nefx; idx++) { + if (emu->efx_voices_mask[idx/32] & (1 << (idx%32))) { + runtime->hw.channels_min++; + runtime->hw.channels_max++; + } } } epcm->capture_cr_val = emu->efx_voices_mask[0]; @@ -1460,7 +1527,7 @@ static void snd_emu10k1_fx8010_playback_tram_poke1(unsigned short *dst_left, unsigned int count, unsigned int tram_shift) { - // printk("tram_poke1: dst_left = 0x%p, dst_right = 0x%p, src = 0x%p, count = 0x%x\n", dst_left, dst_right, src, count); + /* printk("tram_poke1: dst_left = 0x%p, dst_right = 0x%p, src = 0x%p, count = 0x%x\n", dst_left, dst_right, src, count); */ if ((tram_shift & 1) == 0) { while (count--) { *dst_left-- = *src++; @@ -1537,7 +1604,7 @@ static int snd_emu10k1_fx8010_playback_prepare(struct snd_pcm_substream *substre struct snd_emu10k1_fx8010_pcm *pcm = &emu->fx8010.pcm[substream->number]; unsigned int i; - // printk("prepare: etram_pages = 0x%p, dma_area = 0x%x, buffer_size = 0x%x (0x%x)\n", emu->fx8010.etram_pages, runtime->dma_area, runtime->buffer_size, runtime->buffer_size << 2); + /* printk("prepare: etram_pages = 0x%p, dma_area = 0x%x, buffer_size = 0x%x (0x%x)\n", emu->fx8010.etram_pages, runtime->dma_area, runtime->buffer_size, runtime->buffer_size << 2); */ memset(&pcm->pcm_rec, 0, sizeof(pcm->pcm_rec)); pcm->pcm_rec.hw_buffer_size = pcm->buffer_size * 2; /* byte size */ pcm->pcm_rec.sw_buffer_size = snd_pcm_lib_buffer_bytes(substream); diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c index b939e03aaed..2c1585991bc 100644 --- a/sound/pci/emu10k1/emuproc.c +++ b/sound/pci/emu10k1/emuproc.c @@ -3,6 +3,9 @@ * Creative Labs, Inc. * Routines for control of EMU10K1 chips / proc interface routines * + * Copyright (c) by James Courtier-Dutton + * Added EMU 1010 support. + * * BUGS: * -- * @@ -255,7 +258,7 @@ static void snd_emu10k1_proc_rates_read(struct snd_info_entry *entry, unsigned int val, tmp, n; val = snd_emu10k1_ptr20_read(emu, CAPTURE_RATE_STATUS, 0); tmp = (val >> 16) & 0x8; - for (n=0;n<4;n++) { + for (n = 0; n < 4; n++) { tmp = val >> (16 + (n*4)); if (tmp & 0x8) snd_iprintf(buffer, "Channel %d: Rate=%d\n", n, samplerate[tmp & 0x7]); else snd_iprintf(buffer, "Channel %d: No input\n", n); @@ -372,6 +375,27 @@ static void snd_emu10k1_proc_voices_read(struct snd_info_entry *entry, } #ifdef CONFIG_SND_DEBUG +static void snd_emu_proc_emu1010_reg_read(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) +{ + struct snd_emu10k1 *emu = entry->private_data; + unsigned long value; + unsigned long flags; + unsigned long regs; + int i; + snd_iprintf(buffer, "EMU1010 Registers:\n\n"); + + for(i = 0; i < 0x30; i+=1) { + spin_lock_irqsave(&emu->emu_lock, flags); + regs=i+0x40; /* 0x40 upwards are registers. */ + outl(regs, emu->port + A_IOCFG); + outl(regs | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */ + value = inl(emu->port + A_IOCFG); + spin_unlock_irqrestore(&emu->emu_lock, flags); + snd_iprintf(buffer, "%02X: %08lX, %02lX\n", i, value, (value >> 8) & 0x7f); + } +} + static void snd_emu_proc_io_reg_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { @@ -398,7 +422,7 @@ static void snd_emu_proc_io_reg_write(struct snd_info_entry *entry, while (!snd_info_get_line(buffer, line, sizeof(line))) { if (sscanf(line, "%x %x", ®, &val) != 2) continue; - if ((reg < 0x40) && (reg >=0) && (val <= 0xffffffff) ) { + if ((reg < 0x40) && (reg >= 0) && (val <= 0xffffffff) ) { spin_lock_irqsave(&emu->emu_lock, flags); outl(val, emu->port + (reg & 0xfffffffc)); spin_unlock_irqrestore(&emu->emu_lock, flags); @@ -474,7 +498,7 @@ static void snd_emu_proc_ptr_reg_write(struct snd_info_entry *entry, while (!snd_info_get_line(buffer, line, sizeof(line))) { if (sscanf(line, "%x %x %x", ®, &channel_id, &val) != 3) continue; - if ((reg < 0xa0) && (reg >=0) && (val <= 0xffffffff) && (channel_id >=0) && (channel_id <= 3) ) + if ((reg < 0xa0) && (reg >= 0) && (val <= 0xffffffff) && (channel_id >= 0) && (channel_id <= 3) ) snd_ptr_write(emu, iobase, reg, channel_id, val); } } @@ -531,6 +555,10 @@ int __devinit snd_emu10k1_proc_init(struct snd_emu10k1 * emu) { struct snd_info_entry *entry; #ifdef CONFIG_SND_DEBUG + if ((emu->card_capabilities->emu1010) && + snd_card_proc_new(emu->card, "emu1010_regs", &entry)) { + snd_info_set_text_ops(entry, emu, snd_emu_proc_emu1010_reg_read); + } if (! snd_card_proc_new(emu->card, "io_regs", &entry)) { snd_info_set_text_ops(entry, emu, snd_emu_proc_io_reg_read); entry->c.text.write = snd_emu_proc_io_reg_write; diff --git a/sound/pci/emu10k1/io.c b/sound/pci/emu10k1/io.c index 029e7856c43..27ab7d1788a 100644 --- a/sound/pci/emu10k1/io.c +++ b/sound/pci/emu10k1/io.c @@ -167,6 +167,51 @@ int snd_emu10k1_spi_write(struct snd_emu10k1 * emu, return 0; } +int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, int reg, int value) +{ + if (reg < 0 || reg > 0x3f) + return 1; + reg += 0x40; /* 0x40 upwards are registers. */ + if (value < 0 || value > 0x3f) /* 0 to 0x3f are values */ + return 1; + outl(reg, emu->port + A_IOCFG); + udelay(10); + outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */ + udelay(10); + outl(value, emu->port + A_IOCFG); + udelay(10); + outl(value | 0x80 , emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */ + + return 0; +} + +int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, int reg, int *value) +{ + if (reg < 0 || reg > 0x3f) + return 1; + reg += 0x40; /* 0x40 upwards are registers. */ + outl(reg, emu->port + A_IOCFG); + udelay(10); + outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */ + udelay(10); + *value = ((inl(emu->port + A_IOCFG) >> 8) & 0x7f); + + return 0; +} + +/* Each Destination has one and only one Source, + * but one Source can feed any number of Destinations simultaneously. + */ +int snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 * emu, int dst, int src) +{ + snd_emu1010_fpga_write(emu, 0x00, ((dst >> 8) & 0x3f) ); + snd_emu1010_fpga_write(emu, 0x01, (dst & 0x3f) ); + snd_emu1010_fpga_write(emu, 0x02, ((src >> 8) & 0x3f) ); + snd_emu1010_fpga_write(emu, 0x03, (src & 0x3f) ); + + return 0; +} + void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb) { unsigned long flags; diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c index 4e0f95438f4..5da637c7339 100644 --- a/sound/pci/emu10k1/p16v.c +++ b/sound/pci/emu10k1/p16v.c @@ -253,7 +253,7 @@ static int snd_p16v_pcm_close_playback(struct snd_pcm_substream *substream) struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); //struct snd_pcm_runtime *runtime = substream->runtime; //struct snd_emu10k1_pcm *epcm = runtime->private_data; - emu->p16v_voices[substream->pcm->device - emu->p16v_device_offset].use=0; + emu->p16v_voices[substream->pcm->device - emu->p16v_device_offset].use = 0; /* FIXME: maybe zero others */ return 0; } @@ -264,7 +264,7 @@ static int snd_p16v_pcm_close_capture(struct snd_pcm_substream *substream) struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); //struct snd_pcm_runtime *runtime = substream->runtime; //struct snd_emu10k1_pcm *epcm = runtime->private_data; - emu->p16v_capture_voice.use=0; + emu->p16v_capture_voice.use = 0; /* FIXME: maybe zero others */ return 0; } @@ -349,7 +349,7 @@ static int snd_p16v_pcm_prepare_playback(struct snd_pcm_substream *substream) break; } /* FIXME: Check emu->buffer.size before actually writing to it. */ - for(i=0; i < runtime->periods; i++) { + for(i = 0; i < runtime->periods; i++) { table_base[i*2]=runtime->dma_addr+(i*period_size_bytes); table_base[(i*2)+1]=period_size_bytes<<16; } @@ -394,7 +394,7 @@ static int snd_p16v_pcm_prepare_capture(struct snd_pcm_substream *substream) /* FIXME: Check emu->buffer.size before actually writing to it. */ snd_emu10k1_ptr20_write(emu, 0x13, channel, 0); snd_emu10k1_ptr20_write(emu, CAPTURE_DMA_ADDR, channel, runtime->dma_addr); - snd_emu10k1_ptr20_write(emu, CAPTURE_BUFFER_SIZE, channel, frames_to_bytes(runtime, runtime->buffer_size)<<16); // buffer size in bytes + snd_emu10k1_ptr20_write(emu, CAPTURE_BUFFER_SIZE, channel, frames_to_bytes(runtime, runtime->buffer_size) << 16); // buffer size in bytes snd_emu10k1_ptr20_write(emu, CAPTURE_POINTER, channel, 0); //snd_emu10k1_ptr20_write(emu, CAPTURE_SOURCE, 0x0, 0x333300e4); /* Select MIC or Line in */ //snd_emu10k1_ptr20_write(emu, EXTENDED_INT_MASK, 0, snd_emu10k1_ptr20_read(emu, EXTENDED_INT_MASK, 0) | (0x110000<voices[(first_voice + i) % NUM_G]; // printk("voice alloc - %i, %i of %i\n", voice->number, idx-first_voice+1, number); voice->use = 1; -- cgit v1.2.3 From 1700f3080d98323e91864d67cb9f6d46f818ccf0 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Wed, 4 Oct 2006 13:41:25 +0200 Subject: [ALSA] usb-audio: merge playback/capture hardware information structs The hardware information structures for playback and capture streams, respectively, are the same, so we can use just one structure for both streams. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela --- sound/usb/usbaudio.c | 25 +++++-------------------- 1 file changed, 5 insertions(+), 20 deletions(-) (limited to 'sound') diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 19bdcc74c96..478e504f702 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -1511,21 +1511,7 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) return 0; } -static struct snd_pcm_hardware snd_usb_playback = -{ - .info = SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_BATCH | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER, - .buffer_bytes_max = 1024 * 1024, - .period_bytes_min = 64, - .period_bytes_max = 512 * 1024, - .periods_min = 2, - .periods_max = 1024, -}; - -static struct snd_pcm_hardware snd_usb_capture = +static struct snd_pcm_hardware snd_usb_hardware = { .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | @@ -1904,8 +1890,7 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre return 0; } -static int snd_usb_pcm_open(struct snd_pcm_substream *substream, int direction, - struct snd_pcm_hardware *hw) +static int snd_usb_pcm_open(struct snd_pcm_substream *substream, int direction) { struct snd_usb_stream *as = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; @@ -1913,7 +1898,7 @@ static int snd_usb_pcm_open(struct snd_pcm_substream *substream, int direction, subs->interface = -1; subs->format = 0; - runtime->hw = *hw; + runtime->hw = snd_usb_hardware; runtime->private_data = subs; subs->pcm_substream = substream; return setup_hw_info(runtime, subs); @@ -1934,7 +1919,7 @@ static int snd_usb_pcm_close(struct snd_pcm_substream *substream, int direction) static int snd_usb_playback_open(struct snd_pcm_substream *substream) { - return snd_usb_pcm_open(substream, SNDRV_PCM_STREAM_PLAYBACK, &snd_usb_playback); + return snd_usb_pcm_open(substream, SNDRV_PCM_STREAM_PLAYBACK); } static int snd_usb_playback_close(struct snd_pcm_substream *substream) @@ -1944,7 +1929,7 @@ static int snd_usb_playback_close(struct snd_pcm_substream *substream) static int snd_usb_capture_open(struct snd_pcm_substream *substream) { - return snd_usb_pcm_open(substream, SNDRV_PCM_STREAM_CAPTURE, &snd_usb_capture); + return snd_usb_pcm_open(substream, SNDRV_PCM_STREAM_CAPTURE); } static int snd_usb_capture_close(struct snd_pcm_substream *substream) -- cgit v1.2.3 From e4f8e656d8c152c08cd44d0e3c21f009fab09952 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Wed, 4 Oct 2006 13:42:57 +0200 Subject: [ALSA] usb-audio: allow pausing Add pause capabilities for both USB playback and capture streams. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela --- sound/usb/usbaudio.c | 40 +++++++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 478e504f702..d2e066dc5d8 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -391,6 +391,16 @@ static int retire_capture_urb(struct snd_usb_substream *subs, return 0; } +/* + * Process after capture complete when paused. Nothing to do. + */ +static int retire_paused_capture_urb(struct snd_usb_substream *subs, + struct snd_pcm_runtime *runtime, + struct urb *urb) +{ + return 0; +} + /* * prepare urb for full speed playback sync pipe @@ -493,13 +503,13 @@ static int snd_usb_audio_next_packet_size(struct snd_usb_substream *subs) } /* - * Prepare urb for streaming before playback starts. + * Prepare urb for streaming before playback starts or when paused. * - * We don't yet have data, so we send a frame of silence. + * We don't have any data, so we send a frame of silence. */ -static int prepare_startup_playback_urb(struct snd_usb_substream *subs, - struct snd_pcm_runtime *runtime, - struct urb *urb) +static int prepare_nodata_playback_urb(struct snd_usb_substream *subs, + struct snd_pcm_runtime *runtime, + struct urb *urb) { unsigned int i, offs, counts; struct snd_urb_ctx *ctx = urb->context; @@ -622,7 +632,7 @@ static int retire_playback_urb(struct snd_usb_substream *subs, */ static struct snd_urb_ops audio_urb_ops[2] = { { - .prepare = prepare_startup_playback_urb, + .prepare = prepare_nodata_playback_urb, .retire = retire_playback_urb, .prepare_sync = prepare_playback_sync_urb, .retire_sync = retire_playback_sync_urb, @@ -637,7 +647,7 @@ static struct snd_urb_ops audio_urb_ops[2] = { static struct snd_urb_ops audio_urb_ops_high_speed[2] = { { - .prepare = prepare_startup_playback_urb, + .prepare = prepare_nodata_playback_urb, .retire = retire_playback_urb, .prepare_sync = prepare_playback_sync_urb_hs, .retire_sync = retire_playback_sync_urb_hs, @@ -925,10 +935,14 @@ static int snd_usb_pcm_playback_trigger(struct snd_pcm_substream *substream, switch (cmd) { case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: subs->ops.prepare = prepare_playback_urb; return 0; case SNDRV_PCM_TRIGGER_STOP: return deactivate_urbs(subs, 0, 0); + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + subs->ops.prepare = prepare_nodata_playback_urb; + return 0; default: return -EINVAL; } @@ -944,9 +958,16 @@ static int snd_usb_pcm_capture_trigger(struct snd_pcm_substream *substream, switch (cmd) { case SNDRV_PCM_TRIGGER_START: + subs->ops.retire = retire_capture_urb; return start_urbs(subs, substream->runtime); case SNDRV_PCM_TRIGGER_STOP: return deactivate_urbs(subs, 0, 0); + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + subs->ops.retire = retire_paused_capture_urb; + return 0; + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + subs->ops.retire = retire_capture_urb; + return 0; default: return -EINVAL; } @@ -1505,7 +1526,7 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) /* for playback, submit the URBs now; otherwise, the first hwptr_done * updates for all URBs would happen at the same time when starting */ if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) { - subs->ops.prepare = prepare_startup_playback_urb; + subs->ops.prepare = prepare_nodata_playback_urb; return start_urbs(subs, runtime); } else return 0; @@ -1517,7 +1538,8 @@ static struct snd_pcm_hardware snd_usb_hardware = SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_BATCH | SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER, + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_PAUSE, .buffer_bytes_max = 1024 * 1024, .period_bytes_min = 64, .period_bytes_max = 512 * 1024, -- cgit v1.2.3 From a58e7cb16dfae8a3c1c98a7ab7ca02a9e9b38921 Mon Sep 17 00:00:00 2001 From: Jochen Voss Date: Wed, 4 Oct 2006 18:04:10 +0200 Subject: [ALSA] Enable capture from line-in and CD on Revolution 5.1 Enable capture from line-in and CD on the Revolution 5.1 card. This patch adds support for switching between the 5 input channels of the AK5365 ADC and modifies the Revolution 5.1 driver to make use of this facility. Previously the capture channel was fixed to channel 0 (microphone on the Revolution 5.1 card). Signed-off-by: Jochen Voss Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/i2c/other/ak4xxx-adda.c | 85 ++++++++++++++++++++++++++++++++++++++++++- sound/pci/ice1712/revo.c | 10 ++++- 2 files changed, 92 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/i2c/other/ak4xxx-adda.c b/sound/i2c/other/ak4xxx-adda.c index 5da49e2eb35..fe61b92f4e4 100644 --- a/sound/i2c/other/ak4xxx-adda.c +++ b/sound/i2c/other/ak4xxx-adda.c @@ -513,6 +513,66 @@ static int ak4xxx_switch_put(struct snd_kcontrol *kcontrol, return change; } +#define AK5365_NUM_INPUTS 5 + +static int ak4xxx_capture_source_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol); + int mixer_ch = AK_GET_SHIFT(kcontrol->private_value); + const char **input_names; + int num_names, idx; + + input_names = ak->adc_info[mixer_ch].input_names; + + num_names = 0; + while (num_names < AK5365_NUM_INPUTS && input_names[num_names]) + ++num_names; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = num_names; + idx = uinfo->value.enumerated.item; + if (idx >= num_names) + return -EINVAL; + strncpy(uinfo->value.enumerated.name, input_names[idx], + sizeof(uinfo->value.enumerated.name)); + return 0; +} + +static int ak4xxx_capture_source_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol); + int chip = AK_GET_CHIP(kcontrol->private_value); + int addr = AK_GET_ADDR(kcontrol->private_value); + int mask = AK_GET_MASK(kcontrol->private_value); + unsigned char val; + + val = snd_akm4xxx_get(ak, chip, addr) & mask; + ucontrol->value.enumerated.item[0] = val; + return 0; +} + +static int ak4xxx_capture_source_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol); + int chip = AK_GET_CHIP(kcontrol->private_value); + int addr = AK_GET_ADDR(kcontrol->private_value); + int mask = AK_GET_MASK(kcontrol->private_value); + unsigned char oval, val; + + oval = snd_akm4xxx_get(ak, chip, addr); + val = oval & ~mask; + val |= ucontrol->value.enumerated.item[0] & mask; + if (val != oval) { + snd_akm4xxx_write(ak, chip, addr, val); + return 1; + } + return 0; +} + /* * build AK4xxx controls */ @@ -647,9 +707,10 @@ static int build_adc_controls(struct snd_akm4xxx *ak) if (ak->type == SND_AK5365 && (idx % 2) == 0) { if (! ak->adc_info || - ! ak->adc_info[mixer_ch].switch_name) + ! ak->adc_info[mixer_ch].switch_name) { knew.name = "Capture Switch"; - else + knew.index = mixer_ch + ak->idx_offset * 2; + } else knew.name = ak->adc_info[mixer_ch].switch_name; knew.info = ak4xxx_switch_info; knew.get = ak4xxx_switch_get; @@ -662,6 +723,26 @@ static int build_adc_controls(struct snd_akm4xxx *ak) err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak)); if (err < 0) return err; + + memset(&knew, 0, sizeof(knew)); + knew.name = ak->adc_info[mixer_ch].selector_name; + if (!knew.name) { + knew.name = "Capture Channel"; + knew.index = mixer_ch + ak->idx_offset * 2; + } + + knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + knew.info = ak4xxx_capture_source_info; + knew.get = ak4xxx_capture_source_get; + knew.put = ak4xxx_capture_source_put; + knew.access = 0; + /* input selector control: reg. 1, bits 0-2. + * mis-use 'shift' to pass mixer_ch */ + knew.private_value + = AK_COMPOSE(idx/2, 1, mixer_ch, 0x07); + err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak)); + if (err < 0) + return err; } idx += num_stereo; diff --git a/sound/pci/ice1712/revo.c b/sound/pci/ice1712/revo.c index bf98ea34feb..d556de59b9a 100644 --- a/sound/pci/ice1712/revo.c +++ b/sound/pci/ice1712/revo.c @@ -107,11 +107,19 @@ static struct snd_akm4xxx_dac_channel revo51_dac[] = { AK_DAC("PCM Rear Playback Volume", 2), }; +static const char *revo51_adc_input_names[] = { + "Mic", + "Line", + "CD", + NULL +}; + static struct snd_akm4xxx_adc_channel revo51_adc[] = { { .name = "PCM Capture Volume", .switch_name = "PCM Capture Switch", - .num_channels = 2 + .num_channels = 2, + .input_names = revo51_adc_input_names }, }; -- cgit v1.2.3 From feaa6a74d852be40c0e717471aa92eead012052c Mon Sep 17 00:00:00 2001 From: Jochen Voss Date: Wed, 4 Oct 2006 18:08:43 +0200 Subject: [ALSA] Enable the analog loopback of the Revolution 5.1 Enable the analog loopback of the Revolution 5.1 card. This patch adds support for the PT2258 volume controller and modifies the Revolution 5.1 driver to make use of this facility. This allows to control the analog loopback of the card. Signed-off-by: Jochen Voss Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/i2c/Makefile | 1 + sound/i2c/other/Makefile | 4 +- sound/i2c/other/pt2258.c | 233 ++++++++++++++++++++++++++++++++++++++++++++ sound/pci/ice1712/ice1712.h | 14 +++ sound/pci/ice1712/revo.c | 132 +++++++++++++++++++++++-- sound/pci/ice1712/revo.h | 6 +- 6 files changed, 376 insertions(+), 14 deletions(-) create mode 100644 sound/i2c/other/pt2258.c (limited to 'sound') diff --git a/sound/i2c/Makefile b/sound/i2c/Makefile index 816a2e7c88c..45902d48c89 100644 --- a/sound/i2c/Makefile +++ b/sound/i2c/Makefile @@ -16,3 +16,4 @@ obj-$(CONFIG_SND) += other/ # Toplevel Module Dependency obj-$(CONFIG_SND_INTERWAVE_STB) += snd-tea6330t.o snd-i2c.o obj-$(CONFIG_SND_ICE1712) += snd-cs8427.o snd-i2c.o +obj-$(CONFIG_SND_ICE1724) += snd-i2c.o diff --git a/sound/i2c/other/Makefile b/sound/i2c/other/Makefile index 2fe023ef00a..77a8a7c75dd 100644 --- a/sound/i2c/other/Makefile +++ b/sound/i2c/other/Makefile @@ -6,11 +6,11 @@ snd-ak4114-objs := ak4114.o snd-ak4117-objs := ak4117.o snd-ak4xxx-adda-objs := ak4xxx-adda.o +snd-pt2258-objs := pt2258.o snd-tea575x-tuner-objs := tea575x-tuner.o # Module Dependency obj-$(CONFIG_SND_PDAUDIOCF) += snd-ak4117.o obj-$(CONFIG_SND_ICE1712) += snd-ak4xxx-adda.o -obj-$(CONFIG_SND_ICE1724) += snd-ak4xxx-adda.o -obj-$(CONFIG_SND_ICE1724) += snd-ak4114.o +obj-$(CONFIG_SND_ICE1724) += snd-ak4114.o snd-ak4xxx-adda.o snd-pt2258.o obj-$(CONFIG_SND_FM801_TEA575X) += snd-tea575x-tuner.o diff --git a/sound/i2c/other/pt2258.c b/sound/i2c/other/pt2258.c new file mode 100644 index 00000000000..50df1df2f2b --- /dev/null +++ b/sound/i2c/other/pt2258.c @@ -0,0 +1,233 @@ +/* + * ALSA Driver for the PT2258 volume controller. + * + * Copyright (c) 2006 Jochen Voss + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Jochen Voss "); +MODULE_DESCRIPTION("PT2258 volume controller (Princeton Technology Corp.)"); +MODULE_LICENSE("GPL"); + +#define PT2258_CMD_RESET 0xc0 +#define PT2258_CMD_UNMUTE 0xf8 +#define PT2258_CMD_MUTE 0xf9 + +static const unsigned char pt2258_channel_code[12] = { + 0x80, 0x90, /* channel 1: -10dB, -1dB */ + 0x40, 0x50, /* channel 2: -10dB, -1dB */ + 0x00, 0x10, /* channel 3: -10dB, -1dB */ + 0x20, 0x30, /* channel 4: -10dB, -1dB */ + 0x60, 0x70, /* channel 5: -10dB, -1dB */ + 0xa0, 0xb0 /* channel 6: -10dB, -1dB */ +}; + +int snd_pt2258_reset(struct snd_pt2258 *pt) +{ + unsigned char bytes[2]; + int i; + + /* reset chip */ + bytes[0] = PT2258_CMD_RESET; + snd_i2c_lock(pt->i2c_bus); + if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 1) != 1) + goto __error; + snd_i2c_unlock(pt->i2c_bus); + + /* mute all channels */ + pt->mute = 1; + bytes[0] = PT2258_CMD_MUTE; + snd_i2c_lock(pt->i2c_bus); + if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 1) != 1) + goto __error; + snd_i2c_unlock(pt->i2c_bus); + + /* set all channels to 0dB */ + for (i = 0; i < 6; ++i) + pt->volume[i] = 0; + bytes[0] = 0xd0; + bytes[1] = 0xe0; + snd_i2c_lock(pt->i2c_bus); + if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 2) != 2) + goto __error; + snd_i2c_unlock(pt->i2c_bus); + + return 0; + + __error: + snd_i2c_unlock(pt->i2c_bus); + snd_printk(KERN_ERR "PT2258 reset failed\n"); + return -EIO; +} + +static int pt2258_stereo_volume_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 2; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 79; + return 0; +} + +static int pt2258_stereo_volume_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_pt2258 *pt = kcontrol->private_data; + int base = kcontrol->private_value; + + /* chip does not support register reads */ + ucontrol->value.integer.value[0] = 79 - pt->volume[base]; + ucontrol->value.integer.value[1] = 79 - pt->volume[base + 1]; + return 0; +} + +static int pt2258_stereo_volume_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_pt2258 *pt = kcontrol->private_data; + int base = kcontrol->private_value; + unsigned char bytes[2]; + int val0, val1; + + val0 = 79 - ucontrol->value.integer.value[0]; + val1 = 79 - ucontrol->value.integer.value[1]; + if (val0 == pt->volume[base] && val1 == pt->volume[base + 1]) + return 0; + + pt->volume[base] = val0; + bytes[0] = pt2258_channel_code[2 * base] | (val0 / 10); + bytes[1] = pt2258_channel_code[2 * base + 1] | (val0 % 10); + snd_i2c_lock(pt->i2c_bus); + if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 2) != 2) + goto __error; + snd_i2c_unlock(pt->i2c_bus); + + pt->volume[base + 1] = val1; + bytes[0] = pt2258_channel_code[2 * base + 2] | (val1 / 10); + bytes[1] = pt2258_channel_code[2 * base + 3] | (val1 % 10); + snd_i2c_lock(pt->i2c_bus); + if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 2) != 2) + goto __error; + snd_i2c_unlock(pt->i2c_bus); + + return 1; + + __error: + snd_i2c_unlock(pt->i2c_bus); + snd_printk(KERN_ERR "PT2258 access failed\n"); + return -EIO; +} + +static int pt2258_switch_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int pt2258_switch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_pt2258 *pt = kcontrol->private_data; + + ucontrol->value.integer.value[0] = !pt->mute; + return 0; +} + +static int pt2258_switch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_pt2258 *pt = kcontrol->private_data; + unsigned char bytes[2]; + int val; + + val = !ucontrol->value.integer.value[0]; + if (pt->mute == val) + return 0; + + pt->mute = val; + bytes[0] = val ? PT2258_CMD_MUTE : PT2258_CMD_UNMUTE; + snd_i2c_lock(pt->i2c_bus); + if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 1) != 1) + goto __error; + snd_i2c_unlock(pt->i2c_bus); + + return 1; + + __error: + snd_i2c_unlock(pt->i2c_bus); + snd_printk(KERN_ERR "PT2258 access failed 2\n"); + return -EIO; +} + +static DECLARE_TLV_DB_SCALE(pt2258_db_scale, -7900, 100, 0); + +int snd_pt2258_build_controls(struct snd_pt2258 *pt) +{ + struct snd_kcontrol_new knew; + char *names[3] = { + "Mic Loopback Playback Volume", + "Line Loopback Playback Volume", + "CD Loopback Playback Volume" + }; + int i, err; + + for (i = 0; i < 3; ++i) { + memset(&knew, 0, sizeof(knew)); + knew.name = names[i]; + knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + knew.count = 1; + knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ; + knew.private_value = 2 * i; + knew.info = pt2258_stereo_volume_info; + knew.get = pt2258_stereo_volume_get; + knew.put = pt2258_stereo_volume_put; + knew.tlv.p = pt2258_db_scale; + + err = snd_ctl_add(pt->card, snd_ctl_new1(&knew, pt)); + if (err < 0) + return err; + } + + memset(&knew, 0, sizeof(knew)); + knew.name = "Loopback Switch"; + knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + knew.info = pt2258_switch_info; + knew.get = pt2258_switch_get; + knew.put = pt2258_switch_put; + knew.access = 0; + err = snd_ctl_add(pt->card, snd_ctl_new1(&knew, pt)); + if (err < 0) + return err; + + return 0; +} + +EXPORT_SYMBOL(snd_pt2258_reset); +EXPORT_SYMBOL(snd_pt2258_build_controls); diff --git a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h index ce27eac40d4..064542bf3af 100644 --- a/sound/pci/ice1712/ice1712.h +++ b/sound/pci/ice1712/ice1712.h @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -381,6 +382,11 @@ struct snd_ice1712 { unsigned short master[2]; unsigned short vol[8]; } phase28; + /* a non-standard I2C device for revo51 */ + struct revo51_spec { + struct snd_i2c_device *dev; + struct snd_pt2258 *pt2258; + } revo51; /* Hoontech-specific setting */ struct hoontech_spec { unsigned char boxbits[4]; @@ -462,6 +468,14 @@ static inline void snd_ice1712_gpio_write_bits(struct snd_ice1712 *ice, snd_ice1712_gpio_write(ice, mask & bits); } +static inline int snd_ice1712_gpio_read_bits(struct snd_ice1712 *ice, + unsigned int mask) +{ + ice->gpio.direction &= ~mask; + snd_ice1712_gpio_set_dir(ice, ice->gpio.direction); + return (snd_ice1712_gpio_read(ice) & mask); +} + int snd_ice1712_spdif_build_controls(struct snd_ice1712 *ice); int snd_ice1712_akm4xxx_init(struct snd_akm4xxx *ak, const struct snd_akm4xxx *template, diff --git a/sound/pci/ice1712/revo.c b/sound/pci/ice1712/revo.c index d556de59b9a..233e9a5a2e7 100644 --- a/sound/pci/ice1712/revo.c +++ b/sound/pci/ice1712/revo.c @@ -83,6 +83,102 @@ static void revo_set_rate_val(struct snd_akm4xxx *ak, unsigned int rate) snd_akm4xxx_reset(ak, 0); } +/* + * I2C access to the PT2258 volume controller on GPIO 6/7 (Revolution 5.1) + */ + +static void revo_i2c_start(struct snd_i2c_bus *bus) +{ + struct snd_ice1712 *ice = bus->private_data; + snd_ice1712_save_gpio_status(ice); +} + +static void revo_i2c_stop(struct snd_i2c_bus *bus) +{ + struct snd_ice1712 *ice = bus->private_data; + snd_ice1712_restore_gpio_status(ice); +} + +static void revo_i2c_direction(struct snd_i2c_bus *bus, int clock, int data) +{ + struct snd_ice1712 *ice = bus->private_data; + unsigned int mask, val; + + val = 0; + if (clock) + val |= VT1724_REVO_I2C_CLOCK; /* write SCL */ + if (data) + val |= VT1724_REVO_I2C_DATA; /* write SDA */ + mask = VT1724_REVO_I2C_CLOCK | VT1724_REVO_I2C_DATA; + ice->gpio.direction &= ~mask; + ice->gpio.direction |= val; + snd_ice1712_gpio_set_dir(ice, ice->gpio.direction); + snd_ice1712_gpio_set_mask(ice, ~mask); +} + +static void revo_i2c_setlines(struct snd_i2c_bus *bus, int clk, int data) +{ + struct snd_ice1712 *ice = bus->private_data; + unsigned int val = 0; + + if (clk) + val |= VT1724_REVO_I2C_CLOCK; + if (data) + val |= VT1724_REVO_I2C_DATA; + snd_ice1712_gpio_write_bits(ice, + VT1724_REVO_I2C_DATA | + VT1724_REVO_I2C_CLOCK, val); + udelay(5); +} + +static int revo_i2c_getdata(struct snd_i2c_bus *bus, int ack) +{ + struct snd_ice1712 *ice = bus->private_data; + int bit; + + if (ack) + udelay(5); + bit = snd_ice1712_gpio_read_bits(ice, VT1724_REVO_I2C_DATA) ? 1 : 0; + return bit; +} + +static struct snd_i2c_bit_ops revo51_bit_ops = { + .start = revo_i2c_start, + .stop = revo_i2c_stop, + .direction = revo_i2c_direction, + .setlines = revo_i2c_setlines, + .getdata = revo_i2c_getdata, +}; + +static int revo51_i2c_init(struct snd_ice1712 *ice, + struct snd_pt2258 *pt) +{ + int err; + + /* create the I2C bus */ + err = snd_i2c_bus_create(ice->card, "ICE1724 GPIO6", NULL, &ice->i2c); + if (err < 0) + return err; + + ice->i2c->private_data = ice; + ice->i2c->hw_ops.bit = &revo51_bit_ops; + + /* create the I2C device */ + err = snd_i2c_device_create(ice->i2c, "PT2258", 0x40, + &ice->spec.revo51.dev); + if (err < 0) + return err; + + pt->card = ice->card; + pt->i2c_bus = ice->i2c; + pt->i2c_dev = ice->spec.revo51.dev; + ice->spec.revo51.pt2258 = pt; + + snd_pt2258_reset(pt); + + return 0; +} + /* * initialize the chips on M-Audio Revolution cards */ @@ -180,9 +276,9 @@ static struct snd_ak4xxx_private akm_revo51_priv __devinitdata = { .cif = 0, .data_mask = VT1724_REVO_CDOUT, .clk_mask = VT1724_REVO_CCLK, - .cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2, - .cs_addr = VT1724_REVO_CS1 | VT1724_REVO_CS2, - .cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2, + .cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS1, + .cs_addr = VT1724_REVO_CS1, + .cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1, .add_flags = VT1724_REVO_CCLK, /* high at init */ .mask_flags = 0, }; @@ -198,13 +294,15 @@ static struct snd_ak4xxx_private akm_revo51_adc_priv __devinitdata = { .cif = 0, .data_mask = VT1724_REVO_CDOUT, .clk_mask = VT1724_REVO_CCLK, - .cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2, - .cs_addr = VT1724_REVO_CS0 | VT1724_REVO_CS2, - .cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2, + .cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS1, + .cs_addr = VT1724_REVO_CS0, + .cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1, .add_flags = VT1724_REVO_CCLK, /* high at init */ .mask_flags = 0, }; +static struct snd_pt2258 ptc_revo51_volume; + static int __devinit revo_init(struct snd_ice1712 *ice) { struct snd_akm4xxx *ak; @@ -243,14 +341,20 @@ static int __devinit revo_init(struct snd_ice1712 *ice) break; case VT1724_SUBDEVICE_REVOLUTION51: ice->akm_codecs = 2; - if ((err = snd_ice1712_akm4xxx_init(ak, &akm_revo51, &akm_revo51_priv, ice)) < 0) + err = snd_ice1712_akm4xxx_init(ak, &akm_revo51, + &akm_revo51_priv, ice); + if (err < 0) return err; - err = snd_ice1712_akm4xxx_init(ak + 1, &akm_revo51_adc, + err = snd_ice1712_akm4xxx_init(ak+1, &akm_revo51_adc, &akm_revo51_adc_priv, ice); if (err < 0) return err; - /* unmute all codecs - needed! */ - snd_ice1712_gpio_write_bits(ice, VT1724_REVO_MUTE, VT1724_REVO_MUTE); + err = revo51_i2c_init(ice, &ptc_revo51_volume); + if (err < 0) + return err; + /* unmute all codecs */ + snd_ice1712_gpio_write_bits(ice, VT1724_REVO_MUTE, + VT1724_REVO_MUTE); break; } @@ -264,10 +368,18 @@ static int __devinit revo_add_controls(struct snd_ice1712 *ice) switch (ice->eeprom.subvendor) { case VT1724_SUBDEVICE_REVOLUTION71: + err = snd_ice1712_akm4xxx_build_controls(ice); + if (err < 0) + return err; + break; case VT1724_SUBDEVICE_REVOLUTION51: err = snd_ice1712_akm4xxx_build_controls(ice); if (err < 0) return err; + err = snd_pt2258_build_controls(ice->spec.revo51.pt2258); + if (err < 0) + return err; + break; } return 0; } diff --git a/sound/pci/ice1712/revo.h b/sound/pci/ice1712/revo.h index efbb86ec328..c70adaf017c 100644 --- a/sound/pci/ice1712/revo.h +++ b/sound/pci/ice1712/revo.h @@ -42,9 +42,11 @@ extern struct snd_ice1712_card_info snd_vt1724_revo_cards[]; #define VT1724_REVO_CCLK 0x02 #define VT1724_REVO_CDIN 0x04 /* not used */ #define VT1724_REVO_CDOUT 0x08 -#define VT1724_REVO_CS0 0x10 /* AK5365 chipselect for Rev. 5.1 */ +#define VT1724_REVO_CS0 0x10 /* AK5365 chipselect for (revo51) */ #define VT1724_REVO_CS1 0x20 /* front AKM4381 chipselect */ -#define VT1724_REVO_CS2 0x40 /* surround AKM4355 chipselect */ +#define VT1724_REVO_CS2 0x40 /* surround AKM4355 CS (revo71) */ +#define VT1724_REVO_I2C_DATA 0x40 /* I2C: PT 2258 SDA (on revo51) */ +#define VT1724_REVO_I2C_CLOCK 0x80 /* I2C: PT 2258 SCL (on revo51) */ #define VT1724_REVO_MUTE (1<<22) /* 0 = all mute, 1 = normal operation */ #endif /* __SOUND_REVO_H */ -- cgit v1.2.3 From 12b131c4cf3eb1dc8a60082a434b7b100774c2e7 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 5 Oct 2006 15:05:34 +0200 Subject: [ALSA] allow registering an alsa device with struct device pointer This patch adds snd_register_device_for_dev taking a struct device pointer to link the new device to and makes snd_register_device a simple static inline wrapper around it. Signed-off-by: Johannes Berg Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/core/sound.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/core/sound.c b/sound/core/sound.c index 82a61c67cf3..4084de06412 100644 --- a/sound/core/sound.c +++ b/sound/core/sound.c @@ -219,26 +219,27 @@ static int snd_kernel_minor(int type, struct snd_card *card, int dev) #endif /** - * snd_register_device - Register the ALSA device file for the card + * snd_register_device_for_dev - Register the ALSA device file for the card * @type: the device type, SNDRV_DEVICE_TYPE_XXX * @card: the card instance * @dev: the device index * @f_ops: the file operations * @private_data: user pointer for f_ops->open() * @name: the device file name + * @device: the &struct device to link this new device to * * Registers an ALSA device file for the given card. * The operators have to be set in reg parameter. * - * Retrurns zero if successful, or a negative error code on failure. + * Returns zero if successful, or a negative error code on failure. */ -int snd_register_device(int type, struct snd_card *card, int dev, - const struct file_operations *f_ops, void *private_data, - const char *name) +int snd_register_device_for_dev(int type, struct snd_card *card, int dev, + const struct file_operations *f_ops, + void *private_data, + const char *name, struct device *device) { int minor; struct snd_minor *preg; - struct device *device = snd_card_get_device_link(card); snd_assert(name, return -EINVAL); preg = kmalloc(sizeof *preg, GFP_KERNEL); @@ -272,7 +273,7 @@ int snd_register_device(int type, struct snd_card *card, int dev, return 0; } -EXPORT_SYMBOL(snd_register_device); +EXPORT_SYMBOL(snd_register_device_for_dev); /* find the matching minor record * return the index of snd_minor, or -1 if not found -- cgit v1.2.3 From c78085fcd2ce7cd036e1488472eb41a64d70949a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 5 Oct 2006 15:06:34 +0200 Subject: [ALSA] alsa core: add struct device pointer to struct snd_pcm This patch adds a struct device pointer to struct snd_pcm in order to be able to give it a different device than the card. It defaults to the card's device, however, so it should behave identically for drivers not touching the field. Signed-off-by: Johannes Berg Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/core/pcm.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 8e018988551..4701f07ee0a 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -944,6 +944,7 @@ static int snd_pcm_dev_register(struct snd_device *device) struct list_head *list; char str[16]; struct snd_pcm *pcm = device->device_data; + struct device *dev; snd_assert(pcm != NULL && device != NULL, return -ENXIO); mutex_lock(®ister_mutex); @@ -966,11 +967,18 @@ static int snd_pcm_dev_register(struct snd_device *device) devtype = SNDRV_DEVICE_TYPE_PCM_CAPTURE; break; } - if ((err = snd_register_device(devtype, pcm->card, - pcm->device, - &snd_pcm_f_ops[cidx], - pcm, str)) < 0) - { + /* device pointer to use, pcm->dev takes precedence if + * it is assigned, otherwise fall back to card's device + * if possible */ + dev = pcm->dev; + if (!dev) + dev = pcm->card ? pcm->card->dev : NULL; + /* register pcm */ + err = snd_register_device_for_dev(devtype, pcm->card, + pcm->device, + &snd_pcm_f_ops[cidx], + pcm, str, dev); + if (err < 0) { list_del(&pcm->list); mutex_unlock(®ister_mutex); return err; -- cgit v1.2.3 From 73e85fe8452b950b93cfb61377f749e9b15437fb Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 5 Oct 2006 15:07:23 +0200 Subject: [ALSA] aoa: set device pointer in pcms This patch makes a few whitespace cleanups and makes i2sbus assign the new struct device pointer in struct snd_pcm so that the proper device symlink shows up in sysfs. Signed-off-by: Johannes Berg Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/aoa/core/snd-aoa-alsa.c | 2 +- sound/aoa/soundbus/i2sbus/i2sbus-pcm.c | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/aoa/core/snd-aoa-alsa.c b/sound/aoa/core/snd-aoa-alsa.c index b42fdea77ed..8c5a19bd602 100644 --- a/sound/aoa/core/snd-aoa-alsa.c +++ b/sound/aoa/core/snd-aoa-alsa.c @@ -59,7 +59,7 @@ void aoa_alsa_cleanup(void) } int aoa_snd_device_new(snd_device_type_t type, - void * device_data, struct snd_device_ops * ops) + void * device_data, struct snd_device_ops * ops) { struct snd_card *card = aoa_get_card(); int err; diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c b/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c index 5eff30b1020..051bb9b200e 100644 --- a/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c +++ b/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c @@ -901,11 +901,7 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card, } if (!dev->pcm) { - err = snd_pcm_new(card, - dev->pcmname, - dev->pcmid, - 0, - 0, + err = snd_pcm_new(card, dev->pcmname, dev->pcmid, 0, 0, &dev->pcm); if (err) { printk(KERN_DEBUG "i2sbus: failed to create pcm\n"); @@ -915,6 +911,7 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card, module_put(THIS_MODULE); return err; } + dev->pcm->dev = &dev->ofdev.dev; } /* ALSA yet again sucks. -- cgit v1.2.3 From d595ee7e0162ae66faa8c4c7d8c2069b40d64fed Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 5 Oct 2006 15:08:23 +0200 Subject: [ALSA] aoa: fix up i2sbus_attach_codec This patch changes i2sbus_attach_codec to implement a proper error handling strategy using labels to jump to the right part. Since it has an elaborate set-up sequence it also needs that tear-down, which I had hard-coded inbetween all the checks. This increases readability and should reduce .text size as well. Signed-off-by: Johannes Berg Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/aoa/soundbus/i2sbus/i2sbus-pcm.c | 72 ++++++++++++---------------------- 1 file changed, 26 insertions(+), 46 deletions(-) (limited to 'sound') diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c b/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c index 051bb9b200e..7c81db7e52c 100644 --- a/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c +++ b/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c @@ -812,7 +812,6 @@ static void i2sbus_private_free(struct snd_pcm *pcm) module_put(THIS_MODULE); } -/* FIXME: this function needs an error handling strategy with labels */ int i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card, struct codec_info *ci, void *data) @@ -880,24 +879,21 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card, if (!cii->sdev) { printk(KERN_DEBUG "i2sbus: failed to get soundbus dev reference\n"); - kfree(cii); - return -ENODEV; + err = -ENODEV; + goto out_free_cii; } if (!try_module_get(THIS_MODULE)) { printk(KERN_DEBUG "i2sbus: failed to get module reference!\n"); - soundbus_dev_put(dev); - kfree(cii); - return -EBUSY; + err = -EBUSY; + goto out_put_sdev; } if (!try_module_get(ci->owner)) { printk(KERN_DEBUG "i2sbus: failed to get module reference to codec owner!\n"); - module_put(THIS_MODULE); - soundbus_dev_put(dev); - kfree(cii); - return -EBUSY; + err = -EBUSY; + goto out_put_this_module; } if (!dev->pcm) { @@ -905,11 +901,7 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card, &dev->pcm); if (err) { printk(KERN_DEBUG "i2sbus: failed to create pcm\n"); - kfree(cii); - module_put(ci->owner); - soundbus_dev_put(dev); - module_put(THIS_MODULE); - return err; + goto out_put_ci_module; } dev->pcm->dev = &dev->ofdev.dev; } @@ -923,20 +915,12 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card, /* eh? */ printk(KERN_ERR "Can't attach same bus to different cards!\n"); - module_put(ci->owner); - kfree(cii); - soundbus_dev_put(dev); - module_put(THIS_MODULE); - return -EINVAL; - } - if ((err = - snd_pcm_new_stream(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK, 1))) { - module_put(ci->owner); - kfree(cii); - soundbus_dev_put(dev); - module_put(THIS_MODULE); - return err; + err = -EINVAL; + goto out_put_ci_module; } + err = snd_pcm_new_stream(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK, 1); + if (err) + goto out_put_ci_module; snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK, &i2sbus_playback_ops); i2sdev->out.created = 1; @@ -946,20 +930,11 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card, if (dev->pcm->card != card) { printk(KERN_ERR "Can't attach same bus to different cards!\n"); - module_put(ci->owner); - kfree(cii); - soundbus_dev_put(dev); - module_put(THIS_MODULE); - return -EINVAL; - } - if ((err = - snd_pcm_new_stream(dev->pcm, SNDRV_PCM_STREAM_CAPTURE, 1))) { - module_put(ci->owner); - kfree(cii); - soundbus_dev_put(dev); - module_put(THIS_MODULE); - return err; + goto out_put_ci_module; } + err = snd_pcm_new_stream(dev->pcm, SNDRV_PCM_STREAM_CAPTURE, 1); + if (err) + goto out_put_ci_module; snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_CAPTURE, &i2sbus_record_ops); i2sdev->in.created = 1; @@ -974,11 +949,7 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card, err = snd_device_register(card, dev->pcm); if (err) { printk(KERN_ERR "i2sbus: error registering new pcm\n"); - module_put(ci->owner); - kfree(cii); - soundbus_dev_put(dev); - module_put(THIS_MODULE); - return err; + goto out_put_ci_module; } /* no errors any more, so let's add this to our list */ list_add(&cii->list, &dev->codec_list); @@ -993,6 +964,15 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card, 64 * 1024, 64 * 1024); return 0; + out_put_ci_module: + module_put(ci->owner); + out_put_this_module: + module_put(THIS_MODULE); + out_put_sdev: + soundbus_dev_put(dev); + out_free_cii: + kfree(cii); + return err; } void i2sbus_detach_codec(struct soundbus_dev *dev, void *data) -- cgit v1.2.3 From 9244b2c3079faac79b3b961116bd548c45087e2c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 5 Oct 2006 16:02:22 +0200 Subject: [ALSA] alsa core: convert to list_for_each_entry* This patch converts most uses of list_for_each to list_for_each_entry all across alsa. In some place apparently an item can be on a list with different pointers so of course that isn't compatible with list_for_each, I therefore didn't touch those places. Signed-off-by: Johannes Berg Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/core/control.c | 37 +++++--------------- sound/core/control_compat.c | 5 ++- sound/core/device.c | 24 ++++--------- sound/core/hwdep.c | 10 ++---- sound/core/memalloc.c | 10 ++---- sound/core/pcm.c | 32 +++++++----------- sound/core/rawmidi.c | 29 ++++++---------- sound/core/seq/seq_clientmgr.c | 14 +++----- sound/core/seq/seq_device.c | 25 ++++++-------- sound/core/seq/seq_ports.c | 49 ++++++++++----------------- sound/core/seq/seq_virmidi.c | 4 +-- sound/core/timer.c | 77 ++++++++++++++---------------------------- 12 files changed, 102 insertions(+), 214 deletions(-) (limited to 'sound') diff --git a/sound/core/control.c b/sound/core/control.c index 0c7bcd62e5b..67f09b8f85e 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -108,7 +108,6 @@ static void snd_ctl_empty_read_queue(struct snd_ctl_file * ctl) static int snd_ctl_release(struct inode *inode, struct file *file) { unsigned long flags; - struct list_head *list; struct snd_card *card; struct snd_ctl_file *ctl; struct snd_kcontrol *control; @@ -122,12 +121,10 @@ static int snd_ctl_release(struct inode *inode, struct file *file) list_del(&ctl->list); write_unlock_irqrestore(&card->ctl_files_rwlock, flags); down_write(&card->controls_rwsem); - list_for_each(list, &card->controls) { - control = snd_kcontrol(list); + list_for_each_entry(control, &card->controls, list) for (idx = 0; idx < control->count; idx++) if (control->vd[idx].owner == ctl) control->vd[idx].owner = NULL; - } up_write(&card->controls_rwsem); snd_ctl_empty_read_queue(ctl); kfree(ctl); @@ -140,7 +137,6 @@ void snd_ctl_notify(struct snd_card *card, unsigned int mask, struct snd_ctl_elem_id *id) { unsigned long flags; - struct list_head *flist; struct snd_ctl_file *ctl; struct snd_kctl_event *ev; @@ -149,14 +145,11 @@ void snd_ctl_notify(struct snd_card *card, unsigned int mask, #if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) card->mixer_oss_change_count++; #endif - list_for_each(flist, &card->ctl_files) { - struct list_head *elist; - ctl = snd_ctl_file(flist); + list_for_each_entry(ctl, &card->ctl_files, list) { if (!ctl->subscribed) continue; spin_lock_irqsave(&ctl->read_lock, flags); - list_for_each(elist, &ctl->events) { - ev = snd_kctl_event(elist); + list_for_each_entry(ev, &ctl->events, list) { if (ev->id.numid == id->numid) { ev->mask |= mask; goto _found; @@ -277,11 +270,9 @@ EXPORT_SYMBOL(snd_ctl_free_one); static unsigned int snd_ctl_hole_check(struct snd_card *card, unsigned int count) { - struct list_head *list; struct snd_kcontrol *kctl; - list_for_each(list, &card->controls) { - kctl = snd_kcontrol(list); + list_for_each_entry(kctl, &card->controls, list) { if ((kctl->id.numid <= card->last_numid && kctl->id.numid + kctl->count > card->last_numid) || (kctl->id.numid <= card->last_numid + count - 1 && @@ -498,12 +489,10 @@ EXPORT_SYMBOL(snd_ctl_rename_id); */ struct snd_kcontrol *snd_ctl_find_numid(struct snd_card *card, unsigned int numid) { - struct list_head *list; struct snd_kcontrol *kctl; snd_assert(card != NULL && numid != 0, return NULL); - list_for_each(list, &card->controls) { - kctl = snd_kcontrol(list); + list_for_each_entry(kctl, &card->controls, list) { if (kctl->id.numid <= numid && kctl->id.numid + kctl->count > numid) return kctl; } @@ -527,14 +516,12 @@ EXPORT_SYMBOL(snd_ctl_find_numid); struct snd_kcontrol *snd_ctl_find_id(struct snd_card *card, struct snd_ctl_elem_id *id) { - struct list_head *list; struct snd_kcontrol *kctl; snd_assert(card != NULL && id != NULL, return NULL); if (id->numid != 0) return snd_ctl_find_numid(card, id->numid); - list_for_each(list, &card->controls) { - kctl = snd_kcontrol(list); + list_for_each_entry(kctl, &card->controls, list) { if (kctl->id.iface != id->iface) continue; if (kctl->id.device != id->device) @@ -1182,7 +1169,6 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg { struct snd_ctl_file *ctl; struct snd_card *card; - struct list_head *list; struct snd_kctl_ioctl *p; void __user *argp = (void __user *)arg; int __user *ip = argp; @@ -1232,8 +1218,7 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg #endif } down_read(&snd_ioctl_rwsem); - list_for_each(list, &snd_control_ioctls) { - p = list_entry(list, struct snd_kctl_ioctl, list); + list_for_each_entry(p, &snd_control_ioctls, list) { err = p->fioctl(card, ctl, cmd, arg); if (err != -ENOIOCTLCMD) { up_read(&snd_ioctl_rwsem); @@ -1357,13 +1342,11 @@ EXPORT_SYMBOL(snd_ctl_register_ioctl_compat); static int _snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn, struct list_head *lists) { - struct list_head *list; struct snd_kctl_ioctl *p; snd_assert(fcn != NULL, return -EINVAL); down_write(&snd_ioctl_rwsem); - list_for_each(list, lists) { - p = list_entry(list, struct snd_kctl_ioctl, list); + list_for_each_entry(p, lists, list) { if (p->fioctl == fcn) { list_del(&p->list); up_write(&snd_ioctl_rwsem); @@ -1453,7 +1436,6 @@ static int snd_ctl_dev_register(struct snd_device *device) static int snd_ctl_dev_disconnect(struct snd_device *device) { struct snd_card *card = device->device_data; - struct list_head *flist; struct snd_ctl_file *ctl; int err, cardnum; @@ -1462,8 +1444,7 @@ static int snd_ctl_dev_disconnect(struct snd_device *device) snd_assert(cardnum >= 0 && cardnum < SNDRV_CARDS, return -ENXIO); down_read(&card->controls_rwsem); - list_for_each(flist, &card->ctl_files) { - ctl = snd_ctl_file(flist); + list_for_each_entry(ctl, &card->ctl_files, list) { wake_up(&ctl->change_sleep); kill_fasync(&ctl->fasync, SIGIO, POLL_ERR); } diff --git a/sound/core/control_compat.c b/sound/core/control_compat.c index ab48962c48c..9311ca397bb 100644 --- a/sound/core/control_compat.c +++ b/sound/core/control_compat.c @@ -392,7 +392,7 @@ enum { static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg) { struct snd_ctl_file *ctl; - struct list_head *list; + struct snd_kctl_ioctl *p; void __user *argp = compat_ptr(arg); int err; @@ -427,8 +427,7 @@ static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, uns } down_read(&snd_ioctl_rwsem); - list_for_each(list, &snd_control_compat_ioctls) { - struct snd_kctl_ioctl *p = list_entry(list, struct snd_kctl_ioctl, list); + list_for_each_entry(p, &snd_control_compat_ioctls, list) { if (p->fioctl) { err = p->fioctl(ctl->card, ctl, cmd, arg); if (err != -ENOIOCTLCMD) { diff --git a/sound/core/device.c b/sound/core/device.c index ccb25816ac9..5858b02b0b1 100644 --- a/sound/core/device.c +++ b/sound/core/device.c @@ -79,13 +79,11 @@ EXPORT_SYMBOL(snd_device_new); */ int snd_device_free(struct snd_card *card, void *device_data) { - struct list_head *list; struct snd_device *dev; snd_assert(card != NULL, return -ENXIO); snd_assert(device_data != NULL, return -ENXIO); - list_for_each(list, &card->devices) { - dev = snd_device(list); + list_for_each_entry(dev, &card->devices, list) { if (dev->device_data != device_data) continue; /* unlink */ @@ -124,13 +122,11 @@ EXPORT_SYMBOL(snd_device_free); */ int snd_device_disconnect(struct snd_card *card, void *device_data) { - struct list_head *list; struct snd_device *dev; snd_assert(card != NULL, return -ENXIO); snd_assert(device_data != NULL, return -ENXIO); - list_for_each(list, &card->devices) { - dev = snd_device(list); + list_for_each_entry(dev, &card->devices, list) { if (dev->device_data != device_data) continue; if (dev->state == SNDRV_DEV_REGISTERED && @@ -161,14 +157,12 @@ int snd_device_disconnect(struct snd_card *card, void *device_data) */ int snd_device_register(struct snd_card *card, void *device_data) { - struct list_head *list; struct snd_device *dev; int err; snd_assert(card != NULL, return -ENXIO); snd_assert(device_data != NULL, return -ENXIO); - list_for_each(list, &card->devices) { - dev = snd_device(list); + list_for_each_entry(dev, &card->devices, list) { if (dev->device_data != device_data) continue; if (dev->state == SNDRV_DEV_BUILD && dev->ops->dev_register) { @@ -192,13 +186,11 @@ EXPORT_SYMBOL(snd_device_register); */ int snd_device_register_all(struct snd_card *card) { - struct list_head *list; struct snd_device *dev; int err; snd_assert(card != NULL, return -ENXIO); - list_for_each(list, &card->devices) { - dev = snd_device(list); + list_for_each_entry(dev, &card->devices, list) { if (dev->state == SNDRV_DEV_BUILD && dev->ops->dev_register) { if ((err = dev->ops->dev_register(dev)) < 0) return err; @@ -215,12 +207,10 @@ int snd_device_register_all(struct snd_card *card) int snd_device_disconnect_all(struct snd_card *card) { struct snd_device *dev; - struct list_head *list; int err = 0; snd_assert(card != NULL, return -ENXIO); - list_for_each(list, &card->devices) { - dev = snd_device(list); + list_for_each_entry(dev, &card->devices, list) { if (snd_device_disconnect(card, dev->device_data) < 0) err = -ENXIO; } @@ -234,7 +224,6 @@ int snd_device_disconnect_all(struct snd_card *card) int snd_device_free_all(struct snd_card *card, snd_device_cmd_t cmd) { struct snd_device *dev; - struct list_head *list; int err; unsigned int range_low, range_high; @@ -242,8 +231,7 @@ int snd_device_free_all(struct snd_card *card, snd_device_cmd_t cmd) range_low = cmd * SNDRV_DEV_TYPE_RANGE_SIZE; range_high = range_low + SNDRV_DEV_TYPE_RANGE_SIZE - 1; __again: - list_for_each(list, &card->devices) { - dev = snd_device(list); + list_for_each_entry(dev, &card->devices, list) { if (dev->type >= range_low && dev->type <= range_high) { if ((err = snd_device_free(card, dev->device_data)) < 0) return err; diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c index 46b47689362..a6a6ad0ad3c 100644 --- a/sound/core/hwdep.c +++ b/sound/core/hwdep.c @@ -47,14 +47,11 @@ static int snd_hwdep_dev_disconnect(struct snd_device *device); static struct snd_hwdep *snd_hwdep_search(struct snd_card *card, int device) { - struct list_head *p; struct snd_hwdep *hwdep; - list_for_each(p, &snd_hwdep_devices) { - hwdep = list_entry(p, struct snd_hwdep, list); + list_for_each_entry(hwdep, &snd_hwdep_devices, list) if (hwdep->card == card && hwdep->device == device) return hwdep; - } return NULL; } @@ -468,15 +465,12 @@ static int snd_hwdep_dev_disconnect(struct snd_device *device) static void snd_hwdep_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { - struct list_head *p; struct snd_hwdep *hwdep; mutex_lock(®ister_mutex); - list_for_each(p, &snd_hwdep_devices) { - hwdep = list_entry(p, struct snd_hwdep, list); + list_for_each_entry(hwdep, &snd_hwdep_devices, list) snd_iprintf(buffer, "%02i-%02i: %s\n", hwdep->card->number, hwdep->device, hwdep->name); - } mutex_unlock(®ister_mutex); } diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c index bc0bd0910a6..f057430db0d 100644 --- a/sound/core/memalloc.c +++ b/sound/core/memalloc.c @@ -406,19 +406,17 @@ void snd_dma_free_pages(struct snd_dma_buffer *dmab) */ size_t snd_dma_get_reserved_buf(struct snd_dma_buffer *dmab, unsigned int id) { - struct list_head *p; struct snd_mem_list *mem; snd_assert(dmab, return 0); mutex_lock(&list_mutex); - list_for_each(p, &mem_list_head) { - mem = list_entry(p, struct snd_mem_list, list); + list_for_each_entry(mem, &mem_list_head, list) { if (mem->id == id && (mem->buffer.dev.dev == NULL || dmab->dev.dev == NULL || ! memcmp(&mem->buffer.dev, &dmab->dev, sizeof(dmab->dev)))) { struct device *dev = dmab->dev.dev; - list_del(p); + list_del(&mem->list); *dmab = mem->buffer; if (dmab->dev.dev == NULL) dmab->dev.dev = dev; @@ -488,7 +486,6 @@ static int snd_mem_proc_read(char *page, char **start, off_t off, { int len = 0; long pages = snd_allocated_pages >> (PAGE_SHIFT-12); - struct list_head *p; struct snd_mem_list *mem; int devno; static char *types[] = { "UNKNOWN", "CONT", "DEV", "DEV-SG", "SBUS" }; @@ -498,8 +495,7 @@ static int snd_mem_proc_read(char *page, char **start, off_t off, "pages : %li bytes (%li pages per %likB)\n", pages * PAGE_SIZE, pages, PAGE_SIZE / 1024); devno = 0; - list_for_each(p, &mem_list_head) { - mem = list_entry(p, struct snd_mem_list, list); + list_for_each_entry(mem, &mem_list_head, list) { devno++; len += snprintf(page + len, count - len, "buffer %d : ID %08x : type %s\n", diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 4701f07ee0a..76fcc5234d8 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -45,11 +45,9 @@ static int snd_pcm_dev_disconnect(struct snd_device *device); static struct snd_pcm *snd_pcm_search(struct snd_card *card, int device) { - struct list_head *p; struct snd_pcm *pcm; - list_for_each(p, &snd_pcm_devices) { - pcm = list_entry(p, struct snd_pcm, list); + list_for_each_entry(pcm, &snd_pcm_devices, list) { if (pcm->card == card && pcm->device == device) return pcm; } @@ -782,7 +780,6 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, struct snd_pcm_runtime *runtime; struct snd_ctl_file *kctl; struct snd_card *card; - struct list_head *list; int prefer_subdevice = -1; size_t size; @@ -795,8 +792,7 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, card = pcm->card; down_read(&card->controls_rwsem); - list_for_each(list, &card->ctl_files) { - kctl = snd_ctl_file(list); + list_for_each_entry(kctl, &card->ctl_files, list) { if (kctl->pid == current->pid) { prefer_subdevice = kctl->prefer_pcm_subdevice; if (prefer_subdevice != -1) @@ -941,7 +937,7 @@ static int snd_pcm_dev_register(struct snd_device *device) { int cidx, err; struct snd_pcm_substream *substream; - struct list_head *list; + struct snd_pcm_notify *notify; char str[16]; struct snd_pcm *pcm = device->device_data; struct device *dev; @@ -988,11 +984,10 @@ static int snd_pcm_dev_register(struct snd_device *device) for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) snd_pcm_timer_init(substream); } - list_for_each(list, &snd_pcm_notify_list) { - struct snd_pcm_notify *notify; - notify = list_entry(list, struct snd_pcm_notify, list); + + list_for_each_entry(notify, &snd_pcm_notify_list, list) notify->n_register(pcm); - } + mutex_unlock(®ister_mutex); return 0; } @@ -1035,7 +1030,7 @@ static int snd_pcm_dev_disconnect(struct snd_device *device) int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree) { - struct list_head *p; + struct snd_pcm *pcm; snd_assert(notify != NULL && notify->n_register != NULL && @@ -1044,13 +1039,12 @@ int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree) mutex_lock(®ister_mutex); if (nfree) { list_del(¬ify->list); - list_for_each(p, &snd_pcm_devices) - notify->n_unregister(list_entry(p, - struct snd_pcm, list)); + list_for_each_entry(pcm, &snd_pcm_devices, list) + notify->n_unregister(pcm); } else { list_add_tail(¬ify->list, &snd_pcm_notify_list); - list_for_each(p, &snd_pcm_devices) - notify->n_register(list_entry(p, struct snd_pcm, list)); + list_for_each_entry(pcm, &snd_pcm_devices, list) + notify->n_register(pcm); } mutex_unlock(®ister_mutex); return 0; @@ -1066,12 +1060,10 @@ EXPORT_SYMBOL(snd_pcm_notify); static void snd_pcm_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { - struct list_head *p; struct snd_pcm *pcm; mutex_lock(®ister_mutex); - list_for_each(p, &snd_pcm_devices) { - pcm = list_entry(p, struct snd_pcm, list); + list_for_each_entry(pcm, &snd_pcm_devices, list) { snd_iprintf(buffer, "%02i-%02i: %s : %s", pcm->card->number, pcm->device, pcm->id, pcm->name); if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 0f055bfcbda..7e6ceec738d 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -61,14 +61,11 @@ static DEFINE_MUTEX(register_mutex); static struct snd_rawmidi *snd_rawmidi_search(struct snd_card *card, int device) { - struct list_head *p; struct snd_rawmidi *rawmidi; - list_for_each(p, &snd_rawmidi_devices) { - rawmidi = list_entry(p, struct snd_rawmidi, list); + list_for_each_entry(rawmidi, &snd_rawmidi_devices, list) if (rawmidi->card == card && rawmidi->device == device) return rawmidi; - } return NULL; } @@ -389,7 +386,6 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file) struct snd_rawmidi *rmidi; struct snd_rawmidi_file *rawmidi_file; wait_queue_t wait; - struct list_head *list; struct snd_ctl_file *kctl; if (maj == snd_major) { @@ -426,8 +422,7 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file) while (1) { subdevice = -1; down_read(&card->controls_rwsem); - list_for_each(list, &card->ctl_files) { - kctl = snd_ctl_file(list); + list_for_each_entry(kctl, &card->ctl_files, list) { if (kctl->pid == current->pid) { subdevice = kctl->prefer_rawmidi_subdevice; if (subdevice != -1) @@ -575,7 +570,6 @@ int snd_rawmidi_info_select(struct snd_card *card, struct snd_rawmidi_info *info struct snd_rawmidi *rmidi; struct snd_rawmidi_str *pstr; struct snd_rawmidi_substream *substream; - struct list_head *list; mutex_lock(®ister_mutex); rmidi = snd_rawmidi_search(card, info->device); @@ -589,8 +583,7 @@ int snd_rawmidi_info_select(struct snd_card *card, struct snd_rawmidi_info *info return -ENOENT; if (info->subdevice >= pstr->substream_count) return -ENXIO; - list_for_each(list, &pstr->substreams) { - substream = list_entry(list, struct snd_rawmidi_substream, list); + list_for_each_entry(substream, &pstr->substreams, list) { if ((unsigned int)substream->number == info->subdevice) return snd_rawmidi_info(substream, info); } @@ -1313,14 +1306,14 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry, struct snd_rawmidi *rmidi; struct snd_rawmidi_substream *substream; struct snd_rawmidi_runtime *runtime; - struct list_head *list; rmidi = entry->private_data; snd_iprintf(buffer, "%s\n\n", rmidi->name); mutex_lock(&rmidi->open_mutex); if (rmidi->info_flags & SNDRV_RAWMIDI_INFO_OUTPUT) { - list_for_each(list, &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams) { - substream = list_entry(list, struct snd_rawmidi_substream, list); + list_for_each_entry(substream, + &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams, + list) { snd_iprintf(buffer, "Output %d\n" " Tx bytes : %lu\n", @@ -1339,8 +1332,9 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry, } } if (rmidi->info_flags & SNDRV_RAWMIDI_INFO_INPUT) { - list_for_each(list, &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams) { - substream = list_entry(list, struct snd_rawmidi_substream, list); + list_for_each_entry(substream, + &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams, + list) { snd_iprintf(buffer, "Input %d\n" " Rx bytes : %lu\n", @@ -1625,13 +1619,10 @@ static int snd_rawmidi_dev_disconnect(struct snd_device *device) void snd_rawmidi_set_ops(struct snd_rawmidi *rmidi, int stream, struct snd_rawmidi_ops *ops) { - struct list_head *list; struct snd_rawmidi_substream *substream; - list_for_each(list, &rmidi->streams[stream].substreams) { - substream = list_entry(list, struct snd_rawmidi_substream, list); + list_for_each_entry(substream, &rmidi->streams[stream].substreams, list) substream->ops = ops; - } } /* diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 532a660df51..bb9dd9fa8e5 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -659,7 +659,6 @@ static int deliver_to_subscribers(struct snd_seq_client *client, int err = 0, num_ev = 0; struct snd_seq_event event_saved; struct snd_seq_client_port *src_port; - struct list_head *p; struct snd_seq_port_subs_info *grp; src_port = snd_seq_port_use_ptr(client, event->source.port); @@ -674,8 +673,7 @@ static int deliver_to_subscribers(struct snd_seq_client *client, read_lock(&grp->list_lock); else down_read(&grp->list_mutex); - list_for_each(p, &grp->list_head) { - subs = list_entry(p, struct snd_seq_subscribers, src_list); + list_for_each_entry(subs, &grp->list_head, src_list) { event->dest = subs->info.dest; if (subs->info.flags & SNDRV_SEQ_PORT_SUBS_TIMESTAMP) /* convert time according to flag with subscription */ @@ -709,15 +707,14 @@ static int port_broadcast_event(struct snd_seq_client *client, { int num_ev = 0, err = 0; struct snd_seq_client *dest_client; - struct list_head *p; + struct snd_seq_client_port *port; dest_client = get_event_dest_client(event, SNDRV_SEQ_FILTER_BROADCAST); if (dest_client == NULL) return 0; /* no matching destination */ read_lock(&dest_client->ports_lock); - list_for_each(p, &dest_client->ports_list_head) { - struct snd_seq_client_port *port = list_entry(p, struct snd_seq_client_port, list); + list_for_each_entry(port, &dest_client->ports_list_head, list) { event->dest.port = port->addr.port; /* pass NULL as source client to avoid error bounce */ err = snd_seq_deliver_single_event(NULL, event, @@ -2473,11 +2470,10 @@ static void snd_seq_info_dump_subscribers(struct snd_info_buffer *buffer, static void snd_seq_info_dump_ports(struct snd_info_buffer *buffer, struct snd_seq_client *client) { - struct list_head *l; + struct snd_seq_client_port *p; mutex_lock(&client->ports_mutex); - list_for_each(l, &client->ports_list_head) { - struct snd_seq_client_port *p = list_entry(l, struct snd_seq_client_port, list); + list_for_each_entry(p, &client->ports_list_head, list) { snd_iprintf(buffer, " Port %3d : \"%s\" (%c%c%c%c)\n", p->addr.port, p->name, FLAG_PERM_RD(p->capability), diff --git a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c index b79d011813c..37852cdace7 100644 --- a/sound/core/seq/seq_device.c +++ b/sound/core/seq/seq_device.c @@ -106,11 +106,10 @@ static void remove_drivers(void); static void snd_seq_device_info(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { - struct list_head *head; + struct ops_list *ops; mutex_lock(&ops_mutex); - list_for_each(head, &opslist) { - struct ops_list *ops = list_entry(head, struct ops_list, list); + list_for_each_entry(ops, &opslist, list) { snd_iprintf(buffer, "snd-%s%s%s%s,%d\n", ops->id, ops->driver & DRIVER_LOADED ? ",loaded" : (ops->driver == DRIVER_EMPTY ? ",empty" : ""), @@ -143,7 +142,7 @@ void snd_seq_autoload_unlock(void) void snd_seq_device_load_drivers(void) { #ifdef CONFIG_KMOD - struct list_head *head; + struct ops_list *ops; /* Calling request_module during module_init() * may cause blocking. @@ -155,8 +154,7 @@ void snd_seq_device_load_drivers(void) return; mutex_lock(&ops_mutex); - list_for_each(head, &opslist) { - struct ops_list *ops = list_entry(head, struct ops_list, list); + list_for_each_entry(ops, &opslist, list) { if (! (ops->driver & DRIVER_LOADED) && ! (ops->driver & DRIVER_REQUESTED)) { ops->used++; @@ -314,8 +312,8 @@ static int snd_seq_device_dev_disconnect(struct snd_device *device) int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry, int argsize) { - struct list_head *head; struct ops_list *ops; + struct snd_seq_device *dev; if (id == NULL || entry == NULL || entry->init_device == NULL || entry->free_device == NULL) @@ -341,8 +339,7 @@ int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry, ops->argsize = argsize; /* initialize existing devices if necessary */ - list_for_each(head, &ops->dev_list) { - struct snd_seq_device *dev = list_entry(head, struct snd_seq_device, list); + list_for_each_entry(dev, &ops->dev_list, list) { init_device(dev, ops); } mutex_unlock(&ops->reg_mutex); @@ -394,8 +391,8 @@ static struct ops_list * create_driver(char *id) */ int snd_seq_device_unregister_driver(char *id) { - struct list_head *head; struct ops_list *ops; + struct snd_seq_device *dev; ops = find_driver(id, 0); if (ops == NULL) @@ -411,8 +408,7 @@ int snd_seq_device_unregister_driver(char *id) /* close and release all devices associated with this driver */ mutex_lock(&ops->reg_mutex); ops->driver |= DRIVER_LOCKED; /* do not remove this driver recursively */ - list_for_each(head, &ops->dev_list) { - struct snd_seq_device *dev = list_entry(head, struct snd_seq_device, list); + list_for_each_entry(dev, &ops->dev_list, list) { free_device(dev, ops); } @@ -512,11 +508,10 @@ static int free_device(struct snd_seq_device *dev, struct ops_list *ops) */ static struct ops_list * find_driver(char *id, int create_if_empty) { - struct list_head *head; + struct ops_list *ops; mutex_lock(&ops_mutex); - list_for_each(head, &opslist) { - struct ops_list *ops = list_entry(head, struct ops_list, list); + list_for_each_entry(ops, &opslist, list) { if (strcmp(ops->id, id) == 0) { ops->used++; mutex_unlock(&ops_mutex); diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c index 8c64b58ff77..d88153438d6 100644 --- a/sound/core/seq/seq_ports.c +++ b/sound/core/seq/seq_ports.c @@ -59,14 +59,12 @@ much elements are in array. struct snd_seq_client_port *snd_seq_port_use_ptr(struct snd_seq_client *client, int num) { - struct list_head *p; struct snd_seq_client_port *port; if (client == NULL) return NULL; read_lock(&client->ports_lock); - list_for_each(p, &client->ports_list_head) { - port = list_entry(p, struct snd_seq_client_port, list); + list_for_each_entry(port, &client->ports_list_head, list) { if (port->addr.port == num) { if (port->closing) break; /* deleting now */ @@ -85,14 +83,12 @@ struct snd_seq_client_port *snd_seq_port_query_nearest(struct snd_seq_client *cl struct snd_seq_port_info *pinfo) { int num; - struct list_head *p; struct snd_seq_client_port *port, *found; num = pinfo->addr.port; found = NULL; read_lock(&client->ports_lock); - list_for_each(p, &client->ports_list_head) { - port = list_entry(p, struct snd_seq_client_port, list); + list_for_each_entry(port, &client->ports_list_head, list) { if (port->addr.port < num) continue; if (port->addr.port == num) { @@ -131,8 +127,7 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client, int port) { unsigned long flags; - struct snd_seq_client_port *new_port; - struct list_head *l; + struct snd_seq_client_port *new_port, *p; int num = -1; /* sanity check */ @@ -161,15 +156,14 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client, num = port >= 0 ? port : 0; mutex_lock(&client->ports_mutex); write_lock_irqsave(&client->ports_lock, flags); - list_for_each(l, &client->ports_list_head) { - struct snd_seq_client_port *p = list_entry(l, struct snd_seq_client_port, list); + list_for_each_entry(p, &client->ports_list_head, list) { if (p->addr.port > num) break; if (port < 0) /* auto-probe mode */ num = p->addr.port + 1; } /* insert the new port */ - list_add_tail(&new_port->list, l); + list_add_tail(&new_port->list, &p->list); client->num_ports++; new_port->addr.port = num; /* store the port number in the port */ write_unlock_irqrestore(&client->ports_lock, flags); @@ -287,16 +281,14 @@ static int port_delete(struct snd_seq_client *client, int snd_seq_delete_port(struct snd_seq_client *client, int port) { unsigned long flags; - struct list_head *l; - struct snd_seq_client_port *found = NULL; + struct snd_seq_client_port *found = NULL, *p; mutex_lock(&client->ports_mutex); write_lock_irqsave(&client->ports_lock, flags); - list_for_each(l, &client->ports_list_head) { - struct snd_seq_client_port *p = list_entry(l, struct snd_seq_client_port, list); + list_for_each_entry(p, &client->ports_list_head, list) { if (p->addr.port == port) { /* ok found. delete from the list at first */ - list_del(l); + list_del(&p->list); client->num_ports--; found = p; break; @@ -314,7 +306,8 @@ int snd_seq_delete_port(struct snd_seq_client *client, int port) int snd_seq_delete_all_ports(struct snd_seq_client *client) { unsigned long flags; - struct list_head deleted_list, *p, *n; + struct list_head deleted_list; + struct snd_seq_client_port *port, *tmp; /* move the port list to deleted_list, and * clear the port list in the client data. @@ -331,9 +324,8 @@ int snd_seq_delete_all_ports(struct snd_seq_client *client) write_unlock_irqrestore(&client->ports_lock, flags); /* remove each port in deleted_list */ - list_for_each_safe(p, n, &deleted_list) { - struct snd_seq_client_port *port = list_entry(p, struct snd_seq_client_port, list); - list_del(p); + list_for_each_entry_safe(port, tmp, &deleted_list, list) { + list_del(&port->list); snd_seq_system_client_ev_port_exit(port->addr.client, port->addr.port); port_delete(client, port); } @@ -500,8 +492,7 @@ int snd_seq_port_connect(struct snd_seq_client *connector, { struct snd_seq_port_subs_info *src = &src_port->c_src; struct snd_seq_port_subs_info *dest = &dest_port->c_dest; - struct snd_seq_subscribers *subs; - struct list_head *p; + struct snd_seq_subscribers *subs, *s; int err, src_called = 0; unsigned long flags; int exclusive; @@ -525,13 +516,11 @@ int snd_seq_port_connect(struct snd_seq_client *connector, if (src->exclusive || dest->exclusive) goto __error; /* check whether already exists */ - list_for_each(p, &src->list_head) { - struct snd_seq_subscribers *s = list_entry(p, struct snd_seq_subscribers, src_list); + list_for_each_entry(s, &src->list_head, src_list) { if (match_subs_info(info, &s->info)) goto __error; } - list_for_each(p, &dest->list_head) { - struct snd_seq_subscribers *s = list_entry(p, struct snd_seq_subscribers, dest_list); + list_for_each_entry(s, &dest->list_head, dest_list) { if (match_subs_info(info, &s->info)) goto __error; } @@ -582,7 +571,6 @@ int snd_seq_port_disconnect(struct snd_seq_client *connector, struct snd_seq_port_subs_info *src = &src_port->c_src; struct snd_seq_port_subs_info *dest = &dest_port->c_dest; struct snd_seq_subscribers *subs; - struct list_head *p; int err = -ENOENT; unsigned long flags; @@ -590,8 +578,7 @@ int snd_seq_port_disconnect(struct snd_seq_client *connector, down_write_nested(&dest->list_mutex, SINGLE_DEPTH_NESTING); /* look for the connection */ - list_for_each(p, &src->list_head) { - subs = list_entry(p, struct snd_seq_subscribers, src_list); + list_for_each_entry(subs, &src->list_head, src_list) { if (match_subs_info(info, &subs->info)) { write_lock_irqsave(&src->list_lock, flags); // write_lock(&dest->list_lock); // no lock yet @@ -620,12 +607,10 @@ int snd_seq_port_disconnect(struct snd_seq_client *connector, struct snd_seq_subscribers *snd_seq_port_get_subscription(struct snd_seq_port_subs_info *src_grp, struct snd_seq_addr *dest_addr) { - struct list_head *p; struct snd_seq_subscribers *s, *found = NULL; down_read(&src_grp->list_mutex); - list_for_each(p, &src_grp->list_head) { - s = list_entry(p, struct snd_seq_subscribers, src_list); + list_for_each_entry(s, &src_grp->list_head, src_list) { if (addr_match(dest_addr, &s->info.dest)) { found = s; break; diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c index 0cfa06c6b81..972f9340536 100644 --- a/sound/core/seq/seq_virmidi.c +++ b/sound/core/seq/seq_virmidi.c @@ -81,13 +81,11 @@ static int snd_virmidi_dev_receive_event(struct snd_virmidi_dev *rdev, struct snd_seq_event *ev) { struct snd_virmidi *vmidi; - struct list_head *list; unsigned char msg[4]; int len; read_lock(&rdev->filelist_lock); - list_for_each(list, &rdev->filelist) { - vmidi = list_entry(list, struct snd_virmidi, list); + list_for_each_entry(vmidi, &rdev->filelist, list) { if (!vmidi->trigger) continue; if (ev->type == SNDRV_SEQ_EVENT_SYSEX) { diff --git a/sound/core/timer.c b/sound/core/timer.c index 10a79aed33f..4e79f9ce1a8 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -130,11 +130,8 @@ static struct snd_timer_instance *snd_timer_instance_new(char *owner, static struct snd_timer *snd_timer_find(struct snd_timer_id *tid) { struct snd_timer *timer = NULL; - struct list_head *p; - - list_for_each(p, &snd_timer_list) { - timer = list_entry(p, struct snd_timer, device_list); + list_for_each_entry(timer, &snd_timer_list, device_list) { if (timer->tmr_class != tid->dev_class) continue; if ((timer->tmr_class == SNDRV_TIMER_CLASS_CARD || @@ -184,13 +181,10 @@ static void snd_timer_check_slave(struct snd_timer_instance *slave) { struct snd_timer *timer; struct snd_timer_instance *master; - struct list_head *p, *q; /* FIXME: it's really dumb to look up all entries.. */ - list_for_each(p, &snd_timer_list) { - timer = list_entry(p, struct snd_timer, device_list); - list_for_each(q, &timer->open_list_head) { - master = list_entry(q, struct snd_timer_instance, open_list); + list_for_each_entry(timer, &snd_timer_list, device_list) { + list_for_each_entry(master, &timer->open_list_head, open_list) { if (slave->slave_class == master->slave_class && slave->slave_id == master->slave_id) { list_del(&slave->open_list); @@ -214,16 +208,13 @@ static void snd_timer_check_slave(struct snd_timer_instance *slave) */ static void snd_timer_check_master(struct snd_timer_instance *master) { - struct snd_timer_instance *slave; - struct list_head *p, *n; + struct snd_timer_instance *slave, *tmp; /* check all pending slaves */ - list_for_each_safe(p, n, &snd_timer_slave_list) { - slave = list_entry(p, struct snd_timer_instance, open_list); + list_for_each_entry_safe(slave, tmp, &snd_timer_slave_list, open_list) { if (slave->slave_class == master->slave_class && slave->slave_id == master->slave_id) { - list_del(p); - list_add_tail(p, &master->slave_list_head); + list_move_tail(&slave->open_list, &master->slave_list_head); spin_lock_irq(&slave_active_lock); slave->master = master; slave->timer = master->timer; @@ -317,8 +308,7 @@ static int _snd_timer_stop(struct snd_timer_instance *timeri, int snd_timer_close(struct snd_timer_instance *timeri) { struct snd_timer *timer = NULL; - struct list_head *p, *n; - struct snd_timer_instance *slave; + struct snd_timer_instance *slave, *tmp; snd_assert(timeri != NULL, return -ENXIO); @@ -353,12 +343,11 @@ int snd_timer_close(struct snd_timer_instance *timeri) timer->hw.close) timer->hw.close(timer); /* remove slave links */ - list_for_each_safe(p, n, &timeri->slave_list_head) { - slave = list_entry(p, struct snd_timer_instance, open_list); + list_for_each_entry_safe(slave, tmp, &timeri->slave_list_head, + open_list) { spin_lock_irq(&slave_active_lock); _snd_timer_stop(slave, 1, SNDRV_TIMER_EVENT_RESOLUTION); - list_del(p); - list_add_tail(p, &snd_timer_slave_list); + list_move_tail(&slave->open_list, &snd_timer_slave_list); slave->master = NULL; slave->timer = NULL; spin_unlock_irq(&slave_active_lock); @@ -394,7 +383,6 @@ static void snd_timer_notify1(struct snd_timer_instance *ti, int event) unsigned long flags; unsigned long resolution = 0; struct snd_timer_instance *ts; - struct list_head *n; struct timespec tstamp; getnstimeofday(&tstamp); @@ -413,11 +401,9 @@ static void snd_timer_notify1(struct snd_timer_instance *ti, int event) if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE) return; spin_lock_irqsave(&timer->lock, flags); - list_for_each(n, &ti->slave_active_head) { - ts = list_entry(n, struct snd_timer_instance, active_list); + list_for_each_entry(ts, &ti->slave_active_head, active_list) if (ts->ccallback) ts->ccallback(ti, event + 100, &tstamp, resolution); - } spin_unlock_irqrestore(&timer->lock, flags); } @@ -593,10 +579,8 @@ static void snd_timer_reschedule(struct snd_timer * timer, unsigned long ticks_l { struct snd_timer_instance *ti; unsigned long ticks = ~0UL; - struct list_head *p; - list_for_each(p, &timer->active_list_head) { - ti = list_entry(p, struct snd_timer_instance, active_list); + list_for_each_entry(ti, &timer->active_list_head, active_list) { if (ti->flags & SNDRV_TIMER_IFLG_START) { ti->flags &= ~SNDRV_TIMER_IFLG_START; ti->flags |= SNDRV_TIMER_IFLG_RUNNING; @@ -661,9 +645,9 @@ static void snd_timer_tasklet(unsigned long arg) */ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left) { - struct snd_timer_instance *ti, *ts; + struct snd_timer_instance *ti, *ts, *tmp; unsigned long resolution, ticks; - struct list_head *p, *q, *n, *ack_list_head; + struct list_head *p, *ack_list_head; unsigned long flags; int use_tasklet = 0; @@ -679,12 +663,12 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left) resolution = timer->hw.resolution; /* loop for all active instances - * Here we cannot use list_for_each because the active_list of a + * Here we cannot use list_for_each_entry because the active_list of a * processed instance is relinked to done_list_head before the callback * is called. */ - list_for_each_safe(p, n, &timer->active_list_head) { - ti = list_entry(p, struct snd_timer_instance, active_list); + list_for_each_entry_safe(ti, tmp, &timer->active_list_head, + active_list) { if (!(ti->flags & SNDRV_TIMER_IFLG_RUNNING)) continue; ti->pticks += ticks_left; @@ -700,7 +684,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left) } else { ti->flags &= ~SNDRV_TIMER_IFLG_RUNNING; if (--timer->running) - list_del(p); + list_del(&ti->active_list); } if ((timer->hw.flags & SNDRV_TIMER_HW_TASKLET) || (ti->flags & SNDRV_TIMER_IFLG_FAST)) @@ -709,8 +693,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left) ack_list_head = &timer->sack_list_head; if (list_empty(&ti->ack_list)) list_add_tail(&ti->ack_list, ack_list_head); - list_for_each(q, &ti->slave_active_head) { - ts = list_entry(q, struct snd_timer_instance, active_list); + list_for_each_entry(ts, &ti->slave_active_head, active_list) { ts->pticks = ti->pticks; ts->resolution = resolution; if (list_empty(&ts->ack_list)) @@ -844,7 +827,6 @@ static int snd_timer_dev_register(struct snd_device *dev) { struct snd_timer *timer = dev->device_data; struct snd_timer *timer1; - struct list_head *p; snd_assert(timer != NULL && timer->hw.start != NULL && timer->hw.stop != NULL, return -ENXIO); @@ -853,8 +835,7 @@ static int snd_timer_dev_register(struct snd_device *dev) return -EINVAL; mutex_lock(®ister_mutex); - list_for_each(p, &snd_timer_list) { - timer1 = list_entry(p, struct snd_timer, device_list); + list_for_each_entry(timer1, &snd_timer_list, device_list) { if (timer1->tmr_class > timer->tmr_class) break; if (timer1->tmr_class < timer->tmr_class) @@ -877,7 +858,7 @@ static int snd_timer_dev_register(struct snd_device *dev) mutex_unlock(®ister_mutex); return -EBUSY; } - list_add_tail(&timer->device_list, p); + list_add_tail(&timer->device_list, &timer1->device_list); mutex_unlock(®ister_mutex); return 0; } @@ -896,7 +877,6 @@ void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstam unsigned long flags; unsigned long resolution = 0; struct snd_timer_instance *ti, *ts; - struct list_head *p, *n; if (! (timer->hw.flags & SNDRV_TIMER_HW_SLAVE)) return; @@ -911,15 +891,12 @@ void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstam else resolution = timer->hw.resolution; } - list_for_each(p, &timer->active_list_head) { - ti = list_entry(p, struct snd_timer_instance, active_list); + list_for_each_entry(ti, &timer->active_list_head, active_list) { if (ti->ccallback) ti->ccallback(ti, event, tstamp, resolution); - list_for_each(n, &ti->slave_active_head) { - ts = list_entry(n, struct snd_timer_instance, active_list); + list_for_each_entry(ts, &ti->slave_active_head, active_list) if (ts->ccallback) ts->ccallback(ts, event, tstamp, resolution); - } } spin_unlock_irqrestore(&timer->lock, flags); } @@ -1057,11 +1034,9 @@ static void snd_timer_proc_read(struct snd_info_entry *entry, { struct snd_timer *timer; struct snd_timer_instance *ti; - struct list_head *p, *q; mutex_lock(®ister_mutex); - list_for_each(p, &snd_timer_list) { - timer = list_entry(p, struct snd_timer, device_list); + list_for_each_entry(timer, &snd_timer_list, device_list) { switch (timer->tmr_class) { case SNDRV_TIMER_CLASS_GLOBAL: snd_iprintf(buffer, "G%i: ", timer->tmr_device); @@ -1088,14 +1063,12 @@ static void snd_timer_proc_read(struct snd_info_entry *entry, if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE) snd_iprintf(buffer, " SLAVE"); snd_iprintf(buffer, "\n"); - list_for_each(q, &timer->open_list_head) { - ti = list_entry(q, struct snd_timer_instance, open_list); + list_for_each_entry(ti, &timer->open_list_head, open_list) snd_iprintf(buffer, " Client %s : %s\n", ti->owner ? ti->owner : "unknown", ti->flags & (SNDRV_TIMER_IFLG_START | SNDRV_TIMER_IFLG_RUNNING) ? "running" : "stopped"); - } } mutex_unlock(®ister_mutex); } -- cgit v1.2.3 From bbb53551e31dce3cdbf61330e135179a55c82fd1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 5 Oct 2006 16:21:19 +0200 Subject: [ALSA] emu10k1 - Fix compile warning Fixed a compile warning regarding print format for size_t. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/emu10k1/emu10k1_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 891172f2b1d..09c4db8495b 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -615,7 +615,7 @@ static int snd_emu1010_load_firmware(struct snd_emu10k1 * emu, const char * file snd_printk(KERN_ERR "firmware: %s not found. Err=%d\n",filename, err); return err; } - snd_printk(KERN_INFO "firmware size=0x%x\n",fw_entry->size); + snd_printk(KERN_INFO "firmware size=0x%zx\n", fw_entry->size); if (fw_entry->size != 0x133a4) { snd_printk(KERN_ERR "firmware: %s wrong size.\n",filename); return -EINVAL; -- cgit v1.2.3 From b66b3cfe6c2f6560f351278883a325b6ebc478f5 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Fri, 6 Oct 2006 09:34:20 +0200 Subject: [ALSA] hda_intel: increase maximum DMA buffer size to 1024MB See ALSA bug#2481 . Signed-off-by: Jaroslav Kysela --- sound/pci/hda/hda_intel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 1a7e82104bb..d15c9b845f2 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1285,7 +1285,7 @@ static int __devinit create_codec_pcm(struct azx *chip, struct hda_codec *codec, snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &azx_pcm_ops); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), - 1024 * 64, 1024 * 128); + 1024 * 64, 1024 * 1024); chip->pcm[pcm_dev] = pcm; if (chip->pcm_devs < pcm_dev + 1) chip->pcm_devs = pcm_dev + 1; -- cgit v1.2.3 From c7132aeb72ad1106dc76279de4d005f9e1c5815c Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Fri, 6 Oct 2006 15:12:29 +0200 Subject: [ALSA] pcm core: add prealloc_max file to substream directory to show maximum DMA size Users ask us many times about the maximum DMA size for PCM devices. This file gives them a hint in KB. Signed-off-by: Jaroslav Kysela --- sound/core/pcm_memory.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'sound') diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index be030cb4d37..95b1b2f0b1e 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c @@ -101,6 +101,8 @@ int snd_pcm_lib_preallocate_free(struct snd_pcm_substream *substream) { snd_pcm_lib_preallocate_dma_free(substream); #ifdef CONFIG_SND_VERBOSE_PROCFS + snd_info_free_entry(substream->proc_prealloc_max_entry); + substream->proc_prealloc_max_entry = NULL; snd_info_free_entry(substream->proc_prealloc_entry); substream->proc_prealloc_entry = NULL; #endif @@ -141,6 +143,18 @@ static void snd_pcm_lib_preallocate_proc_read(struct snd_info_entry *entry, snd_iprintf(buffer, "%lu\n", (unsigned long) substream->dma_buffer.bytes / 1024); } +/* + * read callback for prealloc_max proc file + * + * prints the maximum allowed size in kB. + */ +static void snd_pcm_lib_preallocate_max_proc_read(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) +{ + struct snd_pcm_substream *substream = entry->private_data; + snd_iprintf(buffer, "%lu\n", (unsigned long) substream->dma_max / 1024); +} + /* * write callback for prealloc proc file * @@ -203,6 +217,15 @@ static inline void preallocate_info_init(struct snd_pcm_substream *substream) } } substream->proc_prealloc_entry = entry; + if ((entry = snd_info_create_card_entry(substream->pcm->card, "prealloc_max", substream->proc_root)) != NULL) { + entry->c.text.read = snd_pcm_lib_preallocate_max_proc_read; + entry->private_data = substream; + if (snd_info_register(entry) < 0) { + snd_info_free_entry(entry); + entry = NULL; + } + } + substream->proc_prealloc_max_entry = entry; } #else /* !CONFIG_SND_VERBOSE_PROCFS */ -- cgit v1.2.3 From 3388c37e04ec0e35ebc1b4c732fdefc9ea938f3b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 6 Oct 2006 17:06:39 +0200 Subject: [ALSA] intel8x0 - Use pci_iomap Use pci_iomap and ioread*/iowrite*() functions for accessing hardwares. pci_iomap is suitable for hardwares like ICH and compatible that have both PIO and MMIO. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/intel8x0.c | 120 ++++++++++++++++++-------------------------------- sound/pci/intel8x0m.c | 118 +++++++++++++++++-------------------------------- 2 files changed, 83 insertions(+), 155 deletions(-) (limited to 'sound') diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 30aaa6092a8..28d5d9deb89 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -368,12 +368,8 @@ struct intel8x0 { int irq; - unsigned int mmio; - unsigned long addr; - void __iomem *remap_addr; - unsigned int bm_mmio; - unsigned long bmaddr; - void __iomem *remap_bmaddr; + void __iomem *addr; + void __iomem *bmaddr; struct pci_dev *pci; struct snd_card *card; @@ -446,72 +442,48 @@ MODULE_DEVICE_TABLE(pci, snd_intel8x0_ids); * Lowlevel I/O - busmaster */ -static u8 igetbyte(struct intel8x0 *chip, u32 offset) +static inline u8 igetbyte(struct intel8x0 *chip, u32 offset) { - if (chip->bm_mmio) - return readb(chip->remap_bmaddr + offset); - else - return inb(chip->bmaddr + offset); + return ioread8(chip->bmaddr + offset); } -static u16 igetword(struct intel8x0 *chip, u32 offset) +static inline u16 igetword(struct intel8x0 *chip, u32 offset) { - if (chip->bm_mmio) - return readw(chip->remap_bmaddr + offset); - else - return inw(chip->bmaddr + offset); + return ioread16(chip->bmaddr + offset); } -static u32 igetdword(struct intel8x0 *chip, u32 offset) +static inline u32 igetdword(struct intel8x0 *chip, u32 offset) { - if (chip->bm_mmio) - return readl(chip->remap_bmaddr + offset); - else - return inl(chip->bmaddr + offset); + return ioread32(chip->bmaddr + offset); } -static void iputbyte(struct intel8x0 *chip, u32 offset, u8 val) +static inline void iputbyte(struct intel8x0 *chip, u32 offset, u8 val) { - if (chip->bm_mmio) - writeb(val, chip->remap_bmaddr + offset); - else - outb(val, chip->bmaddr + offset); + iowrite8(val, chip->bmaddr + offset); } -static void iputword(struct intel8x0 *chip, u32 offset, u16 val) +static inline void iputword(struct intel8x0 *chip, u32 offset, u16 val) { - if (chip->bm_mmio) - writew(val, chip->remap_bmaddr + offset); - else - outw(val, chip->bmaddr + offset); + iowrite16(val, chip->bmaddr + offset); } -static void iputdword(struct intel8x0 *chip, u32 offset, u32 val) +static inline void iputdword(struct intel8x0 *chip, u32 offset, u32 val) { - if (chip->bm_mmio) - writel(val, chip->remap_bmaddr + offset); - else - outl(val, chip->bmaddr + offset); + iowrite32(val, chip->bmaddr + offset); } /* * Lowlevel I/O - AC'97 registers */ -static u16 iagetword(struct intel8x0 *chip, u32 offset) +static inline u16 iagetword(struct intel8x0 *chip, u32 offset) { - if (chip->mmio) - return readw(chip->remap_addr + offset); - else - return inw(chip->addr + offset); + return ioread16(chip->addr + offset); } -static void iaputword(struct intel8x0 *chip, u32 offset, u16 val) +static inline void iaputword(struct intel8x0 *chip, u32 offset, u16 val) { - if (chip->mmio) - writew(val, chip->remap_addr + offset); - else - outw(val, chip->addr + offset); + iowrite16(val, chip->addr + offset); } /* @@ -2443,10 +2415,10 @@ static int snd_intel8x0_free(struct intel8x0 *chip) fill_nocache(chip->bdbars.area, chip->bdbars.bytes, 0); snd_dma_free_pages(&chip->bdbars); } - if (chip->remap_addr) - iounmap(chip->remap_addr); - if (chip->remap_bmaddr) - iounmap(chip->remap_bmaddr); + if (chip->addr) + pci_iounmap(chip->pci, chip->addr); + if (chip->bmaddr) + pci_iounmap(chip->pci, chip->bmaddr); pci_release_regions(chip->pci); pci_disable_device(chip->pci); kfree(chip); @@ -2793,35 +2765,27 @@ static int __devinit snd_intel8x0_create(struct snd_card *card, if (device_type == DEVICE_ALI) { /* ALI5455 has no ac97 region */ - chip->bmaddr = pci_resource_start(pci, 0); + chip->bmaddr = pci_iomap(pci, 0, 0); goto port_inited; } - if (pci_resource_flags(pci, 2) & IORESOURCE_MEM) { /* ICH4 and Nforce */ - chip->mmio = 1; - chip->addr = pci_resource_start(pci, 2); - chip->remap_addr = ioremap_nocache(chip->addr, - pci_resource_len(pci, 2)); - if (chip->remap_addr == NULL) { - snd_printk(KERN_ERR "AC'97 space ioremap problem\n"); - snd_intel8x0_free(chip); - return -EIO; - } - } else { - chip->addr = pci_resource_start(pci, 0); - } - if (pci_resource_flags(pci, 3) & IORESOURCE_MEM) { /* ICH4 */ - chip->bm_mmio = 1; - chip->bmaddr = pci_resource_start(pci, 3); - chip->remap_bmaddr = ioremap_nocache(chip->bmaddr, - pci_resource_len(pci, 3)); - if (chip->remap_bmaddr == NULL) { - snd_printk(KERN_ERR "Controller space ioremap problem\n"); - snd_intel8x0_free(chip); - return -EIO; - } - } else { - chip->bmaddr = pci_resource_start(pci, 1); + if (pci_resource_flags(pci, 2) & IORESOURCE_MEM) /* ICH4 and Nforce */ + chip->addr = pci_iomap(pci, 2, 0); + else + chip->addr = pci_iomap(pci, 0, 0); + if (!chip->addr) { + snd_printk(KERN_ERR "AC'97 space ioremap problem\n"); + snd_intel8x0_free(chip); + return -EIO; + } + if (pci_resource_flags(pci, 3) & IORESOURCE_MEM) /* ICH4 */ + chip->bmaddr = pci_iomap(pci, 3, 0); + else + chip->bmaddr = pci_iomap(pci, 1, 0); + if (!chip->bmaddr) { + snd_printk(KERN_ERR "Controller space ioremap problem\n"); + snd_intel8x0_free(chip); + return -EIO; } port_inited: @@ -3025,8 +2989,8 @@ static int __devinit snd_intel8x0_probe(struct pci_dev *pci, snd_intel8x0_proc_init(chip); snprintf(card->longname, sizeof(card->longname), - "%s with %s at %#lx, irq %i", card->shortname, - snd_ac97_get_short_name(chip->ac97[0]), chip->addr, chip->irq); + "%s with %s at irq %i", card->shortname, + snd_ac97_get_short_name(chip->ac97[0]), chip->irq); if (! ac97_clock) intel8x0_measure_ac97_clock(chip); diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c index 09dcf923b54..936c3cf1693 100644 --- a/sound/pci/intel8x0m.c +++ b/sound/pci/intel8x0m.c @@ -196,12 +196,8 @@ struct intel8x0m { int irq; - unsigned int mmio; - unsigned long addr; - void __iomem *remap_addr; - unsigned int bm_mmio; - unsigned long bmaddr; - void __iomem *remap_bmaddr; + void __iomem *addr; + void __iomem *bmaddr; struct pci_dev *pci; struct snd_card *card; @@ -253,72 +249,48 @@ MODULE_DEVICE_TABLE(pci, snd_intel8x0m_ids); * Lowlevel I/O - busmaster */ -static u8 igetbyte(struct intel8x0m *chip, u32 offset) +static inline u8 igetbyte(struct intel8x0m *chip, u32 offset) { - if (chip->bm_mmio) - return readb(chip->remap_bmaddr + offset); - else - return inb(chip->bmaddr + offset); + return ioread8(chip->bmaddr + offset); } -static u16 igetword(struct intel8x0m *chip, u32 offset) +static inline u16 igetword(struct intel8x0m *chip, u32 offset) { - if (chip->bm_mmio) - return readw(chip->remap_bmaddr + offset); - else - return inw(chip->bmaddr + offset); + return ioread16(chip->bmaddr + offset); } -static u32 igetdword(struct intel8x0m *chip, u32 offset) +static inline u32 igetdword(struct intel8x0m *chip, u32 offset) { - if (chip->bm_mmio) - return readl(chip->remap_bmaddr + offset); - else - return inl(chip->bmaddr + offset); + return ioread32(chip->bmaddr + offset); } -static void iputbyte(struct intel8x0m *chip, u32 offset, u8 val) +static inline void iputbyte(struct intel8x0m *chip, u32 offset, u8 val) { - if (chip->bm_mmio) - writeb(val, chip->remap_bmaddr + offset); - else - outb(val, chip->bmaddr + offset); + iowrite8(val, chip->bmaddr + offset); } -static void iputword(struct intel8x0m *chip, u32 offset, u16 val) +static inline void iputword(struct intel8x0m *chip, u32 offset, u16 val) { - if (chip->bm_mmio) - writew(val, chip->remap_bmaddr + offset); - else - outw(val, chip->bmaddr + offset); + iowrite16(val, chip->bmaddr + offset); } -static void iputdword(struct intel8x0m *chip, u32 offset, u32 val) +static inline void iputdword(struct intel8x0m *chip, u32 offset, u32 val) { - if (chip->bm_mmio) - writel(val, chip->remap_bmaddr + offset); - else - outl(val, chip->bmaddr + offset); + iowrite32(val, chip->bmaddr + offset); } /* * Lowlevel I/O - AC'97 registers */ -static u16 iagetword(struct intel8x0m *chip, u32 offset) +static inline u16 iagetword(struct intel8x0m *chip, u32 offset) { - if (chip->mmio) - return readw(chip->remap_addr + offset); - else - return inw(chip->addr + offset); + return ioread16(chip->addr + offset); } -static void iaputword(struct intel8x0m *chip, u32 offset, u16 val) +static inline void iaputword(struct intel8x0m *chip, u32 offset, u16 val) { - if (chip->mmio) - writew(val, chip->remap_addr + offset); - else - outw(val, chip->addr + offset); + iowrite16(val, chip->addr + offset); } /* @@ -1019,10 +991,10 @@ static int snd_intel8x0_free(struct intel8x0m *chip) __hw_end: if (chip->bdbars.area) snd_dma_free_pages(&chip->bdbars); - if (chip->remap_addr) - iounmap(chip->remap_addr); - if (chip->remap_bmaddr) - iounmap(chip->remap_bmaddr); + if (chip->addr) + pci_iounmap(chip->pci, chip->addr); + if (chip->bmaddr) + pci_iounmap(chip->pci, chip->bmaddr); if (chip->irq >= 0) free_irq(chip->irq, chip); pci_release_regions(chip->pci); @@ -1173,35 +1145,27 @@ static int __devinit snd_intel8x0m_create(struct snd_card *card, if (device_type == DEVICE_ALI) { /* ALI5455 has no ac97 region */ - chip->bmaddr = pci_resource_start(pci, 0); + chip->bmaddr = pci_iomap(pci, 0, 0); goto port_inited; } - if (pci_resource_flags(pci, 2) & IORESOURCE_MEM) { /* ICH4 and Nforce */ - chip->mmio = 1; - chip->addr = pci_resource_start(pci, 2); - chip->remap_addr = ioremap_nocache(chip->addr, - pci_resource_len(pci, 2)); - if (chip->remap_addr == NULL) { - snd_printk(KERN_ERR "AC'97 space ioremap problem\n"); - snd_intel8x0_free(chip); - return -EIO; - } - } else { - chip->addr = pci_resource_start(pci, 0); + if (pci_resource_flags(pci, 2) & IORESOURCE_MEM) /* ICH4 and Nforce */ + chip->addr = pci_iomap(pci, 2, 0); + else + chip->addr = pci_iomap(pci, 0, 0); + if (!chip->addr) { + snd_printk(KERN_ERR "AC'97 space ioremap problem\n"); + snd_intel8x0_free(chip); + return -EIO; } - if (pci_resource_flags(pci, 3) & IORESOURCE_MEM) { /* ICH4 */ - chip->bm_mmio = 1; - chip->bmaddr = pci_resource_start(pci, 3); - chip->remap_bmaddr = ioremap_nocache(chip->bmaddr, - pci_resource_len(pci, 3)); - if (chip->remap_bmaddr == NULL) { - snd_printk(KERN_ERR "Controller space ioremap problem\n"); - snd_intel8x0_free(chip); - return -EIO; - } - } else { - chip->bmaddr = pci_resource_start(pci, 1); + if (pci_resource_flags(pci, 3) & IORESOURCE_MEM) /* ICH4 */ + chip->bmaddr = pci_iomap(pci, 3, 0); + else + chip->bmaddr = pci_iomap(pci, 1, 0); + if (!chip->bmaddr) { + snd_printk(KERN_ERR "Controller space ioremap problem\n"); + snd_intel8x0_free(chip); + return -EIO; } port_inited: @@ -1339,8 +1303,8 @@ static int __devinit snd_intel8x0m_probe(struct pci_dev *pci, snd_intel8x0m_proc_init(chip); - sprintf(card->longname, "%s at 0x%lx, irq %i", - card->shortname, chip->addr, chip->irq); + sprintf(card->longname, "%s at irq %i", + card->shortname, chip->irq); if ((err = snd_card_register(card)) < 0) { snd_card_free(card); -- cgit v1.2.3 From db2a416556af0313db028147e4a22fef6f214f2f Mon Sep 17 00:00:00 2001 From: Frank Mandarino Date: Fri, 6 Oct 2006 18:31:09 +0200 Subject: [ALSA] ASoC: core code This patch is the core of ASoC functionality. The ASoC core is designed to provide the following features :- o Codec independence. Allows reuse of codec drivers on other platforms and machines. o Platform driver code reuse. Reuse of platform specific audio DMA and DAI drivers on different machines. o Easy I2S/PCM digital audio interface configuration between codec and SoC. Each SoC interface and codec registers their audio interface capabilities with the core at initialisation. The capabilities are subsequently matched and configured at run time for best power and performance when the application hw params are known. o Machine specific controls/operations: Allow machines to add controls and operations to the audio subsystem. e.g. volume control for speaker amp. To achieve all this, ASoC splits an embedded audio system into 3 components :- 1. Codec driver: The codec driver is platform independent and contains audio controls, audio interface capabilities, codec dapm and codec IO functions. 2. Platform driver: The platform driver contains the audio dma engine and audio interface drivers (e.g. I2S, AC97, PCM) for that platform. 3. Machine driver: The machine driver handles any machine specific controls and audio events. i.e. turning on an amp at start of playback. Signed-off-by: Frank Mandarino Signed-off-by: Richard Purdie Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/soc-core.c | 1920 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1920 insertions(+) create mode 100644 sound/soc/soc-core.c (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c new file mode 100644 index 00000000000..e841ad46c75 --- /dev/null +++ b/sound/soc/soc-core.c @@ -0,0 +1,1920 @@ +/* + * soc-core.c -- ALSA SoC Audio Layer + * + * Copyright 2005 Wolfson Microelectronics PLC. + * Author: Liam Girdwood + * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision history + * 12th Aug 2005 Initial version. + * 25th Oct 2005 Working Codec, Interface and Platform registration. + * + * TODO: + * o Add hw rules to enforce rates, etc. + * o More testing with other codecs/machines. + * o Add more codecs and platforms to ensure good API coverage. + * o Support TDM on PCM and I2S + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* debug */ +#define SOC_DEBUG 0 +#if SOC_DEBUG +#define dbg(format, arg...) printk(format, ## arg) +#else +#define dbg(format, arg...) +#endif +/* debug DAI capabilities matching */ +#define SOC_DEBUG_DAI 0 +#if SOC_DEBUG_DAI +#define dbgc(format, arg...) printk(format, ## arg) +#else +#define dbgc(format, arg...) +#endif + +static DEFINE_MUTEX(pcm_mutex); +static DEFINE_MUTEX(io_mutex); +static struct workqueue_struct *soc_workq; +static struct work_struct soc_stream_work; +static DECLARE_WAIT_QUEUE_HEAD(soc_pm_waitq); + +/* supported sample rates */ +/* ATTENTION: these values depend on the definition in pcm.h! */ +static const unsigned int rates[] = { + 5512, 8000, 11025, 16000, 22050, 32000, 44100, + 48000, 64000, 88200, 96000, 176400, 192000 +}; + +/* + * This is a timeout to do a DAPM powerdown after a stream is closed(). + * It can be used to eliminate pops between different playback streams, e.g. + * between two audio tracks. + */ +static int pmdown_time = 5000; +module_param(pmdown_time, int, 0); +MODULE_PARM_DESC(pmdown_time, "DAPM stream powerdown time (msecs)"); + +#ifdef CONFIG_SND_SOC_AC97_BUS +/* unregister ac97 codec */ +static int soc_ac97_dev_unregister(struct snd_soc_codec *codec) +{ + if (codec->ac97->dev.bus) + device_unregister(&codec->ac97->dev); + return 0; +} + +/* stop no dev release warning */ +static void soc_ac97_device_release(struct device *dev){} + +/* register ac97 codec to bus */ +static int soc_ac97_dev_register(struct snd_soc_codec *codec) +{ + int err; + + codec->ac97->dev.bus = &ac97_bus_type; + codec->ac97->dev.parent = NULL; + codec->ac97->dev.release = soc_ac97_device_release; + + snprintf(codec->ac97->dev.bus_id, BUS_ID_SIZE, "%d-%d:%s", + codec->card->number, 0, codec->name); + err = device_register(&codec->ac97->dev); + if (err < 0) { + snd_printk(KERN_ERR "Can't register ac97 bus\n"); + codec->ac97->dev.bus = NULL; + return err; + } + return 0; +} +#endif + +static inline const char* get_dai_name(int type) +{ + switch(type) { + case SND_SOC_DAI_AC97: + return "AC97"; + case SND_SOC_DAI_I2S: + return "I2S"; + case SND_SOC_DAI_PCM: + return "PCM"; + } + return NULL; +} + +/* get rate format from rate */ +static inline int soc_get_rate_format(int rate) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(rates); i++) { + if (rates[i] == rate) + return 1 << i; + } + return 0; +} + +/* gets the audio system mclk/sysclk for the given parameters */ +static unsigned inline int soc_get_mclk(struct snd_soc_pcm_runtime *rtd, + struct snd_soc_clock_info *info) +{ + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_machine *machine = socdev->machine; + int i; + + /* find the matching machine config and get it's mclk for the given + * sample rate and hardware format */ + for(i = 0; i < machine->num_links; i++) { + if (machine->dai_link[i].cpu_dai == rtd->cpu_dai && + machine->dai_link[i].config_sysclk) + return machine->dai_link[i].config_sysclk(rtd, info); + } + return 0; +} + +/* changes a bitclk multiplier mask to a divider mask */ +static u16 soc_bfs_mult_to_div(u16 bfs, int rate, unsigned int mclk, + unsigned int pcmfmt, unsigned int chn) +{ + int i, j; + u16 bfs_ = 0; + int size = snd_pcm_format_physical_width(pcmfmt), min = 0; + + if (size <= 0) + return 0; + + /* the minimum bit clock that has enough bandwidth */ + min = size * rate * chn; + dbgc("mult --> div min bclk %d with mclk %d\n", min, mclk); + + for (i = 0; i < 16; i++) { + if ((bfs >> i) & 0x1) { + j = rate * SND_SOC_FSB_REAL(1<= min) { + bfs_ |= SND_SOC_FSBD(mclk/j); + dbgc("mult --> div support mult %d\n", + SND_SOC_FSB_REAL(1<> i) & 0x1) { + j = mclk / (SND_SOC_FSBD_REAL(1<= min) { + bfs_ |= SND_SOC_FSB(j/rate); + dbgc("div --> mult support div %d\n", + SND_SOC_FSBD_REAL(1<private_data; + struct snd_soc_dai_mode *codec_dai_mode = NULL; + struct snd_soc_dai_mode *cpu_dai_mode = NULL; + struct snd_soc_clock_info clk_info; + unsigned int fs, mclk, codec_bfs, cpu_bfs, rate = params_rate(params), + chn, j, k, cpu_bclk, codec_bclk, pcmrate; + u16 fmt = 0; + + dbg("asoc: match version %s\n", SND_SOC_VERSION); + clk_info.rate = rate; + pcmrate = soc_get_rate_format(rate); + + /* try and find a match from the codec and cpu DAI capabilities */ + for (j = 0; j < rtd->codec_dai->caps.num_modes; j++) { + for (k = 0; k < rtd->cpu_dai->caps.num_modes; k++) { + codec_dai_mode = &rtd->codec_dai->caps.mode[j]; + cpu_dai_mode = &rtd->cpu_dai->caps.mode[k]; + + if (!(codec_dai_mode->pcmrate & cpu_dai_mode->pcmrate & + pcmrate)) { + dbgc("asoc: DAI[%d:%d] failed to match rate\n", j, k); + continue; + } + + fmt = codec_dai_mode->fmt & cpu_dai_mode->fmt; + if (!(fmt & SND_SOC_DAIFMT_FORMAT_MASK)) { + dbgc("asoc: DAI[%d:%d] failed to match format\n", j, k); + continue; + } + + if (!(fmt & SND_SOC_DAIFMT_CLOCK_MASK)) { + dbgc("asoc: DAI[%d:%d] failed to match clock masters\n", + j, k); + continue; + } + + if (!(fmt & SND_SOC_DAIFMT_INV_MASK)) { + dbgc("asoc: DAI[%d:%d] failed to match invert\n", j, k); + continue; + } + + if (!(codec_dai_mode->pcmfmt & cpu_dai_mode->pcmfmt)) { + dbgc("asoc: DAI[%d:%d] failed to match pcm format\n", j, k); + continue; + } + + if (!(codec_dai_mode->pcmdir & cpu_dai_mode->pcmdir)) { + dbgc("asoc: DAI[%d:%d] failed to match direction\n", j, k); + continue; + } + + /* todo - still need to add tdm selection */ + rtd->cpu_dai->dai_runtime.fmt = + rtd->codec_dai->dai_runtime.fmt = + 1 << (ffs(fmt & SND_SOC_DAIFMT_FORMAT_MASK) -1) | + 1 << (ffs(fmt & SND_SOC_DAIFMT_CLOCK_MASK) - 1) | + 1 << (ffs(fmt & SND_SOC_DAIFMT_INV_MASK) - 1); + clk_info.bclk_master = + rtd->cpu_dai->dai_runtime.fmt & SND_SOC_DAIFMT_CLOCK_MASK; + + /* make sure the ratio between rate and master + * clock is acceptable*/ + fs = (cpu_dai_mode->fs & codec_dai_mode->fs); + if (fs == 0) { + dbgc("asoc: DAI[%d:%d] failed to match FS\n", j, k); + continue; + } + clk_info.fs = rtd->cpu_dai->dai_runtime.fs = + rtd->codec_dai->dai_runtime.fs = fs; + + /* calculate audio system clocking using slowest clocks possible*/ + mclk = soc_get_mclk(rtd, &clk_info); + if (mclk == 0) { + dbgc("asoc: DAI[%d:%d] configuration not clockable\n", j, k); + dbgc("asoc: rate %d fs %d master %x\n", rate, fs, + clk_info.bclk_master); + continue; + } + + /* calculate word size (per channel) and frame size */ + rtd->codec_dai->dai_runtime.pcmfmt = + rtd->cpu_dai->dai_runtime.pcmfmt = + 1 << params_format(params); + + chn = params_channels(params); + /* i2s always has left and right */ + if (params_channels(params) == 1 && + rtd->cpu_dai->dai_runtime.fmt & (SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_RIGHT_J | SND_SOC_DAIFMT_LEFT_J)) + chn <<= 1; + + /* Calculate bfs - the ratio between bitclock and the sample rate + * We must take into consideration the dividers and multipliers + * used in the codec and cpu DAI modes. We always choose the + * lowest possible clocks to reduce power. + */ + if (codec_dai_mode->flags & cpu_dai_mode->flags & + SND_SOC_DAI_BFS_DIV) { + /* cpu & codec bfs dividers */ + rtd->cpu_dai->dai_runtime.bfs = + rtd->codec_dai->dai_runtime.bfs = + 1 << (fls(codec_dai_mode->bfs & cpu_dai_mode->bfs) - 1); + } else if (codec_dai_mode->flags & SND_SOC_DAI_BFS_DIV) { + /* normalise bfs codec divider & cpu mult */ + codec_bfs = soc_bfs_div_to_mult(codec_dai_mode->bfs, rate, + mclk, rtd->codec_dai->dai_runtime.pcmfmt, chn); + rtd->cpu_dai->dai_runtime.bfs = + 1 << (ffs(codec_bfs & cpu_dai_mode->bfs) - 1); + cpu_bfs = soc_bfs_mult_to_div(cpu_dai_mode->bfs, rate, mclk, + rtd->codec_dai->dai_runtime.pcmfmt, chn); + rtd->codec_dai->dai_runtime.bfs = + 1 << (fls(codec_dai_mode->bfs & cpu_bfs) - 1); + } else if (cpu_dai_mode->flags & SND_SOC_DAI_BFS_DIV) { + /* normalise bfs codec mult & cpu divider */ + codec_bfs = soc_bfs_mult_to_div(codec_dai_mode->bfs, rate, + mclk, rtd->codec_dai->dai_runtime.pcmfmt, chn); + rtd->cpu_dai->dai_runtime.bfs = + 1 << (fls(codec_bfs & cpu_dai_mode->bfs) -1); + cpu_bfs = soc_bfs_div_to_mult(cpu_dai_mode->bfs, rate, mclk, + rtd->codec_dai->dai_runtime.pcmfmt, chn); + rtd->codec_dai->dai_runtime.bfs = + 1 << (ffs(codec_dai_mode->bfs & cpu_bfs) -1); + } else { + /* codec & cpu bfs rate multipliers */ + rtd->cpu_dai->dai_runtime.bfs = + rtd->codec_dai->dai_runtime.bfs = + 1 << (ffs(codec_dai_mode->bfs & cpu_dai_mode->bfs) -1); + } + + /* make sure the bit clock speed is acceptable */ + if (!rtd->cpu_dai->dai_runtime.bfs || + !rtd->codec_dai->dai_runtime.bfs) { + dbgc("asoc: DAI[%d:%d] failed to match BFS\n", j, k); + dbgc("asoc: cpu_dai %x codec %x\n", + rtd->cpu_dai->dai_runtime.bfs, + rtd->codec_dai->dai_runtime.bfs); + dbgc("asoc: mclk %d hwfmt %x\n", mclk, fmt); + continue; + } + + goto found; + } + } + printk(KERN_ERR "asoc: no matching DAI found between codec and CPU\n"); + return -EINVAL; + +found: + /* we have matching DAI's, so complete the runtime info */ + rtd->codec_dai->dai_runtime.pcmrate = + rtd->cpu_dai->dai_runtime.pcmrate = + soc_get_rate_format(rate); + + rtd->codec_dai->dai_runtime.priv = codec_dai_mode->priv; + rtd->cpu_dai->dai_runtime.priv = cpu_dai_mode->priv; + rtd->codec_dai->dai_runtime.flags = codec_dai_mode->flags; + rtd->cpu_dai->dai_runtime.flags = cpu_dai_mode->flags; + + /* for debug atm */ + dbg("asoc: DAI[%d:%d] Match OK\n", j, k); + if (rtd->codec_dai->dai_runtime.flags == SND_SOC_DAI_BFS_DIV) { + codec_bclk = (rtd->codec_dai->dai_runtime.fs * params_rate(params)) / + SND_SOC_FSBD_REAL(rtd->codec_dai->dai_runtime.bfs); + dbg("asoc: codec fs %d mclk %d bfs div %d bclk %d\n", + rtd->codec_dai->dai_runtime.fs, mclk, + SND_SOC_FSBD_REAL(rtd->codec_dai->dai_runtime.bfs), codec_bclk); + } else { + codec_bclk = params_rate(params) * + SND_SOC_FSB_REAL(rtd->codec_dai->dai_runtime.bfs); + dbg("asoc: codec fs %d mclk %d bfs mult %d bclk %d\n", + rtd->codec_dai->dai_runtime.fs, mclk, + SND_SOC_FSB_REAL(rtd->codec_dai->dai_runtime.bfs), codec_bclk); + } + if (rtd->cpu_dai->dai_runtime.flags == SND_SOC_DAI_BFS_DIV) { + cpu_bclk = (rtd->cpu_dai->dai_runtime.fs * params_rate(params)) / + SND_SOC_FSBD_REAL(rtd->cpu_dai->dai_runtime.bfs); + dbg("asoc: cpu fs %d mclk %d bfs div %d bclk %d\n", + rtd->cpu_dai->dai_runtime.fs, mclk, + SND_SOC_FSBD_REAL(rtd->cpu_dai->dai_runtime.bfs), cpu_bclk); + } else { + cpu_bclk = params_rate(params) * + SND_SOC_FSB_REAL(rtd->cpu_dai->dai_runtime.bfs); + dbg("asoc: cpu fs %d mclk %d bfs mult %d bclk %d\n", + rtd->cpu_dai->dai_runtime.fs, mclk, + SND_SOC_FSB_REAL(rtd->cpu_dai->dai_runtime.bfs), cpu_bclk); + } + + /* + * Check we have matching bitclocks. If we don't then it means the + * sysclock returned by either the codec or cpu DAI (selected by the + * machine sysclock function) is wrong compared with the supported DAI + * modes for the codec or cpu DAI. + */ + if (cpu_bclk != codec_bclk){ + printk(KERN_ERR + "asoc: codec and cpu bitclocks differ, audio may be wrong speed\n" + ); + printk(KERN_ERR "asoc: codec %d != cpu %d\n", codec_bclk, cpu_bclk); + } + + switch(rtd->cpu_dai->dai_runtime.fmt & SND_SOC_DAIFMT_CLOCK_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + dbg("asoc: DAI codec BCLK master, LRC master\n"); + break; + case SND_SOC_DAIFMT_CBS_CFM: + dbg("asoc: DAI codec BCLK slave, LRC master\n"); + break; + case SND_SOC_DAIFMT_CBM_CFS: + dbg("asoc: DAI codec BCLK master, LRC slave\n"); + break; + case SND_SOC_DAIFMT_CBS_CFS: + dbg("asoc: DAI codec BCLK slave, LRC slave\n"); + break; + } + dbg("asoc: mode %x, invert %x\n", + rtd->cpu_dai->dai_runtime.fmt & SND_SOC_DAIFMT_FORMAT_MASK, + rtd->cpu_dai->dai_runtime.fmt & SND_SOC_DAIFMT_INV_MASK); + dbg("asoc: audio rate %d chn %d fmt %x\n", params_rate(params), + params_channels(params), params_format(params)); + + return 0; +} + +static inline u32 get_rates(struct snd_soc_dai_mode *modes, int nmodes) +{ + int i; + u32 rates = 0; + + for(i = 0; i < nmodes; i++) + rates |= modes[i].pcmrate; + + return rates; +} + +static inline u64 get_formats(struct snd_soc_dai_mode *modes, int nmodes) +{ + int i; + u64 formats = 0; + + for(i = 0; i < nmodes; i++) + formats |= modes[i].pcmfmt; + + return formats; +} + +/* + * Called by ALSA when a PCM substream is opened, the runtime->hw record is + * then initialized and any private data can be allocated. This also calls + * startup for the cpu DAI, platform, machine and codec DAI. + */ +static int soc_pcm_open(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_machine *machine = socdev->machine; + struct snd_soc_platform *platform = socdev->platform; + struct snd_soc_codec_dai *codec_dai = rtd->codec_dai; + struct snd_soc_cpu_dai *cpu_dai = rtd->cpu_dai; + int ret = 0; + + mutex_lock(&pcm_mutex); + + /* startup the audio subsystem */ + if (rtd->cpu_dai->ops.startup) { + ret = rtd->cpu_dai->ops.startup(substream); + if (ret < 0) { + printk(KERN_ERR "asoc: can't open interface %s\n", + rtd->cpu_dai->name); + goto out; + } + } + + if (platform->pcm_ops->open) { + ret = platform->pcm_ops->open(substream); + if (ret < 0) { + printk(KERN_ERR "asoc: can't open platform %s\n", platform->name); + goto platform_err; + } + } + + if (machine->ops && machine->ops->startup) { + ret = machine->ops->startup(substream); + if (ret < 0) { + printk(KERN_ERR "asoc: %s startup failed\n", machine->name); + goto machine_err; + } + } + + if (rtd->codec_dai->ops.startup) { + ret = rtd->codec_dai->ops.startup(substream); + if (ret < 0) { + printk(KERN_ERR "asoc: can't open codec %s\n", + rtd->codec_dai->name); + goto codec_dai_err; + } + } + + /* create runtime params from DMA, codec and cpu DAI */ + if (runtime->hw.rates) + runtime->hw.rates &= + get_rates(codec_dai->caps.mode, codec_dai->caps.num_modes) & + get_rates(cpu_dai->caps.mode, cpu_dai->caps.num_modes); + else + runtime->hw.rates = + get_rates(codec_dai->caps.mode, codec_dai->caps.num_modes) & + get_rates(cpu_dai->caps.mode, cpu_dai->caps.num_modes); + if (runtime->hw.formats) + runtime->hw.formats &= + get_formats(codec_dai->caps.mode, codec_dai->caps.num_modes) & + get_formats(cpu_dai->caps.mode, cpu_dai->caps.num_modes); + else + runtime->hw.formats = + get_formats(codec_dai->caps.mode, codec_dai->caps.num_modes) & + get_formats(cpu_dai->caps.mode, cpu_dai->caps.num_modes); + + /* Check that the codec and cpu DAI's are compatible */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + runtime->hw.rate_min = + max(rtd->codec_dai->playback.rate_min, + rtd->cpu_dai->playback.rate_min); + runtime->hw.rate_max = + min(rtd->codec_dai->playback.rate_max, + rtd->cpu_dai->playback.rate_max); + runtime->hw.channels_min = + max(rtd->codec_dai->playback.channels_min, + rtd->cpu_dai->playback.channels_min); + runtime->hw.channels_max = + min(rtd->codec_dai->playback.channels_max, + rtd->cpu_dai->playback.channels_max); + } else { + runtime->hw.rate_min = + max(rtd->codec_dai->capture.rate_min, + rtd->cpu_dai->capture.rate_min); + runtime->hw.rate_max = + min(rtd->codec_dai->capture.rate_max, + rtd->cpu_dai->capture.rate_max); + runtime->hw.channels_min = + max(rtd->codec_dai->capture.channels_min, + rtd->cpu_dai->capture.channels_min); + runtime->hw.channels_max = + min(rtd->codec_dai->capture.channels_max, + rtd->cpu_dai->capture.channels_max); + } + + snd_pcm_limit_hw_rates(runtime); + if (!runtime->hw.rates) { + printk(KERN_ERR "asoc: %s <-> %s No matching rates\n", + rtd->codec_dai->name, rtd->cpu_dai->name); + goto codec_dai_err; + } + if (!runtime->hw.formats) { + printk(KERN_ERR "asoc: %s <-> %s No matching formats\n", + rtd->codec_dai->name, rtd->cpu_dai->name); + goto codec_dai_err; + } + if (!runtime->hw.channels_min || !runtime->hw.channels_max) { + printk(KERN_ERR "asoc: %s <-> %s No matching channels\n", + rtd->codec_dai->name, rtd->cpu_dai->name); + goto codec_dai_err; + } + + dbg("asoc: %s <-> %s info:\n", rtd->codec_dai->name, rtd->cpu_dai->name); + dbg("asoc: rate mask 0x%x \nasoc: min ch %d max ch %d\n + asoc: min rate %d max rate %d\n", + runtime->hw.rates, runtime->hw.channels_min, + runtime->hw.channels_max, runtime->hw.rate_min, runtime->hw.rate_max); + + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + rtd->cpu_dai->playback.active = rtd->codec_dai->playback.active = 1; + else + rtd->cpu_dai->capture.active = rtd->codec_dai->capture.active = 1; + rtd->cpu_dai->active = rtd->codec_dai->active = 1; + rtd->cpu_dai->runtime = runtime; + socdev->codec->active++; + mutex_unlock(&pcm_mutex); + return 0; + +codec_dai_err: + if (machine->ops && machine->ops->shutdown) + machine->ops->shutdown(substream); + +machine_err: + if (platform->pcm_ops->close) + platform->pcm_ops->close(substream); + +platform_err: + if (rtd->cpu_dai->ops.shutdown) + rtd->cpu_dai->ops.shutdown(substream); +out: + mutex_unlock(&pcm_mutex); + return ret; +} + +/* + * Power down the audio subsytem pmdown_time msecs after close is called. + * This is to ensure there are no pops or clicks in between any music tracks + * due to DAPM power cycling. + */ +static void close_delayed_work(void *data) +{ + struct snd_soc_device *socdev = data; + struct snd_soc_codec *codec = socdev->codec; + struct snd_soc_codec_dai *codec_dai; + int i; + + mutex_lock(&pcm_mutex); + for(i = 0; i < codec->num_dai; i++) { + codec_dai = &codec->dai[i]; + + dbg("pop wq checking: %s status: %s waiting: %s\n", + codec_dai->playback.stream_name, + codec_dai->playback.active ? "active" : "inactive", + codec_dai->pop_wait ? "yes" : "no"); + + /* are we waiting on this codec DAI stream */ + if (codec_dai->pop_wait == 1) { + + codec_dai->pop_wait = 0; + snd_soc_dapm_stream_event(codec, codec_dai->playback.stream_name, + SND_SOC_DAPM_STREAM_STOP); + + /* power down the codec power domain if no longer active */ + if (codec->active == 0) { + dbg("pop wq D3 %s %s\n", codec->name, + codec_dai->playback.stream_name); + if (codec->dapm_event) + codec->dapm_event(codec, SNDRV_CTL_POWER_D3hot); + } + } + } + mutex_unlock(&pcm_mutex); +} + +/* + * Called by ALSA when a PCM substream is closed. Private data can be + * freed here. The cpu DAI, codec DAI, machine and platform are also + * shutdown. + */ +static int soc_codec_close(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_machine *machine = socdev->machine; + struct snd_soc_platform *platform = socdev->platform; + struct snd_soc_codec *codec = socdev->codec; + + mutex_lock(&pcm_mutex); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + rtd->cpu_dai->playback.active = rtd->codec_dai->playback.active = 0; + else + rtd->cpu_dai->capture.active = rtd->codec_dai->capture.active = 0; + + if (rtd->codec_dai->playback.active == 0 && + rtd->codec_dai->capture.active == 0) { + rtd->cpu_dai->active = rtd->codec_dai->active = 0; + } + codec->active--; + + if (rtd->cpu_dai->ops.shutdown) + rtd->cpu_dai->ops.shutdown(substream); + + if (rtd->codec_dai->ops.shutdown) + rtd->codec_dai->ops.shutdown(substream); + + if (machine->ops && machine->ops->shutdown) + machine->ops->shutdown(substream); + + if (platform->pcm_ops->close) + platform->pcm_ops->close(substream); + rtd->cpu_dai->runtime = NULL; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + /* start delayed pop wq here for playback streams */ + rtd->codec_dai->pop_wait = 1; + queue_delayed_work(soc_workq, &soc_stream_work, + msecs_to_jiffies(pmdown_time)); + } else { + /* capture streams can be powered down now */ + snd_soc_dapm_stream_event(codec, rtd->codec_dai->capture.stream_name, + SND_SOC_DAPM_STREAM_STOP); + + if (codec->active == 0 && rtd->codec_dai->pop_wait == 0){ + if (codec->dapm_event) + codec->dapm_event(codec, SNDRV_CTL_POWER_D3hot); + } + } + + mutex_unlock(&pcm_mutex); + return 0; +} + +/* + * Called by ALSA when the PCM substream is prepared, can set format, sample + * rate, etc. This function is non atomic and can be called multiple times, + * it can refer to the runtime info. + */ +static int soc_pcm_prepare(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_platform *platform = socdev->platform; + struct snd_soc_codec *codec = socdev->codec; + int ret = 0; + + mutex_lock(&pcm_mutex); + if (platform->pcm_ops->prepare) { + ret = platform->pcm_ops->prepare(substream); + if (ret < 0) + goto out; + } + + if (rtd->codec_dai->ops.prepare) { + ret = rtd->codec_dai->ops.prepare(substream); + if (ret < 0) + goto out; + } + + if (rtd->cpu_dai->ops.prepare) + ret = rtd->cpu_dai->ops.prepare(substream); + + /* we only want to start a DAPM playback stream if we are not waiting + * on an existing one stopping */ + if (rtd->codec_dai->pop_wait) { + /* we are waiting for the delayed work to start */ + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) + snd_soc_dapm_stream_event(codec, + rtd->codec_dai->capture.stream_name, + SND_SOC_DAPM_STREAM_START); + else { + rtd->codec_dai->pop_wait = 0; + cancel_delayed_work(&soc_stream_work); + if (rtd->codec_dai->digital_mute) + rtd->codec_dai->digital_mute(codec, rtd->codec_dai, 0); + } + } else { + /* no delayed work - do we need to power up codec */ + if (codec->dapm_state != SNDRV_CTL_POWER_D0) { + + if (codec->dapm_event) + codec->dapm_event(codec, SNDRV_CTL_POWER_D1); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + snd_soc_dapm_stream_event(codec, + rtd->codec_dai->playback.stream_name, + SND_SOC_DAPM_STREAM_START); + else + snd_soc_dapm_stream_event(codec, + rtd->codec_dai->capture.stream_name, + SND_SOC_DAPM_STREAM_START); + + if (codec->dapm_event) + codec->dapm_event(codec, SNDRV_CTL_POWER_D0); + if (rtd->codec_dai->digital_mute) + rtd->codec_dai->digital_mute(codec, rtd->codec_dai, 0); + + } else { + /* codec already powered - power on widgets */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + snd_soc_dapm_stream_event(codec, + rtd->codec_dai->playback.stream_name, + SND_SOC_DAPM_STREAM_START); + else + snd_soc_dapm_stream_event(codec, + rtd->codec_dai->capture.stream_name, + SND_SOC_DAPM_STREAM_START); + if (rtd->codec_dai->digital_mute) + rtd->codec_dai->digital_mute(codec, rtd->codec_dai, 0); + } + } + +out: + mutex_unlock(&pcm_mutex); + return ret; +} + +/* + * Called by ALSA when the hardware params are set by application. This + * function can also be called multiple times and can allocate buffers + * (using snd_pcm_lib_* ). It's non-atomic. + */ +static int soc_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_platform *platform = socdev->platform; + struct snd_soc_machine *machine = socdev->machine; + int ret = 0; + + mutex_lock(&pcm_mutex); + + /* we don't need to match any AC97 params */ + if (rtd->cpu_dai->type != SND_SOC_DAI_AC97) { + ret = soc_hw_match_params(substream, params); + if (ret < 0) + goto out; + } else { + struct snd_soc_clock_info clk_info; + clk_info.rate = params_rate(params); + ret = soc_get_mclk(rtd, &clk_info); + if (ret < 0) + goto out; + } + + if (rtd->codec_dai->ops.hw_params) { + ret = rtd->codec_dai->ops.hw_params(substream, params); + if (ret < 0) { + printk(KERN_ERR "asoc: can't set codec %s hw params\n", + rtd->codec_dai->name); + goto out; + } + } + + if (rtd->cpu_dai->ops.hw_params) { + ret = rtd->cpu_dai->ops.hw_params(substream, params); + if (ret < 0) { + printk(KERN_ERR "asoc: can't set interface %s hw params\n", + rtd->cpu_dai->name); + goto interface_err; + } + } + + if (platform->pcm_ops->hw_params) { + ret = platform->pcm_ops->hw_params(substream, params); + if (ret < 0) { + printk(KERN_ERR "asoc: can't set platform %s hw params\n", + platform->name); + goto platform_err; + } + } + + if (machine->ops && machine->ops->hw_params) { + ret = machine->ops->hw_params(substream, params); + if (ret < 0) { + printk(KERN_ERR "asoc: machine hw_params failed\n"); + goto machine_err; + } + } + +out: + mutex_unlock(&pcm_mutex); + return ret; + +machine_err: + if (platform->pcm_ops->hw_free) + platform->pcm_ops->hw_free(substream); + +platform_err: + if (rtd->cpu_dai->ops.hw_free) + rtd->cpu_dai->ops.hw_free(substream); + +interface_err: + if (rtd->codec_dai->ops.hw_free) + rtd->codec_dai->ops.hw_free(substream); + + mutex_unlock(&pcm_mutex); + return ret; +} + +/* + * Free's resources allocated by hw_params, can be called multiple times + */ +static int soc_pcm_hw_free(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_platform *platform = socdev->platform; + struct snd_soc_codec *codec = socdev->codec; + struct snd_soc_machine *machine = socdev->machine; + + mutex_lock(&pcm_mutex); + + /* apply codec digital mute */ + if (!codec->active && rtd->codec_dai->digital_mute) + rtd->codec_dai->digital_mute(codec, rtd->codec_dai, 1); + + /* free any machine hw params */ + if (machine->ops && machine->ops->hw_free) + machine->ops->hw_free(substream); + + /* free any DMA resources */ + if (platform->pcm_ops->hw_free) + platform->pcm_ops->hw_free(substream); + + /* now free hw params for the DAI's */ + if (rtd->codec_dai->ops.hw_free) + rtd->codec_dai->ops.hw_free(substream); + + if (rtd->cpu_dai->ops.hw_free) + rtd->cpu_dai->ops.hw_free(substream); + + mutex_unlock(&pcm_mutex); + return 0; +} + +static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_platform *platform = socdev->platform; + int ret; + + if (rtd->codec_dai->ops.trigger) { + ret = rtd->codec_dai->ops.trigger(substream, cmd); + if (ret < 0) + return ret; + } + + if (platform->pcm_ops->trigger) { + ret = platform->pcm_ops->trigger(substream, cmd); + if (ret < 0) + return ret; + } + + if (rtd->cpu_dai->ops.trigger) { + ret = rtd->cpu_dai->ops.trigger(substream, cmd); + if (ret < 0) + return ret; + } + return 0; +} + +/* ASoC PCM operations */ +static struct snd_pcm_ops soc_pcm_ops = { + .open = soc_pcm_open, + .close = soc_codec_close, + .hw_params = soc_pcm_hw_params, + .hw_free = soc_pcm_hw_free, + .prepare = soc_pcm_prepare, + .trigger = soc_pcm_trigger, +}; + +#ifdef CONFIG_PM +/* powers down audio subsystem for suspend */ +static int soc_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_machine *machine = socdev->machine; + struct snd_soc_platform *platform = socdev->platform; + struct snd_soc_codec_device *codec_dev = socdev->codec_dev; + struct snd_soc_codec *codec = socdev->codec; + int i; + + /* mute any active DAC's */ + for(i = 0; i < machine->num_links; i++) { + struct snd_soc_codec_dai *dai = machine->dai_link[i].codec_dai; + if (dai->digital_mute && dai->playback.active) + dai->digital_mute(codec, dai, 1); + } + + if (machine->suspend_pre) + machine->suspend_pre(pdev, state); + + for(i = 0; i < machine->num_links; i++) { + struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai; + if (cpu_dai->suspend && cpu_dai->type != SND_SOC_DAI_AC97) + cpu_dai->suspend(pdev, cpu_dai); + if (platform->suspend) + platform->suspend(pdev, cpu_dai); + } + + /* close any waiting streams and save state */ + flush_workqueue(soc_workq); + codec->suspend_dapm_state = codec->dapm_state; + + for(i = 0; i < codec->num_dai; i++) { + char *stream = codec->dai[i].playback.stream_name; + if (stream != NULL) + snd_soc_dapm_stream_event(codec, stream, + SND_SOC_DAPM_STREAM_SUSPEND); + stream = codec->dai[i].capture.stream_name; + if (stream != NULL) + snd_soc_dapm_stream_event(codec, stream, + SND_SOC_DAPM_STREAM_SUSPEND); + } + + if (codec_dev->suspend) + codec_dev->suspend(pdev, state); + + for(i = 0; i < machine->num_links; i++) { + struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai; + if (cpu_dai->suspend && cpu_dai->type == SND_SOC_DAI_AC97) + cpu_dai->suspend(pdev, cpu_dai); + } + + if (machine->suspend_post) + machine->suspend_post(pdev, state); + + return 0; +} + +/* powers up audio subsystem after a suspend */ +static int soc_resume(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_machine *machine = socdev->machine; + struct snd_soc_platform *platform = socdev->platform; + struct snd_soc_codec_device *codec_dev = socdev->codec_dev; + struct snd_soc_codec *codec = socdev->codec; + int i; + + if (machine->resume_pre) + machine->resume_pre(pdev); + + for(i = 0; i < machine->num_links; i++) { + struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai; + if (cpu_dai->resume && cpu_dai->type == SND_SOC_DAI_AC97) + cpu_dai->resume(pdev, cpu_dai); + } + + if (codec_dev->resume) + codec_dev->resume(pdev); + + for(i = 0; i < codec->num_dai; i++) { + char* stream = codec->dai[i].playback.stream_name; + if (stream != NULL) + snd_soc_dapm_stream_event(codec, stream, + SND_SOC_DAPM_STREAM_RESUME); + stream = codec->dai[i].capture.stream_name; + if (stream != NULL) + snd_soc_dapm_stream_event(codec, stream, + SND_SOC_DAPM_STREAM_RESUME); + } + + /* unmute any active DAC's */ + for(i = 0; i < machine->num_links; i++) { + struct snd_soc_codec_dai *dai = machine->dai_link[i].codec_dai; + if (dai->digital_mute && dai->playback.active) + dai->digital_mute(codec, dai, 0); + } + + for(i = 0; i < machine->num_links; i++) { + struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai; + if (cpu_dai->resume && cpu_dai->type != SND_SOC_DAI_AC97) + cpu_dai->resume(pdev, cpu_dai); + if (platform->resume) + platform->resume(pdev, cpu_dai); + } + + if (machine->resume_post) + machine->resume_post(pdev); + + return 0; +} + +#else +#define soc_suspend NULL +#define soc_resume NULL +#endif + +/* probes a new socdev */ +static int soc_probe(struct platform_device *pdev) +{ + int ret = 0, i; + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_machine *machine = socdev->machine; + struct snd_soc_platform *platform = socdev->platform; + struct snd_soc_codec_device *codec_dev = socdev->codec_dev; + + if (machine->probe) { + ret = machine->probe(pdev); + if(ret < 0) + return ret; + } + + for (i = 0; i < machine->num_links; i++) { + struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai; + if (cpu_dai->probe) { + ret = cpu_dai->probe(pdev); + if(ret < 0) + goto cpu_dai_err; + } + } + + if (codec_dev->probe) { + ret = codec_dev->probe(pdev); + if(ret < 0) + goto cpu_dai_err; + } + + if (platform->probe) { + ret = platform->probe(pdev); + if(ret < 0) + goto platform_err; + } + + /* DAPM stream work */ + soc_workq = create_workqueue("kdapm"); + if (soc_workq == NULL) + goto work_err; + INIT_WORK(&soc_stream_work, close_delayed_work, socdev); + return 0; + +work_err: + if (platform->remove) + platform->remove(pdev); + +platform_err: + if (codec_dev->remove) + codec_dev->remove(pdev); + +cpu_dai_err: + for (i--; i > 0; i--) { + struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai; + if (cpu_dai->remove) + cpu_dai->remove(pdev); + } + + if (machine->remove) + machine->remove(pdev); + + return ret; +} + +/* removes a socdev */ +static int soc_remove(struct platform_device *pdev) +{ + int i; + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_machine *machine = socdev->machine; + struct snd_soc_platform *platform = socdev->platform; + struct snd_soc_codec_device *codec_dev = socdev->codec_dev; + + if (soc_workq) + destroy_workqueue(soc_workq); + + if (platform->remove) + platform->remove(pdev); + + if (codec_dev->remove) + codec_dev->remove(pdev); + + for (i = 0; i < machine->num_links; i++) { + struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai; + if (cpu_dai->remove) + cpu_dai->remove(pdev); + } + + if (machine->remove) + machine->remove(pdev); + + return 0; +} + +/* ASoC platform driver */ +static struct platform_driver soc_driver = { + .driver = { + .name = "soc-audio", + }, + .probe = soc_probe, + .remove = soc_remove, + .suspend = soc_suspend, + .resume = soc_resume, +}; + +/* create a new pcm */ +static int soc_new_pcm(struct snd_soc_device *socdev, + struct snd_soc_dai_link *dai_link, int num) +{ + struct snd_soc_codec *codec = socdev->codec; + struct snd_soc_codec_dai *codec_dai = dai_link->codec_dai; + struct snd_soc_cpu_dai *cpu_dai = dai_link->cpu_dai; + struct snd_soc_pcm_runtime *rtd; + struct snd_pcm *pcm; + char new_name[64]; + int ret = 0, playback = 0, capture = 0; + + rtd = kzalloc(sizeof(struct snd_soc_pcm_runtime), GFP_KERNEL); + if (rtd == NULL) + return -ENOMEM; + rtd->cpu_dai = cpu_dai; + rtd->codec_dai = codec_dai; + rtd->socdev = socdev; + + /* check client and interface hw capabilities */ + sprintf(new_name, "%s %s-%s-%d",dai_link->stream_name, codec_dai->name, + get_dai_name(cpu_dai->type), num); + + if (codec_dai->playback.channels_min) + playback = 1; + if (codec_dai->capture.channels_min) + capture = 1; + + ret = snd_pcm_new(codec->card, new_name, codec->pcm_devs++, playback, + capture, &pcm); + if (ret < 0) { + printk(KERN_ERR "asoc: can't create pcm for codec %s\n", codec->name); + kfree(rtd); + return ret; + } + + pcm->private_data = rtd; + soc_pcm_ops.mmap = socdev->platform->pcm_ops->mmap; + soc_pcm_ops.pointer = socdev->platform->pcm_ops->pointer; + soc_pcm_ops.ioctl = socdev->platform->pcm_ops->ioctl; + soc_pcm_ops.copy = socdev->platform->pcm_ops->copy; + soc_pcm_ops.silence = socdev->platform->pcm_ops->silence; + soc_pcm_ops.ack = socdev->platform->pcm_ops->ack; + soc_pcm_ops.page = socdev->platform->pcm_ops->page; + + if (playback) + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &soc_pcm_ops); + + if (capture) + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &soc_pcm_ops); + + ret = socdev->platform->pcm_new(codec->card, codec_dai, pcm); + if (ret < 0) { + printk(KERN_ERR "asoc: platform pcm constructor failed\n"); + kfree(rtd); + return ret; + } + + pcm->private_free = socdev->platform->pcm_free; + printk(KERN_INFO "asoc: %s <-> %s mapping ok\n", codec_dai->name, + cpu_dai->name); + return ret; +} + +/* codec register dump */ +static ssize_t codec_reg_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct snd_soc_device *devdata = dev_get_drvdata(dev); + struct snd_soc_codec *codec = devdata->codec; + int i, step = 1, count = 0; + + if (!codec->reg_cache_size) + return 0; + + if (codec->reg_cache_step) + step = codec->reg_cache_step; + + count += sprintf(buf, "%s registers\n", codec->name); + for(i = 0; i < codec->reg_cache_size; i += step) + count += sprintf(buf + count, "%2x: %4x\n", i, codec->read(codec, i)); + + return count; +} +static DEVICE_ATTR(codec_reg, 0444, codec_reg_show, NULL); + +/** + * snd_soc_new_ac97_codec - initailise AC97 device + * @codec: audio codec + * @ops: AC97 bus operations + * @num: AC97 codec number + * + * Initialises AC97 codec resources for use by ad-hoc devices only. + */ +int snd_soc_new_ac97_codec(struct snd_soc_codec *codec, + struct snd_ac97_bus_ops *ops, int num) +{ + mutex_lock(&codec->mutex); + + codec->ac97 = kzalloc(sizeof(struct snd_ac97), GFP_KERNEL); + if (codec->ac97 == NULL) { + mutex_unlock(&codec->mutex); + return -ENOMEM; + } + + codec->ac97->bus = kzalloc(sizeof(struct snd_ac97_bus), GFP_KERNEL); + if (codec->ac97->bus == NULL) { + kfree(codec->ac97); + codec->ac97 = NULL; + mutex_unlock(&codec->mutex); + return -ENOMEM; + } + + codec->ac97->bus->ops = ops; + codec->ac97->num = num; + mutex_unlock(&codec->mutex); + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_new_ac97_codec); + +/** + * snd_soc_free_ac97_codec - free AC97 codec device + * @codec: audio codec + * + * Frees AC97 codec device resources. + */ +void snd_soc_free_ac97_codec(struct snd_soc_codec *codec) +{ + mutex_lock(&codec->mutex); + kfree(codec->ac97->bus); + kfree(codec->ac97); + codec->ac97 = NULL; + mutex_unlock(&codec->mutex); +} +EXPORT_SYMBOL_GPL(snd_soc_free_ac97_codec); + +/** + * snd_soc_update_bits - update codec register bits + * @codec: audio codec + * @reg: codec register + * @mask: register mask + * @value: new value + * + * Writes new register value. + * + * Returns 1 for change else 0. + */ +int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg, + unsigned short mask, unsigned short value) +{ + int change; + unsigned short old, new; + + mutex_lock(&io_mutex); + old = snd_soc_read(codec, reg); + new = (old & ~mask) | value; + change = old != new; + if (change) + snd_soc_write(codec, reg, new); + + mutex_unlock(&io_mutex); + return change; +} +EXPORT_SYMBOL_GPL(snd_soc_update_bits); + +/** + * snd_soc_test_bits - test register for change + * @codec: audio codec + * @reg: codec register + * @mask: register mask + * @value: new value + * + * Tests a register with a new value and checks if the new value is + * different from the old value. + * + * Returns 1 for change else 0. + */ +int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg, + unsigned short mask, unsigned short value) +{ + int change; + unsigned short old, new; + + mutex_lock(&io_mutex); + old = snd_soc_read(codec, reg); + new = (old & ~mask) | value; + change = old != new; + mutex_unlock(&io_mutex); + + return change; +} +EXPORT_SYMBOL_GPL(snd_soc_test_bits); + +/** + * snd_soc_get_rate - get int sample rate + * @hwpcmrate: the hardware pcm rate + * + * Returns the audio rate integaer value, else 0. + */ +int snd_soc_get_rate(int hwpcmrate) +{ + int rate = ffs(hwpcmrate) - 1; + + if (rate > ARRAY_SIZE(rates)) + return 0; + return rates[rate]; +} +EXPORT_SYMBOL_GPL(snd_soc_get_rate); + +/** + * snd_soc_new_pcms - create new sound card and pcms + * @socdev: the SoC audio device + * + * Create a new sound card based upon the codec and interface pcms. + * + * Returns 0 for success, else error. + */ +int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char * xid) +{ + struct snd_soc_codec *codec = socdev->codec; + struct snd_soc_machine *machine = socdev->machine; + int ret = 0, i; + + mutex_lock(&codec->mutex); + + /* register a sound card */ + codec->card = snd_card_new(idx, xid, codec->owner, 0); + if (!codec->card) { + printk(KERN_ERR "asoc: can't create sound card for codec %s\n", + codec->name); + mutex_unlock(&codec->mutex); + return -ENODEV; + } + + codec->card->dev = socdev->dev; + codec->card->private_data = codec; + strncpy(codec->card->driver, codec->name, sizeof(codec->card->driver)); + + /* create the pcms */ + for(i = 0; i < machine->num_links; i++) { + ret = soc_new_pcm(socdev, &machine->dai_link[i], i); + if (ret < 0) { + printk(KERN_ERR "asoc: can't create pcm %s\n", + machine->dai_link[i].stream_name); + mutex_unlock(&codec->mutex); + return ret; + } + } + + mutex_unlock(&codec->mutex); + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_new_pcms); + +/** + * snd_soc_register_card - register sound card + * @socdev: the SoC audio device + * + * Register a SoC sound card. Also registers an AC97 device if the + * codec is AC97 for ad hoc devices. + * + * Returns 0 for success, else error. + */ +int snd_soc_register_card(struct snd_soc_device *socdev) +{ + struct snd_soc_codec *codec = socdev->codec; + struct snd_soc_machine *machine = socdev->machine; + int ret = 0, i, ac97 = 0; + + mutex_lock(&codec->mutex); + for(i = 0; i < machine->num_links; i++) { + if (socdev->machine->dai_link[i].init) + socdev->machine->dai_link[i].init(codec); + if (socdev->machine->dai_link[i].cpu_dai->type == SND_SOC_DAI_AC97) + ac97 = 1; + } + snprintf(codec->card->shortname, sizeof(codec->card->shortname), + "%s", machine->name); + snprintf(codec->card->longname, sizeof(codec->card->longname), + "%s (%s)", machine->name, codec->name); + + ret = snd_card_register(codec->card); + if (ret < 0) { + printk(KERN_ERR "asoc: failed to register soundcard for codec %s\n", + codec->name); + mutex_unlock(&codec->mutex); + return ret; + } + +#ifdef CONFIG_SND_SOC_AC97_BUS + if (ac97) + soc_ac97_dev_register(codec); +#endif + + snd_soc_dapm_sys_add(socdev->dev); + device_create_file(socdev->dev, &dev_attr_codec_reg); + mutex_unlock(&codec->mutex); + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_register_card); + +/** + * snd_soc_free_pcms - free sound card and pcms + * @socdev: the SoC audio device + * + * Frees sound card and pcms associated with the socdev. + * Also unregister the codec if it is an AC97 device. + */ +void snd_soc_free_pcms(struct snd_soc_device *socdev) +{ + struct snd_soc_codec *codec = socdev->codec; + + mutex_lock(&codec->mutex); +#ifdef CONFIG_SND_SOC_AC97_BUS + if (codec->ac97) + soc_ac97_dev_unregister(codec); +#endif + + if (codec->card) + snd_card_free(codec->card); + device_remove_file(socdev->dev, &dev_attr_codec_reg); + mutex_unlock(&codec->mutex); +} +EXPORT_SYMBOL_GPL(snd_soc_free_pcms); + +/** + * snd_soc_set_runtime_hwparams - set the runtime hardware parameters + * @substream: the pcm substream + * @hw: the hardware parameters + * + * Sets the substream runtime hardware parameters. + */ +int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream, + const struct snd_pcm_hardware *hw) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + runtime->hw.info = hw->info; + runtime->hw.formats = hw->formats; + runtime->hw.period_bytes_min = hw->period_bytes_min; + runtime->hw.period_bytes_max = hw->period_bytes_max; + runtime->hw.periods_min = hw->periods_min; + runtime->hw.periods_max = hw->periods_max; + runtime->hw.buffer_bytes_max = hw->buffer_bytes_max; + runtime->hw.fifo_size = hw->fifo_size; + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_set_runtime_hwparams); + +/** + * snd_soc_cnew - create new control + * @_template: control template + * @data: control private data + * @lnng_name: control long name + * + * Create a new mixer control from a template control. + * + * Returns 0 for success, else error. + */ +struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template, + void *data, char *long_name) +{ + struct snd_kcontrol_new template; + + memcpy(&template, _template, sizeof(template)); + if (long_name) + template.name = long_name; + template.access = SNDRV_CTL_ELEM_ACCESS_READWRITE; + template.index = 0; + + return snd_ctl_new1(&template, data); +} +EXPORT_SYMBOL_GPL(snd_soc_cnew); + +/** + * snd_soc_info_enum_double - enumerated double mixer info callback + * @kcontrol: mixer control + * @uinfo: control element information + * + * Callback to provide information about a double enumerated + * mixer control. + * + * Returns 0 for success. + */ +int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = e->shift_l == e->shift_r ? 1 : 2; + uinfo->value.enumerated.items = e->mask; + + if (uinfo->value.enumerated.item > e->mask - 1) + uinfo->value.enumerated.item = e->mask - 1; + strcpy(uinfo->value.enumerated.name, + e->texts[uinfo->value.enumerated.item]); + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_info_enum_double); + +/** + * snd_soc_get_enum_double - enumerated double mixer get callback + * @kcontrol: mixer control + * @uinfo: control element information + * + * Callback to get the value of a double enumerated mixer. + * + * Returns 0 for success. + */ +int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned short val, bitmask; + + for (bitmask = 1; bitmask < e->mask; bitmask <<= 1) + ; + val = snd_soc_read(codec, e->reg); + ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & (bitmask - 1); + if (e->shift_l != e->shift_r) + ucontrol->value.enumerated.item[1] = + (val >> e->shift_r) & (bitmask - 1); + + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_get_enum_double); + +/** + * snd_soc_put_enum_double - enumerated double mixer put callback + * @kcontrol: mixer control + * @uinfo: control element information + * + * Callback to set the value of a double enumerated mixer. + * + * Returns 0 for success. + */ +int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned short val; + unsigned short mask, bitmask; + + for (bitmask = 1; bitmask < e->mask; bitmask <<= 1) + ; + if (ucontrol->value.enumerated.item[0] > e->mask - 1) + return -EINVAL; + val = ucontrol->value.enumerated.item[0] << e->shift_l; + mask = (bitmask - 1) << e->shift_l; + if (e->shift_l != e->shift_r) { + if (ucontrol->value.enumerated.item[1] > e->mask - 1) + return -EINVAL; + val |= ucontrol->value.enumerated.item[1] << e->shift_r; + mask |= (bitmask - 1) << e->shift_r; + } + + return snd_soc_update_bits(codec, e->reg, mask, val); +} +EXPORT_SYMBOL_GPL(snd_soc_put_enum_double); + +/** + * snd_soc_info_enum_ext - external enumerated single mixer info callback + * @kcontrol: mixer control + * @uinfo: control element information + * + * Callback to provide information about an external enumerated + * single mixer. + * + * Returns 0 for success. + */ +int snd_soc_info_enum_ext(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = e->mask; + + if (uinfo->value.enumerated.item > e->mask - 1) + uinfo->value.enumerated.item = e->mask - 1; + strcpy(uinfo->value.enumerated.name, + e->texts[uinfo->value.enumerated.item]); + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_info_enum_ext); + +/** + * snd_soc_info_volsw_ext - external single mixer info callback + * @kcontrol: mixer control + * @uinfo: control element information + * + * Callback to provide information about a single external mixer control. + * + * Returns 0 for success. + */ +int snd_soc_info_volsw_ext(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + int mask = kcontrol->private_value; + + uinfo->type = + mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = mask; + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_info_volsw_ext); + +/** + * snd_soc_info_bool_ext - external single boolean mixer info callback + * @kcontrol: mixer control + * @uinfo: control element information + * + * Callback to provide information about a single boolean external mixer control. + * + * Returns 0 for success. + */ +int snd_soc_info_bool_ext(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_info_bool_ext); + +/** + * snd_soc_info_volsw - single mixer info callback + * @kcontrol: mixer control + * @uinfo: control element information + * + * Callback to provide information about a single mixer control. + * + * Returns 0 for success. + */ +int snd_soc_info_volsw(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + int mask = (kcontrol->private_value >> 16) & 0xff; + int shift = (kcontrol->private_value >> 8) & 0x0f; + int rshift = (kcontrol->private_value >> 12) & 0x0f; + + uinfo->type = + mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = shift == rshift ? 1 : 2; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = mask; + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_info_volsw); + +/** + * snd_soc_get_volsw - single mixer get callback + * @kcontrol: mixer control + * @uinfo: control element information + * + * Callback to get the value of a single mixer control. + * + * Returns 0 for success. + */ +int snd_soc_get_volsw(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + int reg = kcontrol->private_value & 0xff; + int shift = (kcontrol->private_value >> 8) & 0x0f; + int rshift = (kcontrol->private_value >> 12) & 0x0f; + int mask = (kcontrol->private_value >> 16) & 0xff; + int invert = (kcontrol->private_value >> 24) & 0x01; + + ucontrol->value.integer.value[0] = + (snd_soc_read(codec, reg) >> shift) & mask; + if (shift != rshift) + ucontrol->value.integer.value[1] = + (snd_soc_read(codec, reg) >> rshift) & mask; + if (invert) { + ucontrol->value.integer.value[0] = + mask - ucontrol->value.integer.value[0]; + if (shift != rshift) + ucontrol->value.integer.value[1] = + mask - ucontrol->value.integer.value[1]; + } + + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_get_volsw); + +/** + * snd_soc_put_volsw - single mixer put callback + * @kcontrol: mixer control + * @uinfo: control element information + * + * Callback to set the value of a single mixer control. + * + * Returns 0 for success. + */ +int snd_soc_put_volsw(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + int reg = kcontrol->private_value & 0xff; + int shift = (kcontrol->private_value >> 8) & 0x0f; + int rshift = (kcontrol->private_value >> 12) & 0x0f; + int mask = (kcontrol->private_value >> 16) & 0xff; + int invert = (kcontrol->private_value >> 24) & 0x01; + int err; + unsigned short val, val2, val_mask; + + val = (ucontrol->value.integer.value[0] & mask); + if (invert) + val = mask - val; + val_mask = mask << shift; + val = val << shift; + if (shift != rshift) { + val2 = (ucontrol->value.integer.value[1] & mask); + if (invert) + val2 = mask - val2; + val_mask |= mask << rshift; + val |= val2 << rshift; + } + err = snd_soc_update_bits(codec, reg, val_mask, val); + return err; +} +EXPORT_SYMBOL_GPL(snd_soc_put_volsw); + +/** + * snd_soc_info_volsw_2r - double mixer info callback + * @kcontrol: mixer control + * @uinfo: control element information + * + * Callback to provide information about a double mixer control that + * spans 2 codec registers. + * + * Returns 0 for success. + */ +int snd_soc_info_volsw_2r(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + int mask = (kcontrol->private_value >> 12) & 0xff; + + uinfo->type = + mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 2; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = mask; + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_info_volsw_2r); + +/** + * snd_soc_get_volsw_2r - double mixer get callback + * @kcontrol: mixer control + * @uinfo: control element information + * + * Callback to get the value of a double mixer control that spans 2 registers. + * + * Returns 0 for success. + */ +int snd_soc_get_volsw_2r(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + int reg = kcontrol->private_value & 0xff; + int reg2 = (kcontrol->private_value >> 24) & 0xff; + int shift = (kcontrol->private_value >> 8) & 0x0f; + int mask = (kcontrol->private_value >> 12) & 0xff; + int invert = (kcontrol->private_value >> 20) & 0x01; + + ucontrol->value.integer.value[0] = + (snd_soc_read(codec, reg) >> shift) & mask; + ucontrol->value.integer.value[1] = + (snd_soc_read(codec, reg2) >> shift) & mask; + if (invert) { + ucontrol->value.integer.value[0] = + mask - ucontrol->value.integer.value[0]; + ucontrol->value.integer.value[1] = + mask - ucontrol->value.integer.value[1]; + } + + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_get_volsw_2r); + +/** + * snd_soc_put_volsw_2r - double mixer set callback + * @kcontrol: mixer control + * @uinfo: control element information + * + * Callback to set the value of a double mixer control that spans 2 registers. + * + * Returns 0 for success. + */ +int snd_soc_put_volsw_2r(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + int reg = kcontrol->private_value & 0xff; + int reg2 = (kcontrol->private_value >> 24) & 0xff; + int shift = (kcontrol->private_value >> 8) & 0x0f; + int mask = (kcontrol->private_value >> 12) & 0xff; + int invert = (kcontrol->private_value >> 20) & 0x01; + int err; + unsigned short val, val2, val_mask; + + val_mask = mask << shift; + val = (ucontrol->value.integer.value[0] & mask); + val2 = (ucontrol->value.integer.value[1] & mask); + + if (invert) { + val = mask - val; + val2 = mask - val2; + } + + val = val << shift; + val2 = val2 << shift; + + if ((err = snd_soc_update_bits(codec, reg, val_mask, val)) < 0) + return err; + + err = snd_soc_update_bits(codec, reg2, val_mask, val2); + return err; +} +EXPORT_SYMBOL_GPL(snd_soc_put_volsw_2r); + +static int __devinit snd_soc_init(void) +{ + printk(KERN_INFO "ASoC version %s\n", SND_SOC_VERSION); + return platform_driver_register(&soc_driver); +} + +static void snd_soc_exit(void) +{ + platform_driver_unregister(&soc_driver); +} + +module_init(snd_soc_init); +module_exit(snd_soc_exit); + +/* Module information */ +MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com"); +MODULE_DESCRIPTION("ALSA SoC Core"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 2b97eabc09f42d0f63e8053636e34e1afa0d604e Mon Sep 17 00:00:00 2001 From: Richard Purdie Date: Fri, 6 Oct 2006 18:32:18 +0200 Subject: [ALSA] ASoC: dynamic audio power management (DAPM) This patch adds Dynamic Audio Power Management (DAPM) to ASoC. Dynamic Audio Power Management (DAPM) is designed to allow portable and handheld Linux devices to use the minimum amount of power within the audio subsystem at all times. It is independent of other kernel PM and as such, can easily co-exist with the other PM systems. DAPM is also completely transparent to all user space applications as all power switching is done within the ASoC core. No code changes or recompiling are required for user space applications. DAPM makes power switching decisions based upon any audio stream (capture/playback) activity and audio mixer settings within the device. DAPM spans the whole machine. It covers power control within the entire audio subsystem, this includes internal codec power blocks and machine level power systems. There are 4 power domains within DAPM:- 1. Codec domain - VREF, VMID (core codec and audio power) Usually controlled at codec probe/remove and suspend/resume, although can be set at stream time if power is not needed for sidetone, etc. 2. Platform/Machine domain - physically connected inputs and outputs Is platform/machine and user action specific, is configured by the machine driver and responds to asynchronous events e.g when HP are inserted 3. Path domain - audio subsystem signal paths Automatically set when mixer and mux settings are changed by the user. e.g. alsamixer, amixer. 4. Stream domain - DAC's and ADC's. Enabled and disabled when stream playback/capture is started and stopped respectively. e.g. aplay, arecord. All DAPM power switching decisions are made automatically by consulting an audio routing map of the whole machine. This map is specific to each machine and consists of the interconnections between every audio component (including internal codec components). Signed-off-by: Richard Purdie Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/soc-dapm.c | 1327 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1327 insertions(+) create mode 100644 sound/soc/soc-dapm.c (limited to 'sound') diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c new file mode 100644 index 00000000000..2c2c27f4e9c --- /dev/null +++ b/sound/soc/soc-dapm.c @@ -0,0 +1,1327 @@ +/* + * soc-dapm.c -- ALSA SoC Dynamic Audio Power Management + * + * Copyright 2005 Wolfson Microelectronics PLC. + * Author: Liam Girdwood + * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision history + * 12th Aug 2005 Initial version. + * 25th Oct 2005 Implemented path power domain. + * 18th Dec 2005 Implemented machine and stream level power domain. + * + * Features: + * o Changes power status of internal codec blocks depending on the + * dynamic configuration of codec internal audio paths and active + * DAC's/ADC's. + * o Platform power domain - can support external components i.e. amps and + * mic/meadphone insertion events. + * o Automatic Mic Bias support + * o Jack insertion power event initiation - e.g. hp insertion will enable + * sinks, dacs, etc + * o Delayed powerdown of audio susbsytem to reduce pops between a quick + * device reopen. + * + * Todo: + * o DAPM power change sequencing - allow for configurable per + * codec sequences. + * o Support for analogue bias optimisation. + * o Support for reduced codec oversampling rates. + * o Support for reduced codec bias currents. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* debug */ +#define DAPM_DEBUG 0 +#if DAPM_DEBUG +#define dump_dapm(codec, action) dbg_dump_dapm(codec, action) +#define dbg(format, arg...) printk(format, ## arg) +#else +#define dump_dapm(codec, action) +#define dbg(format, arg...) +#endif + +#define POP_DEBUG 0 +#if POP_DEBUG +#define POP_TIME 500 /* 500 msecs - change if pop debug is too fast */ +#define pop_wait(time) schedule_timeout_interruptible(msecs_to_jiffies(time)) +#define pop_dbg(format, arg...) printk(format, ## arg); pop_wait(POP_TIME) +#else +#define pop_dbg(format, arg...) +#define pop_wait(time) +#endif + +/* dapm power sequences - make this per codec in the future */ +static int dapm_up_seq[] = { + snd_soc_dapm_pre, snd_soc_dapm_micbias, snd_soc_dapm_mic, + snd_soc_dapm_mux, snd_soc_dapm_dac, snd_soc_dapm_mixer, snd_soc_dapm_pga, + snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk, snd_soc_dapm_post +}; +static int dapm_down_seq[] = { + snd_soc_dapm_pre, snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk, + snd_soc_dapm_pga, snd_soc_dapm_mixer, snd_soc_dapm_dac, snd_soc_dapm_mic, + snd_soc_dapm_micbias, snd_soc_dapm_mux, snd_soc_dapm_post +}; + +static int dapm_status = 1; +module_param(dapm_status, int, 0); +MODULE_PARM_DESC(dapm_status, "enable DPM sysfs entries"); + +/* create a new dapm widget */ +static struct snd_soc_dapm_widget *dapm_cnew_widget( + const struct snd_soc_dapm_widget *_widget) +{ + struct snd_soc_dapm_widget* widget; + widget = kmalloc(sizeof(struct snd_soc_dapm_widget), GFP_KERNEL); + if (!widget) + return NULL; + + memcpy(widget, _widget, sizeof(struct snd_soc_dapm_widget)); + return widget; +} + +/* set up initial codec paths */ +static void dapm_set_path_status(struct snd_soc_dapm_widget *w, + struct snd_soc_dapm_path *p, int i) +{ + switch (w->id) { + case snd_soc_dapm_switch: + case snd_soc_dapm_mixer: { + int val; + int reg = w->kcontrols[i].private_value & 0xff; + int shift = (w->kcontrols[i].private_value >> 8) & 0x0f; + int mask = (w->kcontrols[i].private_value >> 16) & 0xff; + int invert = (w->kcontrols[i].private_value >> 24) & 0x01; + + val = snd_soc_read(w->codec, reg); + val = (val >> shift) & mask; + + if ((invert && !val) || (!invert && val)) + p->connect = 1; + else + p->connect = 0; + } + break; + case snd_soc_dapm_mux: { + struct soc_enum *e = (struct soc_enum *)w->kcontrols[i].private_value; + int val, item, bitmask; + + for (bitmask = 1; bitmask < e->mask; bitmask <<= 1) + ; + val = snd_soc_read(w->codec, e->reg); + item = (val >> e->shift_l) & (bitmask - 1); + + p->connect = 0; + for (i = 0; i < e->mask; i++) { + if (!(strcmp(p->name, e->texts[i])) && item == i) + p->connect = 1; + } + } + break; + /* does not effect routing - always connected */ + case snd_soc_dapm_pga: + case snd_soc_dapm_output: + case snd_soc_dapm_adc: + case snd_soc_dapm_input: + case snd_soc_dapm_dac: + case snd_soc_dapm_micbias: + case snd_soc_dapm_vmid: + p->connect = 1; + break; + /* does effect routing - dynamically connected */ + case snd_soc_dapm_hp: + case snd_soc_dapm_mic: + case snd_soc_dapm_spk: + case snd_soc_dapm_line: + case snd_soc_dapm_pre: + case snd_soc_dapm_post: + p->connect = 0; + break; + } +} + +/* connect mux widget to it's interconnecting audio paths */ +static int dapm_connect_mux(struct snd_soc_codec *codec, + struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest, + struct snd_soc_dapm_path *path, const char *control_name, + const struct snd_kcontrol_new *kcontrol) +{ + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + int i; + + for (i = 0; i < e->mask; i++) { + if (!(strcmp(control_name, e->texts[i]))) { + list_add(&path->list, &codec->dapm_paths); + list_add(&path->list_sink, &dest->sources); + list_add(&path->list_source, &src->sinks); + path->name = (char*)e->texts[i]; + dapm_set_path_status(dest, path, 0); + return 0; + } + } + + return -ENODEV; +} + +/* connect mixer widget to it's interconnecting audio paths */ +static int dapm_connect_mixer(struct snd_soc_codec *codec, + struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest, + struct snd_soc_dapm_path *path, const char *control_name) +{ + int i; + + /* search for mixer kcontrol */ + for (i = 0; i < dest->num_kcontrols; i++) { + if (!strcmp(control_name, dest->kcontrols[i].name)) { + list_add(&path->list, &codec->dapm_paths); + list_add(&path->list_sink, &dest->sources); + list_add(&path->list_source, &src->sinks); + path->name = dest->kcontrols[i].name; + dapm_set_path_status(dest, path, i); + return 0; + } + } + return -ENODEV; +} + +/* update dapm codec register bits */ +static int dapm_update_bits(struct snd_soc_dapm_widget *widget) +{ + int change, power; + unsigned short old, new; + struct snd_soc_codec *codec = widget->codec; + + /* check for valid widgets */ + if (widget->reg < 0 || widget->id == snd_soc_dapm_input || + widget->id == snd_soc_dapm_output || + widget->id == snd_soc_dapm_hp || + widget->id == snd_soc_dapm_mic || + widget->id == snd_soc_dapm_line || + widget->id == snd_soc_dapm_spk) + return 0; + + power = widget->power; + if (widget->invert) + power = (power ? 0:1); + + old = snd_soc_read(codec, widget->reg); + new = (old & ~(0x1 << widget->shift)) | (power << widget->shift); + + change = old != new; + if (change) { + pop_dbg("pop test %s : %s in %d ms\n", widget->name, + widget->power ? "on" : "off", POP_TIME); + snd_soc_write(codec, widget->reg, new); + pop_wait(POP_TIME); + } + dbg("reg old %x new %x change %d\n", old, new, change); + return change; +} + +/* ramps the volume up or down to minimise pops before or after a + * DAPM power event */ +static int dapm_set_pga(struct snd_soc_dapm_widget *widget, int power) +{ + const struct snd_kcontrol_new *k = widget->kcontrols; + + if (widget->muted && !power) + return 0; + if (!widget->muted && power) + return 0; + + if (widget->num_kcontrols && k) { + int reg = k->private_value & 0xff; + int shift = (k->private_value >> 8) & 0x0f; + int mask = (k->private_value >> 16) & 0xff; + int invert = (k->private_value >> 24) & 0x01; + + if (power) { + int i; + /* power up has happended, increase volume to last level */ + if (invert) { + for (i = mask; i > widget->saved_value; i--) + snd_soc_update_bits(widget->codec, reg, mask, i); + } else { + for (i = 0; i < widget->saved_value; i++) + snd_soc_update_bits(widget->codec, reg, mask, i); + } + widget->muted = 0; + } else { + /* power down is about to occur, decrease volume to mute */ + int val = snd_soc_read(widget->codec, reg); + int i = widget->saved_value = (val >> shift) & mask; + if (invert) { + for (; i < mask; i++) + snd_soc_update_bits(widget->codec, reg, mask, i); + } else { + for (; i > 0; i--) + snd_soc_update_bits(widget->codec, reg, mask, i); + } + widget->muted = 1; + } + } + return 0; +} + +/* create new dapm mixer control */ +static int dapm_new_mixer(struct snd_soc_codec *codec, + struct snd_soc_dapm_widget *w) +{ + int i, ret = 0; + char name[32]; + struct snd_soc_dapm_path *path; + + /* add kcontrol */ + for (i = 0; i < w->num_kcontrols; i++) { + + /* match name */ + list_for_each_entry(path, &w->sources, list_sink) { + + /* mixer/mux paths name must match control name */ + if (path->name != (char*)w->kcontrols[i].name) + continue; + + /* add dapm control with long name */ + snprintf(name, 32, "%s %s", w->name, w->kcontrols[i].name); + path->long_name = kstrdup (name, GFP_KERNEL); + if (path->long_name == NULL) + return -ENOMEM; + + path->kcontrol = snd_soc_cnew(&w->kcontrols[i], w, + path->long_name); + ret = snd_ctl_add(codec->card, path->kcontrol); + if (ret < 0) { + printk(KERN_ERR "asoc: failed to add dapm kcontrol %s\n", + path->long_name); + kfree(path->long_name); + path->long_name = NULL; + return ret; + } + } + } + return ret; +} + +/* create new dapm mux control */ +static int dapm_new_mux(struct snd_soc_codec *codec, + struct snd_soc_dapm_widget *w) +{ + struct snd_soc_dapm_path *path = NULL; + struct snd_kcontrol *kcontrol; + int ret = 0; + + if (!w->num_kcontrols) { + printk(KERN_ERR "asoc: mux %s has no controls\n", w->name); + return -EINVAL; + } + + kcontrol = snd_soc_cnew(&w->kcontrols[0], w, w->name); + ret = snd_ctl_add(codec->card, kcontrol); + if (ret < 0) + goto err; + + list_for_each_entry(path, &w->sources, list_sink) + path->kcontrol = kcontrol; + + return ret; + +err: + printk(KERN_ERR "asoc: failed to add kcontrol %s\n", w->name); + return ret; +} + +/* create new dapm volume control */ +static int dapm_new_pga(struct snd_soc_codec *codec, + struct snd_soc_dapm_widget *w) +{ + struct snd_kcontrol *kcontrol; + int ret = 0; + + if (!w->num_kcontrols) + return -EINVAL; + + kcontrol = snd_soc_cnew(&w->kcontrols[0], w, w->name); + ret = snd_ctl_add(codec->card, kcontrol); + if (ret < 0) { + printk(KERN_ERR "asoc: failed to add kcontrol %s\n", w->name); + return ret; + } + + return ret; +} + +/* reset 'walked' bit for each dapm path */ +static inline void dapm_clear_walk(struct snd_soc_codec *codec) +{ + struct snd_soc_dapm_path *p; + + list_for_each_entry(p, &codec->dapm_paths, list) + p->walked = 0; +} + +/* + * Recursively check for a completed path to an active or physically connected + * output widget. Returns number of complete paths. + */ +static int is_connected_output_ep(struct snd_soc_dapm_widget *widget) +{ + struct snd_soc_dapm_path *path; + int con = 0; + + if (widget->id == snd_soc_dapm_adc && widget->active) + return 1; + + if (widget->connected) { + /* connected pin ? */ + if (widget->id == snd_soc_dapm_output && !widget->ext) + return 1; + + /* connected jack or spk ? */ + if (widget->id == snd_soc_dapm_hp || widget->id == snd_soc_dapm_spk || + widget->id == snd_soc_dapm_line) + return 1; + } + + list_for_each_entry(path, &widget->sinks, list_source) { + if (path->walked) + continue; + + if (path->sink && path->connect) { + path->walked = 1; + con += is_connected_output_ep(path->sink); + } + } + + return con; +} + +/* + * Recursively check for a completed path to an active or physically connected + * input widget. Returns number of complete paths. + */ +static int is_connected_input_ep(struct snd_soc_dapm_widget *widget) +{ + struct snd_soc_dapm_path *path; + int con = 0; + + /* active stream ? */ + if (widget->id == snd_soc_dapm_dac && widget->active) + return 1; + + if (widget->connected) { + /* connected pin ? */ + if (widget->id == snd_soc_dapm_input && !widget->ext) + return 1; + + /* connected VMID/Bias for lower pops */ + if (widget->id == snd_soc_dapm_vmid) + return 1; + + /* connected jack ? */ + if (widget->id == snd_soc_dapm_mic || widget->id == snd_soc_dapm_line) + return 1; + } + + list_for_each_entry(path, &widget->sources, list_sink) { + if (path->walked) + continue; + + if (path->source && path->connect) { + path->walked = 1; + con += is_connected_input_ep(path->source); + } + } + + return con; +} + +/* + * Scan each dapm widget for complete audio path. + * A complete path is a route that has valid endpoints i.e.:- + * + * o DAC to output pin. + * o Input Pin to ADC. + * o Input pin to Output pin (bypass, sidetone) + * o DAC to ADC (loopback). + */ +int dapm_power_widgets(struct snd_soc_codec *codec, int event) +{ + struct snd_soc_dapm_widget *w; + int in, out, i, c = 1, *seq = NULL, ret = 0, power_change, power; + + /* do we have a sequenced stream event */ + if (event == SND_SOC_DAPM_STREAM_START) { + c = ARRAY_SIZE(dapm_up_seq); + seq = dapm_up_seq; + } else if (event == SND_SOC_DAPM_STREAM_STOP) { + c = ARRAY_SIZE(dapm_down_seq); + seq = dapm_down_seq; + } + + for(i = 0; i < c; i++) { + list_for_each_entry(w, &codec->dapm_widgets, list) { + + /* is widget in stream order */ + if (seq && seq[i] && w->id != seq[i]) + continue; + + /* vmid - no action */ + if (w->id == snd_soc_dapm_vmid) + continue; + + /* active ADC */ + if (w->id == snd_soc_dapm_adc && w->active) { + in = is_connected_input_ep(w); + dapm_clear_walk(w->codec); + w->power = (in != 0) ? 1 : 0; + dapm_update_bits(w); + continue; + } + + /* active DAC */ + if (w->id == snd_soc_dapm_dac && w->active) { + out = is_connected_output_ep(w); + dapm_clear_walk(w->codec); + w->power = (out != 0) ? 1 : 0; + dapm_update_bits(w); + continue; + } + + /* programmable gain/attenuation */ + if (w->id == snd_soc_dapm_pga) { + int on; + in = is_connected_input_ep(w); + dapm_clear_walk(w->codec); + out = is_connected_output_ep(w); + dapm_clear_walk(w->codec); + w->power = on = (out != 0 && in != 0) ? 1 : 0; + + if (!on) + dapm_set_pga(w, on); /* lower volume to reduce pops */ + dapm_update_bits(w); + if (on) + dapm_set_pga(w, on); /* restore volume from zero */ + + continue; + } + + /* pre and post event widgets */ + if (w->id == snd_soc_dapm_pre) { + if (!w->event) + continue; + + if (event == SND_SOC_DAPM_STREAM_START) { + ret = w->event(w, SND_SOC_DAPM_PRE_PMU); + if (ret < 0) + return ret; + } else if (event == SND_SOC_DAPM_STREAM_STOP) { + ret = w->event(w, SND_SOC_DAPM_PRE_PMD); + if (ret < 0) + return ret; + } + continue; + } + if (w->id == snd_soc_dapm_post) { + if (!w->event) + continue; + + if (event == SND_SOC_DAPM_STREAM_START) { + ret = w->event(w, SND_SOC_DAPM_POST_PMU); + if (ret < 0) + return ret; + } else if (event == SND_SOC_DAPM_STREAM_STOP) { + ret = w->event(w, SND_SOC_DAPM_POST_PMD); + if (ret < 0) + return ret; + } + continue; + } + + /* all other widgets */ + in = is_connected_input_ep(w); + dapm_clear_walk(w->codec); + out = is_connected_output_ep(w); + dapm_clear_walk(w->codec); + power = (out != 0 && in != 0) ? 1 : 0; + power_change = (w->power == power) ? 0: 1; + w->power = power; + + /* call any power change event handlers */ + if (power_change) { + if (w->event) { + dbg("power %s event for %s flags %x\n", + w->power ? "on" : "off", w->name, w->event_flags); + if (power) { + /* power up event */ + if (w->event_flags & SND_SOC_DAPM_PRE_PMU) { + ret = w->event(w, SND_SOC_DAPM_PRE_PMU); + if (ret < 0) + return ret; + } + dapm_update_bits(w); + if (w->event_flags & SND_SOC_DAPM_POST_PMU){ + ret = w->event(w, SND_SOC_DAPM_POST_PMU); + if (ret < 0) + return ret; + } + } else { + /* power down event */ + if (w->event_flags & SND_SOC_DAPM_PRE_PMD) { + ret = w->event(w, SND_SOC_DAPM_PRE_PMD); + if (ret < 0) + return ret; + } + dapm_update_bits(w); + if (w->event_flags & SND_SOC_DAPM_POST_PMD) { + ret = w->event(w, SND_SOC_DAPM_POST_PMD); + if (ret < 0) + return ret; + } + } + } else + /* no event handler */ + dapm_update_bits(w); + } + } + } + + return ret; +} + +#if DAPM_DEBUG +static void dbg_dump_dapm(struct snd_soc_codec* codec, const char *action) +{ + struct snd_soc_dapm_widget *w; + struct snd_soc_dapm_path *p = NULL; + int in, out; + + printk("DAPM %s %s\n", codec->name, action); + + list_for_each_entry(w, &codec->dapm_widgets, list) { + + /* only display widgets that effect routing */ + switch (w->id) { + case snd_soc_dapm_pre: + case snd_soc_dapm_post: + case snd_soc_dapm_vmid: + continue; + case snd_soc_dapm_mux: + case snd_soc_dapm_output: + case snd_soc_dapm_input: + case snd_soc_dapm_switch: + case snd_soc_dapm_hp: + case snd_soc_dapm_mic: + case snd_soc_dapm_spk: + case snd_soc_dapm_line: + case snd_soc_dapm_micbias: + case snd_soc_dapm_dac: + case snd_soc_dapm_adc: + case snd_soc_dapm_pga: + case snd_soc_dapm_mixer: + if (w->name) { + in = is_connected_input_ep(w); + dapm_clear_walk(w->codec); + out = is_connected_output_ep(w); + dapm_clear_walk(w->codec); + printk("%s: %s in %d out %d\n", w->name, + w->power ? "On":"Off",in, out); + + list_for_each_entry(p, &w->sources, list_sink) { + if (p->connect) + printk(" in %s %s\n", p->name ? p->name : "static", + p->source->name); + } + list_for_each_entry(p, &w->sinks, list_source) { + p = list_entry(lp, struct snd_soc_dapm_path, list_source); + if (p->connect) + printk(" out %s %s\n", p->name ? p->name : "static", + p->sink->name); + } + } + break; + } + } +} +#endif + +/* test and update the power status of a mux widget */ +int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, + struct snd_kcontrol *kcontrol, int mask, int val, struct soc_enum* e) +{ + struct snd_soc_dapm_path *path; + int found = 0; + + if (widget->id != snd_soc_dapm_mux) + return -ENODEV; + + if (!snd_soc_test_bits(widget->codec, e->reg, mask, val)) + return 0; + + /* find dapm widget path assoc with kcontrol */ + list_for_each_entry(path, &widget->codec->dapm_paths, list) { + if (path->kcontrol != kcontrol) + continue; + + if (!path->name || ! e->texts[val]) + continue; + + found = 1; + /* we now need to match the string in the enum to the path */ + if (!(strcmp(path->name, e->texts[val]))) + path->connect = 1; /* new connection */ + else + path->connect = 0; /* old connection must be powered down */ + } + + if (found) + dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP); + + return 0; +} +EXPORT_SYMBOL_GPL(dapm_mux_update_power); + +/* test and update the power status of a mixer widget */ +int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, + struct snd_kcontrol *kcontrol, int reg, int val_mask, int val, int invert) +{ + struct snd_soc_dapm_path *path; + int found = 0; + + if (widget->id != snd_soc_dapm_mixer) + return -ENODEV; + + if (!snd_soc_test_bits(widget->codec, reg, val_mask, val)) + return 0; + + /* find dapm widget path assoc with kcontrol */ + list_for_each_entry(path, &widget->codec->dapm_paths, list) { + if (path->kcontrol != kcontrol) + continue; + + /* found, now check type */ + found = 1; + if (val) + /* new connection */ + path->connect = invert ? 0:1; + else + /* old connection must be powered down */ + path->connect = invert ? 1:0; + break; + } + + if (found) + dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP); + + return 0; +} +EXPORT_SYMBOL_GPL(dapm_mixer_update_power); + +/* show dapm widget status in sys fs */ +static ssize_t dapm_widget_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct snd_soc_device *devdata = dev_get_drvdata(dev); + struct snd_soc_codec *codec = devdata->codec; + struct snd_soc_dapm_widget *w; + int count = 0; + char *state = "not set"; + + list_for_each_entry(w, &codec->dapm_widgets, list) { + + /* only display widgets that burnm power */ + switch (w->id) { + case snd_soc_dapm_hp: + case snd_soc_dapm_mic: + case snd_soc_dapm_spk: + case snd_soc_dapm_line: + case snd_soc_dapm_micbias: + case snd_soc_dapm_dac: + case snd_soc_dapm_adc: + case snd_soc_dapm_pga: + case snd_soc_dapm_mixer: + if (w->name) + count += sprintf(buf + count, "%s: %s\n", + w->name, w->power ? "On":"Off"); + break; + default: + break; + } + } + + switch(codec->dapm_state){ + case SNDRV_CTL_POWER_D0: + state = "D0"; + break; + case SNDRV_CTL_POWER_D1: + state = "D1"; + break; + case SNDRV_CTL_POWER_D2: + state = "D2"; + break; + case SNDRV_CTL_POWER_D3hot: + state = "D3hot"; + break; + case SNDRV_CTL_POWER_D3cold: + state = "D3cold"; + break; + } + count += sprintf(buf + count, "PM State: %s\n", state); + + return count; +} + +static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL); + +int snd_soc_dapm_sys_add(struct device *dev) +{ + int ret = 0; + + if (dapm_status) + ret = device_create_file(dev, &dev_attr_dapm_widget); + + return ret; +} + +static void snd_soc_dapm_sys_remove(struct device *dev) +{ + if (dapm_status) + device_remove_file(dev, &dev_attr_dapm_widget); +} + +/* free all dapm widgets and resources */ +void dapm_free_widgets(struct snd_soc_codec *codec) +{ + struct snd_soc_dapm_widget *w, *next_w; + struct snd_soc_dapm_path *p, *next_p; + + list_for_each_entry_safe(w, next_w, &codec->dapm_widgets, list) { + list_del(&w->list); + kfree(w); + } + + list_for_each_entry_safe(p, next_p, &codec->dapm_paths, list) { + list_del(&p->list); + kfree(p->long_name); + kfree(p); + } +} + +/** + * snd_soc_dapm_sync_endpoints - scan and power dapm paths + * @codec: audio codec + * + * Walks all dapm audio paths and powers widgets according to their + * stream or path usage. + * + * Returns 0 for success. + */ +int snd_soc_dapm_sync_endpoints(struct snd_soc_codec *codec) +{ + return dapm_power_widgets(codec, SND_SOC_DAPM_STREAM_NOP); +} +EXPORT_SYMBOL_GPL(snd_soc_dapm_sync_endpoints); + +/** + * snd_soc_dapm_connect_input - connect dapm widgets + * @codec: audio codec + * @sink: name of target widget + * @control: mixer control name + * @source: name of source name + * + * Connects 2 dapm widgets together via a named audio path. The sink is + * the widget receiving the audio signal, whilst the source is the sender + * of the audio signal. + * + * Returns 0 for success else error. + */ +int snd_soc_dapm_connect_input(struct snd_soc_codec *codec, const char *sink, + const char * control, const char *source) +{ + struct snd_soc_dapm_path *path; + struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w; + int ret = 0; + + /* find src and dest widgets */ + list_for_each_entry(w, &codec->dapm_widgets, list) { + + if (!wsink && !(strcmp(w->name, sink))) { + wsink = w; + continue; + } + if (!wsource && !(strcmp(w->name, source))) { + wsource = w; + } + } + + if (wsource == NULL || wsink == NULL) + return -ENODEV; + + path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL); + if (!path) + return -ENOMEM; + + path->source = wsource; + path->sink = wsink; + INIT_LIST_HEAD(&path->list); + INIT_LIST_HEAD(&path->list_source); + INIT_LIST_HEAD(&path->list_sink); + + /* check for external widgets */ + if (wsink->id == snd_soc_dapm_input) { + if (wsource->id == snd_soc_dapm_micbias || + wsource->id == snd_soc_dapm_mic || + wsink->id == snd_soc_dapm_line) + wsink->ext = 1; + } + if (wsource->id == snd_soc_dapm_output) { + if (wsink->id == snd_soc_dapm_spk || + wsink->id == snd_soc_dapm_hp || + wsink->id == snd_soc_dapm_line) + wsource->ext = 1; + } + + /* connect static paths */ + if (control == NULL) { + list_add(&path->list, &codec->dapm_paths); + list_add(&path->list_sink, &wsink->sources); + list_add(&path->list_source, &wsource->sinks); + path->connect = 1; + return 0; + } + + /* connect dynamic paths */ + switch(wsink->id) { + case snd_soc_dapm_adc: + case snd_soc_dapm_dac: + case snd_soc_dapm_pga: + case snd_soc_dapm_input: + case snd_soc_dapm_output: + case snd_soc_dapm_micbias: + case snd_soc_dapm_vmid: + case snd_soc_dapm_pre: + case snd_soc_dapm_post: + list_add(&path->list, &codec->dapm_paths); + list_add(&path->list_sink, &wsink->sources); + list_add(&path->list_source, &wsource->sinks); + path->connect = 1; + return 0; + case snd_soc_dapm_mux: + ret = dapm_connect_mux(codec, wsource, wsink, path, control, + &wsink->kcontrols[0]); + if (ret != 0) + goto err; + break; + case snd_soc_dapm_switch: + case snd_soc_dapm_mixer: + ret = dapm_connect_mixer(codec, wsource, wsink, path, control); + if (ret != 0) + goto err; + break; + case snd_soc_dapm_hp: + case snd_soc_dapm_mic: + case snd_soc_dapm_line: + case snd_soc_dapm_spk: + list_add(&path->list, &codec->dapm_paths); + list_add(&path->list_sink, &wsink->sources); + list_add(&path->list_source, &wsource->sinks); + path->connect = 0; + return 0; + } + return 0; + +err: + printk(KERN_WARNING "asoc: no dapm match for %s --> %s --> %s\n", source, + control, sink); + kfree(path); + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_dapm_connect_input); + +/** + * snd_soc_dapm_new_widgets - add new dapm widgets + * @codec: audio codec + * + * Checks the codec for any new dapm widgets and creates them if found. + * + * Returns 0 for success. + */ +int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec) +{ + struct snd_soc_dapm_widget *w; + + mutex_lock(&codec->mutex); + list_for_each_entry(w, &codec->dapm_widgets, list) + { + if (w->new) + continue; + + switch(w->id) { + case snd_soc_dapm_switch: + case snd_soc_dapm_mixer: + dapm_new_mixer(codec, w); + break; + case snd_soc_dapm_mux: + dapm_new_mux(codec, w); + break; + case snd_soc_dapm_adc: + case snd_soc_dapm_dac: + case snd_soc_dapm_pga: + dapm_new_pga(codec, w); + break; + case snd_soc_dapm_input: + case snd_soc_dapm_output: + case snd_soc_dapm_micbias: + case snd_soc_dapm_spk: + case snd_soc_dapm_hp: + case snd_soc_dapm_mic: + case snd_soc_dapm_line: + case snd_soc_dapm_vmid: + case snd_soc_dapm_pre: + case snd_soc_dapm_post: + break; + } + w->new = 1; + } + + dapm_power_widgets(codec, SND_SOC_DAPM_STREAM_NOP); + mutex_unlock(&codec->mutex); + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets); + +/** + * snd_soc_dapm_get_volsw - dapm mixer get callback + * @kcontrol: mixer control + * @uinfo: control element information + * + * Callback to get the value of a dapm mixer control. + * + * Returns 0 for success. + */ +int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); + int reg = kcontrol->private_value & 0xff; + int shift = (kcontrol->private_value >> 8) & 0x0f; + int rshift = (kcontrol->private_value >> 12) & 0x0f; + int mask = (kcontrol->private_value >> 16) & 0xff; + int invert = (kcontrol->private_value >> 24) & 0x01; + + /* return the saved value if we are powered down */ + if (widget->id == snd_soc_dapm_pga && !widget->power) { + ucontrol->value.integer.value[0] = widget->saved_value; + return 0; + } + + ucontrol->value.integer.value[0] = + (snd_soc_read(widget->codec, reg) >> shift) & mask; + if (shift != rshift) + ucontrol->value.integer.value[1] = + (snd_soc_read(widget->codec, reg) >> rshift) & mask; + if (invert) { + ucontrol->value.integer.value[0] = + mask - ucontrol->value.integer.value[0]; + if (shift != rshift) + ucontrol->value.integer.value[1] = + mask - ucontrol->value.integer.value[1]; + } + + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw); + +/** + * snd_soc_dapm_put_volsw - dapm mixer set callback + * @kcontrol: mixer control + * @uinfo: control element information + * + * Callback to set the value of a dapm mixer control. + * + * Returns 0 for success. + */ +int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); + int reg = kcontrol->private_value & 0xff; + int shift = (kcontrol->private_value >> 8) & 0x0f; + int rshift = (kcontrol->private_value >> 12) & 0x0f; + int mask = (kcontrol->private_value >> 16) & 0xff; + int invert = (kcontrol->private_value >> 24) & 0x01; + unsigned short val, val2, val_mask; + int ret; + + val = (ucontrol->value.integer.value[0] & mask); + + if (invert) + val = mask - val; + val_mask = mask << shift; + val = val << shift; + if (shift != rshift) { + val2 = (ucontrol->value.integer.value[1] & mask); + if (invert) + val2 = mask - val2; + val_mask |= mask << rshift; + val |= val2 << rshift; + } + + mutex_lock(&widget->codec->mutex); + widget->value = val; + + /* save volume value if the widget is powered down */ + if (widget->id == snd_soc_dapm_pga && !widget->power) { + widget->saved_value = val; + mutex_unlock(&widget->codec->mutex); + return 1; + } + + dapm_mixer_update_power(widget, kcontrol, reg, val_mask, val, invert); + if (widget->event) { + if (widget->event_flags & SND_SOC_DAPM_PRE_REG) { + ret = widget->event(widget, SND_SOC_DAPM_PRE_REG); + if (ret < 0) + goto out; + } + ret = snd_soc_update_bits(widget->codec, reg, val_mask, val); + if (widget->event_flags & SND_SOC_DAPM_POST_REG) + ret = widget->event(widget, SND_SOC_DAPM_POST_REG); + } else + ret = snd_soc_update_bits(widget->codec, reg, val_mask, val); + +out: + mutex_unlock(&widget->codec->mutex); + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw); + +/** + * snd_soc_dapm_get_enum_double - dapm enumerated double mixer get callback + * @kcontrol: mixer control + * @uinfo: control element information + * + * Callback to get the value of a dapm enumerated double mixer control. + * + * Returns 0 for success. + */ +int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned short val, bitmask; + + for (bitmask = 1; bitmask < e->mask; bitmask <<= 1) + ; + val = snd_soc_read(widget->codec, e->reg); + ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & (bitmask - 1); + if (e->shift_l != e->shift_r) + ucontrol->value.enumerated.item[1] = + (val >> e->shift_r) & (bitmask - 1); + + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double); + +/** + * snd_soc_dapm_put_enum_double - dapm enumerated double mixer set callback + * @kcontrol: mixer control + * @uinfo: control element information + * + * Callback to set the value of a dapm enumerated double mixer control. + * + * Returns 0 for success. + */ +int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned short val, mux; + unsigned short mask, bitmask; + int ret = 0; + + for (bitmask = 1; bitmask < e->mask; bitmask <<= 1) + ; + if (ucontrol->value.enumerated.item[0] > e->mask - 1) + return -EINVAL; + mux = ucontrol->value.enumerated.item[0]; + val = mux << e->shift_l; + mask = (bitmask - 1) << e->shift_l; + if (e->shift_l != e->shift_r) { + if (ucontrol->value.enumerated.item[1] > e->mask - 1) + return -EINVAL; + val |= ucontrol->value.enumerated.item[1] << e->shift_r; + mask |= (bitmask - 1) << e->shift_r; + } + + mutex_lock(&widget->codec->mutex); + widget->value = val; + dapm_mux_update_power(widget, kcontrol, mask, mux, e); + if (widget->event) { + if (widget->event_flags & SND_SOC_DAPM_PRE_REG) { + ret = widget->event(widget, SND_SOC_DAPM_PRE_REG); + if (ret < 0) + goto out; + } + ret = snd_soc_update_bits(widget->codec, e->reg, mask, val); + if (widget->event_flags & SND_SOC_DAPM_POST_REG) + ret = widget->event(widget, SND_SOC_DAPM_POST_REG); + } else + ret = snd_soc_update_bits(widget->codec, e->reg, mask, val); + +out: + mutex_unlock(&widget->codec->mutex); + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double); + +/** + * snd_soc_dapm_new_control - create new dapm control + * @codec: audio codec + * @widget: widget template + * + * Creates a new dapm control based upon the template. + * + * Returns 0 for success else error. + */ +int snd_soc_dapm_new_control(struct snd_soc_codec *codec, + const struct snd_soc_dapm_widget *widget) +{ + struct snd_soc_dapm_widget *w; + + if ((w = dapm_cnew_widget(widget)) == NULL) + return -ENOMEM; + + w->codec = codec; + INIT_LIST_HEAD(&w->sources); + INIT_LIST_HEAD(&w->sinks); + INIT_LIST_HEAD(&w->list); + list_add(&w->list, &codec->dapm_widgets); + + /* machine layer set ups unconnected pins and insertions */ + w->connected = 1; + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control); + +/** + * snd_soc_dapm_stream_event - send a stream event to the dapm core + * @codec: audio codec + * @stream: stream name + * @event: stream event + * + * Sends a stream event to the dapm core. The core then makes any + * necessary widget power changes. + * + * Returns 0 for success else error. + */ +int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, + char *stream, int event) +{ + struct snd_soc_dapm_widget *w; + + mutex_lock(&codec->mutex); + list_for_each_entry(w, &codec->dapm_widgets, list) + { + if (!w->sname) + continue; + dbg("widget %s\n %s stream %s event %d\n", w->name, w->sname, + stream, event); + if (strstr(w->sname, stream)) { + switch(event) { + case SND_SOC_DAPM_STREAM_START: + w->active = 1; + break; + case SND_SOC_DAPM_STREAM_STOP: + w->active = 0; + break; + case SND_SOC_DAPM_STREAM_SUSPEND: + if (w->active) + w->suspend = 1; + w->active = 0; + break; + case SND_SOC_DAPM_STREAM_RESUME: + if (w->suspend) { + w->active = 1; + w->suspend = 0; + } + break; + case SND_SOC_DAPM_STREAM_PAUSE_PUSH: + break; + case SND_SOC_DAPM_STREAM_PAUSE_RELEASE: + break; + } + } + } + mutex_unlock(&codec->mutex); + + dapm_power_widgets(codec, event); + dump_dapm(codec, __FUNCTION__); + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event); + +/** + * snd_soc_dapm_set_endpoint - set audio endpoint status + * @codec: audio codec + * @endpoint: audio signal endpoint (or start point) + * @status: point status + * + * Set audio endpoint status - connected or disconnected. + * + * Returns 0 for success else error. + */ +int snd_soc_dapm_set_endpoint(struct snd_soc_codec *codec, + char *endpoint, int status) +{ + struct snd_soc_dapm_widget *w; + + list_for_each_entry(w, &codec->dapm_widgets, list) { + if (!strcmp(w->name, endpoint)) { + w->connected = status; + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_dapm_set_endpoint); + +/** + * snd_soc_dapm_free - free dapm resources + * @socdev: SoC device + * + * Free all dapm widgets and resources. + */ +void snd_soc_dapm_free(struct snd_soc_device *socdev) +{ + struct snd_soc_codec *codec = socdev->codec; + + snd_soc_dapm_sys_remove(socdev->dev); + dapm_free_widgets(codec); +} +EXPORT_SYMBOL_GPL(snd_soc_dapm_free); + +/* Module information */ +MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com"); +MODULE_DESCRIPTION("Dynamic Audio Power Management core for ALSA SoC"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From a3288176de3fdd439d9bca0a0b9ca749c12ac5ac Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 6 Oct 2006 18:33:55 +0200 Subject: [ALSA] ASoC: Build files This patch adds support for building the ASoC core and the dynamic audio power management support. Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/Kconfig | 2 ++ sound/Makefile | 2 +- sound/soc/Kconfig | 19 +++++++++++++++++++ sound/soc/Makefile | 4 ++++ 4 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 sound/soc/Kconfig create mode 100644 sound/soc/Makefile (limited to 'sound') diff --git a/sound/Kconfig b/sound/Kconfig index 9d77300746c..97532bbc2cc 100644 --- a/sound/Kconfig +++ b/sound/Kconfig @@ -76,6 +76,8 @@ source "sound/sparc/Kconfig" source "sound/parisc/Kconfig" +source "sound/soc/Kconfig" + endmenu menu "Open Sound System" diff --git a/sound/Makefile b/sound/Makefile index 9aee54c4882..b7c7fb7c24c 100644 --- a/sound/Makefile +++ b/sound/Makefile @@ -5,7 +5,7 @@ obj-$(CONFIG_SOUND) += soundcore.o obj-$(CONFIG_SOUND_PRIME) += sound_firmware.o obj-$(CONFIG_SOUND_PRIME) += oss/ obj-$(CONFIG_DMASOUND) += oss/ -obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ synth/ usb/ sparc/ parisc/ pcmcia/ mips/ +obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ synth/ usb/ sparc/ parisc/ pcmcia/ mips/ soc/ obj-$(CONFIG_SND_AOA) += aoa/ # This one must be compilable even if sound is configured out diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig new file mode 100644 index 00000000000..200709f4b70 --- /dev/null +++ b/sound/soc/Kconfig @@ -0,0 +1,19 @@ +# +# SoC audio configuration +# + +menu "SoC audio support" + depends on SND!=n + +config SND_SOC + tristate "SoC audio support" + ---help--- + + If you want SoC support, you should say Y here and also to the + specific driver for your SoC below. You will also need to select the + specific codec(s) attached to the SoC + + This SoC audio support can also be built as a module. If so, the module + will be called snd-soc-core. + +endmenu diff --git a/sound/soc/Makefile b/sound/soc/Makefile new file mode 100644 index 00000000000..b211ee63fd7 --- /dev/null +++ b/sound/soc/Makefile @@ -0,0 +1,4 @@ +snd-soc-core-objs := soc-core.o soc-dapm.o + +obj-$(CONFIG_SND_SOC) += snd-soc-core.o + -- cgit v1.2.3 From 40e0aa64660b4e28a9348e57bfbda6c114617969 Mon Sep 17 00:00:00 2001 From: Richard Purdie Date: Fri, 6 Oct 2006 18:36:07 +0200 Subject: [ALSA] ASoC codecs: WM8731 support This patch adds ASoC support for the WM8731 codec. Supported features:- o Capture/Playback/Sidetone/Bypass. o 16 & 24 bit audio. o 8k - 96k sample rates. o DAPM. Signed-off-by: Richard Purdie Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/codecs/wm8731.c | 789 ++++++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/wm8731.h | 41 +++ 2 files changed, 830 insertions(+) create mode 100644 sound/soc/codecs/wm8731.c create mode 100644 sound/soc/codecs/wm8731.h (limited to 'sound') diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c new file mode 100644 index 00000000000..cd0ece650f3 --- /dev/null +++ b/sound/soc/codecs/wm8731.c @@ -0,0 +1,789 @@ +/* + * wm8731.c -- WM8731 ALSA SoC Audio driver + * + * Copyright 2005 Openedhand Ltd. + * + * Author: Richard Purdie + * + * Based on wm8753.c by Liam Girdwood + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wm8731.h" + +#define AUDIO_NAME "wm8731" +#define WM8731_VERSION "0.12" + +/* + * Debug + */ + +#define WM8731_DEBUG 0 + +#ifdef WM8731_DEBUG +#define dbg(format, arg...) \ + printk(KERN_DEBUG AUDIO_NAME ": " format "\n" , ## arg) +#else +#define dbg(format, arg...) do {} while (0) +#endif +#define err(format, arg...) \ + printk(KERN_ERR AUDIO_NAME ": " format "\n" , ## arg) +#define info(format, arg...) \ + printk(KERN_INFO AUDIO_NAME ": " format "\n" , ## arg) +#define warn(format, arg...) \ + printk(KERN_WARNING AUDIO_NAME ": " format "\n" , ## arg) + +struct snd_soc_codec_device soc_codec_dev_wm8731; + +/* + * wm8731 register cache + * We can't read the WM8731 register space when we are + * using 2 wire for device control, so we cache them instead. + * There is no point in caching the reset register + */ +static const u16 wm8731_reg[WM8731_CACHEREGNUM] = { + 0x0097, 0x0097, 0x0079, 0x0079, + 0x000a, 0x0008, 0x009f, 0x000a, + 0x0000, 0x0000 +}; + +#define WM8731_DAIFMT \ + (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_RIGHT_J | \ + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_NB_IF | SND_SOC_DAIFMT_IB_NF | \ + SND_SOC_DAIFMT_IB_IF) + +#define WM8731_DIR \ + (SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE) + +#define WM8731_RATES \ + (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \ + SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) + +#define WM8731_HIFI_BITS \ + (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_mode wm8731_modes[] = { + /* codec frame and clock master modes */ + /* 8k */ + {WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, SND_SOC_DAITDM_LRDW(0,0), + WM8731_HIFI_BITS, SNDRV_PCM_RATE_8000, WM8731_DIR, 0, + 1536, SND_SOC_FSB(64)}, + {WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, SND_SOC_DAITDM_LRDW(0,0), + WM8731_HIFI_BITS, SNDRV_PCM_RATE_8000, WM8731_DIR, 0, + 2304, SND_SOC_FSB(64)}, + {WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, SND_SOC_DAITDM_LRDW(0,0), + WM8731_HIFI_BITS, SNDRV_PCM_RATE_8000, WM8731_DIR, 0, + 1408, SND_SOC_FSB(64)}, + {WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, SND_SOC_DAITDM_LRDW(0,0), + WM8731_HIFI_BITS, SNDRV_PCM_RATE_8000, WM8731_DIR, 0, + 2112, SND_SOC_FSB(64)}, + + /* 32k */ + {WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, SND_SOC_DAITDM_LRDW(0,0), + WM8731_HIFI_BITS, SNDRV_PCM_RATE_32000, WM8731_DIR, 0, + 384, SND_SOC_FSB(64)}, + {WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, SND_SOC_DAITDM_LRDW(0,0), + WM8731_HIFI_BITS, SNDRV_PCM_RATE_32000, WM8731_DIR, 0, + 576, SND_SOC_FSB(64)}, + + /* 44.1k & 48k */ + {WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, SND_SOC_DAITDM_LRDW(0,0), + WM8731_HIFI_BITS, SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, + WM8731_DIR, 0, 256, SND_SOC_FSB(64)}, + {WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, SND_SOC_DAITDM_LRDW(0,0), + WM8731_HIFI_BITS, SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, + WM8731_DIR, 0, 384, SND_SOC_FSB(64)}, + + /* 88.2 & 96k */ + {WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, SND_SOC_DAITDM_LRDW(0,0), + WM8731_HIFI_BITS, SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000, + WM8731_DIR, 0, 128, SND_SOC_FSB(64)}, + {WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, SND_SOC_DAITDM_LRDW(0,0), + WM8731_HIFI_BITS, SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000, + WM8731_DIR, 0, 192, SND_SOC_FSB(64)}, + + + /* USB codec frame and clock master modes */ + /* 8k */ + {WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, SND_SOC_DAITDM_LRDW(0,0), + WM8731_HIFI_BITS, SNDRV_PCM_RATE_8000, WM8731_DIR, + SND_SOC_DAI_BFS_DIV, 1500, SND_SOC_FSBD(1)}, + + /* 44.1k */ + {WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, SND_SOC_DAITDM_LRDW(0,0), + WM8731_HIFI_BITS, SNDRV_PCM_RATE_44100, WM8731_DIR, + SND_SOC_DAI_BFS_DIV, 272, SND_SOC_FSBD(1)}, + + /* 48k */ + {WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, SND_SOC_DAITDM_LRDW(0,0), + WM8731_HIFI_BITS, SNDRV_PCM_RATE_48000, WM8731_DIR, + SND_SOC_DAI_BFS_DIV, 250, SND_SOC_FSBD(1)}, + + /* 88.2k */ + {WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, SND_SOC_DAITDM_LRDW(0,0), + WM8731_HIFI_BITS, SNDRV_PCM_RATE_88200, WM8731_DIR, + SND_SOC_DAI_BFS_DIV, 136, SND_SOC_FSBD(1)}, + + /* 96k */ + {WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, SND_SOC_DAITDM_LRDW(0,0), + WM8731_HIFI_BITS, SNDRV_PCM_RATE_96000, WM8731_DIR, + SND_SOC_DAI_BFS_DIV, 125, SND_SOC_FSBD(1)}, + + /* codec frame and clock slave modes */ + {WM8731_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, SND_SOC_DAITDM_LRDW(0,0), + WM8731_HIFI_BITS, WM8731_RATES, WM8731_DIR, SND_SOC_DAI_BFS_DIV, + SND_SOC_FS_ALL, SND_SOC_FSBD_ALL}, +}; + +/* + * read wm8731 register cache + */ +static inline unsigned int wm8731_read_reg_cache(struct snd_soc_codec *codec, + unsigned int reg) +{ + u16 *cache = codec->reg_cache; + if (reg == WM8731_RESET) + return 0; + if (reg >= WM8731_CACHEREGNUM) + return -1; + return cache[reg]; +} + +/* + * write wm8731 register cache + */ +static inline void wm8731_write_reg_cache(struct snd_soc_codec *codec, + u16 reg, unsigned int value) +{ + u16 *cache = codec->reg_cache; + if (reg >= WM8731_CACHEREGNUM) + return; + cache[reg] = value; +} + +/* + * write to the WM8731 register space + */ +static int wm8731_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + u8 data[2]; + + /* data is + * D15..D9 WM8731 register offset + * D8...D0 register data + */ + data[0] = (reg << 1) | ((value >> 8) & 0x0001); + data[1] = value & 0x00ff; + + wm8731_write_reg_cache (codec, reg, value); + if (codec->hw_write(codec->control_data, data, 2) == 2) + return 0; + else + return -EIO; +} + +#define wm8731_reset(c) wm8731_write(c, WM8731_RESET, 0) + +static const char *wm8731_input_select[] = {"Line In", "Mic"}; +static const char *wm8731_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"}; + +static const struct soc_enum wm8731_enum[] = { + SOC_ENUM_SINGLE(WM8731_APANA, 2, 2, wm8731_input_select), + SOC_ENUM_SINGLE(WM8731_APDIGI, 1, 4, wm8731_deemph), +}; + +static const struct snd_kcontrol_new wm8731_snd_controls[] = { + +SOC_DOUBLE_R("Playback Volume", WM8731_LOUT1V, WM8731_ROUT1V, 0, 127, 0), +SOC_DOUBLE_R("Playback ZC Switch", WM8731_LOUT1V, WM8731_ROUT1V, 7, 1, 0), + +SOC_DOUBLE_R("Capture Volume", WM8731_LINVOL, WM8731_RINVOL, 0, 31, 0), +SOC_DOUBLE_R("Line Capture Switch", WM8731_LINVOL, WM8731_RINVOL, 7, 1, 1), + +SOC_SINGLE("Mic Boost (+20dB)", WM8731_APANA, 0, 1, 0), +SOC_SINGLE("Capture Mic Switch", WM8731_APANA, 1, 1, 1), + +SOC_SINGLE("Sidetone Playback Volume", WM8731_APANA, 6, 3, 1), + +SOC_SINGLE("ADC High Pass Filter Switch", WM8731_APDIGI, 0, 1, 1), +SOC_SINGLE("Store DC Offset Switch", WM8731_APDIGI, 4, 1, 0), + +SOC_ENUM("Playback De-emphasis", wm8731_enum[1]), +}; + +/* add non dapm controls */ +static int wm8731_add_controls(struct snd_soc_codec *codec) +{ + int err, i; + + for (i = 0; i < ARRAY_SIZE(wm8731_snd_controls); i++) { + if ((err = snd_ctl_add(codec->card, + snd_soc_cnew(&wm8731_snd_controls[i],codec, NULL))) < 0) + return err; + } + + return 0; +} + +/* Output Mixer */ +static const struct snd_kcontrol_new wm8731_output_mixer_controls[] = { +SOC_DAPM_SINGLE("Line Bypass Switch", WM8731_APANA, 3, 1, 0), +SOC_DAPM_SINGLE("Mic Sidetone Switch", WM8731_APANA, 5, 1, 0), +SOC_DAPM_SINGLE("HiFi Playback Switch", WM8731_APANA, 4, 1, 0), +}; + +/* Input mux */ +static const struct snd_kcontrol_new wm8731_input_mux_controls = +SOC_DAPM_ENUM("Input Select", wm8731_enum[0]); + +static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = { +SND_SOC_DAPM_MIXER("Output Mixer", WM8731_PWR, 4, 1, + &wm8731_output_mixer_controls[0], + ARRAY_SIZE(wm8731_output_mixer_controls)), +SND_SOC_DAPM_DAC("DAC", "HiFi Playback", WM8731_PWR, 3, 1), +SND_SOC_DAPM_OUTPUT("LOUT"), +SND_SOC_DAPM_OUTPUT("LHPOUT"), +SND_SOC_DAPM_OUTPUT("ROUT"), +SND_SOC_DAPM_OUTPUT("RHPOUT"), +SND_SOC_DAPM_ADC("ADC", "HiFi Capture", WM8731_PWR, 2, 1), +SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, &wm8731_input_mux_controls), +SND_SOC_DAPM_PGA("Line Input", WM8731_PWR, 0, 1, NULL, 0), +SND_SOC_DAPM_MICBIAS("Mic Bias", WM8731_PWR, 1, 1), +SND_SOC_DAPM_INPUT("MICIN"), +SND_SOC_DAPM_INPUT("RLINEIN"), +SND_SOC_DAPM_INPUT("LLINEIN"), +}; + +static const char *intercon[][3] = { + /* output mixer */ + {"Output Mixer", "Line Bypass Switch", "Line Input"}, + {"Output Mixer", "HiFi Playback Switch", "DAC"}, + {"Output Mixer", "Mic Sidetone Switch", "Mic Bias"}, + + /* outputs */ + {"RHPOUT", NULL, "Output Mixer"}, + {"ROUT", NULL, "Output Mixer"}, + {"LHPOUT", NULL, "Output Mixer"}, + {"LOUT", NULL, "Output Mixer"}, + + /* input mux */ + {"Input Mux", "Line In", "Line Input"}, + {"Input Mux", "Mic", "Mic Bias"}, + {"ADC", NULL, "Input Mux"}, + + /* inputs */ + {"Line Input", NULL, "LLINEIN"}, + {"Line Input", NULL, "RLINEIN"}, + {"Mic Bias", NULL, "MICIN"}, + + /* terminator */ + {NULL, NULL, NULL}, +}; + +static int wm8731_add_widgets(struct snd_soc_codec *codec) +{ + int i; + + for(i = 0; i < ARRAY_SIZE(wm8731_dapm_widgets); i++) { + snd_soc_dapm_new_control(codec, &wm8731_dapm_widgets[i]); + } + + /* set up audio path interconnects */ + for(i = 0; intercon[i][0] != NULL; i++) { + snd_soc_dapm_connect_input(codec, intercon[i][0], + intercon[i][1], intercon[i][2]); + } + + snd_soc_dapm_new_widgets(codec); + return 0; +} + +struct _coeff_div { + u32 mclk; + u32 rate; + u16 fs; + u8 sr:4; + u8 bosr:1; + u8 usb:1; +}; + +/* codec mclk clock divider coefficients */ +static const struct _coeff_div coeff_div[] = { + /* 48k */ + {12288000, 48000, 256, 0x0, 0x0, 0x0}, + {18432000, 48000, 384, 0x0, 0x1, 0x0}, + {12000000, 48000, 250, 0x0, 0x0, 0x1}, + + /* 32k */ + {12288000, 32000, 384, 0x6, 0x0, 0x0}, + {18432000, 32000, 576, 0x6, 0x1, 0x0}, + + /* 8k */ + {12288000, 8000, 1536, 0x3, 0x0, 0x0}, + {18432000, 8000, 2304, 0x3, 0x1, 0x0}, + {11289600, 8000, 1408, 0xb, 0x0, 0x0}, + {16934400, 8000, 2112, 0xb, 0x1, 0x0}, + {12000000, 8000, 1500, 0x3, 0x0, 0x1}, + + /* 96k */ + {12288000, 96000, 128, 0x7, 0x0, 0x0}, + {18432000, 96000, 192, 0x7, 0x1, 0x0}, + {12000000, 96000, 125, 0x7, 0x0, 0x1}, + + /* 44.1k */ + {11289600, 44100, 256, 0x8, 0x0, 0x0}, + {16934400, 44100, 384, 0x8, 0x1, 0x0}, + {12000000, 44100, 272, 0x8, 0x1, 0x1}, + + /* 88.2k */ + {11289600, 88200, 128, 0xf, 0x0, 0x0}, + {16934400, 88200, 192, 0xf, 0x1, 0x0}, + {12000000, 88200, 136, 0xf, 0x1, 0x1}, +}; + +static inline int get_coeff(int mclk, int rate) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(coeff_div); i++) { + if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk) + return i; + } + return 0; +} + +/* WM8731 supports numerous clocks per sample rate */ +static unsigned int wm8731_config_sysclk(struct snd_soc_codec_dai *dai, + struct snd_soc_clock_info *info, unsigned int clk) +{ + dai->mclk = 0; + + /* check that the calculated FS and rate actually match a clock from + * the machine driver */ + if (info->fs * info->rate == clk) + dai->mclk = clk; + + return dai->mclk; +} + +static int wm8731_pcm_prepare(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->codec; + u16 iface = 0, srate; + int i = get_coeff(rtd->codec_dai->mclk, + snd_soc_get_rate(rtd->codec_dai->dai_runtime.pcmrate)); + + /* set master/slave audio interface */ + switch (rtd->codec_dai->dai_runtime.fmt & SND_SOC_DAIFMT_CLOCK_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + iface |= 0x0040; + break; + case SND_SOC_DAIFMT_CBS_CFS: + break; + } + srate = (coeff_div[i].sr << 2) | + (coeff_div[i].bosr << 1) | coeff_div[i].usb; + wm8731_write(codec, WM8731_SRATE, srate); + + /* interface format */ + switch (rtd->codec_dai->dai_runtime.fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + iface |= 0x0002; + break; + case SND_SOC_DAIFMT_RIGHT_J: + break; + case SND_SOC_DAIFMT_LEFT_J: + iface |= 0x0001; + break; + case SND_SOC_DAIFMT_DSP_A: + iface |= 0x0003; + break; + case SND_SOC_DAIFMT_DSP_B: + iface |= 0x0013; + break; + } + + /* bit size */ + switch (rtd->codec_dai->dai_runtime.pcmfmt) { + case SNDRV_PCM_FMTBIT_S16_LE: + break; + case SNDRV_PCM_FMTBIT_S20_3LE: + iface |= 0x0004; + break; + case SNDRV_PCM_FMTBIT_S24_LE: + iface |= 0x0008; + break; + case SNDRV_PCM_FMTBIT_S32_LE: + iface |= 0x000c; + break; + } + + /* clock inversion */ + switch (rtd->codec_dai->dai_runtime.fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_IF: + iface |= 0x0090; + break; + case SND_SOC_DAIFMT_IB_NF: + iface |= 0x0080; + break; + case SND_SOC_DAIFMT_NB_IF: + iface |= 0x0010; + break; + } + + /* set iface */ + wm8731_write(codec, WM8731_IFACE, iface); + + /* set active */ + wm8731_write(codec, WM8731_ACTIVE, 0x0001); + return 0; +} + +static void wm8731_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->codec; + + /* deactivate */ + if (!codec->active) { + udelay(50); + wm8731_write(codec, WM8731_ACTIVE, 0x0); + } +} + +static int wm8731_mute(struct snd_soc_codec *codec, + struct snd_soc_codec_dai *dai, int mute) +{ + u16 mute_reg = wm8731_read_reg_cache(codec, WM8731_APDIGI) & 0xfff7; + if (mute) + wm8731_write(codec, WM8731_APDIGI, mute_reg | 0x8); + else + wm8731_write(codec, WM8731_APDIGI, mute_reg); + return 0; +} + +static int wm8731_dapm_event(struct snd_soc_codec *codec, int event) +{ + u16 reg = wm8731_read_reg_cache(codec, WM8731_PWR) & 0xff7f; + + switch (event) { + case SNDRV_CTL_POWER_D0: /* full On */ + /* vref/mid, osc on, dac unmute */ + wm8731_write(codec, WM8731_PWR, reg); + break; + case SNDRV_CTL_POWER_D1: /* partial On */ + case SNDRV_CTL_POWER_D2: /* partial On */ + break; + case SNDRV_CTL_POWER_D3hot: /* Off, with power */ + /* everything off except vref/vmid, */ + wm8731_write(codec, WM8731_PWR, reg | 0x0040); + break; + case SNDRV_CTL_POWER_D3cold: /* Off, without power */ + /* everything off, dac mute, inactive */ + wm8731_write(codec, WM8731_ACTIVE, 0x0); + wm8731_write(codec, WM8731_PWR, 0xffff); + break; + } + codec->dapm_state = event; + return 0; +} + +struct snd_soc_codec_dai wm8731_dai = { + .name = "WM8731", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + }, + .config_sysclk = wm8731_config_sysclk, + .digital_mute = wm8731_mute, + .ops = { + .prepare = wm8731_pcm_prepare, + .shutdown = wm8731_shutdown, + }, + .caps = { + .num_modes = ARRAY_SIZE(wm8731_modes), + .mode = wm8731_modes, + }, +}; +EXPORT_SYMBOL_GPL(wm8731_dai); + +static int wm8731_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->codec; + + wm8731_write(codec, WM8731_ACTIVE, 0x0); + wm8731_dapm_event(codec, SNDRV_CTL_POWER_D3cold); + return 0; +} + +static int wm8731_resume(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->codec; + int i; + u8 data[2]; + u16 *cache = codec->reg_cache; + + /* Sync reg_cache with the hardware */ + for (i = 0; i < ARRAY_SIZE(wm8731_reg); i++) { + data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001); + data[1] = cache[i] & 0x00ff; + codec->hw_write(codec->control_data, data, 2); + } + wm8731_dapm_event(codec, SNDRV_CTL_POWER_D3hot); + wm8731_dapm_event(codec, codec->suspend_dapm_state); + return 0; +} + +/* + * initialise the WM8731 driver + * register the mixer and dsp interfaces with the kernel + */ +static int wm8731_init(struct snd_soc_device *socdev) +{ + struct snd_soc_codec *codec = socdev->codec; + int reg, ret = 0; + + codec->name = "WM8731"; + codec->owner = THIS_MODULE; + codec->read = wm8731_read_reg_cache; + codec->write = wm8731_write; + codec->dapm_event = wm8731_dapm_event; + codec->dai = &wm8731_dai; + codec->num_dai = 1; + codec->reg_cache_size = ARRAY_SIZE(wm8731_reg); + + codec->reg_cache = + kzalloc(sizeof(u16) * ARRAY_SIZE(wm8731_reg), GFP_KERNEL); + if (codec->reg_cache == NULL) + return -ENOMEM; + memcpy(codec->reg_cache, + wm8731_reg, sizeof(u16) * ARRAY_SIZE(wm8731_reg)); + codec->reg_cache_size = sizeof(u16) * ARRAY_SIZE(wm8731_reg); + + wm8731_reset(codec); + + /* register pcms */ + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) { + kfree(codec->reg_cache); + return ret; + } + + /* power on device */ + wm8731_dapm_event(codec, SNDRV_CTL_POWER_D3hot); + + /* set the update bits */ + reg = wm8731_read_reg_cache(codec, WM8731_LOUT1V); + wm8731_write(codec, WM8731_LOUT1V, reg | 0x0100); + reg = wm8731_read_reg_cache(codec, WM8731_ROUT1V); + wm8731_write(codec, WM8731_ROUT1V, reg | 0x0100); + reg = wm8731_read_reg_cache(codec, WM8731_LINVOL); + wm8731_write(codec, WM8731_LINVOL, reg | 0x0100); + reg = wm8731_read_reg_cache(codec, WM8731_RINVOL); + wm8731_write(codec, WM8731_RINVOL, reg | 0x0100); + + wm8731_add_controls(codec); + wm8731_add_widgets(codec); + ret = snd_soc_register_card(socdev); + if (ret < 0) { + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); + } + + return ret; +} + +static struct snd_soc_device *wm8731_socdev; + +#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE) + +/* + * WM8731 2 wire address is determined by GPIO5 + * state during powerup. + * low = 0x1a + * high = 0x1b + */ +static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; + +/* Magic definition of all other variables and things */ +I2C_CLIENT_INSMOD; + +static struct i2c_driver wm8731_i2c_driver; +static struct i2c_client client_template; + +/* If the i2c layer weren't so broken, we could pass this kind of data + around */ + +static int wm8731_codec_probe(struct i2c_adapter *adap, int addr, int kind) +{ + struct snd_soc_device *socdev = wm8731_socdev; + struct wm8731_setup_data *setup = socdev->codec_data; + struct snd_soc_codec *codec = socdev->codec; + struct i2c_client *i2c; + int ret; + + if (addr != setup->i2c_address) + return -ENODEV; + + client_template.adapter = adap; + client_template.addr = addr; + + i2c = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (i2c == NULL) { + kfree(codec); + return -ENOMEM; + } + memcpy(i2c, &client_template, sizeof(struct i2c_client)); + i2c_set_clientdata(i2c, codec); + codec->control_data = i2c; + + ret = i2c_attach_client(i2c); + if (ret < 0) { + err("failed to attach codec at addr %x\n", addr); + goto err; + } + + ret = wm8731_init(socdev); + if (ret < 0) { + err("failed to initialise WM8731\n"); + goto err; + } + return ret; + +err: + kfree(codec); + kfree(i2c); + return ret; +} + +static int wm8731_i2c_detach(struct i2c_client *client) +{ + struct snd_soc_codec* codec = i2c_get_clientdata(client); + i2c_detach_client(client); + kfree(codec->reg_cache); + kfree(client); + return 0; +} + +static int wm8731_i2c_attach(struct i2c_adapter *adap) +{ + return i2c_probe(adap, &addr_data, wm8731_codec_probe); +} + +/* corgi i2c codec control layer */ +static struct i2c_driver wm8731_i2c_driver = { + .driver = { + .name = "WM8731 I2C Codec", + .owner = THIS_MODULE, + }, + .id = I2C_DRIVERID_WM8731, + .attach_adapter = wm8731_i2c_attach, + .detach_client = wm8731_i2c_detach, + .command = NULL, +}; + +static struct i2c_client client_template = { + .name = "WM8731", + .driver = &wm8731_i2c_driver, +}; +#endif + +static int wm8731_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct wm8731_setup_data *setup; + struct snd_soc_codec *codec; + int ret = 0; + + info("WM8731 Audio Codec %s", WM8731_VERSION); + + setup = socdev->codec_data; + codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); + if (codec == NULL) + return -ENOMEM; + + socdev->codec = codec; + mutex_init(&codec->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + + wm8731_socdev = socdev; +#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE) + if (setup->i2c_address) { + normal_i2c[0] = setup->i2c_address; + codec->hw_write = (hw_write_t)i2c_master_send; + ret = i2c_add_driver(&wm8731_i2c_driver); + if (ret != 0) + printk(KERN_ERR "can't add i2c driver"); + } +#else + /* Add other interfaces here */ +#endif + return ret; +} + +/* power down chip */ +static int wm8731_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->codec; + + if (codec->control_data) + wm8731_dapm_event(codec, SNDRV_CTL_POWER_D3cold); + + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); +#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE) + i2c_del_driver(&wm8731_i2c_driver); +#endif + kfree(codec); + + return 0; +} + +struct snd_soc_codec_device soc_codec_dev_wm8731 = { + .probe = wm8731_probe, + .remove = wm8731_remove, + .suspend = wm8731_suspend, + .resume = wm8731_resume, +}; + +EXPORT_SYMBOL_GPL(soc_codec_dev_wm8731); + +MODULE_DESCRIPTION("ASoC WM8731 driver"); +MODULE_AUTHOR("Richard Purdie"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8731.h b/sound/soc/codecs/wm8731.h new file mode 100644 index 00000000000..8fa0f53bef1 --- /dev/null +++ b/sound/soc/codecs/wm8731.h @@ -0,0 +1,41 @@ +/* + * wm8731.h -- WM8731 Soc Audio driver + * + * Copyright 2005 Openedhand Ltd. + * + * Author: Richard Purdie + * + * Based on wm8753.h + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _WM8731_H +#define _WM8731_H + +/* WM8731 register space */ + +#define WM8731_LINVOL 0x00 +#define WM8731_RINVOL 0x01 +#define WM8731_LOUT1V 0x02 +#define WM8731_ROUT1V 0x03 +#define WM8731_APANA 0x04 +#define WM8731_APDIGI 0x05 +#define WM8731_PWR 0x06 +#define WM8731_IFACE 0x07 +#define WM8731_SRATE 0x08 +#define WM8731_ACTIVE 0x09 +#define WM8731_RESET 0x0f + +#define WM8731_CACHEREGNUM 10 + +struct wm8731_setup_data { + unsigned short i2c_address; +}; + +extern struct snd_soc_codec_dai wm8731_dai; +extern struct snd_soc_codec_device soc_codec_dev_wm8731; + +#endif -- cgit v1.2.3 From abadfc928a27e1cf27c834e8e29e6b1f64ca2d55 Mon Sep 17 00:00:00 2001 From: Richard Purdie Date: Fri, 6 Oct 2006 18:36:39 +0200 Subject: [ALSA] ASoC codecs: WM8750 support This patch adds ASoC support for the WM8750 codec. Supported features:- o Capture/Playback/Sidetone/Bypass. o 16 & 24 bit audio. o 8k - 96k sample rates. o DAPM. Signed-off-by: Richard Purdie Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/codecs/wm8750.c | 1131 +++++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/wm8750.h | 66 +++ 2 files changed, 1197 insertions(+) create mode 100644 sound/soc/codecs/wm8750.c create mode 100644 sound/soc/codecs/wm8750.h (limited to 'sound') diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c new file mode 100644 index 00000000000..6a8b2799b3b --- /dev/null +++ b/sound/soc/codecs/wm8750.c @@ -0,0 +1,1131 @@ +/* + * wm8750.c -- WM8750 ALSA SoC audio driver + * + * Copyright 2005 Openedhand Ltd. + * + * Author: Richard Purdie + * + * Based on WM8753.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wm8750.h" + +#define AUDIO_NAME "WM8750" +#define WM8750_VERSION "0.11" + +/* + * Debug + */ + +#define WM8750_DEBUG 0 + +#ifdef WM8750_DEBUG +#define dbg(format, arg...) \ + printk(KERN_DEBUG AUDIO_NAME ": " format "\n" , ## arg) +#else +#define dbg(format, arg...) do {} while (0) +#endif +#define err(format, arg...) \ + printk(KERN_ERR AUDIO_NAME ": " format "\n" , ## arg) +#define info(format, arg...) \ + printk(KERN_INFO AUDIO_NAME ": " format "\n" , ## arg) +#define warn(format, arg...) \ + printk(KERN_WARNING AUDIO_NAME ": " format "\n" , ## arg) + +static struct workqueue_struct *wm8750_workq = NULL; +static struct work_struct wm8750_dapm_work; + +/* + * wm8750 register cache + * We can't read the WM8750 register space when we + * are using 2 wire for device control, so we cache them instead. + */ +static const u16 wm8750_reg[] = { + 0x0097, 0x0097, 0x0079, 0x0079, /* 0 */ + 0x0000, 0x0008, 0x0000, 0x000a, /* 4 */ + 0x0000, 0x0000, 0x00ff, 0x00ff, /* 8 */ + 0x000f, 0x000f, 0x0000, 0x0000, /* 12 */ + 0x0000, 0x007b, 0x0000, 0x0032, /* 16 */ + 0x0000, 0x00c3, 0x00c3, 0x00c0, /* 20 */ + 0x0000, 0x0000, 0x0000, 0x0000, /* 24 */ + 0x0000, 0x0000, 0x0000, 0x0000, /* 28 */ + 0x0000, 0x0000, 0x0050, 0x0050, /* 32 */ + 0x0050, 0x0050, 0x0050, 0x0050, /* 36 */ + 0x0079, 0x0079, 0x0079, /* 40 */ +}; + +#define WM8750_HIFI_DAIFMT \ + (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_RIGHT_J | \ + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_NB_IF | SND_SOC_DAIFMT_IB_NF | \ + SND_SOC_DAIFMT_IB_IF) + +#define WM8750_DIR \ + (SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE) + +#define WM8750_HIFI_FSB \ + (SND_SOC_FSBD(1) | SND_SOC_FSBD(2) | SND_SOC_FSBD(4) | \ + SND_SOC_FSBD(8) | SND_SOC_FSBD(16)) + +#define WM8750_HIFI_RATES \ + (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \ + SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) + +#define WM8750_HIFI_BITS \ + (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_mode wm8750_modes[] = { + /* common codec frame and clock master modes */ + /* 8k */ + {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_8000, + WM8750_DIR, SND_SOC_DAI_BFS_DIV, 1536, WM8750_HIFI_FSB}, + {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_8000, + WM8750_DIR, SND_SOC_DAI_BFS_DIV, 1408, WM8750_HIFI_FSB}, + {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_8000, + WM8750_DIR, SND_SOC_DAI_BFS_DIV, 2304, WM8750_HIFI_FSB}, + {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_8000, + WM8750_DIR, SND_SOC_DAI_BFS_DIV, 2112, WM8750_HIFI_FSB}, + {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_8000, + WM8750_DIR, SND_SOC_DAI_BFS_DIV, 1500, WM8750_HIFI_FSB}, + + /* 11.025k */ + {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_11025, + WM8750_DIR, SND_SOC_DAI_BFS_DIV, 1024, WM8750_HIFI_FSB}, + {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_11025, + WM8750_DIR, SND_SOC_DAI_BFS_DIV, 1536, WM8750_HIFI_FSB}, + {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_11025, + WM8750_DIR, SND_SOC_DAI_BFS_DIV, 1088, WM8750_HIFI_FSB}, + + /* 16k */ + {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_16000, + WM8750_DIR, SND_SOC_DAI_BFS_DIV, 768, WM8750_HIFI_FSB}, + {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_16000, + WM8750_DIR, SND_SOC_DAI_BFS_DIV, 1152, WM8750_HIFI_FSB}, + {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_16000, + WM8750_DIR, SND_SOC_DAI_BFS_DIV, 750, WM8750_HIFI_FSB}, + + /* 22.05k */ + {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_22050, + WM8750_DIR, SND_SOC_DAI_BFS_DIV, 512, WM8750_HIFI_FSB}, + {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_22050, + WM8750_DIR, SND_SOC_DAI_BFS_DIV, 768, WM8750_HIFI_FSB}, + {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_22050, + WM8750_DIR, SND_SOC_DAI_BFS_DIV, 544, WM8750_HIFI_FSB}, + + /* 32k */ + {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_16000, + WM8750_DIR, SND_SOC_DAI_BFS_DIV, 384, WM8750_HIFI_FSB}, + {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_16000, + WM8750_DIR, SND_SOC_DAI_BFS_DIV, 576, WM8750_HIFI_FSB}, + {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_16000, + WM8750_DIR, SND_SOC_DAI_BFS_DIV, 375, WM8750_HIFI_FSB}, + + /* 44.1k & 48k */ + {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000, WM8750_DIR, SND_SOC_DAI_BFS_DIV, 256, + WM8750_HIFI_FSB}, + {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000, WM8750_DIR, SND_SOC_DAI_BFS_DIV, 384, + WM8750_HIFI_FSB}, + {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_44100, + WM8750_DIR, SND_SOC_DAI_BFS_DIV, 272, WM8750_HIFI_FSB}, + {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_48000, + WM8750_DIR, SND_SOC_DAI_BFS_DIV, 250, WM8750_HIFI_FSB}, + + /* 88.2k & 96k */ + {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000, WM8750_DIR, SND_SOC_DAI_BFS_DIV, 128, + WM8750_HIFI_FSB}, + {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000, WM8750_DIR, SND_SOC_DAI_BFS_DIV, 192, + WM8750_HIFI_FSB}, + {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_88200, + WM8750_DIR, SND_SOC_DAI_BFS_DIV, 136, WM8750_HIFI_FSB}, + {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_96000, + WM8750_DIR, SND_SOC_DAI_BFS_DIV, 125, WM8750_HIFI_FSB}, + + /* codec frame and clock slave modes */ + {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, SND_SOC_DAITDM_LRDW(0,0), + WM8750_HIFI_BITS, WM8750_HIFI_RATES, WM8750_DIR, + SND_SOC_DAI_BFS_DIV, SND_SOC_FS_ALL, SND_SOC_FSBD_ALL}, +}; + +/* + * read wm8750 register cache + */ +static inline unsigned int wm8750_read_reg_cache(struct snd_soc_codec *codec, + unsigned int reg) +{ + u16 *cache = codec->reg_cache; + if (reg > WM8750_CACHE_REGNUM) + return -1; + return cache[reg]; +} + +/* + * write wm8750 register cache + */ +static inline void wm8750_write_reg_cache(struct snd_soc_codec *codec, + unsigned int reg, unsigned int value) +{ + u16 *cache = codec->reg_cache; + if (reg > WM8750_CACHE_REGNUM) + return; + cache[reg] = value; +} + +static int wm8750_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + u8 data[2]; + + /* data is + * D15..D9 WM8753 register offset + * D8...D0 register data + */ + data[0] = (reg << 1) | ((value >> 8) & 0x0001); + data[1] = value & 0x00ff; + + wm8750_write_reg_cache (codec, reg, value); + if (codec->hw_write(codec->control_data, data, 2) == 2) + return 0; + else + return -EIO; +} + +#define wm8750_reset(c) wm8750_write(c, WM8750_RESET, 0) + +/* + * WM8750 Controls + */ +static const char *wm8750_bass[] = {"Linear Control", "Adaptive Boost"}; +static const char *wm8750_bass_filter[] = { "130Hz @ 48kHz", "200Hz @ 48kHz" }; +static const char *wm8750_treble[] = {"8kHz", "4kHz"}; +static const char *wm8750_3d_lc[] = {"200Hz", "500Hz"}; +static const char *wm8750_3d_uc[] = {"2.2kHz", "1.5kHz"}; +static const char *wm8750_3d_func[] = {"Capture", "Playback"}; +static const char *wm8750_alc_func[] = {"Off", "Right", "Left", "Stereo"}; +static const char *wm8750_ng_type[] = {"Constant PGA Gain", + "Mute ADC Output"}; +static const char *wm8750_line_mux[] = {"Line 1", "Line 2", "Line 3", "PGA", + "Differential"}; +static const char *wm8750_pga_sel[] = {"Line 1", "Line 2", "Line 3", + "Differential"}; +static const char *wm8750_out3[] = {"VREF", "ROUT1 + Vol", "MonoOut", + "ROUT1"}; +static const char *wm8750_diff_sel[] = {"Line 1", "Line 2"}; +static const char *wm8750_adcpol[] = {"Normal", "L Invert", "R Invert", + "L + R Invert"}; +static const char *wm8750_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"}; +static const char *wm8750_mono_mux[] = {"Stereo", "Mono (Left)", + "Mono (Right)", "Digital Mono"}; + +static const struct soc_enum wm8750_enum[] = { +SOC_ENUM_SINGLE(WM8750_BASS, 7, 2, wm8750_bass), +SOC_ENUM_SINGLE(WM8750_BASS, 6, 2, wm8750_bass_filter), +SOC_ENUM_SINGLE(WM8750_TREBLE, 6, 2, wm8750_treble), +SOC_ENUM_SINGLE(WM8750_3D, 5, 2, wm8750_3d_lc), +SOC_ENUM_SINGLE(WM8750_3D, 6, 2, wm8750_3d_uc), +SOC_ENUM_SINGLE(WM8750_3D, 7, 2, wm8750_3d_func), +SOC_ENUM_SINGLE(WM8750_ALC1, 7, 4, wm8750_alc_func), +SOC_ENUM_SINGLE(WM8750_NGATE, 1, 2, wm8750_ng_type), +SOC_ENUM_SINGLE(WM8750_LOUTM1, 0, 5, wm8750_line_mux), +SOC_ENUM_SINGLE(WM8750_ROUTM1, 0, 5, wm8750_line_mux), +SOC_ENUM_SINGLE(WM8750_LADCIN, 6, 4, wm8750_pga_sel), /* 10 */ +SOC_ENUM_SINGLE(WM8750_RADCIN, 6, 4, wm8750_pga_sel), +SOC_ENUM_SINGLE(WM8750_ADCTL2, 7, 4, wm8750_out3), +SOC_ENUM_SINGLE(WM8750_ADCIN, 8, 2, wm8750_diff_sel), +SOC_ENUM_SINGLE(WM8750_ADCDAC, 5, 4, wm8750_adcpol), +SOC_ENUM_SINGLE(WM8750_ADCDAC, 1, 4, wm8750_deemph), +SOC_ENUM_SINGLE(WM8750_ADCIN, 6, 4, wm8750_mono_mux), /* 16 */ + +}; + +static const struct snd_kcontrol_new wm8750_snd_controls[] = { + +SOC_DOUBLE_R("Capture Volume", WM8750_LINVOL, WM8750_RINVOL, 0, 63, 0), +SOC_DOUBLE_R("Capture ZC Switch", WM8750_LINVOL, WM8750_RINVOL, 6, 1, 0), +SOC_DOUBLE_R("Capture Switch", WM8750_LINVOL, WM8750_RINVOL, 7, 1, 1), + +SOC_DOUBLE_R("Out1 Playback ZC Switch", WM8750_LOUT1V, + WM8750_ROUT1V, 7, 1, 0), +SOC_DOUBLE_R("Out2 Playback ZC Switch", WM8750_LOUT2V, + WM8750_ROUT2V, 7, 1, 0), + +SOC_ENUM("Playback De-emphasis", wm8750_enum[15]), + +SOC_ENUM("Capture Polarity", wm8750_enum[14]), +SOC_SINGLE("Playback 6dB Attenuate", WM8750_ADCDAC, 7, 1, 0), +SOC_SINGLE("Capture 6dB Attenuate", WM8750_ADCDAC, 8, 1, 0), + +SOC_DOUBLE_R("PCM Volume", WM8750_LDAC, WM8750_RDAC, 0, 255, 0), + +SOC_ENUM("Bass Boost", wm8750_enum[0]), +SOC_ENUM("Bass Filter", wm8750_enum[1]), +SOC_SINGLE("Bass Volume", WM8750_BASS, 0, 15, 1), + +SOC_SINGLE("Treble Volume", WM8750_TREBLE, 0, 15, 0), +SOC_ENUM("Treble Cut-off", wm8750_enum[2]), + +SOC_SINGLE("3D Switch", WM8750_3D, 0, 1, 0), +SOC_SINGLE("3D Volume", WM8750_3D, 1, 15, 0), +SOC_ENUM("3D Lower Cut-off", wm8750_enum[3]), +SOC_ENUM("3D Upper Cut-off", wm8750_enum[4]), +SOC_ENUM("3D Mode", wm8750_enum[5]), + +SOC_SINGLE("ALC Capture Target Volume", WM8750_ALC1, 0, 7, 0), +SOC_SINGLE("ALC Capture Max Volume", WM8750_ALC1, 4, 7, 0), +SOC_ENUM("ALC Capture Function", wm8750_enum[6]), +SOC_SINGLE("ALC Capture ZC Switch", WM8750_ALC2, 7, 1, 0), +SOC_SINGLE("ALC Capture Hold Time", WM8750_ALC2, 0, 15, 0), +SOC_SINGLE("ALC Capture Decay Time", WM8750_ALC3, 4, 15, 0), +SOC_SINGLE("ALC Capture Attack Time", WM8750_ALC3, 0, 15, 0), +SOC_SINGLE("ALC Capture NG Threshold", WM8750_NGATE, 3, 31, 0), +SOC_ENUM("ALC Capture NG Type", wm8750_enum[4]), +SOC_SINGLE("ALC Capture NG Switch", WM8750_NGATE, 0, 1, 0), + +SOC_SINGLE("Left ADC Capture Volume", WM8750_LADC, 0, 255, 0), +SOC_SINGLE("Right ADC Capture Volume", WM8750_RADC, 0, 255, 0), + +SOC_SINGLE("ZC Timeout Switch", WM8750_ADCTL1, 0, 1, 0), +SOC_SINGLE("Playback Invert Switch", WM8750_ADCTL1, 1, 1, 0), + +SOC_SINGLE("Right Out2 Playback Invert Switch", WM8750_ADCTL2, 4, 1, 0), + +/* Unimplemented */ +/* ADCDAC Bit 0 - ADCHPD */ +/* ADCDAC Bit 4 - HPOR */ +/* ADCTL1 Bit 2,3 - DATSEL */ +/* ADCTL1 Bit 4,5 - DMONOMIX */ +/* ADCTL1 Bit 6,7 - VSEL */ +/* ADCTL2 Bit 2 - LRCM */ +/* ADCTL2 Bit 3 - TRI */ +/* ADCTL3 Bit 5 - HPFLREN */ +/* ADCTL3 Bit 6 - VROI */ +/* ADCTL3 Bit 7,8 - ADCLRM */ +/* ADCIN Bit 4 - LDCM */ +/* ADCIN Bit 5 - RDCM */ + +SOC_DOUBLE_R("Mic Boost", WM8750_LADCIN, WM8750_RADCIN, 4, 3, 0), + +SOC_DOUBLE_R("Bypass Left Playback Volume", WM8750_LOUTM1, + WM8750_LOUTM2, 4, 7, 1), +SOC_DOUBLE_R("Bypass Right Playback Volume", WM8750_ROUTM1, + WM8750_ROUTM2, 4, 7, 1), +SOC_DOUBLE_R("Bypass Mono Playback Volume", WM8750_MOUTM1, + WM8750_MOUTM2, 4, 7, 1), + +SOC_SINGLE("Mono Playback ZC Switch", WM8750_MOUTV, 7, 1, 0), + +SOC_DOUBLE_R("Out1 Playback Volume", WM8750_LOUT1V, WM8750_ROUT1V, 0, 127, 0), +SOC_DOUBLE_R("Out2 Playback Volume", WM8750_LOUT2V, WM8750_ROUT2V, 0, 127, 0), + +SOC_SINGLE("Mono Playback Volume", WM8750_MOUTV, 0, 127, 0), + +}; + +/* add non dapm controls */ +static int wm8750_add_controls(struct snd_soc_codec *codec) +{ + int err, i; + + for (i = 0; i < ARRAY_SIZE(wm8750_snd_controls); i++) { + err = snd_ctl_add(codec->card, + snd_soc_cnew(&wm8750_snd_controls[i],codec, NULL)); + if (err < 0) + return err; + } + return 0; +} + +/* + * DAPM Controls + */ + +/* Left Mixer */ +static const struct snd_kcontrol_new wm8750_left_mixer_controls[] = { +SOC_DAPM_SINGLE("Playback Switch", WM8750_LOUTM1, 8, 1, 0), +SOC_DAPM_SINGLE("Left Bypass Switch", WM8750_LOUTM1, 7, 1, 0), +SOC_DAPM_SINGLE("Right Playback Switch", WM8750_LOUTM2, 8, 1, 0), +SOC_DAPM_SINGLE("Right Bypass Switch", WM8750_LOUTM2, 7, 1, 0), +}; + +/* Right Mixer */ +static const struct snd_kcontrol_new wm8750_right_mixer_controls[] = { +SOC_DAPM_SINGLE("Left Playback Switch", WM8750_ROUTM1, 8, 1, 0), +SOC_DAPM_SINGLE("Left Bypass Switch", WM8750_ROUTM1, 7, 1, 0), +SOC_DAPM_SINGLE("Playback Switch", WM8750_ROUTM2, 8, 1, 0), +SOC_DAPM_SINGLE("Right Bypass Switch", WM8750_ROUTM2, 7, 1, 0), +}; + +/* Mono Mixer */ +static const struct snd_kcontrol_new wm8750_mono_mixer_controls[] = { +SOC_DAPM_SINGLE("Left Playback Switch", WM8750_MOUTM1, 8, 1, 0), +SOC_DAPM_SINGLE("Left Bypass Switch", WM8750_MOUTM1, 7, 1, 0), +SOC_DAPM_SINGLE("Right Playback Switch", WM8750_MOUTM2, 8, 1, 0), +SOC_DAPM_SINGLE("Right Bypass Switch", WM8750_MOUTM2, 7, 1, 0), +}; + +/* Left Line Mux */ +static const struct snd_kcontrol_new wm8750_left_line_controls = +SOC_DAPM_ENUM("Route", wm8750_enum[8]); + +/* Right Line Mux */ +static const struct snd_kcontrol_new wm8750_right_line_controls = +SOC_DAPM_ENUM("Route", wm8750_enum[9]); + +/* Left PGA Mux */ +static const struct snd_kcontrol_new wm8750_left_pga_controls = +SOC_DAPM_ENUM("Route", wm8750_enum[10]); + +/* Right PGA Mux */ +static const struct snd_kcontrol_new wm8750_right_pga_controls = +SOC_DAPM_ENUM("Route", wm8750_enum[11]); + +/* Out 3 Mux */ +static const struct snd_kcontrol_new wm8750_out3_controls = +SOC_DAPM_ENUM("Route", wm8750_enum[12]); + +/* Differential Mux */ +static const struct snd_kcontrol_new wm8750_diffmux_controls = +SOC_DAPM_ENUM("Route", wm8750_enum[13]); + +/* Mono ADC Mux */ +static const struct snd_kcontrol_new wm8750_monomux_controls = +SOC_DAPM_ENUM("Route", wm8750_enum[16]); + +static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = { + SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0, + &wm8750_left_mixer_controls[0], + ARRAY_SIZE(wm8750_left_mixer_controls)), + SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0, + &wm8750_right_mixer_controls[0], + ARRAY_SIZE(wm8750_right_mixer_controls)), + SND_SOC_DAPM_MIXER("Mono Mixer", WM8750_PWR2, 2, 0, + &wm8750_mono_mixer_controls[0], + ARRAY_SIZE(wm8750_mono_mixer_controls)), + + SND_SOC_DAPM_PGA("Right Out 2", WM8750_PWR2, 3, 0, NULL, 0), + SND_SOC_DAPM_PGA("Left Out 2", WM8750_PWR2, 4, 0, NULL, 0), + SND_SOC_DAPM_PGA("Right Out 1", WM8750_PWR2, 5, 0, NULL, 0), + SND_SOC_DAPM_PGA("Left Out 1", WM8750_PWR2, 6, 0, NULL, 0), + SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8750_PWR2, 7, 0), + SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8750_PWR2, 8, 0), + + SND_SOC_DAPM_MICBIAS("Mic Bias", WM8750_PWR1, 1, 0), + SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8750_PWR1, 2, 0), + SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8750_PWR1, 3, 0), + + SND_SOC_DAPM_MUX("Left PGA Mux", WM8750_PWR1, 5, 0, + &wm8750_left_pga_controls), + SND_SOC_DAPM_MUX("Right PGA Mux", WM8750_PWR1, 4, 0, + &wm8750_right_pga_controls), + SND_SOC_DAPM_MUX("Left Line Mux", SND_SOC_NOPM, 0, 0, + &wm8750_left_line_controls), + SND_SOC_DAPM_MUX("Right Line Mux", SND_SOC_NOPM, 0, 0, + &wm8750_right_line_controls), + + SND_SOC_DAPM_MUX("Out3 Mux", SND_SOC_NOPM, 0, 0, &wm8750_out3_controls), + SND_SOC_DAPM_PGA("Out 3", WM8750_PWR2, 1, 0, NULL, 0), + SND_SOC_DAPM_PGA("Mono Out 1", WM8750_PWR2, 2, 0, NULL, 0), + + SND_SOC_DAPM_MUX("Differential Mux", SND_SOC_NOPM, 0, 0, + &wm8750_diffmux_controls), + SND_SOC_DAPM_MUX("Left ADC Mux", SND_SOC_NOPM, 0, 0, + &wm8750_monomux_controls), + SND_SOC_DAPM_MUX("Right ADC Mux", SND_SOC_NOPM, 0, 0, + &wm8750_monomux_controls), + + SND_SOC_DAPM_OUTPUT("LOUT1"), + SND_SOC_DAPM_OUTPUT("ROUT1"), + SND_SOC_DAPM_OUTPUT("LOUT2"), + SND_SOC_DAPM_OUTPUT("ROUT2"), + SND_SOC_DAPM_OUTPUT("MONO"), + SND_SOC_DAPM_OUTPUT("OUT3"), + + SND_SOC_DAPM_INPUT("LINPUT1"), + SND_SOC_DAPM_INPUT("LINPUT2"), + SND_SOC_DAPM_INPUT("LINPUT3"), + SND_SOC_DAPM_INPUT("RINPUT1"), + SND_SOC_DAPM_INPUT("RINPUT2"), + SND_SOC_DAPM_INPUT("RINPUT3"), +}; + +static const char *audio_map[][3] = { + /* left mixer */ + {"Left Mixer", "Playback Switch", "Left DAC"}, + {"Left Mixer", "Left Bypass Switch", "Left Line Mux"}, + {"Left Mixer", "Right Playback Switch", "Right DAC"}, + {"Left Mixer", "Right Bypass Switch", "Right Line Mux"}, + + /* right mixer */ + {"Right Mixer", "Left Playback Switch", "Left DAC"}, + {"Right Mixer", "Left Bypass Switch", "Left Line Mux"}, + {"Right Mixer", "Playback Switch", "Right DAC"}, + {"Right Mixer", "Right Bypass Switch", "Right Line Mux"}, + + /* left out 1 */ + {"Left Out 1", NULL, "Left Mixer"}, + {"LOUT1", NULL, "Left Out 1"}, + + /* left out 2 */ + {"Left Out 2", NULL, "Left Mixer"}, + {"LOUT2", NULL, "Left Out 2"}, + + /* right out 1 */ + {"Right Out 1", NULL, "Right Mixer"}, + {"ROUT1", NULL, "Right Out 1"}, + + /* right out 2 */ + {"Right Out 2", NULL, "Right Mixer"}, + {"ROUT2", NULL, "Right Out 2"}, + + /* mono mixer */ + {"Mono Mixer", "Left Playback Switch", "Left DAC"}, + {"Mono Mixer", "Left Bypass Switch", "Left Line Mux"}, + {"Mono Mixer", "Right Playback Switch", "Right DAC"}, + {"Mono Mixer", "Right Bypass Switch", "Right Line Mux"}, + + /* mono out */ + {"Mono Out 1", NULL, "Mono Mixer"}, + {"MONO1", NULL, "Mono Out 1"}, + + /* out 3 */ + {"Out3 Mux", "VREF", "VREF"}, + {"Out3 Mux", "ROUT1 + Vol", "ROUT1"}, + {"Out3 Mux", "ROUT1", "Right Mixer"}, + {"Out3 Mux", "MonoOut", "MONO1"}, + {"Out 3", NULL, "Out3 Mux"}, + {"OUT3", NULL, "Out 3"}, + + /* Left Line Mux */ + {"Left Line Mux", "Line 1", "LINPUT1"}, + {"Left Line Mux", "Line 2", "LINPUT2"}, + {"Left Line Mux", "Line 3", "LINPUT3"}, + {"Left Line Mux", "PGA", "Left PGA Mux"}, + {"Left Line Mux", "Differential", "Differential Mux"}, + + /* Right Line Mux */ + {"Right Line Mux", "Line 1", "RINPUT1"}, + {"Right Line Mux", "Line 2", "RINPUT2"}, + {"Right Line Mux", "Line 3", "RINPUT3"}, + {"Right Line Mux", "PGA", "Right PGA Mux"}, + {"Right Line Mux", "Differential", "Differential Mux"}, + + /* Left PGA Mux */ + {"Left PGA Mux", "Line 1", "LINPUT1"}, + {"Left PGA Mux", "Line 2", "LINPUT2"}, + {"Left PGA Mux", "Line 3", "LINPUT3"}, + {"Left PGA Mux", "Differential", "Differential Mux"}, + + /* Right PGA Mux */ + {"Right PGA Mux", "Line 1", "RINPUT1"}, + {"Right PGA Mux", "Line 2", "RINPUT2"}, + {"Right PGA Mux", "Line 3", "RINPUT3"}, + {"Right PGA Mux", "Differential", "Differential Mux"}, + + /* Differential Mux */ + {"Differential Mux", "Line 1", "LINPUT1"}, + {"Differential Mux", "Line 1", "RINPUT1"}, + {"Differential Mux", "Line 2", "LINPUT2"}, + {"Differential Mux", "Line 2", "RINPUT2"}, + + /* Left ADC Mux */ + {"Left ADC Mux", "Stereo", "Left PGA Mux"}, + {"Left ADC Mux", "Mono (Left)", "Left PGA Mux"}, + {"Left ADC Mux", "Digital Mono", "Left PGA Mux"}, + + /* Right ADC Mux */ + {"Right ADC Mux", "Stereo", "Right PGA Mux"}, + {"Right ADC Mux", "Mono (Right)", "Right PGA Mux"}, + {"Right ADC Mux", "Digital Mono", "Right PGA Mux"}, + + /* ADC */ + {"Left ADC", NULL, "Left ADC Mux"}, + {"Right ADC", NULL, "Right ADC Mux"}, + + /* terminator */ + {NULL, NULL, NULL}, +}; + +static int wm8750_add_widgets(struct snd_soc_codec *codec) +{ + int i; + + for(i = 0; i < ARRAY_SIZE(wm8750_dapm_widgets); i++) { + snd_soc_dapm_new_control(codec, &wm8750_dapm_widgets[i]); + } + + /* set up audio path audio_mapnects */ + for(i = 0; audio_map[i][0] != NULL; i++) { + snd_soc_dapm_connect_input(codec, audio_map[i][0], + audio_map[i][1], audio_map[i][2]); + } + + snd_soc_dapm_new_widgets(codec); + return 0; +} + +struct _coeff_div { + u32 mclk; + u32 rate; + u16 fs; + u8 sr:5; + u8 usb:1; +}; + +/* codec hifi mclk clock divider coefficients */ +static const struct _coeff_div coeff_div[] = { + /* 8k */ + {12288000, 8000, 1536, 0x6, 0x0}, + {11289600, 8000, 1408, 0x16, 0x0}, + {18432000, 8000, 2304, 0x7, 0x0}, + {16934400, 8000, 2112, 0x17, 0x0}, + {12000000, 8000, 1500, 0x6, 0x1}, + + /* 11.025k */ + {11289600, 11025, 1024, 0x18, 0x0}, + {16934400, 11025, 1536, 0x19, 0x0}, + {12000000, 11025, 1088, 0x19, 0x1}, + + /* 16k */ + {12288000, 16000, 768, 0xa, 0x0}, + {18432000, 16000, 1152, 0xb, 0x0}, + {12000000, 16000, 750, 0xa, 0x1}, + + /* 22.05k */ + {11289600, 22050, 512, 0x1a, 0x0}, + {16934400, 22050, 768, 0x1b, 0x0}, + {12000000, 22050, 544, 0x1b, 0x1}, + + /* 32k */ + {12288000, 32000, 384, 0xc, 0x0}, + {18432000, 32000, 576, 0xd, 0x0}, + {12000000, 32000, 375, 0xa, 0x1}, + + /* 44.1k */ + {11289600, 44100, 256, 0x10, 0x0}, + {16934400, 44100, 384, 0x11, 0x0}, + {12000000, 44100, 272, 0x11, 0x1}, + + /* 48k */ + {12288000, 48000, 256, 0x0, 0x0}, + {18432000, 48000, 384, 0x1, 0x0}, + {12000000, 48000, 250, 0x0, 0x1}, + + /* 88.2k */ + {11289600, 88200, 128, 0x1e, 0x0}, + {16934400, 88200, 192, 0x1f, 0x0}, + {12000000, 88200, 136, 0x1f, 0x1}, + + /* 96k */ + {12288000, 96000, 128, 0xe, 0x0}, + {18432000, 96000, 192, 0xf, 0x0}, + {12000000, 96000, 125, 0xe, 0x1}, +}; + +static inline int get_coeff(int mclk, int rate) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(coeff_div); i++) { + if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk) + return i; + } + return -EINVAL; +} + +/* WM8750 supports numerous input clocks per sample rate */ +static unsigned int wm8750_config_sysclk(struct snd_soc_codec_dai *dai, + struct snd_soc_clock_info *info, unsigned int clk) +{ + dai->mclk = 0; + + /* check that the calculated FS and rate actually match a clock from + * the machine driver */ + if (info->fs * info->rate == clk) + dai->mclk = clk; + + return dai->mclk; +} + +static int wm8750_pcm_prepare(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->codec; + u16 iface = 0, bfs, srate = 0; + int i = get_coeff(rtd->codec_dai->mclk, + snd_soc_get_rate(rtd->codec_dai->dai_runtime.pcmrate)); + + /* is coefficient valid ? */ + if (i < 0) + return i; + + bfs = SND_SOC_FSB_REAL(rtd->codec_dai->dai_runtime.bfs); + + /* set master/slave audio interface */ + switch (rtd->codec_dai->dai_runtime.fmt & SND_SOC_DAIFMT_CLOCK_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + iface = 0x0040; + break; + case SND_SOC_DAIFMT_CBS_CFS: + break; + } + + /* interface format */ + switch (rtd->codec_dai->dai_runtime.fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + iface |= 0x0002; + break; + case SND_SOC_DAIFMT_RIGHT_J: + break; + case SND_SOC_DAIFMT_LEFT_J: + iface |= 0x0001; + break; + case SND_SOC_DAIFMT_DSP_A: + iface |= 0x0003; + break; + case SND_SOC_DAIFMT_DSP_B: + iface |= 0x0013; + break; + } + + /* bit size */ + switch (rtd->codec_dai->dai_runtime.pcmfmt) { + case SNDRV_PCM_FMTBIT_S16_LE: + break; + case SNDRV_PCM_FMTBIT_S20_3LE: + iface |= 0x0004; + break; + case SNDRV_PCM_FMTBIT_S24_LE: + iface |= 0x0008; + break; + case SNDRV_PCM_FMTBIT_S32_LE: + iface |= 0x000c; + break; + } + + /* clock inversion */ + switch (rtd->codec_dai->dai_runtime.fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_IF: + iface |= 0x0090; + break; + case SND_SOC_DAIFMT_IB_NF: + iface |= 0x0080; + break; + case SND_SOC_DAIFMT_NB_IF: + iface |= 0x0010; + break; + } + + /* set bclk divisor rate */ + switch (bfs) { + case 1: + break; + case 4: + srate |= (0x1 << 7); + break; + case 8: + srate |= (0x2 << 7); + break; + case 16: + srate |= (0x3 << 7); + break; + } + + /* set iface & srate */ + wm8750_write(codec, WM8750_IFACE, iface); + wm8750_write(codec, WM8750_SRATE, srate | + (coeff_div[i].sr << 1) | coeff_div[i].usb); + + return 0; +} + +static int wm8750_mute(struct snd_soc_codec *codec, + struct snd_soc_codec_dai *dai, int mute) +{ + u16 mute_reg = wm8750_read_reg_cache(codec, WM8750_ADCDAC) & 0xfff7; + if (mute) + wm8750_write(codec, WM8750_ADCDAC, mute_reg | 0x8); + else + wm8750_write(codec, WM8750_ADCDAC, mute_reg); + return 0; +} + +static int wm8750_dapm_event(struct snd_soc_codec *codec, int event) +{ + u16 pwr_reg = wm8750_read_reg_cache(codec, WM8750_PWR1) & 0xfe3e; + + switch (event) { + case SNDRV_CTL_POWER_D0: /* full On */ + /* set vmid to 50k and unmute dac */ + wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x00c0); + break; + case SNDRV_CTL_POWER_D1: /* partial On */ + case SNDRV_CTL_POWER_D2: /* partial On */ + /* set vmid to 5k for quick power up */ + wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x01c1); + break; + case SNDRV_CTL_POWER_D3hot: /* Off, with power */ + /* mute dac and set vmid to 500k, enable VREF */ + wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x0141); + break; + case SNDRV_CTL_POWER_D3cold: /* Off, without power */ + wm8750_write(codec, WM8750_PWR1, 0x0001); + break; + } + codec->dapm_state = event; + return 0; +} + +struct snd_soc_codec_dai wm8750_dai = { + .name = "WM8750", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + }, + .config_sysclk = wm8750_config_sysclk, + .digital_mute = wm8750_mute, + .ops = { + .prepare = wm8750_pcm_prepare, + }, + .caps = { + .num_modes = ARRAY_SIZE(wm8750_modes), + .mode = wm8750_modes, + }, +}; +EXPORT_SYMBOL_GPL(wm8750_dai); + +static void wm8750_work(void *data) +{ + struct snd_soc_codec *codec = (struct snd_soc_codec *)data; + wm8750_dapm_event(codec, codec->dapm_state); +} + +static int wm8750_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->codec; + + wm8750_dapm_event(codec, SNDRV_CTL_POWER_D3cold); + return 0; +} + +static int wm8750_resume(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->codec; + int i; + u8 data[2]; + u16 *cache = codec->reg_cache; + + /* Sync reg_cache with the hardware */ + for (i = 0; i < ARRAY_SIZE(wm8750_reg); i++) { + if (i == WM8750_RESET) + continue; + data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001); + data[1] = cache[i] & 0x00ff; + codec->hw_write(codec->control_data, data, 2); + } + + wm8750_dapm_event(codec, SNDRV_CTL_POWER_D3hot); + + /* charge wm8750 caps */ + if (codec->suspend_dapm_state == SNDRV_CTL_POWER_D0) { + wm8750_dapm_event(codec, SNDRV_CTL_POWER_D2); + codec->dapm_state = SNDRV_CTL_POWER_D0; + queue_delayed_work(wm8750_workq, &wm8750_dapm_work, + msecs_to_jiffies(1000)); + } + + return 0; +} + +/* + * initialise the WM8750 driver + * register the mixer and dsp interfaces with the kernel + */ +static int wm8750_init(struct snd_soc_device *socdev) +{ + struct snd_soc_codec *codec = socdev->codec; + int reg, ret = 0; + + codec->name = "WM8750"; + codec->owner = THIS_MODULE; + codec->read = wm8750_read_reg_cache; + codec->write = wm8750_write; + codec->dapm_event = wm8750_dapm_event; + codec->dai = &wm8750_dai; + codec->num_dai = 1; + codec->reg_cache_size = ARRAY_SIZE(wm8750_reg); + + codec->reg_cache = + kzalloc(sizeof(u16) * ARRAY_SIZE(wm8750_reg), GFP_KERNEL); + if (codec->reg_cache == NULL) + return -ENOMEM; + memcpy(codec->reg_cache, wm8750_reg, + sizeof(u16) * ARRAY_SIZE(wm8750_reg)); + codec->reg_cache_size = sizeof(u16) * ARRAY_SIZE(wm8750_reg); + + wm8750_reset(codec); + + /* register pcms */ + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) { + kfree(codec->reg_cache); + return ret; + } + + /* charge output caps */ + wm8750_dapm_event(codec, SNDRV_CTL_POWER_D2); + codec->dapm_state = SNDRV_CTL_POWER_D3hot; + queue_delayed_work(wm8750_workq, &wm8750_dapm_work, + msecs_to_jiffies(1000)); + + /* set the update bits */ + reg = wm8750_read_reg_cache(codec, WM8750_LDAC); + wm8750_write(codec, WM8750_LDAC, reg | 0x0100); + reg = wm8750_read_reg_cache(codec, WM8750_RDAC); + wm8750_write(codec, WM8750_RDAC, reg | 0x0100); + reg = wm8750_read_reg_cache(codec, WM8750_LOUT1V); + wm8750_write(codec, WM8750_LOUT1V, reg | 0x0100); + reg = wm8750_read_reg_cache(codec, WM8750_ROUT1V); + wm8750_write(codec, WM8750_ROUT1V, reg | 0x0100); + reg = wm8750_read_reg_cache(codec, WM8750_LOUT2V); + wm8750_write(codec, WM8750_LOUT2V, reg | 0x0100); + reg = wm8750_read_reg_cache(codec, WM8750_ROUT2V); + wm8750_write(codec, WM8750_ROUT2V, reg | 0x0100); + reg = wm8750_read_reg_cache(codec, WM8750_LINVOL); + wm8750_write(codec, WM8750_LINVOL, reg | 0x0100); + reg = wm8750_read_reg_cache(codec, WM8750_RINVOL); + wm8750_write(codec, WM8750_RINVOL, reg | 0x0100); + + wm8750_add_controls(codec); + wm8750_add_widgets(codec); + ret = snd_soc_register_card(socdev); + if (ret < 0) { + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); + } + + return ret; +} + +/* If the i2c layer weren't so broken, we could pass this kind of data + around */ +static struct snd_soc_device *wm8750_socdev; + +#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE) + +/* + * WM8731 2 wire address is determined by GPIO5 + * state during powerup. + * low = 0x1a + * high = 0x1b + */ +static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; + +/* Magic definition of all other variables and things */ +I2C_CLIENT_INSMOD; + +static struct i2c_driver wm8750_i2c_driver; +static struct i2c_client client_template; + +static int wm8750_codec_probe(struct i2c_adapter *adap, int addr, int kind) +{ + struct snd_soc_device *socdev = wm8750_socdev; + struct wm8750_setup_data *setup = socdev->codec_data; + struct snd_soc_codec *codec = socdev->codec; + struct i2c_client *i2c; + int ret; + + if (addr != setup->i2c_address) + return -ENODEV; + + client_template.adapter = adap; + client_template.addr = addr; + + i2c = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (i2c == NULL) { + kfree(codec); + return -ENOMEM; + } + memcpy(i2c, &client_template, sizeof(struct i2c_client)); + i2c_set_clientdata(i2c, codec); + codec->control_data = i2c; + + ret = i2c_attach_client(i2c); + if (ret < 0) { + err("failed to attach codec at addr %x\n", addr); + goto err; + } + + ret = wm8750_init(socdev); + if (ret < 0) { + err("failed to initialise WM8750\n"); + goto err; + } + return ret; + +err: + kfree(codec); + kfree(i2c); + return ret; +} + +static int wm8750_i2c_detach(struct i2c_client *client) +{ + struct snd_soc_codec *codec = i2c_get_clientdata(client); + i2c_detach_client(client); + kfree(codec->reg_cache); + kfree(client); + return 0; +} + +static int wm8750_i2c_attach(struct i2c_adapter *adap) +{ + return i2c_probe(adap, &addr_data, wm8750_codec_probe); +} + +/* corgi i2c codec control layer */ +static struct i2c_driver wm8750_i2c_driver = { + .driver = { + .name = "WM8750 I2C Codec", + .owner = THIS_MODULE, + }, + .id = I2C_DRIVERID_WM8750, + .attach_adapter = wm8750_i2c_attach, + .detach_client = wm8750_i2c_detach, + .command = NULL, +}; + +static struct i2c_client client_template = { + .name = "WM8750", + .driver = &wm8750_i2c_driver, +}; +#endif + +static int wm8750_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct wm8750_setup_data *setup = socdev->codec_data; + struct snd_soc_codec *codec; + int ret = 0; + + info("WM8750 Audio Codec %s", WM8750_VERSION); + codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); + if (codec == NULL) + return -ENOMEM; + + socdev->codec = codec; + mutex_init(&codec->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + wm8750_socdev = socdev; + INIT_WORK(&wm8750_dapm_work, wm8750_work, codec); + wm8750_workq = create_workqueue("wm8750"); + if (wm8750_workq == NULL) { + kfree(codec); + return -ENOMEM; + } +#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE) + if (setup->i2c_address) { + normal_i2c[0] = setup->i2c_address; + codec->hw_write = (hw_write_t)i2c_master_send; + ret = i2c_add_driver(&wm8750_i2c_driver); + if (ret != 0) + printk(KERN_ERR "can't add i2c driver"); + } +#else + /* Add other interfaces here */ +#endif + + return ret; +} + +/* power down chip */ +static int wm8750_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->codec; + + if (codec->control_data) + wm8750_dapm_event(codec, SNDRV_CTL_POWER_D3cold); + if (wm8750_workq) + destroy_workqueue(wm8750_workq); + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); +#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE) + i2c_del_driver(&wm8750_i2c_driver); +#endif + kfree(codec); + + return 0; +} + +struct snd_soc_codec_device soc_codec_dev_wm8750 = { + .probe = wm8750_probe, + .remove = wm8750_remove, + .suspend = wm8750_suspend, + .resume = wm8750_resume, +}; + +EXPORT_SYMBOL_GPL(soc_codec_dev_wm8750); + +MODULE_DESCRIPTION("ASoC WM8750 driver"); +MODULE_AUTHOR("Liam Girdwood"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8750.h b/sound/soc/codecs/wm8750.h new file mode 100644 index 00000000000..ee5eea4a2d3 --- /dev/null +++ b/sound/soc/codecs/wm8750.h @@ -0,0 +1,66 @@ +/* + * Copyright 2005 Openedhand Ltd. + * + * Author: Richard Purdie + * + * Based on WM8753.h + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#ifndef _WM8750_H +#define _WM8750_H + +/* WM8750 register space */ + +#define WM8750_LINVOL 0x00 +#define WM8750_RINVOL 0x01 +#define WM8750_LOUT1V 0x02 +#define WM8750_ROUT1V 0x03 +#define WM8750_ADCDAC 0x05 +#define WM8750_IFACE 0x07 +#define WM8750_SRATE 0x08 +#define WM8750_LDAC 0x0a +#define WM8750_RDAC 0x0b +#define WM8750_BASS 0x0c +#define WM8750_TREBLE 0x0d +#define WM8750_RESET 0x0f +#define WM8750_3D 0x10 +#define WM8750_ALC1 0x11 +#define WM8750_ALC2 0x12 +#define WM8750_ALC3 0x13 +#define WM8750_NGATE 0x14 +#define WM8750_LADC 0x15 +#define WM8750_RADC 0x16 +#define WM8750_ADCTL1 0x17 +#define WM8750_ADCTL2 0x18 +#define WM8750_PWR1 0x19 +#define WM8750_PWR2 0x1a +#define WM8750_ADCTL3 0x1b +#define WM8750_ADCIN 0x1f +#define WM8750_LADCIN 0x20 +#define WM8750_RADCIN 0x21 +#define WM8750_LOUTM1 0x22 +#define WM8750_LOUTM2 0x23 +#define WM8750_ROUTM1 0x24 +#define WM8750_ROUTM2 0x25 +#define WM8750_MOUTM1 0x26 +#define WM8750_MOUTM2 0x27 +#define WM8750_LOUT2V 0x28 +#define WM8750_ROUT2V 0x29 +#define WM8750_MOUTV 0x2a + +#define WM8750_CACHE_REGNUM 0x2a + +struct wm8750_setup_data { + unsigned short i2c_address; + unsigned int mclk; +}; + +extern struct snd_soc_codec_dai wm8750_dai; +extern struct snd_soc_codec_device soc_codec_dev_wm8750; + +#endif -- cgit v1.2.3 From 10c5cf30446fe91b7173436b75c4f00dfb4cd9f8 Mon Sep 17 00:00:00 2001 From: Richard Purdie Date: Fri, 6 Oct 2006 18:37:32 +0200 Subject: [ALSA] ASoC codecs: WM9712 support This patch adds ASoC support for the WM9712 codec. Supported features:- o Capture/Playback/Sidetone/Bypass. o Aux DAC. o 8k - 48k sample rates. o DAPM. Signed-off-by: Richard Purdie Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/codecs/wm9712.c | 778 ++++++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/wm9712.h | 14 + 2 files changed, 792 insertions(+) create mode 100644 sound/soc/codecs/wm9712.c create mode 100644 sound/soc/codecs/wm9712.h (limited to 'sound') diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c new file mode 100644 index 00000000000..4850550e2e3 --- /dev/null +++ b/sound/soc/codecs/wm9712.c @@ -0,0 +1,778 @@ +/* + * wm9712.c -- ALSA Soc WM9712 codec support + * + * Copyright 2006 Wolfson Microelectronics PLC. + * Author: Liam Girdwood + * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision history + * 4th Feb 2006 Initial version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define WM9712_VERSION "0.4" + +static unsigned int ac97_read(struct snd_soc_codec *codec, + unsigned int reg); +static int ac97_write(struct snd_soc_codec *codec, + unsigned int reg, unsigned int val); + +#define AC97_DIR \ + (SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE) + +#define AC97_RATES \ + (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \ + SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_48000) + +/* may need to expand this */ +static struct snd_soc_dai_mode ac97_modes[] = { + {0, 0, SNDRV_PCM_FMTBIT_S16_LE, AC97_RATES}, + {0, 0, SNDRV_PCM_FMTBIT_S18_3LE, AC97_RATES}, +}; + +/* + * WM9712 register cache + */ +static const u16 wm9712_reg[] = { + 0x6174, 0x8000, 0x8000, 0x8000, // 6 + 0xf0f0, 0xaaa0, 0xc008, 0x6808, // e + 0xe808, 0xaaa0, 0xad00, 0x8000, // 16 + 0xe808, 0x3000, 0x8000, 0x0000, // 1e + 0x0000, 0x0000, 0x0000, 0x000f, // 26 + 0x0405, 0x0410, 0xbb80, 0xbb80, // 2e + 0x0000, 0xbb80, 0x0000, 0x0000, // 36 + 0x0000, 0x2000, 0x0000, 0x0000, // 3e + 0x0000, 0x0000, 0x0000, 0x0000, // 46 + 0x0000, 0x0000, 0xf83e, 0xffff, // 4e + 0x0000, 0x0000, 0x0000, 0xf83e, // 56 + 0x0008, 0x0000, 0x0000, 0x0000, // 5e + 0xb032, 0x3e00, 0x0000, 0x0000, // 66 + 0x0000, 0x0000, 0x0000, 0x0000, // 6e + 0x0000, 0x0000, 0x0000, 0x0006, // 76 + 0x0001, 0x0000, 0x574d, 0x4c12, // 7e + 0x0000, 0x0000 // virtual hp mixers +}; + +/* virtual HP mixers regs */ +#define HPL_MIXER 0x80 +#define HPR_MIXER 0x82 + +static const char *wm9712_alc_select[] = {"None", "Left", "Right", "Stereo"}; +static const char *wm9712_alc_mux[] = {"Stereo", "Left", "Right", "None"}; +static const char *wm9712_out3_src[] = {"Left", "VREF", "Left + Right", + "Mono"}; +static const char *wm9712_spk_src[] = {"Speaker Mix", "Headphone Mix"}; +static const char *wm9712_rec_adc[] = {"Stereo", "Left", "Right", "Mute"}; +static const char *wm9712_base[] = {"Linear Control", "Adaptive Boost"}; +static const char *wm9712_rec_gain[] = {"+1.5dB Steps", "+0.75dB Steps"}; +static const char *wm9712_mic[] = {"Mic 1", "Differential", "Mic 2", + "Stereo"}; +static const char *wm9712_rec_sel[] = {"Mic", "NC", "NC", "Speaker Mixer", + "Line", "Headphone Mixer", "Phone Mixer", "Phone"}; +static const char *wm9712_ng_type[] = {"Constant Gain", "Mute"}; +static const char *wm9712_diff_sel[] = {"Mic", "Line"}; + +static const struct soc_enum wm9712_enum[] = { +SOC_ENUM_SINGLE(AC97_PCI_SVID, 14, 4, wm9712_alc_select), +SOC_ENUM_SINGLE(AC97_VIDEO, 12, 4, wm9712_alc_mux), +SOC_ENUM_SINGLE(AC97_AUX, 9, 4, wm9712_out3_src), +SOC_ENUM_SINGLE(AC97_AUX, 8, 2, wm9712_spk_src), +SOC_ENUM_SINGLE(AC97_REC_SEL, 12, 4, wm9712_rec_adc), +SOC_ENUM_SINGLE(AC97_MASTER_TONE, 15, 2, wm9712_base), +SOC_ENUM_DOUBLE(AC97_REC_GAIN, 14, 6, 2, wm9712_rec_gain), +SOC_ENUM_SINGLE(AC97_MIC, 5, 4, wm9712_mic), +SOC_ENUM_SINGLE(AC97_REC_SEL, 8, 8, wm9712_rec_sel), +SOC_ENUM_SINGLE(AC97_REC_SEL, 0, 8, wm9712_rec_sel), +SOC_ENUM_SINGLE(AC97_PCI_SVID, 5, 2, wm9712_ng_type), +SOC_ENUM_SINGLE(0x5c, 8, 2, wm9712_diff_sel), +}; + +static const struct snd_kcontrol_new wm9712_snd_ac97_controls[] = { +SOC_DOUBLE("Speaker Playback Volume", AC97_MASTER, 8, 0, 31, 1), +SOC_SINGLE("Speaker Playback Switch", AC97_MASTER, 15, 1, 1), +SOC_DOUBLE("Headphone Playback Volume", AC97_HEADPHONE, 8, 0, 31, 1), +SOC_SINGLE("Headphone Playback Switch", AC97_HEADPHONE,15, 1, 1), + +SOC_SINGLE("Speaker Playback ZC Switch", AC97_MASTER, 7, 1, 0), +SOC_SINGLE("Speaker Playback Invert Switch", AC97_MASTER, 6, 1, 0), +SOC_SINGLE("Headphone Playback ZC Switch", AC97_HEADPHONE, 7, 1, 0), +SOC_SINGLE("Mono Playback ZC Switch", AC97_MASTER_MONO, 7, 1, 0), +SOC_SINGLE("Mono Playback Volume", AC97_MASTER_MONO, 0, 31, 0), + +SOC_SINGLE("ALC Target Volume", AC97_CODEC_CLASS_REV, 12, 15, 0), +SOC_SINGLE("ALC Hold Time", AC97_CODEC_CLASS_REV, 8, 15, 0), +SOC_SINGLE("ALC Decay Time", AC97_CODEC_CLASS_REV, 4, 15, 0), +SOC_SINGLE("ALC Attack Time", AC97_CODEC_CLASS_REV, 0, 15, 0), +SOC_ENUM("ALC Function", wm9712_enum[0]), +SOC_SINGLE("ALC Max Volume", AC97_PCI_SVID, 11, 7, 0), +SOC_SINGLE("ALC ZC Timeout", AC97_PCI_SVID, 9, 3, 1), +SOC_SINGLE("ALC ZC Switch", AC97_PCI_SVID, 8, 1, 0), +SOC_SINGLE("ALC NG Switch", AC97_PCI_SVID, 7, 1, 0), +SOC_ENUM("ALC NG Type", wm9712_enum[10]), +SOC_SINGLE("ALC NG Threshold", AC97_PCI_SVID, 0, 31, 1), + +SOC_SINGLE("Mic Headphone Volume", AC97_VIDEO, 12, 7, 1), +SOC_SINGLE("ALC Headphone Volume", AC97_VIDEO, 7, 7, 1), + +SOC_SINGLE("Out3 Switch", AC97_AUX, 15, 1, 1), +SOC_SINGLE("Out3 ZC Switch", AC97_AUX, 7, 1, 1), +SOC_SINGLE("Out3 Volume", AC97_AUX, 0, 31, 1), + +SOC_SINGLE("PCBeep Bypass Headphone Volume", AC97_PC_BEEP, 12, 7, 1), +SOC_SINGLE("PCBeep Bypass Speaker Volume", AC97_PC_BEEP, 8, 7, 1), +SOC_SINGLE("PCBeep Bypass Phone Volume", AC97_PC_BEEP, 4, 7, 1), + +SOC_SINGLE("Aux Playback Headphone Volume", AC97_CD, 12, 7, 1), +SOC_SINGLE("Aux Playback Speaker Volume", AC97_CD, 8, 7, 1), +SOC_SINGLE("Aux Playback Phone Volume", AC97_CD, 4, 7, 1), + +SOC_SINGLE("Phone Volume", AC97_PHONE, 0, 15, 0), +SOC_DOUBLE("Line Capture Volume", AC97_LINE, 8, 0, 31, 1), + +SOC_SINGLE("Capture 20dB Boost Switch", AC97_REC_SEL, 14, 1, 0), +SOC_SINGLE("Capture to Phone 20dB Boost Switch", AC97_REC_SEL, 11, 1, 1), + +SOC_SINGLE("3D Upper Cut-off Switch", AC97_3D_CONTROL, 5, 1, 1), +SOC_SINGLE("3D Lower Cut-off Switch", AC97_3D_CONTROL, 4, 1, 1), +SOC_SINGLE("3D Playback Volume", AC97_3D_CONTROL, 0, 15, 0), + +SOC_ENUM("Bass Control", wm9712_enum[5]), +SOC_SINGLE("Bass Cut-off Switch", AC97_MASTER_TONE, 12, 1, 1), +SOC_SINGLE("Tone Cut-off Switch", AC97_MASTER_TONE, 4, 1, 1), +SOC_SINGLE("Playback Attenuate (-6dB) Switch", AC97_MASTER_TONE, 6, 1, 0), +SOC_SINGLE("Bass Volume", AC97_MASTER_TONE, 8, 15, 0), +SOC_SINGLE("Treble Volume", AC97_MASTER_TONE, 0, 15, 0), + +SOC_SINGLE("Capture ADC Switch", AC97_REC_GAIN, 15, 1, 1), +SOC_ENUM("Capture Volume Steps", wm9712_enum[6]), +SOC_DOUBLE("Capture Volume", AC97_REC_GAIN, 8, 0, 63, 1), +SOC_SINGLE("Capture ZC Switch", AC97_REC_GAIN, 7, 1, 0), + +SOC_SINGLE("Mic 1 Volume", AC97_MIC, 8, 31, 1), +SOC_SINGLE("Mic 2 Volume", AC97_MIC, 0, 31, 1), +SOC_SINGLE("Mic 20dB Boost Switch", AC97_MIC, 7, 1, 0), +}; + +/* add non dapm controls */ +static int wm9712_add_controls(struct snd_soc_codec *codec) +{ + int err, i; + + for (i = 0; i < ARRAY_SIZE(wm9712_snd_ac97_controls); i++) { + err = snd_ctl_add(codec->card, + snd_soc_cnew(&wm9712_snd_ac97_controls[i],codec, NULL)); + if (err < 0) + return err; + } + return 0; +} + +/* We have to create a fake left and right HP mixers because + * the codec only has a single control that is shared by both channels. + * This makes it impossible to determine the audio path. + */ +static int mixer_event (struct snd_soc_dapm_widget *w, int event) +{ + u16 l, r, beep, line, phone, mic, pcm, aux; + + l = ac97_read(w->codec, HPL_MIXER); + r = ac97_read(w->codec, HPR_MIXER); + beep = ac97_read(w->codec, AC97_PC_BEEP); + mic = ac97_read(w->codec, AC97_VIDEO); + phone = ac97_read(w->codec, AC97_PHONE); + line = ac97_read(w->codec, AC97_LINE); + pcm = ac97_read(w->codec, AC97_PCM); + aux = ac97_read(w->codec, AC97_CD); + + if (l & 0x1 || r & 0x1) + ac97_write(w->codec, AC97_VIDEO, mic & 0x7fff); + else + ac97_write(w->codec, AC97_VIDEO, mic | 0x8000); + + if (l & 0x2 || r & 0x2) + ac97_write(w->codec, AC97_PCM, pcm & 0x7fff); + else + ac97_write(w->codec, AC97_PCM, pcm | 0x8000); + + if (l & 0x4 || r & 0x4) + ac97_write(w->codec, AC97_LINE, line & 0x7fff); + else + ac97_write(w->codec, AC97_LINE, line | 0x8000); + + if (l & 0x8 || r & 0x8) + ac97_write(w->codec, AC97_PHONE, phone & 0x7fff); + else + ac97_write(w->codec, AC97_PHONE, phone | 0x8000); + + if (l & 0x10 || r & 0x10) + ac97_write(w->codec, AC97_CD, aux & 0x7fff); + else + ac97_write(w->codec, AC97_CD, aux | 0x8000); + + if (l & 0x20 || r & 0x20) + ac97_write(w->codec, AC97_PC_BEEP, beep & 0x7fff); + else + ac97_write(w->codec, AC97_PC_BEEP, beep | 0x8000); + + return 0; +} + +/* Left Headphone Mixers */ +static const struct snd_kcontrol_new wm9712_hpl_mixer_controls[] = { + SOC_DAPM_SINGLE("PCBeep Bypass Switch", HPL_MIXER, 5, 1, 0), + SOC_DAPM_SINGLE("Aux Playback Switch", HPL_MIXER, 4, 1, 0), + SOC_DAPM_SINGLE("Phone Bypass Switch", HPL_MIXER, 3, 1, 0), + SOC_DAPM_SINGLE("Line Bypass Switch", HPL_MIXER, 2, 1, 0), + SOC_DAPM_SINGLE("PCM Playback Switch", HPL_MIXER, 1, 1, 0), + SOC_DAPM_SINGLE("Mic Sidetone Switch", HPL_MIXER, 0, 1, 0), +}; + +/* Right Headphone Mixers */ +static const struct snd_kcontrol_new wm9712_hpr_mixer_controls[] = { + SOC_DAPM_SINGLE("PCBeep Bypass Switch", HPR_MIXER, 5, 1, 0), + SOC_DAPM_SINGLE("Aux Playback Switch", HPR_MIXER, 4, 1, 0), + SOC_DAPM_SINGLE("Phone Bypass Switch", HPR_MIXER, 3, 1, 0), + SOC_DAPM_SINGLE("Line Bypass Switch", HPR_MIXER, 2, 1, 0), + SOC_DAPM_SINGLE("PCM Playback Switch", HPR_MIXER, 1, 1, 0), + SOC_DAPM_SINGLE("Mic Sidetone Switch", HPR_MIXER, 0, 1, 0), +}; + +/* Speaker Mixer */ +static const struct snd_kcontrol_new wm9712_speaker_mixer_controls[] = { + SOC_DAPM_SINGLE("PCBeep Bypass Switch", AC97_PC_BEEP, 11, 1, 1), + SOC_DAPM_SINGLE("Aux Playback Switch", AC97_CD, 11, 1, 1), + SOC_DAPM_SINGLE("Phone Bypass Switch", AC97_PHONE, 14, 1, 1), + SOC_DAPM_SINGLE("Line Bypass Switch", AC97_LINE, 14, 1, 1), + SOC_DAPM_SINGLE("PCM Playback Switch", AC97_PCM, 14, 1, 1), +}; + +/* Phone Mixer */ +static const struct snd_kcontrol_new wm9712_phone_mixer_controls[] = { + SOC_DAPM_SINGLE("PCBeep Bypass Switch", AC97_PC_BEEP, 7, 1, 1), + SOC_DAPM_SINGLE("Aux Playback Switch", AC97_CD, 7, 1, 1), + SOC_DAPM_SINGLE("Line Bypass Switch", AC97_LINE, 13, 1, 1), + SOC_DAPM_SINGLE("PCM Playback Switch", AC97_PCM, 13, 1, 1), + SOC_DAPM_SINGLE("Mic 1 Sidetone Switch", AC97_MIC, 14, 1, 1), + SOC_DAPM_SINGLE("Mic 2 Sidetone Switch", AC97_MIC, 13, 1, 1), +}; + +/* ALC headphone mux */ +static const struct snd_kcontrol_new wm9712_alc_mux_controls = +SOC_DAPM_ENUM("Route", wm9712_enum[1]); + +/* out 3 mux */ +static const struct snd_kcontrol_new wm9712_out3_mux_controls = +SOC_DAPM_ENUM("Route", wm9712_enum[2]); + +/* spk mux */ +static const struct snd_kcontrol_new wm9712_spk_mux_controls = +SOC_DAPM_ENUM("Route", wm9712_enum[3]); + +/* Capture to Phone mux */ +static const struct snd_kcontrol_new wm9712_capture_phone_mux_controls = +SOC_DAPM_ENUM("Route", wm9712_enum[4]); + +/* Capture left select */ +static const struct snd_kcontrol_new wm9712_capture_selectl_controls = +SOC_DAPM_ENUM("Route", wm9712_enum[8]); + +/* Capture right select */ +static const struct snd_kcontrol_new wm9712_capture_selectr_controls = +SOC_DAPM_ENUM("Route", wm9712_enum[9]); + +/* Mic select */ +static const struct snd_kcontrol_new wm9712_mic_src_controls = +SOC_DAPM_ENUM("Route", wm9712_enum[7]); + +/* diff select */ +static const struct snd_kcontrol_new wm9712_diff_sel_controls = +SOC_DAPM_ENUM("Route", wm9712_enum[11]); + +static const struct snd_soc_dapm_widget wm9712_dapm_widgets[] = { +SND_SOC_DAPM_MUX("ALC Sidetone Mux", SND_SOC_NOPM, 0, 0, + &wm9712_alc_mux_controls), +SND_SOC_DAPM_MUX("Out3 Mux", SND_SOC_NOPM, 0, 0, + &wm9712_out3_mux_controls), +SND_SOC_DAPM_MUX("Speaker Mux", SND_SOC_NOPM, 0, 0, + &wm9712_spk_mux_controls), +SND_SOC_DAPM_MUX("Capture Phone Mux", SND_SOC_NOPM, 0, 0, + &wm9712_capture_phone_mux_controls), +SND_SOC_DAPM_MUX("Left Capture Select", SND_SOC_NOPM, 0, 0, + &wm9712_capture_selectl_controls), +SND_SOC_DAPM_MUX("Right Capture Select", SND_SOC_NOPM, 0, 0, + &wm9712_capture_selectr_controls), +SND_SOC_DAPM_MUX("Mic Select Source", SND_SOC_NOPM, 0, 0, + &wm9712_mic_src_controls), +SND_SOC_DAPM_MUX("Differential Source", SND_SOC_NOPM, 0, 0, + &wm9712_diff_sel_controls), +SND_SOC_DAPM_MIXER("AC97 Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), +SND_SOC_DAPM_MIXER_E("Left HP Mixer", AC97_INT_PAGING, 9, 1, + &wm9712_hpl_mixer_controls[0], ARRAY_SIZE(wm9712_hpl_mixer_controls), + mixer_event, SND_SOC_DAPM_POST_REG), +SND_SOC_DAPM_MIXER_E("Right HP Mixer", AC97_INT_PAGING, 8, 1, + &wm9712_hpr_mixer_controls[0], ARRAY_SIZE(wm9712_hpr_mixer_controls), + mixer_event, SND_SOC_DAPM_POST_REG), +SND_SOC_DAPM_MIXER("Phone Mixer", AC97_INT_PAGING, 6, 1, + &wm9712_phone_mixer_controls[0], ARRAY_SIZE(wm9712_phone_mixer_controls)), +SND_SOC_DAPM_MIXER("Speaker Mixer", AC97_INT_PAGING, 7, 1, + &wm9712_speaker_mixer_controls[0], + ARRAY_SIZE(wm9712_speaker_mixer_controls)), +SND_SOC_DAPM_MIXER("Mono Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), +SND_SOC_DAPM_DAC("Left DAC", "Left HiFi Playback", AC97_INT_PAGING, 14, 1), +SND_SOC_DAPM_DAC("Right DAC", "Right HiFi Playback", AC97_INT_PAGING, 13, 1), +SND_SOC_DAPM_DAC("Aux DAC", "Aux Playback", SND_SOC_NOPM, 0, 0), +SND_SOC_DAPM_ADC("Left ADC", "Left HiFi Capture", AC97_INT_PAGING, 12, 1), +SND_SOC_DAPM_ADC("Right ADC", "Right HiFi Capture", AC97_INT_PAGING, 11, 1), +SND_SOC_DAPM_PGA("Headphone PGA", AC97_INT_PAGING, 4, 1, NULL, 0), +SND_SOC_DAPM_PGA("Speaker PGA", AC97_INT_PAGING, 3, 1, NULL, 0), +SND_SOC_DAPM_PGA("Out 3 PGA", AC97_INT_PAGING, 5, 1, NULL, 0), +SND_SOC_DAPM_PGA("Line PGA", AC97_INT_PAGING, 2, 1, NULL, 0), +SND_SOC_DAPM_PGA("Phone PGA", AC97_INT_PAGING, 1, 1, NULL, 0), +SND_SOC_DAPM_PGA("Mic PGA", AC97_INT_PAGING, 0, 1, NULL, 0), +SND_SOC_DAPM_MICBIAS("Mic Bias", AC97_INT_PAGING, 10, 1), +SND_SOC_DAPM_OUTPUT("MONOOUT"), +SND_SOC_DAPM_OUTPUT("HPOUTL"), +SND_SOC_DAPM_OUTPUT("HPOUTR"), +SND_SOC_DAPM_OUTPUT("LOUT2"), +SND_SOC_DAPM_OUTPUT("ROUT2"), +SND_SOC_DAPM_OUTPUT("OUT3"), +SND_SOC_DAPM_INPUT("LINEINL"), +SND_SOC_DAPM_INPUT("LINEINR"), +SND_SOC_DAPM_INPUT("PHONE"), +SND_SOC_DAPM_INPUT("PCBEEP"), +SND_SOC_DAPM_INPUT("MIC1"), +SND_SOC_DAPM_INPUT("MIC2"), +}; + +static const char *audio_map[][3] = { + /* virtual mixer - mixes left & right channels for spk and mono */ + {"AC97 Mixer", NULL, "Left DAC"}, + {"AC97 Mixer", NULL, "Right DAC"}, + + /* Left HP mixer */ + {"Left HP Mixer", "PCBeep Bypass Switch", "PCBEEP"}, + {"Left HP Mixer", "Aux Playback Switch", "Aux DAC"}, + {"Left HP Mixer", "Phone Bypass Switch", "Phone PGA"}, + {"Left HP Mixer", "Line Bypass Switch", "Line PGA"}, + {"Left HP Mixer", "PCM Playback Switch", "Left DAC"}, + {"Left HP Mixer", "Mic Sidetone Switch", "Mic PGA"}, + {"Left HP Mixer", NULL, "ALC Sidetone Mux"}, + //{"Right HP Mixer", NULL, "HP Mixer"}, + + /* Right HP mixer */ + {"Right HP Mixer", "PCBeep Bypass Switch", "PCBEEP"}, + {"Right HP Mixer", "Aux Playback Switch", "Aux DAC"}, + {"Right HP Mixer", "Phone Bypass Switch", "Phone PGA"}, + {"Right HP Mixer", "Line Bypass Switch", "Line PGA"}, + {"Right HP Mixer", "PCM Playback Switch", "Right DAC"}, + {"Right HP Mixer", "Mic Sidetone Switch", "Mic PGA"}, + {"Right HP Mixer", NULL, "ALC Sidetone Mux"}, + + /* speaker mixer */ + {"Speaker Mixer", "PCBeep Bypass Switch", "PCBEEP"}, + {"Speaker Mixer", "Line Bypass Switch", "Line PGA"}, + {"Speaker Mixer", "PCM Playback Switch", "AC97 Mixer"}, + {"Speaker Mixer", "Phone Bypass Switch", "Phone PGA"}, + {"Speaker Mixer", "Aux Playback Switch", "Aux DAC"}, + + /* Phone mixer */ + {"Phone Mixer", "PCBeep Bypass Switch", "PCBEEP"}, + {"Phone Mixer", "Line Bypass Switch", "Line PGA"}, + {"Phone Mixer", "Aux Playback Switch", "Aux DAC"}, + {"Phone Mixer", "PCM Playback Switch", "AC97 Mixer"}, + {"Phone Mixer", "Mic 1 Sidetone Switch", "Mic PGA"}, + {"Phone Mixer", "Mic 2 Sidetone Switch", "Mic PGA"}, + + /* inputs */ + {"Line PGA", NULL, "LINEINL"}, + {"Line PGA", NULL, "LINEINR"}, + {"Phone PGA", NULL, "PHONE"}, + {"Mic PGA", NULL, "MIC1"}, + {"Mic PGA", NULL, "MIC2"}, + + /* left capture selector */ + {"Left Capture Select", "Mic", "MIC1"}, + {"Left Capture Select", "Speaker Mixer", "Speaker Mixer"}, + {"Left Capture Select", "Line", "LINEINL"}, + {"Left Capture Select", "Headphone Mixer", "Left HP Mixer"}, + {"Left Capture Select", "Phone Mixer", "Phone Mixer"}, + {"Left Capture Select", "Phone", "PHONE"}, + + /* right capture selector */ + {"Right Capture Select", "Mic", "MIC2"}, + {"Right Capture Select", "Speaker Mixer", "Speaker Mixer"}, + {"Right Capture Select", "Line", "LINEINR"}, + {"Right Capture Select", "Headphone Mixer", "Right HP Mixer"}, + {"Right Capture Select", "Phone Mixer", "Phone Mixer"}, + {"Right Capture Select", "Phone", "PHONE"}, + + /* ALC Sidetone */ + {"ALC Sidetone Mux", "Stereo", "Left Capture Select"}, + {"ALC Sidetone Mux", "Stereo", "Right Capture Select"}, + {"ALC Sidetone Mux", "Left", "Left Capture Select"}, + {"ALC Sidetone Mux", "Right", "Right Capture Select"}, + + /* ADC's */ + {"Left ADC", NULL, "Left Capture Select"}, + {"Right ADC", NULL, "Right Capture Select"}, + + /* outputs */ + {"MONOOUT", NULL, "Phone Mixer"}, + {"HPOUTL", NULL, "Headphone PGA"}, + {"Headphone PGA", NULL, "Left HP Mixer"}, + {"HPOUTR", NULL, "Headphone PGA"}, + {"Headphone PGA", NULL, "Right HP Mixer"}, + + /* mono hp mixer */ + {"Mono HP Mixer", NULL, "Left HP Mixer"}, + {"Mono HP Mixer", NULL, "Right HP Mixer"}, + + /* Out3 Mux */ + {"Out3 Mux", "Left", "Left HP Mixer"}, + {"Out3 Mux", "Mono", "Phone Mixer"}, + {"Out3 Mux", "Left + Right", "Mono HP Mixer"}, + {"Out 3 PGA", NULL, "Out3 Mux"}, + {"OUT3", NULL, "Out 3 PGA"}, + + /* speaker Mux */ + {"Speaker Mux", "Speaker Mix", "Speaker Mixer"}, + {"Speaker Mux", "Headphone Mix", "Mono HP Mixer"}, + {"Speaker PGA", NULL, "Speaker Mux"}, + {"LOUT2", NULL, "Speaker PGA"}, + {"ROUT2", NULL, "Speaker PGA"}, + + {NULL, NULL, NULL}, +}; + +static int wm9712_add_widgets(struct snd_soc_codec *codec) +{ + int i; + + for(i = 0; i < ARRAY_SIZE(wm9712_dapm_widgets); i++) { + snd_soc_dapm_new_control(codec, &wm9712_dapm_widgets[i]); + } + + /* set up audio path audio_mapnects */ + for(i = 0; audio_map[i][0] != NULL; i++) { + snd_soc_dapm_connect_input(codec, audio_map[i][0], + audio_map[i][1], audio_map[i][2]); + } + + snd_soc_dapm_new_widgets(codec); + return 0; +} + +static unsigned int ac97_read(struct snd_soc_codec *codec, + unsigned int reg) +{ + u16 *cache = codec->reg_cache; + + if (reg == AC97_RESET || reg == AC97_GPIO_STATUS || + reg == AC97_VENDOR_ID1 || reg == AC97_VENDOR_ID2 || + reg == AC97_REC_GAIN) + return soc_ac97_ops.read(codec->ac97, reg); + else { + reg = reg >> 1; + + if (reg > (ARRAY_SIZE(wm9712_reg))) + return -EIO; + + return cache[reg]; + } +} + +static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int val) +{ + u16 *cache = codec->reg_cache; + + soc_ac97_ops.write(codec->ac97, reg, val); + reg = reg >> 1; + if (reg <= (ARRAY_SIZE(wm9712_reg))) + cache[reg] = val; + + return 0; +} + +static int ac97_prepare(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->codec; + int reg; + u16 vra; + + vra = ac97_read(codec, AC97_EXTENDED_STATUS); + ac97_write(codec, AC97_EXTENDED_STATUS, vra | 0x1); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + reg = AC97_PCM_FRONT_DAC_RATE; + else + reg = AC97_PCM_LR_ADC_RATE; + + return ac97_write(codec, reg, runtime->rate); +} + +static int ac97_aux_prepare(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->codec; + u16 vra, xsle; + + vra = ac97_read(codec, AC97_EXTENDED_STATUS); + ac97_write(codec, AC97_EXTENDED_STATUS, vra | 0x1); + xsle = ac97_read(codec, AC97_PCI_SID); + ac97_write(codec, AC97_PCI_SID, xsle | 0x8000); + + if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) + return -ENODEV; + + return ac97_write(codec, AC97_PCM_SURR_DAC_RATE, runtime->rate); +} + +struct snd_soc_codec_dai wm9712_dai[] = { +{ + .name = "AC97 HiFi", + .playback = { + .stream_name = "HiFi Playback", + .channels_min = 1, + .channels_max = 2,}, + .capture = { + .stream_name = "HiFi Capture", + .channels_min = 1, + .channels_max = 2,}, + .ops = { + .prepare = ac97_prepare,}, + .caps = { + .num_modes = ARRAY_SIZE(ac97_modes), + .mode = ac97_modes,}, + }, + { + .name = "AC97 Aux", + .playback = { + .stream_name = "Aux Playback", + .channels_min = 1, + .channels_max = 1,}, + .ops = { + .prepare = ac97_aux_prepare,}, + .caps = { + .num_modes = ARRAY_SIZE(ac97_modes), + .mode = ac97_modes,}, + }, +}; +EXPORT_SYMBOL_GPL(wm9712_dai); + +static int wm9712_dapm_event(struct snd_soc_codec *codec, int event) +{ + u16 reg; + + switch (event) { + case SNDRV_CTL_POWER_D0: /* full On */ + /* liam - maybe enable thermal shutdown */ + reg = ac97_read(codec, AC97_EXTENDED_MID) & 0xdfff; + ac97_write(codec, AC97_EXTENDED_MID, reg); + break; + case SNDRV_CTL_POWER_D1: /* partial On */ + case SNDRV_CTL_POWER_D2: /* partial On */ + break; + case SNDRV_CTL_POWER_D3hot: /* Off, with power */ + /* enable master bias and vmid */ + reg = ac97_read(codec, AC97_EXTENDED_MID) & 0xbbff; + ac97_write(codec, AC97_EXTENDED_MID, reg); + ac97_write(codec, AC97_POWERDOWN, 0x0000); + break; + case SNDRV_CTL_POWER_D3cold: /* Off, without power */ + /* disable everything including AC link */ + ac97_write(codec, AC97_EXTENDED_MID, 0xffff); + ac97_write(codec, AC97_EXTENDED_MSTATUS, 0xffff); + ac97_write(codec, AC97_POWERDOWN, 0xffff); + break; + } + codec->dapm_state = event; + return 0; +} + +static int wm9712_reset(struct snd_soc_codec *codec, int try_warm) +{ + if (try_warm && soc_ac97_ops.warm_reset) { + soc_ac97_ops.warm_reset(codec->ac97); + if (!(ac97_read(codec, 0) & 0x8000)) + return 1; + } + + soc_ac97_ops.reset(codec->ac97); + if (ac97_read(codec, 0) & 0x8000) + goto err; + return 0; + +err: + printk(KERN_ERR "WM9712 AC97 reset failed\n"); + return -EIO; +} + +static int wm9712_soc_suspend(struct platform_device *pdev, + pm_message_t state) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->codec; + + wm9712_dapm_event(codec, SNDRV_CTL_POWER_D3cold); + return 0; +} + +static int wm9712_soc_resume(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->codec; + int i, ret; + u16 *cache = codec->reg_cache; + + ret = wm9712_reset(codec, 1); + if (ret < 0){ + printk(KERN_ERR "could not reset AC97 codec\n"); + return ret; + } + + wm9712_dapm_event(codec, SNDRV_CTL_POWER_D3hot); + + if (ret == 0) { + /* Sync reg_cache with the hardware after cold reset */ + for (i = 2; i < ARRAY_SIZE(wm9712_reg) << 1; i+=2) { + if (i == AC97_INT_PAGING || i == AC97_POWERDOWN || + (i > 0x58 && i != 0x5c)) + continue; + soc_ac97_ops.write(codec->ac97, i, cache[i>>1]); + } + } + + if (codec->suspend_dapm_state == SNDRV_CTL_POWER_D0) + wm9712_dapm_event(codec, SNDRV_CTL_POWER_D0); + + return ret; +} + +static int wm9712_soc_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec; + int ret = 0; + + printk(KERN_INFO "WM9711/WM9712 SoC Audio Codec %s\n", WM9712_VERSION); + + socdev->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); + if (socdev->codec == NULL) + return -ENOMEM; + codec = socdev->codec; + mutex_init(&codec->mutex); + + codec->reg_cache = + kzalloc(sizeof(u16) * ARRAY_SIZE(wm9712_reg), GFP_KERNEL); + if (codec->reg_cache == NULL) { + kfree(codec->ac97); + kfree(socdev->codec); + socdev->codec = NULL; + return -ENOMEM; + } + memcpy(codec->reg_cache, wm9712_reg, sizeof(u16) * ARRAY_SIZE(wm9712_reg)); + codec->reg_cache_size = sizeof(u16) * ARRAY_SIZE(wm9712_reg); + codec->reg_cache_step = 2; + + codec->name = "WM9712"; + codec->owner = THIS_MODULE; + codec->dai = wm9712_dai; + codec->num_dai = ARRAY_SIZE(wm9712_dai); + codec->write = ac97_write; + codec->read = ac97_read; + codec->dapm_event = wm9712_dapm_event; + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + + ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0); + if (ret < 0) + goto err; + + /* register pcms */ + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) + goto pcm_err; + + ret = wm9712_reset(codec, 0); + if (ret < 0) { + printk(KERN_ERR "AC97 link error\n"); + goto reset_err; + } + + /* set alc mux to none */ + ac97_write(codec, AC97_VIDEO, ac97_read(codec, AC97_VIDEO) | 0x3000); + + wm9712_dapm_event(codec, SNDRV_CTL_POWER_D3hot); + wm9712_add_controls(codec); + wm9712_add_widgets(codec); + ret = snd_soc_register_card(socdev); + if (ret < 0) + goto reset_err; + + return 0; + +reset_err: + snd_soc_free_pcms(socdev); + +pcm_err: + snd_soc_free_ac97_codec(codec); + +err: + kfree(socdev->codec->reg_cache); + kfree(socdev->codec); + socdev->codec = NULL; + return ret; +} + +static int wm9712_soc_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->codec; + + if (codec == NULL) + return 0; + + snd_soc_dapm_free(socdev); + snd_soc_free_pcms(socdev); + snd_soc_free_ac97_codec(codec); + kfree(codec->reg_cache); + kfree(codec); + return 0; +} + +struct snd_soc_codec_device soc_codec_dev_wm9712 = { + .probe = wm9712_soc_probe, + .remove = wm9712_soc_remove, + .suspend = wm9712_soc_suspend, + .resume = wm9712_soc_resume, +}; + +EXPORT_SYMBOL_GPL(soc_codec_dev_wm9712); + +MODULE_DESCRIPTION("ASoC WM9711/WM9712 driver"); +MODULE_AUTHOR("Liam Girdwood"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm9712.h b/sound/soc/codecs/wm9712.h new file mode 100644 index 00000000000..719105d61e6 --- /dev/null +++ b/sound/soc/codecs/wm9712.h @@ -0,0 +1,14 @@ +/* + * wm9712.h -- WM9712 Soc Audio driver + */ + +#ifndef _WM9712_H +#define _WM9712_H + +#define WM9712_DAI_AC97_HIFI 0 +#define WM9712_DAI_AC97_AUX 1 + +extern struct snd_soc_codec_dai wm9712_dai[2]; +extern struct snd_soc_codec_device soc_codec_dev_wm9712; + +#endif -- cgit v1.2.3 From dbc6b6ad767c86907db373e85139b0e975ba7599 Mon Sep 17 00:00:00 2001 From: Richard Purdie Date: Fri, 6 Oct 2006 18:38:03 +0200 Subject: [ALSA] ASoC codecs: generic AC97 support This patch allows the std Alsa AC97 codec driver to use any AsoC AC97 controller driver. Currently, only HiFi playback and Capture are supported atm. Signed-off-by: Richard Purdie Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/codecs/ac97.c | 167 ++++++++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/ac97.h | 18 ++++++ 2 files changed, 185 insertions(+) create mode 100644 sound/soc/codecs/ac97.c create mode 100644 sound/soc/codecs/ac97.h (limited to 'sound') diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c new file mode 100644 index 00000000000..dd1a9f579a6 --- /dev/null +++ b/sound/soc/codecs/ac97.c @@ -0,0 +1,167 @@ +/* + * ac97.c -- ALSA Soc AC97 codec support + * + * Copyright 2005 Wolfson Microelectronics PLC. + * Author: Liam Girdwood + * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision history + * 17th Oct 2005 Initial version. + * + * Generic AC97 support. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define AC97_VERSION "0.5" + +#define AC97_DIR \ + (SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE) + +#define AC97_RATES \ + (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \ + SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_48000) + +/* may need to expand this */ +static struct snd_soc_dai_mode soc_ac97[] = { + {0, 0, SNDRV_PCM_FMTBIT_S16_LE, AC97_RATES}, + {0, 0, SNDRV_PCM_FMTBIT_S18_3LE, AC97_RATES}, + {0, 0, SNDRV_PCM_FMTBIT_S20_3LE, AC97_RATES}, +}; + +static int ac97_prepare(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->codec; + + int reg = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? + AC97_PCM_FRONT_DAC_RATE : AC97_PCM_LR_ADC_RATE; + return snd_ac97_set_rate(codec->ac97, reg, runtime->rate); +} + +static struct snd_soc_codec_dai ac97_dai = { + .name = "AC97 HiFi", + .playback = { + .stream_name = "AC97 Playback", + .channels_min = 1, + .channels_max = 2,}, + .capture = { + .stream_name = "AC97 Capture", + .channels_min = 1, + .channels_max = 2,}, + .ops = { + .prepare = ac97_prepare,}, + .caps = { + .num_modes = ARRAY_SIZE(soc_ac97), + .mode = soc_ac97,}, +}; + +static unsigned int ac97_read(struct snd_soc_codec *codec, + unsigned int reg) +{ + return soc_ac97_ops.read(codec->ac97, reg); +} + +static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int val) +{ + soc_ac97_ops.write(codec->ac97, reg, val); + return 0; +} + +static int ac97_soc_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec; + struct snd_ac97_bus *ac97_bus; + struct snd_ac97_template ac97_template; + int ret = 0; + + printk(KERN_INFO "AC97 SoC Audio Codec %s\n", AC97_VERSION); + + socdev->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); + if (socdev->codec == NULL) + return -ENOMEM; + codec = socdev->codec; + mutex_init(&codec->mutex); + + codec->name = "AC97"; + codec->owner = THIS_MODULE; + codec->dai = &ac97_dai; + codec->num_dai = 1; + codec->write = ac97_write; + codec->read = ac97_read; + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + + /* register pcms */ + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if(ret < 0) + goto err; + + /* add codec as bus device for standard ac97 */ + ret = snd_ac97_bus(codec->card, 0, &soc_ac97_ops, NULL, &ac97_bus); + if(ret < 0) + goto bus_err; + + memset(&ac97_template, 0, sizeof(struct snd_ac97_template)); + ret = snd_ac97_mixer(ac97_bus, &ac97_template, &codec->ac97); + if(ret < 0) + goto bus_err; + + ret = snd_soc_register_card(socdev); + if (ret < 0) + goto bus_err; + return 0; + +bus_err: + snd_soc_free_pcms(socdev); + +err: + kfree(socdev->codec->reg_cache); + kfree(socdev->codec); + socdev->codec = NULL; + return ret; +} + +static int ac97_soc_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->codec; + + if(codec == NULL) + return 0; + + snd_soc_free_pcms(socdev); + kfree(socdev->codec->reg_cache); + kfree(socdev->codec); + + return 0; +} + +struct snd_soc_codec_device soc_codec_dev_ac97= { + .probe = ac97_soc_probe, + .remove = ac97_soc_remove, +}; + +EXPORT_SYMBOL_GPL(soc_codec_dev_ac97); + +MODULE_DESCRIPTION("Soc Generic AC97 driver"); +MODULE_AUTHOR("Liam Girdwood"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/ac97.h b/sound/soc/codecs/ac97.h new file mode 100644 index 00000000000..930ddfc2321 --- /dev/null +++ b/sound/soc/codecs/ac97.h @@ -0,0 +1,18 @@ +/* + * linux/sound/codecs/ac97.h -- ALSA SoC Layer + * + * Author: Liam Girdwood + * Created: Dec 1st 2005 + * Copyright: Wolfson Microelectronics. PLC. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __LINUX_SND_SOC_AC97_H +#define __LINUX_SND_SOC_AC97_H + +extern struct snd_soc_codec_device soc_codec_dev_ac97; + +#endif -- cgit v1.2.3 From 7f137ab673124ee0a210ab5b74c1f7234d6145fa Mon Sep 17 00:00:00 2001 From: Richard Purdie Date: Fri, 6 Oct 2006 18:38:37 +0200 Subject: [ALSA] ASoC codecs: build files This patch adds an ASoC Makefile and Kconfig for the WM8731, WM8750 and WM9712 codecs. Signed-off-by: Richard Purdie Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/Kconfig | 6 ++++++ sound/soc/Makefile | 2 +- sound/soc/codecs/Kconfig | 15 +++++++++++++++ sound/soc/codecs/Makefile | 9 +++++++++ 4 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 sound/soc/codecs/Kconfig create mode 100644 sound/soc/codecs/Makefile (limited to 'sound') diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index 200709f4b70..288bad30b21 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -5,6 +5,9 @@ menu "SoC audio support" depends on SND!=n +config SND_SOC_AC97_BUS + bool + config SND_SOC tristate "SoC audio support" ---help--- @@ -16,4 +19,7 @@ config SND_SOC This SoC audio support can also be built as a module. If so, the module will be called snd-soc-core. +# Supported codecs +source "sound/soc/codecs/Kconfig" + endmenu diff --git a/sound/soc/Makefile b/sound/soc/Makefile index b211ee63fd7..3dd4f20c5ec 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -1,4 +1,4 @@ snd-soc-core-objs := soc-core.o soc-dapm.o obj-$(CONFIG_SND_SOC) += snd-soc-core.o - +obj-$(CONFIG_SND_SOC) += codecs/ diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig new file mode 100644 index 00000000000..78ac2688e12 --- /dev/null +++ b/sound/soc/codecs/Kconfig @@ -0,0 +1,15 @@ +config SND_SOC_AC97_CODEC + tristate + depends SND_SOC + +config SND_SOC_WM8731 + tristate + depends SND_SOC + +config SND_SOC_WM8750 + tristate + depends SND_SOC + +config SND_SOC_WM9712 + tristate + depends SND_SOC diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile new file mode 100644 index 00000000000..3249a6e4f1d --- /dev/null +++ b/sound/soc/codecs/Makefile @@ -0,0 +1,9 @@ +snd-soc-ac97-objs := ac97.o +snd-soc-wm8731-objs := wm8731.o +snd-soc-wm8750-objs := wm8750.o +snd-soc-wm9712-objs := wm9712.o + +obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o +obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o +obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o +obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o -- cgit v1.2.3 From ff9abf5b0a655b59d59ea61aec5be6285bf3ac30 Mon Sep 17 00:00:00 2001 From: Frank Mandarino Date: Fri, 6 Oct 2006 18:39:29 +0200 Subject: [ALSA] ASoC AT91RM92000 audio DMA This patch adds ASoC audio DMA support to the Atmel AT91RM9200 CPU. Features:- o Playback/Capture supported. o 16 Bit data size. Signed-off-by: Frank Mandarino Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/at91/at91rm9200-pcm.c | 428 ++++++++++++++++++++++++++++++++++++++++ sound/soc/at91/at91rm9200-pcm.h | 75 +++++++ 2 files changed, 503 insertions(+) create mode 100644 sound/soc/at91/at91rm9200-pcm.c create mode 100644 sound/soc/at91/at91rm9200-pcm.h (limited to 'sound') diff --git a/sound/soc/at91/at91rm9200-pcm.c b/sound/soc/at91/at91rm9200-pcm.c new file mode 100644 index 00000000000..237bc5f0757 --- /dev/null +++ b/sound/soc/at91/at91rm9200-pcm.c @@ -0,0 +1,428 @@ +/* + * at91rm9200-pcm.c -- ALSA PCM interface for the Atmel AT91RM9200 chip. + * + * Author: Frank Mandarino + * Endrelia Technologies Inc. + * Created: Mar 3, 2006 + * + * Based on pxa2xx-pcm.c by: + * + * Author: Nicolas Pitre + * Created: Nov 30, 2004 + * Copyright: (C) 2004 MontaVista Software, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "at91rm9200-pcm.h" + +#if 0 +#define DBG(x...) printk(KERN_INFO "at91rm9200-pcm: " x) +#else +#define DBG(x...) +#endif + +static const snd_pcm_hardware_t at91rm9200_pcm_hardware = { + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .period_bytes_min = 32, + .period_bytes_max = 8192, + .periods_min = 2, + .periods_max = 1024, + .buffer_bytes_max = 32 * 1024, +}; + +struct at91rm9200_runtime_data { + at91rm9200_pcm_dma_params_t *params; + dma_addr_t dma_buffer; /* physical address of dma buffer */ + dma_addr_t dma_buffer_end; /* first address beyond DMA buffer */ + size_t period_size; + dma_addr_t period_ptr; /* physical address of next period */ + u32 pdc_xpr_save; /* PDC register save */ + u32 pdc_xcr_save; + u32 pdc_xnpr_save; + u32 pdc_xncr_save; +}; + +static void at91rm9200_pcm_dma_irq(u32 ssc_sr, + struct snd_pcm_substream *substream) +{ + struct at91rm9200_runtime_data *prtd = substream->runtime->private_data; + at91rm9200_pcm_dma_params_t *params = prtd->params; + static int count = 0; + + count++; + + if (ssc_sr & params->mask->ssc_endbuf) { + + printk(KERN_WARNING + "at91rm9200-pcm: buffer %s on %s (SSC_SR=%#x, count=%d)\n", + substream->stream == SNDRV_PCM_STREAM_PLAYBACK + ? "underrun" : "overrun", + params->name, ssc_sr, count); + + /* re-start the PDC */ + at91_ssc_write(params->pdc->ptcr, params->mask->pdc_disable); + + prtd->period_ptr += prtd->period_size; + if (prtd->period_ptr >= prtd->dma_buffer_end) { + prtd->period_ptr = prtd->dma_buffer; + } + + at91_ssc_write(params->pdc->xpr, prtd->period_ptr); + at91_ssc_write(params->pdc->xcr, + prtd->period_size / params->pdc_xfer_size); + + at91_ssc_write(params->pdc->ptcr, params->mask->pdc_enable); + } + + if (ssc_sr & params->mask->ssc_endx) { + + /* Load the PDC next pointer and counter registers */ + prtd->period_ptr += prtd->period_size; + if (prtd->period_ptr >= prtd->dma_buffer_end) { + prtd->period_ptr = prtd->dma_buffer; + } + at91_ssc_write(params->pdc->xnpr, prtd->period_ptr); + at91_ssc_write(params->pdc->xncr, + prtd->period_size / params->pdc_xfer_size); + } + + snd_pcm_period_elapsed(substream); +} + +static int at91rm9200_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + snd_pcm_runtime_t *runtime = substream->runtime; + struct at91rm9200_runtime_data *prtd = runtime->private_data; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + + /* this may get called several times by oss emulation + * with different params */ + + snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); + runtime->dma_bytes = params_buffer_bytes(params); + + prtd->params = rtd->cpu_dai->dma_data; + prtd->params->dma_intr_handler = at91rm9200_pcm_dma_irq; + + prtd->dma_buffer = runtime->dma_addr; + prtd->dma_buffer_end = runtime->dma_addr + runtime->dma_bytes; + prtd->period_size = params_period_bytes(params); + + DBG("hw_params: DMA for %s initialized (dma_bytes=%d, period_size=%d)\n", + prtd->params->name, runtime->dma_bytes, prtd->period_size); + return 0; +} + +static int at91rm9200_pcm_hw_free(struct snd_pcm_substream *substream) +{ + struct at91rm9200_runtime_data *prtd = substream->runtime->private_data; + at91rm9200_pcm_dma_params_t *params = prtd->params; + + if (params != NULL) { + at91_ssc_write(params->pdc->ptcr, params->mask->pdc_disable); + prtd->params->dma_intr_handler = NULL; + } + + return 0; +} + +static int at91rm9200_pcm_prepare(struct snd_pcm_substream *substream) +{ + struct at91rm9200_runtime_data *prtd = substream->runtime->private_data; + at91rm9200_pcm_dma_params_t *params = prtd->params; + + at91_ssc_write(params->ssc->idr, + params->mask->ssc_endx | params->mask->ssc_endbuf); + + at91_ssc_write(params->pdc->ptcr, params->mask->pdc_disable); + return 0; +} + +static int at91rm9200_pcm_trigger(struct snd_pcm_substream *substream, + int cmd) +{ + struct at91rm9200_runtime_data *prtd = substream->runtime->private_data; + at91rm9200_pcm_dma_params_t *params = prtd->params; + int ret = 0; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + prtd->period_ptr = prtd->dma_buffer; + + at91_ssc_write(params->pdc->xpr, prtd->period_ptr); + at91_ssc_write(params->pdc->xcr, + prtd->period_size / params->pdc_xfer_size); + + prtd->period_ptr += prtd->period_size; + at91_ssc_write(params->pdc->xnpr, prtd->period_ptr); + at91_ssc_write(params->pdc->xncr, + prtd->period_size / params->pdc_xfer_size); + + DBG("trigger: period_ptr=%lx, xpr=%lx, xcr=%ld, xnpr=%lx, xncr=%ld\n", + (unsigned long) prtd->period_ptr, + at91_ssc_read(params->pdc->xpr), + at91_ssc_read(params->pdc->xcr), + at91_ssc_read(params->pdc->xnpr), + at91_ssc_read(params->pdc->xncr)); + + at91_ssc_write(params->ssc->ier, + params->mask->ssc_endx | params->mask->ssc_endbuf); + + at91_ssc_write(params->pdc->ptcr, params->mask->pdc_enable); + + DBG("sr=%lx imr=%lx\n", at91_ssc_read(params->ssc->ier - 4), + at91_ssc_read(params->ssc->ier + 8)); + break; + + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + at91_ssc_write(params->pdc->ptcr, params->mask->pdc_disable); + break; + + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + at91_ssc_write(params->pdc->ptcr, params->mask->pdc_enable); + break; + + default: + ret = -EINVAL; + } + + return ret; +} + +static snd_pcm_uframes_t at91rm9200_pcm_pointer( + struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct at91rm9200_runtime_data *prtd = runtime->private_data; + at91rm9200_pcm_dma_params_t *params = prtd->params; + dma_addr_t ptr; + snd_pcm_uframes_t x; + + ptr = (dma_addr_t) at91_ssc_read(params->pdc->xpr); + x = bytes_to_frames(runtime, ptr - prtd->dma_buffer); + + if (x == runtime->buffer_size) + x = 0; + return x; +} + +static int at91rm9200_pcm_open(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct at91rm9200_runtime_data *prtd; + int ret = 0; + + snd_soc_set_runtime_hwparams(substream, &at91rm9200_pcm_hardware); + + /* ensure that buffer size is a multiple of period size */ + ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + if (ret < 0) + goto out; + + prtd = kzalloc(sizeof(struct at91rm9200_runtime_data), GFP_KERNEL); + if (prtd == NULL) { + ret = -ENOMEM; + goto out; + } + runtime->private_data = prtd; + + out: + return ret; +} + +static int at91rm9200_pcm_close(struct snd_pcm_substream *substream) +{ + struct at91rm9200_runtime_data *prtd = substream->runtime->private_data; + + kfree(prtd); + return 0; +} + +static int at91rm9200_pcm_mmap(struct snd_pcm_substream *substream, + struct vm_area_struct *vma) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + return dma_mmap_writecombine(substream->pcm->card->dev, vma, + runtime->dma_area, + runtime->dma_addr, + runtime->dma_bytes); +} + +struct snd_pcm_ops at91rm9200_pcm_ops = { + .open = at91rm9200_pcm_open, + .close = at91rm9200_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = at91rm9200_pcm_hw_params, + .hw_free = at91rm9200_pcm_hw_free, + .prepare = at91rm9200_pcm_prepare, + .trigger = at91rm9200_pcm_trigger, + .pointer = at91rm9200_pcm_pointer, + .mmap = at91rm9200_pcm_mmap, +}; + +static int at91rm9200_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, + int stream) +{ + struct snd_pcm_substream *substream = pcm->streams[stream].substream; + struct snd_dma_buffer *buf = &substream->dma_buffer; + size_t size = at91rm9200_pcm_hardware.buffer_bytes_max; + + buf->dev.type = SNDRV_DMA_TYPE_DEV; + buf->dev.dev = pcm->card->dev; + buf->private_data = NULL; + buf->area = dma_alloc_writecombine(pcm->card->dev, size, + &buf->addr, GFP_KERNEL); + + DBG("preallocate_dma_buffer: area=%p, addr=%p, size=%d\n", + (void *) buf->area, + (void *) buf->addr, + size); + + if (!buf->area) + return -ENOMEM; + + buf->bytes = size; + return 0; +} + +static u64 at91rm9200_pcm_dmamask = 0xffffffff; + +static int at91rm9200_pcm_new(struct snd_card *card, + struct snd_soc_codec_dai *dai, struct snd_pcm *pcm) +{ + int ret = 0; + + if (!card->dev->dma_mask) + card->dev->dma_mask = &at91rm9200_pcm_dmamask; + if (!card->dev->coherent_dma_mask) + card->dev->coherent_dma_mask = 0xffffffff; + + if (dai->playback.channels_min) { + ret = at91rm9200_pcm_preallocate_dma_buffer(pcm, + SNDRV_PCM_STREAM_PLAYBACK); + if (ret) + goto out; + } + + if (dai->capture.channels_min) { + ret = at91rm9200_pcm_preallocate_dma_buffer(pcm, + SNDRV_PCM_STREAM_CAPTURE); + if (ret) + goto out; + } + out: + return ret; +} + +static void at91rm9200_pcm_free_dma_buffers(struct snd_pcm *pcm) +{ + struct snd_pcm_substream *substream; + struct snd_dma_buffer *buf; + int stream; + + for (stream = 0; stream < 2; stream++) { + substream = pcm->streams[stream].substream; + if (!substream) + continue; + + buf = &substream->dma_buffer; + if (!buf->area) + continue; + + dma_free_writecombine(pcm->card->dev, buf->bytes, + buf->area, buf->addr); + buf->area = NULL; + } +} + +static int at91rm9200_pcm_suspend(struct platform_device *pdev, + struct snd_soc_cpu_dai *dai) +{ + struct snd_pcm_runtime *runtime = dai->runtime; + struct at91rm9200_runtime_data *prtd; + at91rm9200_pcm_dma_params_t *params; + + if (!runtime) + return 0; + + prtd = runtime->private_data; + params = prtd->params; + + /* disable the PDC and save the PDC registers */ + + at91_ssc_write(params->pdc->ptcr, params->mask->pdc_disable); + + prtd->pdc_xpr_save = at91_ssc_read(params->pdc->xpr); + prtd->pdc_xcr_save = at91_ssc_read(params->pdc->xcr); + prtd->pdc_xnpr_save = at91_ssc_read(params->pdc->xnpr); + prtd->pdc_xncr_save = at91_ssc_read(params->pdc->xncr); + + return 0; +} + +static int at91rm9200_pcm_resume(struct platform_device *pdev, + struct snd_soc_cpu_dai *dai) +{ + struct snd_pcm_runtime *runtime = dai->runtime; + struct at91rm9200_runtime_data *prtd; + at91rm9200_pcm_dma_params_t *params; + + if (!runtime) + return 0; + + prtd = runtime->private_data; + params = prtd->params; + + /* restore the PDC registers and enable the PDC */ + at91_ssc_write(params->pdc->xpr, prtd->pdc_xpr_save); + at91_ssc_write(params->pdc->xcr, prtd->pdc_xcr_save); + at91_ssc_write(params->pdc->xnpr, prtd->pdc_xnpr_save); + at91_ssc_write(params->pdc->xncr, prtd->pdc_xncr_save); + + at91_ssc_write(params->pdc->ptcr, params->mask->pdc_enable); + return 0; +} + +struct snd_soc_platform at91rm9200_soc_platform = { + .name = "at91rm9200-audio", + .pcm_ops = &at91rm9200_pcm_ops, + .pcm_new = at91rm9200_pcm_new, + .pcm_free = at91rm9200_pcm_free_dma_buffers, + .suspend = at91rm9200_pcm_suspend, + .resume = at91rm9200_pcm_resume, +}; + +EXPORT_SYMBOL_GPL(at91rm9200_soc_platform); + +MODULE_AUTHOR("Frank Mandarino "); +MODULE_DESCRIPTION("Atmel AT91RM9200 PCM module"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/at91/at91rm9200-pcm.h b/sound/soc/at91/at91rm9200-pcm.h new file mode 100644 index 00000000000..65468f17377 --- /dev/null +++ b/sound/soc/at91/at91rm9200-pcm.h @@ -0,0 +1,75 @@ +/* + * at91rm9200-pcm.h - ALSA PCM interface for the Atmel AT91RM9200 chip + * + * Author: Frank Mandarino + * Endrelia Technologies Inc. + * Created: Mar 3, 2006 + * + * Based on pxa2xx-pcm.h by: + * + * Author: Nicolas Pitre + * Created: Nov 30, 2004 + * Copyright: MontaVista Software, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * Registers and status bits that are required by the PCM driver. + */ +struct at91rm9200_ssc_regs { + void __iomem *cr; /* SSC control */ + void __iomem *ier; /* SSC interrupt enable */ + void __iomem *idr; /* SSC interrupt disable */ +}; + +struct at91rm9200_pdc_regs { + void __iomem *xpr; /* PDC recv/trans pointer */ + void __iomem *xcr; /* PDC recv/trans counter */ + void __iomem *xnpr; /* PDC next recv/trans pointer */ + void __iomem *xncr; /* PDC next recv/trans counter */ + void __iomem *ptcr; /* PDC transfer control */ +}; + +struct at91rm9200_ssc_mask { + u32 ssc_enable; /* SSC recv/trans enable */ + u32 ssc_disable; /* SSC recv/trans disable */ + u32 ssc_endx; /* SSC ENDTX or ENDRX */ + u32 ssc_endbuf; /* SSC TXBUFE or RXBUFF */ + u32 pdc_enable; /* PDC recv/trans enable */ + u32 pdc_disable; /* PDC recv/trans disable */ +}; + + +/* + * This structure, shared between the PCM driver and the interface, + * contains all information required by the PCM driver to perform the + * PDC DMA operation. All fields except dma_intr_handler() are initialized + * by the interface. The dms_intr_handler() pointer is set by the PCM + * driver and called by the interface SSC interrupt handler if it is + * non-NULL. + */ +typedef struct { + char *name; /* stream identifier */ + int pdc_xfer_size; /* PDC counter increment in bytes */ + struct at91rm9200_ssc_regs *ssc; /* SSC register addresses */ + struct at91rm9200_pdc_regs *pdc; /* PDC receive/transmit registers */ + struct at91rm9200_ssc_mask *mask;/* SSC & PDC status bits */ + snd_pcm_substream_t *substream; + void (*dma_intr_handler)(u32, snd_pcm_substream_t *); +} at91rm9200_pcm_dma_params_t; + +extern struct snd_soc_cpu_dai at91rm9200_i2s_dai[3]; +extern struct snd_soc_platform at91rm9200_soc_platform; + + +/* + * SSC I/O helpers. + * E.g., at91_ssc_write(AT91_SSC(1) + AT91_SSC_CR, AT91_SSC_RXEN); + */ +#define AT91_SSC(x) (((x)==0) ? AT91_VA_BASE_SSC0 :\ + ((x)==1) ? AT91_VA_BASE_SSC1 : ((x)==2) ? AT91_VA_BASE_SSC2 : NULL) +#define at91_ssc_read(a) ((unsigned long) __raw_readl(a)) +#define at91_ssc_write(a,v) __raw_writel((v),(a)) -- cgit v1.2.3 From 0cbbec0984f10f216ed8332e0d39ac93cbe33a0b Mon Sep 17 00:00:00 2001 From: Frank Mandarino Date: Fri, 6 Oct 2006 18:40:25 +0200 Subject: [ALSA] ASoC AT91RM92000 I2S support This patch adds I2S support to the Atmel AT91RM9200 CPU. Features:- o Playback/Capture supported. o 16 Bit data size. o 8k - 48k sample rates. o ssc0, ssc1 and ssc2 supported as I2S ports. Signed-off-by: Frank Mandarino Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/at91/at91rm9200-i2s.c | 688 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 688 insertions(+) create mode 100644 sound/soc/at91/at91rm9200-i2s.c (limited to 'sound') diff --git a/sound/soc/at91/at91rm9200-i2s.c b/sound/soc/at91/at91rm9200-i2s.c new file mode 100644 index 00000000000..a74c5d85589 --- /dev/null +++ b/sound/soc/at91/at91rm9200-i2s.c @@ -0,0 +1,688 @@ +/* + * at91rm9200-i2s.c -- ALSA Soc Audio Layer Platform driver and DMA engine + * + * Author: Frank Mandarino + * Endrelia Technologies Inc. + * + * Based on pxa2xx Platform drivers by + * Liam Girdwood + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision history + * 3rd Mar 2006 Initial version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "at91rm9200-pcm.h" + +#if 0 +#define DBG(x...) printk(KERN_DEBUG "at91rm9200-i2s:" x) +#else +#define DBG(x...) +#endif + +#define AT91RM9200_I2S_DAIFMT \ + (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_NB_NF) + +#define AT91RM9200_I2S_DIR \ + (SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE) + +/* priv is (SSC_CMR.DIV << 16 | SSC_TCMR.PERIOD ) */ +static struct snd_soc_dai_mode at91rm9200_i2s[] = { + + /* 8k: BCLK = (MCLK/10) = (60MHz/50) = 1.2MHz */ + { AT91RM9200_I2S_DAIFMT, SND_SOC_DAITDM_LRDW(0,0), + SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_8000, AT91RM9200_I2S_DIR, + SND_SOC_DAI_BFS_DIV, 1500, SND_SOC_FSBD(10), (25 << 16 | 74) }, + + /* 16k: BCLK = (MCLK/3) ~= (60MHz/14) = 4.285714MHz */ + { AT91RM9200_I2S_DAIFMT, SND_SOC_DAITDM_LRDW(0,0), + SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_16000, AT91RM9200_I2S_DIR, + SND_SOC_DAI_BFS_DIV, 750, SND_SOC_FSBD(3) , (7 << 16 | 133) }, + + /* 24k: BCLK = (MCLK/10) = (60MHz/50) = 1.2MHz */ + { AT91RM9200_I2S_DAIFMT, SND_SOC_DAITDM_LRDW(0,0), + SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_22050, AT91RM9200_I2S_DIR, + SND_SOC_DAI_BFS_DIV, 500, SND_SOC_FSBD(10), (25 << 16 | 24) }, + + /* 48kHz: BCLK = (MCLK/5) ~= (60MHz/26) = 2.3076923MHz */ + { AT91RM9200_I2S_DAIFMT, SND_SOC_DAITDM_LRDW(0,0), + SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_48000, AT91RM9200_I2S_DIR, + SND_SOC_DAI_BFS_DIV, 250, SND_SOC_FSBD(5), (13 << 16 | 23) }, +}; + + +/* + * SSC registers required by the PCM DMA engine. + */ +static struct at91rm9200_ssc_regs ssc_reg[3] = { + { + .cr = (void __iomem *) (AT91_VA_BASE_SSC0 + AT91_SSC_CR), + .ier = (void __iomem *) (AT91_VA_BASE_SSC0 + AT91_SSC_IER), + .idr = (void __iomem *) (AT91_VA_BASE_SSC0 + AT91_SSC_IDR), + }, + { + .cr = (void __iomem *) (AT91_VA_BASE_SSC1 + AT91_SSC_CR), + .ier = (void __iomem *) (AT91_VA_BASE_SSC1 + AT91_SSC_IER), + .idr = (void __iomem *) (AT91_VA_BASE_SSC1 + AT91_SSC_IDR), + }, + { + .cr = (void __iomem *) (AT91_VA_BASE_SSC2 + AT91_SSC_CR), + .ier = (void __iomem *) (AT91_VA_BASE_SSC2 + AT91_SSC_IER), + .idr = (void __iomem *) (AT91_VA_BASE_SSC2 + AT91_SSC_IDR), + }, +}; + +static struct at91rm9200_pdc_regs pdc_tx_reg[3] = { + { + .xpr = (void __iomem *) (AT91_VA_BASE_SSC0 + AT91_PDC_TPR), + .xcr = (void __iomem *) (AT91_VA_BASE_SSC0 + AT91_PDC_TCR), + .xnpr = (void __iomem *) (AT91_VA_BASE_SSC0 + AT91_PDC_TNPR), + .xncr = (void __iomem *) (AT91_VA_BASE_SSC0 + AT91_PDC_TNCR), + .ptcr = (void __iomem *) (AT91_VA_BASE_SSC0 + AT91_PDC_PTCR), + }, + { + .xpr = (void __iomem *) (AT91_VA_BASE_SSC1 + AT91_PDC_TPR), + .xcr = (void __iomem *) (AT91_VA_BASE_SSC1 + AT91_PDC_TCR), + .xnpr = (void __iomem *) (AT91_VA_BASE_SSC1 + AT91_PDC_TNPR), + .xncr = (void __iomem *) (AT91_VA_BASE_SSC1 + AT91_PDC_TNCR), + .ptcr = (void __iomem *) (AT91_VA_BASE_SSC1 + AT91_PDC_PTCR), + }, + { + .xpr = (void __iomem *) (AT91_VA_BASE_SSC2 + AT91_PDC_TPR), + .xcr = (void __iomem *) (AT91_VA_BASE_SSC2 + AT91_PDC_TCR), + .xnpr = (void __iomem *) (AT91_VA_BASE_SSC2 + AT91_PDC_TNPR), + .xncr = (void __iomem *) (AT91_VA_BASE_SSC2 + AT91_PDC_TNCR), + .ptcr = (void __iomem *) (AT91_VA_BASE_SSC2 + AT91_PDC_PTCR), + }, +}; + +static struct at91rm9200_pdc_regs pdc_rx_reg[3] = { + { + .xpr = (void __iomem *) (AT91_VA_BASE_SSC0 + AT91_PDC_RPR), + .xcr = (void __iomem *) (AT91_VA_BASE_SSC0 + AT91_PDC_RCR), + .xnpr = (void __iomem *) (AT91_VA_BASE_SSC0 + AT91_PDC_RNPR), + .xncr = (void __iomem *) (AT91_VA_BASE_SSC0 + AT91_PDC_RNCR), + .ptcr = (void __iomem *) (AT91_VA_BASE_SSC0 + AT91_PDC_PTCR), + }, + { + .xpr = (void __iomem *) (AT91_VA_BASE_SSC1 + AT91_PDC_RPR), + .xcr = (void __iomem *) (AT91_VA_BASE_SSC1 + AT91_PDC_RCR), + .xnpr = (void __iomem *) (AT91_VA_BASE_SSC1 + AT91_PDC_RNPR), + .xncr = (void __iomem *) (AT91_VA_BASE_SSC1 + AT91_PDC_RNCR), + .ptcr = (void __iomem *) (AT91_VA_BASE_SSC1 + AT91_PDC_PTCR), + }, + { + .xpr = (void __iomem *) (AT91_VA_BASE_SSC2 + AT91_PDC_RPR), + .xcr = (void __iomem *) (AT91_VA_BASE_SSC2 + AT91_PDC_RCR), + .xnpr = (void __iomem *) (AT91_VA_BASE_SSC2 + AT91_PDC_RNPR), + .xncr = (void __iomem *) (AT91_VA_BASE_SSC2 + AT91_PDC_RNCR), + .ptcr = (void __iomem *) (AT91_VA_BASE_SSC2 + AT91_PDC_PTCR), + }, +}; + +/* + * SSC & PDC status bits for transmit and receive. + */ +static struct at91rm9200_ssc_mask ssc_tx_mask = { + .ssc_enable = AT91_SSC_TXEN, + .ssc_disable = AT91_SSC_TXDIS, + .ssc_endx = AT91_SSC_ENDTX, + .ssc_endbuf = AT91_SSC_TXBUFE, + .pdc_enable = AT91_PDC_TXTEN, + .pdc_disable = AT91_PDC_TXTDIS, +}; + +static struct at91rm9200_ssc_mask ssc_rx_mask = { + .ssc_enable = AT91_SSC_RXEN, + .ssc_disable = AT91_SSC_RXDIS, + .ssc_endx = AT91_SSC_ENDRX, + .ssc_endbuf = AT91_SSC_RXBUFF, + .pdc_enable = AT91_PDC_RXTEN, + .pdc_disable = AT91_PDC_RXTDIS, +}; + +/* + * A MUTEX is used to protect an SSC initialzed flag which allows + * the substream hw_params() call to initialize the SSC only if + * there are no other substreams open. If there are other + * substreams open, the hw_param() call can only check that + * it is using the same format and rate. + */ +static DECLARE_MUTEX(ssc0_mutex); +static DECLARE_MUTEX(ssc1_mutex); +static DECLARE_MUTEX(ssc2_mutex); + +/* + * DMA parameters. + */ +static at91rm9200_pcm_dma_params_t ssc_dma_params[3][2] = { + {{ + .name = "SSC0/I2S PCM Stereo out", + .ssc = &ssc_reg[0], + .pdc = &pdc_tx_reg[0], + .mask = &ssc_tx_mask, + }, + { + .name = "SSC0/I2S PCM Stereo in", + .ssc = &ssc_reg[0], + .pdc = &pdc_rx_reg[0], + .mask = &ssc_rx_mask, + }}, + {{ + .name = "SSC1/I2S PCM Stereo out", + .ssc = &ssc_reg[1], + .pdc = &pdc_tx_reg[1], + .mask = &ssc_tx_mask, + }, + { + .name = "SSC1/I2S PCM Stereo in", + .ssc = &ssc_reg[1], + .pdc = &pdc_rx_reg[1], + .mask = &ssc_rx_mask, + }}, + {{ + .name = "SSC2/I2S PCM Stereo out", + .ssc = &ssc_reg[2], + .pdc = &pdc_tx_reg[2], + .mask = &ssc_tx_mask, + }, + { + .name = "SSC1/I2S PCM Stereo in", + .ssc = &ssc_reg[2], + .pdc = &pdc_rx_reg[2], + .mask = &ssc_rx_mask, + }}, +}; + + +struct at91rm9200_ssc_state { + u32 ssc_cmr; + u32 ssc_rcmr; + u32 ssc_rfmr; + u32 ssc_tcmr; + u32 ssc_tfmr; + u32 ssc_sr; + u32 ssc_imr; +}; + +static struct at91rm9200_ssc_info { + char *name; + void __iomem *ssc_base; + u32 pid; + spinlock_t lock; /* lock for dir_mask */ + int dir_mask; /* 0=unused, 1=playback, 2=capture */ + struct semaphore *mutex; + int initialized; + int pcmfmt; + int rate; + at91rm9200_pcm_dma_params_t *dma_params[2]; + struct at91rm9200_ssc_state ssc_state; + +} ssc_info[3] = { + { + .name = "ssc0", + .ssc_base = (void __iomem *) AT91_VA_BASE_SSC0, + .pid = AT91_ID_SSC0, + .lock = SPIN_LOCK_UNLOCKED, + .dir_mask = 0, + .mutex = &ssc0_mutex, + .initialized = 0, + }, + { + .name = "ssc1", + .ssc_base = (void __iomem *) AT91_VA_BASE_SSC1, + .pid = AT91_ID_SSC1, + .lock = SPIN_LOCK_UNLOCKED, + .dir_mask = 0, + .mutex = &ssc1_mutex, + .initialized = 0, + }, + { + .name = "ssc2", + .ssc_base = (void __iomem *) AT91_VA_BASE_SSC2, + .pid = AT91_ID_SSC2, + .lock = SPIN_LOCK_UNLOCKED, + .dir_mask = 0, + .mutex = &ssc2_mutex, + .initialized = 0, + }, +}; + + +static int at91rm9200_i2s_interrupt(int irq, void *dev_id, + struct pt_regs *regs) +{ + struct at91rm9200_ssc_info *ssc_p = dev_id; + at91rm9200_pcm_dma_params_t *dma_params; + u32 ssc_sr; + int i; + + ssc_sr = at91_ssc_read(ssc_p->ssc_base + AT91_SSC_SR) + & at91_ssc_read(ssc_p->ssc_base + AT91_SSC_IMR); + + /* + * Loop through the substreams attached to this SSC. If + * a DMA-related interrupt occurred on that substream, call + * the DMA interrupt handler function, if one has been + * registered in the dma_params structure by the PCM driver. + */ + for (i = 0; i < ARRAY_SIZE(ssc_p->dma_params); i++) { + dma_params = ssc_p->dma_params[i]; + + if (dma_params != NULL && dma_params->dma_intr_handler != NULL && + (ssc_sr & + (dma_params->mask->ssc_endx | dma_params->mask->ssc_endbuf))) + + dma_params->dma_intr_handler(ssc_sr, dma_params->substream); + } + + return IRQ_HANDLED; +} + +static int at91rm9200_i2s_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct at91rm9200_ssc_info *ssc_p = &ssc_info[rtd->cpu_dai->id]; + int dir_mask; + + DBG("i2s_startup: SSC_SR=0x%08lx\n", + at91_ssc_read(ssc_p->ssc_base + AT91_SSC_SR)); + dir_mask = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0x1 : 0x2; + + spin_lock_irq(&ssc_p->lock); + if (ssc_p->dir_mask & dir_mask) { + spin_unlock_irq(&ssc_p->lock); + return -EBUSY; + } + ssc_p->dir_mask |= dir_mask; + spin_unlock_irq(&ssc_p->lock); + + return 0; +} + +static void at91rm9200_i2s_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct at91rm9200_ssc_info *ssc_p = &ssc_info[rtd->cpu_dai->id]; + at91rm9200_pcm_dma_params_t *dma_params = rtd->cpu_dai->dma_data; + int dir, dir_mask; + + dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1; + + if (dma_params != NULL) { + at91_ssc_write(dma_params->ssc->cr, dma_params->mask->ssc_disable); + DBG("%s disabled SSC_SR=0x%08lx\n", (dir ? "receive" : "transmit"), + at91_ssc_read(ssc_p->ssc_base + AT91_SSC_SR)); + + dma_params->substream = NULL; + ssc_p->dma_params[dir] = NULL; + } + + dir_mask = 1 << dir; + + spin_lock_irq(&ssc_p->lock); + ssc_p->dir_mask &= ~dir_mask; + if (!ssc_p->dir_mask) { + /* Shutdown the SSC clock. */ + DBG("Stopping pid %d clock\n", ssc_p->pid); + at91_sys_write(AT91_PMC_PCDR, ssc_p->pid); + + if (ssc_p->initialized) + free_irq(ssc_p->pid, ssc_p); + + /* Reset the SSC */ + at91_ssc_write(ssc_p->ssc_base + AT91_SSC_CR, AT91_SSC_SWRST); + + /* Force a re-init on the next hw_params() call. */ + ssc_p->initialized = 0; + } + spin_unlock_irq(&ssc_p->lock); +} + +#ifdef CONFIG_PM +static int at91rm9200_i2s_suspend(struct platform_device *pdev, + struct snd_soc_cpu_dai *dai) +{ + struct at91rm9200_ssc_info *ssc_p; + + if(!dai->active) + return 0; + + ssc_p = &ssc_info[dai->id]; + + /* Save the status register before disabling transmit and receive. */ + ssc_p->state->ssc_sr = at91_ssc_read(ssc_p->ssc_base + AT91_SSC_SR); + at91_ssc_write(ssc_p->ssc_base + + AT91_SSC_CR, AT91_SSC_TXDIS | AT91_SSC_RXDIS); + + /* Save the current interrupt mask, then disable unmasked interrupts. */ + ssc_p->state->ssc_imr = at91_ssc_read(ssc_p->ssc_base + AT91_SSC_IMR); + at91_ssc_write(ssc_p->ssc_base + AT91_SSC_IDR, ssc_p->state->ssc_imr); + + ssc_p->state->ssc_cmr = at91_ssc_read(ssc_p->ssc_base + AT91_SSC_CMR); + ssc_p->state->ssc_rcmr = at91_ssc_read(ssc_p->ssc_base + AT91_SSC_RCMR); + ssc_p->state->ssc_rfmr = at91_ssc_read(ssc_p->ssc_base + AT91_SSC_RCMR); + ssc_p->state->ssc_tcmr = at91_ssc_read(ssc_p->ssc_base + AT91_SSC_RCMR); + ssc_p->state->ssc_tfmr = at91_ssc_read(ssc_p->ssc_base + AT91_SSC_RCMR); + + return 0; +} + +static int at91rm9200_i2s_resume(struct platform_device *pdev, + struct snd_soc_cpu_dai *dai) +{ + struct at91rm9200_ssc_info *ssc_p; + u32 cr_mask; + + if(!dai->active) + return 0; + + ssc_p = &ssc_info[dai->id]; + + at91_ssc_write(ssc_p->ssc_base + AT91_SSC_RCMR, ssc_p->state->ssc_tfmr); + at91_ssc_write(ssc_p->ssc_base + AT91_SSC_RCMR, ssc_p->state->ssc_tcmr); + at91_ssc_write(ssc_p->ssc_base + AT91_SSC_RCMR, ssc_p->state->ssc_rfmr); + at91_ssc_write(ssc_p->ssc_base + AT91_SSC_RCMR, ssc_p->state->ssc_rcmr); + at91_ssc_write(ssc_p->ssc_base + AT91_SSC_CMR, ssc_p->state->ssc_cmr); + + at91_ssc_write(ssc_p->ssc_base + AT91_SSC_IER, ssc_p->state->ssc_imr); + + at91_ssc_write(ssc_p->ssc_base + AT91_SSC_CR, + ((ssc_p->state->ssc_sr & AT91_SSC_RXENA) ? AT91_SSC_RXEN : 0) | + ((ssc_p->state->ssc_sr & AT91_SSC_TXENA) ? AT91_SSC_TXEN : 0)); + + return 0; +} + +#else +#define at91rm9200_i2s_suspend NULL +#define at91rm9200_i2s_resume NULL +#endif + +static unsigned int at91rm9200_i2s_config_sysclk( + struct snd_soc_cpu_dai *iface, struct snd_soc_clock_info *info, + unsigned int clk) +{ + /* Currently, there is only support for USB (12Mhz) mode */ + if (clk != 12000000) + return 0; + return 12000000; +} + +static int at91rm9200_i2s_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + int id = rtd->cpu_dai->id; + struct at91rm9200_ssc_info *ssc_p = &ssc_info[id]; + at91rm9200_pcm_dma_params_t *dma_params; + unsigned int pcmfmt, rate; + int dir, channels, bits; + struct clk *mck_clk; + unsigned long bclk; + u32 div, period, tfmr, rfmr, tcmr, rcmr; + int ret; + + /* + * Currently, there is only one set of dma params for + * each direction. If more are added, this code will + * have to be changed to select the proper set. + */ + dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1; + + dma_params = &ssc_dma_params[id][dir]; + dma_params->substream = substream; + + ssc_p->dma_params[dir] = dma_params; + rtd->cpu_dai->dma_data = dma_params; + + rate = params_rate(params); + channels = params_channels(params); + + pcmfmt = rtd->cpu_dai->dai_runtime.pcmfmt; + switch (pcmfmt) { + case SNDRV_PCM_FMTBIT_S16_LE: + /* likely this is all we'll ever support, but ... */ + bits = 16; + dma_params->pdc_xfer_size = 2; + break; + default: + printk(KERN_WARNING "at91rm9200-i2s: unsupported format %x\n", + pcmfmt); + return -EINVAL; + } + + /* Don't allow both SSC substreams to initialize at the same time. */ + down(ssc_p->mutex); + + /* + * If this SSC is alreadly initialized, then this substream must use + * the same format and rate. + */ + if (ssc_p->initialized) { + if (pcmfmt != ssc_p->pcmfmt || rate != ssc_p->rate) { + printk(KERN_WARNING "at91rm9200-i2s: " + "incompatible substream in other direction\n"); + up(ssc_p->mutex); + return -EINVAL; + } + } else { + /* Enable PMC peripheral clock for this SSC */ + DBG("Starting pid %d clock\n", ssc_p->pid); + at91_sys_write(AT91_PMC_PCER, 1<pid); + + /* Reset the SSC */ + at91_ssc_write(ssc_p->ssc_base + AT91_SSC_CR, AT91_SSC_SWRST); + + at91_ssc_write(ssc_p->ssc_base + AT91_PDC_RPR, 0); + at91_ssc_write(ssc_p->ssc_base + AT91_PDC_RCR, 0); + at91_ssc_write(ssc_p->ssc_base + AT91_PDC_RNPR, 0); + at91_ssc_write(ssc_p->ssc_base + AT91_PDC_RNCR, 0); + at91_ssc_write(ssc_p->ssc_base + AT91_PDC_TPR, 0); + at91_ssc_write(ssc_p->ssc_base + AT91_PDC_TCR, 0); + at91_ssc_write(ssc_p->ssc_base + AT91_PDC_TNPR, 0); + at91_ssc_write(ssc_p->ssc_base + AT91_PDC_TNCR, 0); + + mck_clk = clk_get(NULL, "mck"); + + div = rtd->cpu_dai->dai_runtime.priv >> 16; + period = rtd->cpu_dai->dai_runtime.priv & 0xffff; + bclk = 60000000 / (2 * div); + + DBG("mck %ld fsbd %d bfs %d bfs_real %d bclk %ld div %d period %d\n", + clk_get_rate(mck_clk), + SND_SOC_FSBD(6), + rtd->cpu_dai->dai_runtime.bfs, + SND_SOC_FSBD_REAL(rtd->cpu_dai->dai_runtime.bfs), + bclk, + div, + period); + + clk_put(mck_clk); + + at91_ssc_write(ssc_p->ssc_base + AT91_SSC_CMR, div); + + /* + * Setup the TFMR and RFMR for the proper data format. + */ + tfmr = + (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE) + | (( 0 << 23) & AT91_SSC_FSDEN) + | (( AT91_SSC_FSOS_NEGATIVE ) & AT91_SSC_FSOS) + | (((bits - 1) << 16) & AT91_SSC_FSLEN) + | (((channels - 1) << 8) & AT91_SSC_DATNB) + | (( 1 << 7) & AT91_SSC_MSBF) + | (( 0 << 5) & AT91_SSC_DATDEF) + | (((bits - 1) << 0) & AT91_SSC_DATALEN); + DBG("SSC_TFMR=0x%08x\n", tfmr); + at91_ssc_write(ssc_p->ssc_base + AT91_SSC_TFMR, tfmr); + + rfmr = + (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE) + | (( AT91_SSC_FSOS_NONE ) & AT91_SSC_FSOS) + | (( 0 << 16) & AT91_SSC_FSLEN) + | (((channels - 1) << 8) & AT91_SSC_DATNB) + | (( 1 << 7) & AT91_SSC_MSBF) + | (( 0 << 5) & AT91_SSC_LOOP) + | (((bits - 1) << 0) & AT91_SSC_DATALEN); + + DBG("SSC_RFMR=0x%08x\n", rfmr); + at91_ssc_write(ssc_p->ssc_base + AT91_SSC_RFMR, rfmr); + + /* + * Setup the TCMR and RCMR to generate the proper BCLK + * and LRC signals. + */ + tcmr = + (( period << 24) & AT91_SSC_PERIOD) + | (( 1 << 16) & AT91_SSC_STTDLY) + | (( AT91_SSC_START_FALLING_RF ) & AT91_SSC_START) + | (( AT91_SSC_CKI_FALLING ) & AT91_SSC_CKI) + | (( AT91_SSC_CKO_CONTINUOUS ) & AT91_SSC_CKO) + | (( AT91_SSC_CKS_DIV ) & AT91_SSC_CKS); + + DBG("SSC_TCMR=0x%08x\n", tcmr); + at91_ssc_write(ssc_p->ssc_base + AT91_SSC_TCMR, tcmr); + + rcmr = + (( 0 << 24) & AT91_SSC_PERIOD) + | (( 1 << 16) & AT91_SSC_STTDLY) + | (( AT91_SSC_START_TX_RX ) & AT91_SSC_START) + | (( AT91_SSC_CK_RISING ) & AT91_SSC_CKI) + | (( AT91_SSC_CKO_NONE ) & AT91_SSC_CKO) + | (( AT91_SSC_CKS_CLOCK ) & AT91_SSC_CKS); + + DBG("SSC_RCMR=0x%08x\n", rcmr); + at91_ssc_write(ssc_p->ssc_base + AT91_SSC_RCMR, rcmr); + + if ((ret = request_irq(ssc_p->pid, at91rm9200_i2s_interrupt, + 0, ssc_p->name, ssc_p)) < 0) { + printk(KERN_WARNING "at91rm9200-i2s: request_irq failure\n"); + return ret; + } + + /* + * Save the current substream parameters in order to check + * that the substream in the opposite direction uses the + * same parameters. + */ + ssc_p->pcmfmt = pcmfmt; + ssc_p->rate = rate; + ssc_p->initialized = 1; + + DBG("hw_params: SSC initialized\n"); + } + + up(ssc_p->mutex); + + return 0; +} + + +static int at91rm9200_i2s_prepare(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + at91rm9200_pcm_dma_params_t *dma_params = rtd->cpu_dai->dma_data; + + at91_ssc_write(dma_params->ssc->cr, dma_params->mask->ssc_enable); + + DBG("%s enabled SSC_SR=0x%08lx\n", + substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? "transmit" : "receive", + at91_ssc_read(ssc_info[rtd->cpu_dai->id].ssc_base + AT91_SSC_SR)); + return 0; +} + + +struct snd_soc_cpu_dai at91rm9200_i2s_dai[] = { + { .name = "at91rm9200-ssc0/i2s", + .id = 0, + .type = SND_SOC_DAI_I2S, + .suspend = at91rm9200_i2s_suspend, + .resume = at91rm9200_i2s_resume, + .config_sysclk = at91rm9200_i2s_config_sysclk, + .playback = { + .channels_min = 1, + .channels_max = 2,}, + .capture = { + .channels_min = 1, + .channels_max = 2,}, + .ops = { + .startup = at91rm9200_i2s_startup, + .shutdown = at91rm9200_i2s_shutdown, + .prepare = at91rm9200_i2s_prepare, + .hw_params = at91rm9200_i2s_hw_params,}, + .caps = { + .mode = &at91rm9200_i2s[0], + .num_modes = ARRAY_SIZE(at91rm9200_i2s),}, + }, + { .name = "at91rm9200-ssc1/i2s", + .id = 1, + .type = SND_SOC_DAI_I2S, + .suspend = at91rm9200_i2s_suspend, + .resume = at91rm9200_i2s_resume, + .config_sysclk = at91rm9200_i2s_config_sysclk, + .playback = { + .channels_min = 1, + .channels_max = 2,}, + .capture = { + .channels_min = 1, + .channels_max = 2,}, + .ops = { + .startup = at91rm9200_i2s_startup, + .shutdown = at91rm9200_i2s_shutdown, + .prepare = at91rm9200_i2s_prepare, + .hw_params = at91rm9200_i2s_hw_params,}, + .caps = { + .mode = &at91rm9200_i2s[0], + .num_modes = ARRAY_SIZE(at91rm9200_i2s),}, + }, + { .name = "at91rm9200-ssc2/i2s", + .id = 2, + .type = SND_SOC_DAI_I2S, + .suspend = at91rm9200_i2s_suspend, + .resume = at91rm9200_i2s_resume, + .config_sysclk = at91rm9200_i2s_config_sysclk, + .playback = { + .channels_min = 1, + .channels_max = 2,}, + .capture = { + .channels_min = 1, + .channels_max = 2,}, + .ops = { + .startup = at91rm9200_i2s_startup, + .shutdown = at91rm9200_i2s_shutdown, + .prepare = at91rm9200_i2s_prepare, + .hw_params = at91rm9200_i2s_hw_params,}, + .caps = { + .mode = &at91rm9200_i2s[0], + .num_modes = ARRAY_SIZE(at91rm9200_i2s),}, + }, +}; + +EXPORT_SYMBOL_GPL(at91rm9200_i2s_dai); + +/* Module information */ +MODULE_AUTHOR("Frank Mandarino, fmandarino@endrelia.com, www.endrelia.com"); +MODULE_DESCRIPTION("AT91RM9200 I2S ASoC Interface"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From b41bf38a4323a32ec4890c74818c4a3d2661fe6c Mon Sep 17 00:00:00 2001 From: Frank Mandarino Date: Fri, 6 Oct 2006 18:41:10 +0200 Subject: [ALSA] ASoC AT91RM92000 eti_b1 machine support This patch adds support for the Endrelia ETI_B1 machine using the WM8731 codec and the AT91RM9200 platform. Signed-off-by: Frank Mandarino Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/at91/eti_b1_wm8731.c | 230 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 230 insertions(+) create mode 100644 sound/soc/at91/eti_b1_wm8731.c (limited to 'sound') diff --git a/sound/soc/at91/eti_b1_wm8731.c b/sound/soc/at91/eti_b1_wm8731.c new file mode 100644 index 00000000000..d955cacf2d0 --- /dev/null +++ b/sound/soc/at91/eti_b1_wm8731.c @@ -0,0 +1,230 @@ +/* + * eti_b1_wm8731 -- SoC audio for Endrelia ETI_B1. + * + * Author: Frank Mandarino + * Endrelia Technologies Inc. + * Created: Mar 29, 2006 + * + * Based on corgi.c by: + * + * Copyright 2005 Wolfson Microelectronics PLC. + * Copyright 2005 Openedhand Ltd. + * + * Authors: Liam Girdwood + * Richard Purdie + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision history + * 30th Nov 2005 Initial version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "../codecs/wm8731.h" +#include "at91rm9200-pcm.h" + +#if 0 +#define DBG(x...) printk(KERN_INFO "eti_b1_wm8731:" x) +#else +#define DBG(x...) +#endif + +static struct clk *pck1_clk; +static struct clk *pllb_clk; + +static int eti_b1_startup(snd_pcm_substream_t *substream) +{ + /* Start PCK1 clock. */ + clk_enable(pck1_clk); + DBG("pck1 started\n"); + + return 0; +} + +static void eti_b1_shutdown(snd_pcm_substream_t *substream) +{ + /* Stop PCK1 clock. */ + clk_disable(pck1_clk); + DBG("pck1 stopped\n"); +} + +static struct snd_soc_ops eti_b1_ops = { + .startup = eti_b1_startup, + .shutdown = eti_b1_shutdown, +}; + + +static const struct snd_soc_dapm_widget eti_b1_dapm_widgets[] = { + SND_SOC_DAPM_MIC("Int Mic", NULL), + SND_SOC_DAPM_SPK("Ext Spk", NULL), +}; + +static const char *intercon[][3] = { + + /* speaker connected to LHPOUT */ + {"Ext Spk", NULL, "LHPOUT"}, + + /* mic is connected to Mic Jack, with WM8731 Mic Bias */ + {"MICIN", NULL, "Mic Bias"}, + {"Mic Bias", NULL, "Int Mic"}, + + /* terminator */ + {NULL, NULL, NULL}, +}; + +/* + * Logic for a wm8731 as connected on a Endrelia ETI-B1 board. + */ +static int eti_b1_wm8731_init(struct snd_soc_codec *codec) +{ + int i; + + DBG("eti_b1_wm8731_init() called\n"); + + /* Add specific widgets */ + for(i = 0; i < ARRAY_SIZE(eti_b1_dapm_widgets); i++) { + snd_soc_dapm_new_control(codec, &eti_b1_dapm_widgets[i]); + } + + /* Set up specific audio path interconnects */ + for(i = 0; intercon[i][0] != NULL; i++) { + snd_soc_dapm_connect_input(codec, intercon[i][0], + intercon[i][1], intercon[i][2]); + } + + /* not connected */ + snd_soc_dapm_set_endpoint(codec, "RLINEIN", 0); + snd_soc_dapm_set_endpoint(codec, "LLINEIN", 0); + + /* always connected */ + snd_soc_dapm_set_endpoint(codec, "Int Mic", 1); + snd_soc_dapm_set_endpoint(codec, "Ext Spk", 1); + + snd_soc_dapm_sync_endpoints(codec); + + return 0; +} + +unsigned int eti_b1_config_sysclk(struct snd_soc_pcm_runtime *rtd, + struct snd_soc_clock_info *info) +{ + if(info->bclk_master & SND_SOC_DAIFMT_CBS_CFS) { + return rtd->codec_dai->config_sysclk(rtd->codec_dai, info, 12000000); + } + return 0; +} + +static struct snd_soc_dai_link eti_b1_dai = { + .name = "WM8731", + .stream_name = "WM8731", + .cpu_dai = &at91rm9200_i2s_dai[1], + .codec_dai = &wm8731_dai, + .init = eti_b1_wm8731_init, + .config_sysclk = eti_b1_config_sysclk, +}; + +static struct snd_soc_machine snd_soc_machine_eti_b1 = { + .name = "ETI_B1", + .dai_link = &eti_b1_dai, + .num_links = 1, + .ops = &eti_b1_ops, +}; + +static struct wm8731_setup_data eti_b1_wm8731_setup = { + .i2c_address = 0x1a, +}; + +static struct snd_soc_device eti_b1_snd_devdata = { + .machine = &snd_soc_machine_eti_b1, + .platform = &at91rm9200_soc_platform, + .codec_dev = &soc_codec_dev_wm8731, + .codec_data = &eti_b1_wm8731_setup, +}; + +static struct platform_device *eti_b1_snd_device; + +static int __init eti_b1_init(void) +{ + int ret; + u32 ssc_pio_lines; + + eti_b1_snd_device = platform_device_alloc("soc-audio", -1); + if (!eti_b1_snd_device) + return -ENOMEM; + + platform_set_drvdata(eti_b1_snd_device, &eti_b1_snd_devdata); + eti_b1_snd_devdata.dev = &eti_b1_snd_device->dev; + + ret = platform_device_add(eti_b1_snd_device); + if (ret) { + platform_device_put(eti_b1_snd_device); + return ret; + } + + ssc_pio_lines = AT91_PB6_TF1 | AT91_PB7_TK1 | AT91_PB8_TD1 + | AT91_PB9_RD1 /* | AT91_PB10_RK1 | AT91_PB11_RF1 */; + + /* Reset all PIO registers and assign lines to peripheral A */ + at91_sys_write(AT91_PIOB + PIO_PDR, ssc_pio_lines); + at91_sys_write(AT91_PIOB + PIO_ODR, ssc_pio_lines); + at91_sys_write(AT91_PIOB + PIO_IFDR, ssc_pio_lines); + at91_sys_write(AT91_PIOB + PIO_CODR, ssc_pio_lines); + at91_sys_write(AT91_PIOB + PIO_IDR, ssc_pio_lines); + at91_sys_write(AT91_PIOB + PIO_MDDR, ssc_pio_lines); + at91_sys_write(AT91_PIOB + PIO_PUDR, ssc_pio_lines); + at91_sys_write(AT91_PIOB + PIO_ASR, ssc_pio_lines); + at91_sys_write(AT91_PIOB + PIO_OWDR, ssc_pio_lines); + + /* + * Set PCK1 parent to PLLB and its rate to 12 Mhz. + */ + pllb_clk = clk_get(NULL, "pllb"); + pck1_clk = clk_get(NULL, "pck1"); + + clk_set_parent(pck1_clk, pllb_clk); + clk_set_rate(pck1_clk, 12000000); + + DBG("MCLK rate %luHz\n", clk_get_rate(pck1_clk)); + + /* assign the GPIO pin to PCK1 */ + at91_set_B_periph(AT91_PIN_PA24, 0); + + return ret; +} + +static void __exit eti_b1_exit(void) +{ + clk_put(pck1_clk); + clk_put(pllb_clk); + + platform_device_unregister(eti_b1_snd_device); +} + +module_init(eti_b1_init); +module_exit(eti_b1_exit); + +/* Module information */ +MODULE_AUTHOR("Frank Mandarino "); +MODULE_DESCRIPTION("ALSA SoC ETI-B1-WM8731"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 8dafc0fb49b903c4e7262b2622bef8342345c700 Mon Sep 17 00:00:00 2001 From: Frank Mandarino Date: Fri, 6 Oct 2006 18:41:42 +0200 Subject: [ALSA] ASoC AT91RM92000 build This patch adds a Makefile and Kconfig to build the ASoC AT91RM9200 support. Signed-off-by: Frank Mandarino Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/Kconfig | 6 ++++++ sound/soc/Makefile | 2 +- sound/soc/at91/Kconfig | 24 ++++++++++++++++++++++++ sound/soc/at91/Makefile | 11 +++++++++++ 4 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 sound/soc/at91/Kconfig create mode 100644 sound/soc/at91/Makefile (limited to 'sound') diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index 288bad30b21..e7dab5bdc6b 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -19,6 +19,12 @@ config SND_SOC This SoC audio support can also be built as a module. If so, the module will be called snd-soc-core. +# All the supported Soc's +menu "SoC Platforms" +depends on SND_SOC +source "sound/soc/at91/Kconfig" +endmenu + # Supported codecs source "sound/soc/codecs/Kconfig" diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 3dd4f20c5ec..3e12a1654c4 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -1,4 +1,4 @@ snd-soc-core-objs := soc-core.o soc-dapm.o obj-$(CONFIG_SND_SOC) += snd-soc-core.o -obj-$(CONFIG_SND_SOC) += codecs/ +obj-$(CONFIG_SND_SOC) += codecs/ at91/ diff --git a/sound/soc/at91/Kconfig b/sound/soc/at91/Kconfig new file mode 100644 index 00000000000..d38ba9203bd --- /dev/null +++ b/sound/soc/at91/Kconfig @@ -0,0 +1,24 @@ +menu "SoC Audio for the Atmel AT91" + +config SND_AT91_SOC + tristate "SoC Audio for the Atmel AT91 System-on-Chip" + depends on ARCH_AT91 && SND + select SND_PCM + help + Say Y or M if you want to add support for codecs attached to + the AT91 SSC interface. You will also need + to select the audio interfaces to support below. + +config SND_AT91_SOC_I2S + tristate + +config SND_AT91_SOC_ETI_B1_WM8731 + tristate "SoC I2S Audio support for Endrelia ETI-B1 board" + depends on SND_AT91_SOC && MACH_ETI_B1 + select SND_AT91_SOC_I2S + select SND_SOC_WM8731 + help + Say Y if you want to add support for SoC audio on Endrelia + ETI-B1 board. + +endmenu diff --git a/sound/soc/at91/Makefile b/sound/soc/at91/Makefile new file mode 100644 index 00000000000..eb12ea2d194 --- /dev/null +++ b/sound/soc/at91/Makefile @@ -0,0 +1,11 @@ +# AT91 Platform Support +snd-soc-at91-objs := at91rm9200-pcm.o +snd-soc-at91-i2s-objs := at91rm9200-i2s.o + +obj-$(CONFIG_SND_AT91_SOC) += snd-soc-at91.o +obj-$(CONFIG_SND_AT91_SOC_I2S) += snd-soc-at91-i2s.o + +# AT91 Machine Support +snd-soc-eti-b1-wm8731-objs := eti_b1_wm8731.o + +obj-$(CONFIG_SND_AT91_SOC_ETI_B1_WM8731) += snd-soc-eti-b1-wm8731.o -- cgit v1.2.3 From e117483e3e713c6411968afea825daa1133bc28d Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 9 Oct 2006 08:14:58 +0200 Subject: [ALSA] soc-core: fix multi-line string literal Properly quote a string that had an embedded newline. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela --- sound/soc/soc-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index e841ad46c75..eba0a101253 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -575,8 +575,8 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) } dbg("asoc: %s <-> %s info:\n", rtd->codec_dai->name, rtd->cpu_dai->name); - dbg("asoc: rate mask 0x%x \nasoc: min ch %d max ch %d\n - asoc: min rate %d max rate %d\n", + dbg("asoc: rate mask 0x%x \nasoc: min ch %d max ch %d\n" + "asoc: min rate %d max rate %d\n", runtime->hw.rates, runtime->hw.channels_min, runtime->hw.channels_max, runtime->hw.rate_min, runtime->hw.rate_max); -- cgit v1.2.3 From 8a89876bc108cacebbe5cc47049c162a8a143b26 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 9 Oct 2006 08:17:48 +0200 Subject: [ALSA] pci: select FW_LOADER instead of depending on it Let the AudioScience, Echoaudio and Riptide drivers select FW_LOADER instead of depending on it so that they can be configured without having to enable FW_LOADER manually. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela --- sound/pci/Kconfig | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'sound') diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 8a6b1803c76..ae82024f87c 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -236,7 +236,7 @@ config SND_CS5535AUDIO config SND_DARLA20 tristate "(Echoaudio) Darla20" depends on SND - depends on FW_LOADER + select FW_LOADER select SND_PCM help Say 'Y' or 'M' to include support for Echoaudio Darla. @@ -247,7 +247,7 @@ config SND_DARLA20 config SND_GINA20 tristate "(Echoaudio) Gina20" depends on SND - depends on FW_LOADER + select FW_LOADER select SND_PCM help Say 'Y' or 'M' to include support for Echoaudio Gina. @@ -258,7 +258,7 @@ config SND_GINA20 config SND_LAYLA20 tristate "(Echoaudio) Layla20" depends on SND - depends on FW_LOADER + select FW_LOADER select SND_RAWMIDI select SND_PCM help @@ -270,7 +270,7 @@ config SND_LAYLA20 config SND_DARLA24 tristate "(Echoaudio) Darla24" depends on SND - depends on FW_LOADER + select FW_LOADER select SND_PCM help Say 'Y' or 'M' to include support for Echoaudio Darla24. @@ -281,7 +281,7 @@ config SND_DARLA24 config SND_GINA24 tristate "(Echoaudio) Gina24" depends on SND - depends on FW_LOADER + select FW_LOADER select SND_PCM help Say 'Y' or 'M' to include support for Echoaudio Gina24. @@ -292,7 +292,7 @@ config SND_GINA24 config SND_LAYLA24 tristate "(Echoaudio) Layla24" depends on SND - depends on FW_LOADER + select FW_LOADER select SND_RAWMIDI select SND_PCM help @@ -304,7 +304,7 @@ config SND_LAYLA24 config SND_MONA tristate "(Echoaudio) Mona" depends on SND - depends on FW_LOADER + select FW_LOADER select SND_RAWMIDI select SND_PCM help @@ -316,7 +316,7 @@ config SND_MONA config SND_MIA tristate "(Echoaudio) Mia" depends on SND - depends on FW_LOADER + select FW_LOADER select SND_RAWMIDI select SND_PCM help @@ -328,7 +328,7 @@ config SND_MIA config SND_ECHO3G tristate "(Echoaudio) 3G cards" depends on SND - depends on FW_LOADER + select FW_LOADER select SND_RAWMIDI select SND_PCM help @@ -340,7 +340,7 @@ config SND_ECHO3G config SND_INDIGO tristate "(Echoaudio) Indigo" depends on SND - depends on FW_LOADER + select FW_LOADER select SND_PCM help Say 'Y' or 'M' to include support for Echoaudio Indigo. @@ -351,7 +351,7 @@ config SND_INDIGO config SND_INDIGOIO tristate "(Echoaudio) Indigo IO" depends on SND - depends on FW_LOADER + select FW_LOADER select SND_PCM help Say 'Y' or 'M' to include support for Echoaudio Indigo IO. @@ -362,7 +362,7 @@ config SND_INDIGOIO config SND_INDIGODJ tristate "(Echoaudio) Indigo DJ" depends on SND - depends on FW_LOADER + select FW_LOADER select SND_PCM help Say 'Y' or 'M' to include support for Echoaudio Indigo DJ. @@ -629,7 +629,7 @@ config SND_PCXHR config SND_RIPTIDE tristate "Conexant Riptide" depends on SND - depends on FW_LOADER + select FW_LOADER select SND_OPL3_LIB select SND_MPU401_UART select SND_AC97_CODEC -- cgit v1.2.3 From 9bf5f8aa222e0f943bd5037207628ad70b729576 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 9 Oct 2006 08:18:26 +0200 Subject: [ALSA] emu10k1: select FW_LOADER Let the emu10k1 driver select FW_LOADER because the new Emu1010 support requires it. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela --- sound/pci/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index ae82024f87c..ee37de940c6 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -373,6 +373,7 @@ config SND_INDIGODJ config SND_EMU10K1 tristate "Emu10k1 (SB Live!, Audigy, E-mu APS)" depends on SND + select FW_LOADER select SND_HWDEP select SND_RAWMIDI select SND_AC97_CODEC -- cgit v1.2.3 From 6add0f4242fc52a97a92fca99a39f35298c2b50b Mon Sep 17 00:00:00 2001 From: Remy Bruno Date: Mon, 9 Oct 2006 15:52:01 +0200 Subject: [ALSA] hdsp: support for mixer matrix of RME9632 rev 152 Added the support for mixer matrix of RME9632 rev 152. Signed-off-by: Remy Bruno Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/rme9652/hdsp.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index 6383987b460..849ffe4aa5c 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -598,6 +598,7 @@ static int hdsp_playback_to_output_key (struct hdsp *hdsp, int in, int out) return (64 * out) + (32 + (in)); case 0x96: case 0x97: + case 0x98: return (32 * out) + (16 + (in)); default: return (52 * out) + (26 + (in)); @@ -611,6 +612,7 @@ static int hdsp_input_to_output_key (struct hdsp *hdsp, int in, int out) return (64 * out) + in; case 0x96: case 0x97: + case 0x98: return (32 * out) + in; default: return (52 * out) + in; -- cgit v1.2.3 From 9148cc502752b12051760e6c5ba5daaea3367360 Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Mon, 9 Oct 2006 23:08:00 +0100 Subject: [ALSA] snd_emu10k1: Added support for 14dB Attenuation PADS on DACs and ADCs. Signed-off-by: James Courtier-Dutton Signed-off-by: Jaroslav Kysela --- sound/pci/emu10k1/emu10k1_main.c | 29 +++--- sound/pci/emu10k1/emumixer.c | 216 ++++++++++++++++++++++++++++++--------- 2 files changed, 187 insertions(+), 58 deletions(-) (limited to 'sound') diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 09c4db8495b..341a2775d28 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -725,25 +725,27 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu) snd_emu1010_fpga_read(emu, EMU_HANA_OPTICAL_TYPE, &tmp ); /* ADAT input. */ snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, 0x01 ); - snd_emu1010_fpga_read(emu, EMU_HANA_DOCK_PADS, &tmp ); + snd_emu1010_fpga_read(emu, EMU_HANA_ADC_PADS, &tmp ); /* Set no attenuation on Audio Dock pads. */ - snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PADS, 0x00 ); + snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, 0x00 ); + emu->emu1010.adc_pads = 0x00; snd_emu1010_fpga_read(emu, EMU_HANA_DOCK_MISC, &tmp ); /* Unmute Audio dock DACs, Headphone source DAC-4. */ snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_MISC, 0x30 ); snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12 ); - snd_emu1010_fpga_read(emu, EMU_HANA_UNKNOWN13, &tmp ); - /* Unknown. */ - snd_emu1010_fpga_write(emu, EMU_HANA_UNKNOWN13, 0x0f ); + snd_emu1010_fpga_read(emu, EMU_HANA_DAC_PADS, &tmp ); + /* DAC PADs. */ + snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, 0x0f ); + emu->emu1010.dac_pads = 0x0f; snd_emu1010_fpga_read(emu, EMU_HANA_DOCK_MISC, &tmp ); snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_MISC, 0x30 ); snd_emu1010_fpga_read(emu, EMU_HANA_SPDIF_MODE, &tmp ); /* SPDIF Format. Set Consumer mode, 24bit, copy enable */ snd_emu1010_fpga_write(emu, EMU_HANA_SPDIF_MODE, 0x10 ); /* MIDI routing */ - snd_emu1010_fpga_write(emu, EMU_HANA_MIDI, 0x19 ); + snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, 0x19 ); /* Unknown. */ - snd_emu1010_fpga_write(emu, EMU_HANA_UNKNOWN12, 0x0c ); + snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, 0x0c ); /* snd_emu1010_fpga_write(emu, 0x09, 0x0f ); // IRQ Enable: All on */ /* IRQ Enable: All off */ snd_emu1010_fpga_write(emu, EMU_HANA_IRQ_ENABLE, 0x00 ); @@ -880,10 +882,10 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu) /* Initial boot complete. Now patches */ snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &tmp ); - snd_emu1010_fpga_write(emu, EMU_HANA_MIDI, 0x19 ); /* MIDI Route */ - snd_emu1010_fpga_write(emu, EMU_HANA_UNKNOWN12, 0x0c ); /* Unknown */ - snd_emu1010_fpga_write(emu, EMU_HANA_MIDI, 0x19 ); /* MIDI Route */ - snd_emu1010_fpga_write(emu, EMU_HANA_UNKNOWN12, 0x0c ); /* Unknown */ + snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, 0x19 ); /* MIDI Route */ + snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, 0x0c ); /* Unknown */ + snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, 0x19 ); /* MIDI Route */ + snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, 0x0c ); /* Unknown */ snd_emu1010_fpga_read(emu, EMU_HANA_SPDIF_MODE, &tmp ); snd_emu1010_fpga_write(emu, EMU_HANA_SPDIF_MODE, 0x10 ); /* SPDIF Format spdif (or 0x11 for aes/ebu) */ @@ -902,7 +904,6 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu) if ((err = snd_emu1010_load_firmware(emu, dock_filename)) != 0) { return err; } - snd_printk(KERN_INFO "emu1010: Audio Dock Firmware loaded\n"); snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0 ); snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, ® ); snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_IRQ_STATUS=0x%x\n",reg); @@ -915,6 +916,10 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu) return 0; return -ENODEV; } + snd_printk(KERN_INFO "emu1010: Audio Dock Firmware loaded\n"); + snd_emu1010_fpga_read(emu, EMU_DOCK_MAJOR_REV, &tmp ); + snd_emu1010_fpga_read(emu, EMU_DOCK_MINOR_REV, &tmp2 ); + snd_printk("Audio Dock ver:%d.%d\n",tmp ,tmp2); } #if 0 snd_emu1010_fpga_link_dst_src_write(emu, diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index c8176dc8142..2edf92a4f06 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c @@ -315,30 +315,30 @@ static int snd_emu1010_input_source_put(struct snd_kcontrol *kcontrol, } static struct snd_kcontrol_new snd_emu1010_output_enum_ctls[] __devinitdata = { - EMU1010_SOURCE_OUTPUT("Playback Dock DAC1 Left", 0), - EMU1010_SOURCE_OUTPUT("Playback Dock DAC1 Right", 1), - EMU1010_SOURCE_OUTPUT("Playback Dock DAC2 Left", 2), - EMU1010_SOURCE_OUTPUT("Playback Dock DAC2 Right", 3), - EMU1010_SOURCE_OUTPUT("Playback Dock DAC3 Left", 4), - EMU1010_SOURCE_OUTPUT("Playback Dock DAC3 Right", 5), - EMU1010_SOURCE_OUTPUT("Playback Dock DAC4 Left", 6), - EMU1010_SOURCE_OUTPUT("Playback Dock DAC4 Right", 7), - EMU1010_SOURCE_OUTPUT("Playback Dock Phones Left", 8), - EMU1010_SOURCE_OUTPUT("Playback Dock Phones Right", 9), - EMU1010_SOURCE_OUTPUT("Playback Dock SPDIF Left", 0xa), - EMU1010_SOURCE_OUTPUT("Playback Dock SPDIF Right", 0xb), - EMU1010_SOURCE_OUTPUT("Playback 1010 SPDIF Left", 0xc), - EMU1010_SOURCE_OUTPUT("Playback 1010 SPDIF Right", 0xd), - EMU1010_SOURCE_OUTPUT("Playback 0202 DAC Left", 0xe), - EMU1010_SOURCE_OUTPUT("Playback 0202 DAC Right", 0xf), - EMU1010_SOURCE_OUTPUT("Playback 1010 ADAT 0", 0x10), - EMU1010_SOURCE_OUTPUT("Playback 1010 ADAT 1", 0x11), - EMU1010_SOURCE_OUTPUT("Playback 1010 ADAT 2", 0x12), - EMU1010_SOURCE_OUTPUT("Playback 1010 ADAT 3", 0x13), - EMU1010_SOURCE_OUTPUT("Playback 1010 ADAT 4", 0x14), - EMU1010_SOURCE_OUTPUT("Playback 1010 ADAT 5", 0x15), - EMU1010_SOURCE_OUTPUT("Playback 1010 ADAT 6", 0x16), - EMU1010_SOURCE_OUTPUT("Playback 1010 ADAT 7", 0x17), + EMU1010_SOURCE_OUTPUT("Dock DAC1 Left Playback Switch", 0), + EMU1010_SOURCE_OUTPUT("Dock DAC1 Right Playback Switch", 1), + EMU1010_SOURCE_OUTPUT("Dock DAC2 Left Playback Switch", 2), + EMU1010_SOURCE_OUTPUT("Dock DAC2 Right Playback Switch", 3), + EMU1010_SOURCE_OUTPUT("Dock DAC3 Left Playback Switch", 4), + EMU1010_SOURCE_OUTPUT("Dock DAC3 Right Playback Switch", 5), + EMU1010_SOURCE_OUTPUT("Dock DAC4 Left Playback Switch", 6), + EMU1010_SOURCE_OUTPUT("Dock DAC4 Right Playback Switch", 7), + EMU1010_SOURCE_OUTPUT("Dock Phones Left Playback Switch", 8), + EMU1010_SOURCE_OUTPUT("Dock Phones Right Playback Switch", 9), + EMU1010_SOURCE_OUTPUT("Dock SPDIF Left Playback Switch", 0xa), + EMU1010_SOURCE_OUTPUT("Dock SPDIF Right Playback Switch", 0xb), + EMU1010_SOURCE_OUTPUT("1010 SPDIF Left Playback Switch", 0xc), + EMU1010_SOURCE_OUTPUT("1010 SPDIF Right Playback Switch", 0xd), + EMU1010_SOURCE_OUTPUT("0202 DAC Left Playback Switch", 0xe), + EMU1010_SOURCE_OUTPUT("0202 DAC Right Playback Switch", 0xf), + EMU1010_SOURCE_OUTPUT("1010 ADAT 0 Playback Switch", 0x10), + EMU1010_SOURCE_OUTPUT("1010 ADAT 1 Playback Switch", 0x11), + EMU1010_SOURCE_OUTPUT("1010 ADAT 2 Playback Switch", 0x12), + EMU1010_SOURCE_OUTPUT("1010 ADAT 3 Playback Switch", 0x13), + EMU1010_SOURCE_OUTPUT("1010 ADAT 4 Playback Switch", 0x14), + EMU1010_SOURCE_OUTPUT("1010 ADAT 5 Playback Switch", 0x15), + EMU1010_SOURCE_OUTPUT("1010 ADAT 6 Playback Switch", 0x16), + EMU1010_SOURCE_OUTPUT("1010 ADAT 7 Playback Switch", 0x17), }; #define EMU1010_SOURCE_INPUT(xname,chid) \ @@ -352,28 +352,142 @@ static struct snd_kcontrol_new snd_emu1010_output_enum_ctls[] __devinitdata = { } static struct snd_kcontrol_new snd_emu1010_input_enum_ctls[] __devinitdata = { - EMU1010_SOURCE_INPUT("DSP 0 CAPTURE ENUM", 0), - EMU1010_SOURCE_INPUT("DSP 1 CAPTURE ENUM", 1), - EMU1010_SOURCE_INPUT("DSP 2 CAPTURE ENUM", 2), - EMU1010_SOURCE_INPUT("DSP 3 CAPTURE ENUM", 3), - EMU1010_SOURCE_INPUT("DSP 4 CAPTURE ENUM", 4), - EMU1010_SOURCE_INPUT("DSP 5 CAPTURE ENUM", 5), - EMU1010_SOURCE_INPUT("DSP 6 CAPTURE ENUM", 6), - EMU1010_SOURCE_INPUT("DSP 7 CAPTURE ENUM", 7), - EMU1010_SOURCE_INPUT("DSP 8 CAPTURE ENUM", 8), - EMU1010_SOURCE_INPUT("DSP 9 CAPTURE ENUM", 9), - EMU1010_SOURCE_INPUT("DSP A CAPTURE ENUM", 0xa), - EMU1010_SOURCE_INPUT("DSP B CAPTURE ENUM", 0xb), - EMU1010_SOURCE_INPUT("DSP C CAPTURE ENUM", 0xc), - EMU1010_SOURCE_INPUT("DSP D CAPTURE ENUM", 0xd), - EMU1010_SOURCE_INPUT("DSP E CAPTURE ENUM", 0xe), - EMU1010_SOURCE_INPUT("DSP F CAPTURE ENUM", 0xf), - EMU1010_SOURCE_INPUT("DSP 10 CAPTURE ENUM", 0x10), - EMU1010_SOURCE_INPUT("DSP 11 CAPTURE ENUM", 0x11), - EMU1010_SOURCE_INPUT("DSP 12 CAPTURE ENUM", 0x12), - EMU1010_SOURCE_INPUT("DSP 13 CAPTURE ENUM", 0x13), - EMU1010_SOURCE_INPUT("DSP 14 CAPTURE ENUM", 0x14), - EMU1010_SOURCE_INPUT("DSP 15 CAPTURE ENUM", 0x15), + EMU1010_SOURCE_INPUT("DSP 0 Capture Switch", 0), + EMU1010_SOURCE_INPUT("DSP 1 Capture Switch", 1), + EMU1010_SOURCE_INPUT("DSP 2 Capture Switch", 2), + EMU1010_SOURCE_INPUT("DSP 3 Capture Switch", 3), + EMU1010_SOURCE_INPUT("DSP 4 Capture Switch", 4), + EMU1010_SOURCE_INPUT("DSP 5 Capture Switch", 5), + EMU1010_SOURCE_INPUT("DSP 6 Capture Switch", 6), + EMU1010_SOURCE_INPUT("DSP 7 Capture Switch", 7), + EMU1010_SOURCE_INPUT("DSP 8 Capture Switch", 8), + EMU1010_SOURCE_INPUT("DSP 9 Capture Switch", 9), + EMU1010_SOURCE_INPUT("DSP A Capture Switch", 0xa), + EMU1010_SOURCE_INPUT("DSP B Capture Switch", 0xb), + EMU1010_SOURCE_INPUT("DSP C Capture Switch", 0xc), + EMU1010_SOURCE_INPUT("DSP D Capture Switch", 0xd), + EMU1010_SOURCE_INPUT("DSP E Capture Switch", 0xe), + EMU1010_SOURCE_INPUT("DSP F Capture Switch", 0xf), + EMU1010_SOURCE_INPUT("DSP 10 Capture Switch", 0x10), + EMU1010_SOURCE_INPUT("DSP 11 Capture Switch", 0x11), + EMU1010_SOURCE_INPUT("DSP 12 Capture Switch", 0x12), + EMU1010_SOURCE_INPUT("DSP 13 Capture Switch", 0x13), + EMU1010_SOURCE_INPUT("DSP 14 Capture Switch", 0x14), + EMU1010_SOURCE_INPUT("DSP 15 Capture Switch", 0x15), +}; + + + + +static int snd_emu1010_adc_pads_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int snd_emu1010_adc_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); + unsigned int mask = kcontrol->private_value & 0xff; + ucontrol->value.integer.value[0] = (emu->emu1010.adc_pads & mask) ? 1 : 0; + return 0; +} + +static int snd_emu1010_adc_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); + unsigned int mask = kcontrol->private_value & 0xff; + unsigned int val, cache; + val = ucontrol->value.integer.value[0]; + cache = emu->emu1010.adc_pads; + if (val == 1) + cache = cache | mask; + else + cache = cache & ~mask; + if (cache != emu->emu1010.adc_pads) { + snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, cache ); + emu->emu1010.adc_pads = cache; + } + + return 0; +} + + + +#define EMU1010_ADC_PADS(xname,chid) \ +{ \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ + .info = snd_emu1010_adc_pads_info, \ + .get = snd_emu1010_adc_pads_get, \ + .put = snd_emu1010_adc_pads_put, \ + .private_value = chid \ +} + +static struct snd_kcontrol_new snd_emu1010_adc_pads[] __devinitdata = { + EMU1010_ADC_PADS("ADC1 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD1), + EMU1010_ADC_PADS("ADC2 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD2), + EMU1010_ADC_PADS("ADC3 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD3), + EMU1010_ADC_PADS("ADC1 14dB PAD 0202 Capture Switch", EMU_HANA_0202_ADC_PAD1), +}; + +static int snd_emu1010_dac_pads_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int snd_emu1010_dac_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); + unsigned int mask = kcontrol->private_value & 0xff; + ucontrol->value.integer.value[0] = (emu->emu1010.dac_pads & mask) ? 1 : 0; + return 0; +} + +static int snd_emu1010_dac_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); + unsigned int mask = kcontrol->private_value & 0xff; + unsigned int val, cache; + val = ucontrol->value.integer.value[0]; + cache = emu->emu1010.dac_pads; + if (val == 1) + cache = cache | mask; + else + cache = cache & ~mask; + if (cache != emu->emu1010.dac_pads) { + snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, cache ); + emu->emu1010.dac_pads = cache; + } + + return 0; +} + + + +#define EMU1010_DAC_PADS(xname,chid) \ +{ \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ + .info = snd_emu1010_dac_pads_info, \ + .get = snd_emu1010_dac_pads_get, \ + .put = snd_emu1010_dac_pads_put, \ + .private_value = chid \ +} + +static struct snd_kcontrol_new snd_emu1010_dac_pads[] __devinitdata = { + EMU1010_DAC_PADS("DAC1 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD1), + EMU1010_DAC_PADS("DAC2 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD2), + EMU1010_DAC_PADS("DAC3 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD3), + EMU1010_DAC_PADS("DAC4 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD4), + EMU1010_DAC_PADS("DAC1 0202 14dB PAD Playback Switch", EMU_HANA_0202_DAC_PAD1), }; #if 0 @@ -1367,6 +1481,16 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, if (err < 0) return err; } + for (i = 0; i < ARRAY_SIZE(snd_emu1010_adc_pads); i++) { + err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_adc_pads[i], emu)); + if (err < 0) + return err; + } + for (i = 0; i < ARRAY_SIZE(snd_emu1010_dac_pads); i++) { + err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_dac_pads[i], emu)); + if (err < 0) + return err; + } } return 0; -- cgit v1.2.3 From 0f71e8b98506252db22a0c4fcfecb0aadcf393cc Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 10 Oct 2006 15:59:46 +0200 Subject: [ALSA] Fix irq handler in soc/at91/at91rm9200-i2s.c Fixed the irq handler in soc/at91-at91rm9200-i2s.c to follow the new style without pt_regs. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/at91/at91rm9200-i2s.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/at91/at91rm9200-i2s.c b/sound/soc/at91/at91rm9200-i2s.c index a74c5d85589..044a774b430 100644 --- a/sound/soc/at91/at91rm9200-i2s.c +++ b/sound/soc/at91/at91rm9200-i2s.c @@ -270,8 +270,7 @@ static struct at91rm9200_ssc_info { }; -static int at91rm9200_i2s_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t at91rm9200_i2s_interrupt(int irq, void *dev_id) { struct at91rm9200_ssc_info *ssc_p = dev_id; at91rm9200_pcm_dma_params_t *dma_params; -- cgit v1.2.3 From b0dbdaea55d55c05be972cd2a040acfa073b0509 Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Tue, 10 Oct 2006 18:08:45 +0100 Subject: [ALSA] snd-emu10k1: Add emu1010 internal clock rate control for 44100 or 48000. Signed-off-by: James Courtier-Dutton Signed-off-by: Jaroslav Kysela --- sound/pci/emu10k1/emu10k1_main.c | 1 + sound/pci/emu10k1/emumixer.c | 92 ++++++++++++++++++++++++++++++++++++++++ sound/pci/emu10k1/emupcm.c | 28 +++++++++--- 3 files changed, 115 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 341a2775d28..711e819e4a0 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -1014,6 +1014,7 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu) /* Word Clock source, Internal 48kHz x1 */ snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K ); //snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_4X ); + emu->emu1010.internal_clock = 1; /* 48000 */ snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12);/* Set LEDs on Audio Dock */ snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, 0x1); /* Unmute all */ //snd_emu1010_fpga_write(emu, 0x7, 0x0); /* Mute all */ diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index 2edf92a4f06..a118fee11cd 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c @@ -35,6 +35,7 @@ #include #include #include +#include #define AC97_ID_STAC9758 0x83847658 @@ -490,6 +491,94 @@ static struct snd_kcontrol_new snd_emu1010_dac_pads[] __devinitdata = { EMU1010_DAC_PADS("DAC1 0202 14dB PAD Playback Switch", EMU_HANA_0202_DAC_PAD1), }; + +static int snd_emu1010_internal_clock_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + static char *texts[2] = { + "44100", "48000" + }; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 2; + if (uinfo->value.enumerated.item > 1) + uinfo->value.enumerated.item = 1; + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + return 0; +} + +static int snd_emu1010_internal_clock_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); + + ucontrol->value.enumerated.item[0] = emu->emu1010.internal_clock; + return 0; +} + +static int snd_emu1010_internal_clock_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); + unsigned int val; + int change = 0; + + val = ucontrol->value.enumerated.item[0] ; + change = (emu->emu1010.internal_clock != val); + if (change) { + emu->emu1010.internal_clock = val; + switch (val) { + case 0: + /* 44100 */ + /* Mute all */ + snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); + /* Default fallback clock 48kHz */ + snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_44_1K ); + /* Word Clock source, Internal 44.1kHz x1 */ + snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, + EMU_HANA_WCLOCK_INT_44_1K | EMU_HANA_WCLOCK_1X ); + /* Set LEDs on Audio Dock */ + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, + EMU_HANA_DOCK_LEDS_2_44K | EMU_HANA_DOCK_LEDS_2_LOCK ); + /* Allow DLL to settle */ + udelay(10000); + /* Unmute all */ + snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); + break; + case 1: + /* 48000 */ + /* Mute all */ + snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); + /* Default fallback clock 48kHz */ + snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K ); + /* Word Clock source, Internal 48kHz x1 */ + snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, + EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_1X ); + /* Set LEDs on Audio Dock */ + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, + EMU_HANA_DOCK_LEDS_2_48K | EMU_HANA_DOCK_LEDS_2_LOCK ); + /* Allow DLL to settle */ + udelay(10000); + /* Unmute all */ + snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); + break; + } + } + return change; +} + +static struct snd_kcontrol_new snd_emu1010_internal_clock = +{ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Clock Internal Rate", + .count = 1, + .info = snd_emu1010_internal_clock_info, + .get = snd_emu1010_internal_clock_get, + .put = snd_emu1010_internal_clock_put +}; + #if 0 static int snd_audigy_spdif_output_rate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -1491,6 +1580,9 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, if (err < 0) return err; } + err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_internal_clock, emu)); + if (err < 0) + return err; } return 0; diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index 44d098ac86d..ab4f5df5241 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c @@ -358,7 +358,10 @@ static void snd_emu10k1_pcm_init_voice(struct snd_emu10k1 *emu, snd_emu10k1_ptr_write(emu, PTRX, voice, (send_amount[0] << 8) | send_amount[1]); snd_emu10k1_ptr_write(emu, DSL, voice, end_addr | (send_amount[3] << 24)); snd_emu10k1_ptr_write(emu, PSST, voice, start_addr | (send_amount[2] << 24)); - pitch_target = emu10k1_calc_pitch_target(runtime->rate); + if (emu->card_capabilities->emu1010) + pitch_target = PITCH_48000; /* Disable interpolators on emu1010 card */ + else + pitch_target = emu10k1_calc_pitch_target(runtime->rate); if (extra) snd_emu10k1_ptr_write(emu, CCCA, voice, start_addr | emu10k1_select_interprom(pitch_target) | @@ -698,7 +701,10 @@ static void snd_emu10k1_playback_trigger_voice(struct snd_emu10k1 *emu, struct s voice = evoice->number; pitch = snd_emu10k1_rate_to_pitch(runtime->rate) >> 8; - pitch_target = emu10k1_calc_pitch_target(runtime->rate); + if (emu->card_capabilities->emu1010) + pitch_target = PITCH_48000; /* Disable interpolators on emu1010 card */ + else + pitch_target = emu10k1_calc_pitch_target(runtime->rate); snd_emu10k1_ptr_write(emu, PTRX_PITCHTARGET, voice, pitch_target); if (master || evoice->epcm->type == PLAYBACK_EFX) snd_emu10k1_ptr_write(emu, CPF_CURRENTPITCH, voice, pitch_target); @@ -1247,10 +1253,20 @@ static int snd_emu10k1_capture_efx_open(struct snd_pcm_substream *substream) * for 192kHz 24bit, one has 2 channels */ #if 1 - /* For 48kHz */ - runtime->hw.rates = SNDRV_PCM_RATE_48000; - runtime->hw.rate_min = runtime->hw.rate_max = 48000; - runtime->hw.channels_min = runtime->hw.channels_max = 8; + switch (emu->emu1010.internal_clock) { + case 0: + /* For 44.1kHz */ + runtime->hw.rates = SNDRV_PCM_RATE_44100; + runtime->hw.rate_min = runtime->hw.rate_max = 44100; + runtime->hw.channels_min = runtime->hw.channels_max = 8; + break; + case 1: + /* For 48kHz */ + runtime->hw.rates = SNDRV_PCM_RATE_48000; + runtime->hw.rate_min = runtime->hw.rate_max = 48000; + runtime->hw.channels_min = runtime->hw.channels_max = 8; + break; + }; #endif #if 0 /* For 96kHz */ -- cgit v1.2.3 From e40a0b2e9d73c69e6b9e5d55eb56696f81fbf802 Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Tue, 10 Oct 2006 18:44:29 +0100 Subject: [ALSA] snd-emu10k1: emu1010: replace long udelay with msleep. Signed-off-by: James Courtier-Dutton Signed-off-by: Jaroslav Kysela --- sound/pci/emu10k1/emumixer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index a118fee11cd..5ceb8dd5cb3 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c @@ -542,7 +542,7 @@ static int snd_emu1010_internal_clock_put(struct snd_kcontrol *kcontrol, snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, EMU_HANA_DOCK_LEDS_2_44K | EMU_HANA_DOCK_LEDS_2_LOCK ); /* Allow DLL to settle */ - udelay(10000); + msleep(10); /* Unmute all */ snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); break; @@ -559,7 +559,7 @@ static int snd_emu1010_internal_clock_put(struct snd_kcontrol *kcontrol, snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, EMU_HANA_DOCK_LEDS_2_48K | EMU_HANA_DOCK_LEDS_2_LOCK ); /* Allow DLL to settle */ - udelay(10000); + msleep(10); /* Unmute all */ snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); break; -- cgit v1.2.3 From 102fa9060e114a53628a6594034b6ecf624dffc6 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Wed, 11 Oct 2006 12:05:59 +0200 Subject: [ALSA] ymfpci: add request_firmware() Load the DSP and controller microcode using request_firmware(), if possible, instead of using the built-in firmware. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela --- sound/pci/Kconfig | 1 + sound/pci/ymfpci/ymfpci_image.h | 6 +- sound/pci/ymfpci/ymfpci_main.c | 125 ++++++++++++++++++++++++++++++++-------- 3 files changed, 106 insertions(+), 26 deletions(-) (limited to 'sound') diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index ee37de940c6..fcbf9673db6 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -735,6 +735,7 @@ config SND_VX222 config SND_YMFPCI tristate "Yamaha YMF724/740/744/754" depends on SND + select FW_LOADER select SND_OPL3_LIB select SND_MPU401_UART select SND_AC97_CODEC diff --git a/sound/pci/ymfpci/ymfpci_image.h b/sound/pci/ymfpci/ymfpci_image.h index 1b074699166..112f2fff6c8 100644 --- a/sound/pci/ymfpci/ymfpci_image.h +++ b/sound/pci/ymfpci/ymfpci_image.h @@ -1,7 +1,7 @@ #ifndef _HWMCODE_ #define _HWMCODE_ -static unsigned long DspInst[YDSXG_DSPLENGTH / 4] = { +static u32 DspInst[YDSXG_DSPLENGTH / 4] = { 0x00000081, 0x000001a4, 0x0000000a, 0x0000002f, 0x00080253, 0x01800317, 0x0000407b, 0x0000843f, 0x0001483c, 0x0001943c, 0x0005d83c, 0x00001c3c, @@ -12,7 +12,7 @@ static unsigned long DspInst[YDSXG_DSPLENGTH / 4] = { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }; -static unsigned long CntrlInst[YDSXG_CTRLLENGTH / 4] = { +static u32 CntrlInst[YDSXG_CTRLLENGTH / 4] = { 0x000007, 0x240007, 0x0C0007, 0x1C0007, 0x060007, 0x700002, 0x000020, 0x030040, 0x007104, 0x004286, 0x030040, 0x000F0D, @@ -791,7 +791,7 @@ static unsigned long CntrlInst[YDSXG_CTRLLENGTH / 4] = { // 04/09 creat // 04/12 stop nise fix // 06/21 WorkingOff timming -static unsigned long CntrlInst1E[YDSXG_CTRLLENGTH / 4] = { +static u32 CntrlInst1E[YDSXG_CTRLLENGTH / 4] = { 0x000007, 0x240007, 0x0C0007, 0x1C0007, 0x060007, 0x700002, 0x000020, 0x030040, 0x007104, 0x004286, 0x030040, 0x000F0D, diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c index 7881944a195..5bde816cd5c 100644 --- a/sound/pci/ymfpci/ymfpci_main.c +++ b/sound/pci/ymfpci/ymfpci_main.c @@ -2,12 +2,6 @@ * Copyright (c) by Jaroslav Kysela * Routines for control of YMF724/740/744/754 chips * - * BUGS: - * -- - * - * TODO: - * -- - * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -26,6 +20,7 @@ #include #include +#include #include #include #include @@ -42,10 +37,7 @@ #include #include - -/* - * constants - */ +#include /* * common I/O routines @@ -1971,13 +1963,94 @@ static void snd_ymfpci_disable_dsp(struct snd_ymfpci *chip) } } +#define FIRMWARE_IN_THE_KERNEL + +#ifdef FIRMWARE_IN_THE_KERNEL + #include "ymfpci_image.h" +static struct firmware snd_ymfpci_dsp_microcode = { + .size = YDSXG_DSPLENGTH, + .data = (u8 *)DspInst, +}; +static struct firmware snd_ymfpci_controller_microcode = { + .size = YDSXG_CTRLLENGTH, + .data = (u8 *)CntrlInst, +}; +static struct firmware snd_ymfpci_controller_1e_microcode = { + .size = YDSXG_CTRLLENGTH, + .data = (u8 *)CntrlInst1E, +}; +#endif + +#ifdef __LITTLE_ENDIAN +static inline void snd_ymfpci_convert_from_le(const struct firmware *fw) { } +#else +static void snd_ymfpci_convert_from_le(const struct firmware *fw) +{ + int i; + u32 *data = (u32 *)fw->data; + + for (i = 0; i < fw->size / 4; ++i) + le32_to_cpus(&data[i]); +} +#endif + +static int snd_ymfpci_request_firmware(struct snd_ymfpci *chip) +{ + int err, is_1e; + const char *name; + + err = request_firmware(&chip->dsp_microcode, "yamaha/ds1_dsp.fw", + &chip->pci->dev); + if (err >= 0) { + if (chip->dsp_microcode->size == YDSXG_DSPLENGTH) + snd_ymfpci_convert_from_le(chip->dsp_microcode); + else { + snd_printk(KERN_ERR "DSP microcode has wrong size\n"); + err = -EINVAL; + } + } + if (err < 0) { +#ifdef FIRMWARE_IN_THE_KERNEL + chip->dsp_microcode = &snd_ymfpci_dsp_microcode; +#else + return err; +#endif + } + is_1e = chip->device_id == PCI_DEVICE_ID_YAMAHA_724F || + chip->device_id == PCI_DEVICE_ID_YAMAHA_740C || + chip->device_id == PCI_DEVICE_ID_YAMAHA_744 || + chip->device_id == PCI_DEVICE_ID_YAMAHA_754; + name = is_1e ? "yamaha/ds1e_ctrl.fw" : "yamaha/ds1_ctrl.fw"; + err = request_firmware(&chip->controller_microcode, name, + &chip->pci->dev); + if (err >= 0) { + if (chip->controller_microcode->size == YDSXG_CTRLLENGTH) + snd_ymfpci_convert_from_le(chip->controller_microcode); + else { + snd_printk(KERN_ERR "controller microcode" + " has wrong size\n"); + err = -EINVAL; + } + } + if (err < 0) { +#ifdef FIRMWARE_IN_THE_KERNEL + chip->controller_microcode = + is_1e ? &snd_ymfpci_controller_1e_microcode + : &snd_ymfpci_controller_microcode; +#else + return err; +#endif + } + return 0; +} + static void snd_ymfpci_download_image(struct snd_ymfpci *chip) { int i; u16 ctrl; - unsigned long *inst; + u32 *inst; snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0x00000000); snd_ymfpci_disable_dsp(chip); @@ -1992,21 +2065,12 @@ static void snd_ymfpci_download_image(struct snd_ymfpci *chip) snd_ymfpci_writew(chip, YDSXGR_GLOBALCTRL, ctrl & ~0x0007); /* setup DSP instruction code */ + inst = (u32 *)chip->dsp_microcode->data; for (i = 0; i < YDSXG_DSPLENGTH / 4; i++) - snd_ymfpci_writel(chip, YDSXGR_DSPINSTRAM + (i << 2), DspInst[i]); + snd_ymfpci_writel(chip, YDSXGR_DSPINSTRAM + (i << 2), inst[i]); /* setup control instruction code */ - switch (chip->device_id) { - case PCI_DEVICE_ID_YAMAHA_724F: - case PCI_DEVICE_ID_YAMAHA_740C: - case PCI_DEVICE_ID_YAMAHA_744: - case PCI_DEVICE_ID_YAMAHA_754: - inst = CntrlInst1E; - break; - default: - inst = CntrlInst; - break; - } + inst = (u32 *)chip->controller_microcode->data; for (i = 0; i < YDSXG_CTRLLENGTH / 4; i++) snd_ymfpci_writel(chip, YDSXGR_CTRLINSTRAM + (i << 2), inst[i]); @@ -2160,6 +2224,15 @@ static int snd_ymfpci_free(struct snd_ymfpci *chip) pci_write_config_word(chip->pci, 0x40, chip->old_legacy_ctrl); pci_disable_device(chip->pci); +#ifdef FIRMWARE_IN_THE_KERNEL + if (chip->dsp_microcode != &snd_ymfpci_dsp_microcode) +#endif + release_firmware(chip->dsp_microcode); +#ifdef FIRMWARE_IN_THE_KERNEL + if (chip->controller_microcode != &snd_ymfpci_controller_microcode && + chip->controller_microcode != &snd_ymfpci_controller_1e_microcode) +#endif + release_firmware(chip->controller_microcode); kfree(chip); return 0; } @@ -2315,6 +2388,12 @@ int __devinit snd_ymfpci_create(struct snd_card *card, return -EIO; } + err = snd_ymfpci_request_firmware(chip); + if (err < 0) { + snd_printk(KERN_ERR "firmware request failed: %d\n", err); + snd_ymfpci_free(chip); + return err; + } snd_ymfpci_download_image(chip); udelay(100); /* seems we need a delay after downloading image.. */ -- cgit v1.2.3 From f11a96d5cd94202479e603f9dfaff6e92f342135 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Thu, 12 Oct 2006 14:26:55 +0200 Subject: [ALSA] ASoC pxa2xx DMA support This patch adds pxa2xx ASoC DMA audio support. It's based on sound/arm/pxa-pcm.c by Nicolas Pitre with the following differences. o Modified driver structure to use ASoC core PCM callbacks and data structures. o Registration with ASoC core. From: Liam Girdwood Signed-off-by: Nicolas Pitre Signed-off-by: Richard Purdie Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/pxa/pxa2xx-pcm.c | 363 +++++++++++++++++++++++++++++++++++++++++++++ sound/soc/pxa/pxa2xx-pcm.h | 48 ++++++ 2 files changed, 411 insertions(+) create mode 100644 sound/soc/pxa/pxa2xx-pcm.c create mode 100644 sound/soc/pxa/pxa2xx-pcm.h (limited to 'sound') diff --git a/sound/soc/pxa/pxa2xx-pcm.c b/sound/soc/pxa/pxa2xx-pcm.c new file mode 100644 index 00000000000..ff32f892287 --- /dev/null +++ b/sound/soc/pxa/pxa2xx-pcm.c @@ -0,0 +1,363 @@ +/* + * linux/sound/arm/pxa2xx-pcm.c -- ALSA PCM interface for the Intel PXA2xx chip + * + * Author: Nicolas Pitre + * Created: Nov 30, 2004 + * Copyright: (C) 2004 MontaVista Software, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "pxa2xx-pcm.h" + +static const struct snd_pcm_hardware pxa2xx_pcm_hardware = { + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_RESUME, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, + .period_bytes_min = 32, + .period_bytes_max = 8192 - 32, + .periods_min = 1, + .periods_max = PAGE_SIZE/sizeof(pxa_dma_desc), + .buffer_bytes_max = 128 * 1024, + .fifo_size = 32, +}; + +struct pxa2xx_runtime_data { + int dma_ch; + struct pxa2xx_pcm_dma_params *params; + pxa_dma_desc *dma_desc_array; + dma_addr_t dma_desc_array_phys; +}; + +static void pxa2xx_pcm_dma_irq(int dma_ch, void *dev_id) +{ + struct snd_pcm_substream *substream = dev_id; + struct pxa2xx_runtime_data *prtd = substream->runtime->private_data; + int dcsr; + + dcsr = DCSR(dma_ch); + DCSR(dma_ch) = dcsr & ~DCSR_STOPIRQEN; + + if (dcsr & DCSR_ENDINTR) { + snd_pcm_period_elapsed(substream); + } else { + printk( KERN_ERR "%s: DMA error on channel %d (DCSR=%#x)\n", + prtd->params->name, dma_ch, dcsr ); + } +} + +static int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct pxa2xx_runtime_data *prtd = runtime->private_data; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct pxa2xx_pcm_dma_params *dma = rtd->cpu_dai->dma_data; + size_t totsize = params_buffer_bytes(params); + size_t period = params_period_bytes(params); + pxa_dma_desc *dma_desc; + dma_addr_t dma_buff_phys, next_desc_phys; + int ret; + + /* this may get called several times by oss emulation + * with different params */ + if (prtd->params == NULL) { + prtd->params = dma; + ret = pxa_request_dma(prtd->params->name, DMA_PRIO_LOW, + pxa2xx_pcm_dma_irq, substream); + if (ret < 0) + return ret; + prtd->dma_ch = ret; + } else if (prtd->params != dma) { + pxa_free_dma(prtd->dma_ch); + prtd->params = dma; + ret = pxa_request_dma(prtd->params->name, DMA_PRIO_LOW, + pxa2xx_pcm_dma_irq, substream); + if (ret < 0) + return ret; + prtd->dma_ch = ret; + } + + snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); + runtime->dma_bytes = totsize; + + dma_desc = prtd->dma_desc_array; + next_desc_phys = prtd->dma_desc_array_phys; + dma_buff_phys = runtime->dma_addr; + do { + next_desc_phys += sizeof(pxa_dma_desc); + dma_desc->ddadr = next_desc_phys; + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + dma_desc->dsadr = dma_buff_phys; + dma_desc->dtadr = prtd->params->dev_addr; + } else { + dma_desc->dsadr = prtd->params->dev_addr; + dma_desc->dtadr = dma_buff_phys; + } + if (period > totsize) + period = totsize; + dma_desc->dcmd = prtd->params->dcmd | period | DCMD_ENDIRQEN; + dma_desc++; + dma_buff_phys += period; + } while (totsize -= period); + dma_desc[-1].ddadr = prtd->dma_desc_array_phys; + + return 0; +} + +static int pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream) +{ + struct pxa2xx_runtime_data *prtd = substream->runtime->private_data; + + if (prtd && prtd->params) + *prtd->params->drcmr = 0; + + if (prtd->dma_ch) { + snd_pcm_set_runtime_buffer(substream, NULL); + pxa_free_dma(prtd->dma_ch); + prtd->dma_ch = 0; + } + + return 0; +} + +static int pxa2xx_pcm_prepare(struct snd_pcm_substream *substream) +{ + struct pxa2xx_runtime_data *prtd = substream->runtime->private_data; + + DCSR(prtd->dma_ch) &= ~DCSR_RUN; + DCSR(prtd->dma_ch) = 0; + DCMD(prtd->dma_ch) = 0; + *prtd->params->drcmr = prtd->dma_ch | DRCMR_MAPVLD; + + return 0; +} + +static int pxa2xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct pxa2xx_runtime_data *prtd = substream->runtime->private_data; + int ret = 0; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + DDADR(prtd->dma_ch) = prtd->dma_desc_array_phys; + DCSR(prtd->dma_ch) = DCSR_RUN; + break; + + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + DCSR(prtd->dma_ch) &= ~DCSR_RUN; + break; + + case SNDRV_PCM_TRIGGER_RESUME: + DCSR(prtd->dma_ch) |= DCSR_RUN; + break; + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + DDADR(prtd->dma_ch) = prtd->dma_desc_array_phys; + DCSR(prtd->dma_ch) |= DCSR_RUN; + break; + + default: + ret = -EINVAL; + } + + return ret; +} + +static snd_pcm_uframes_t +pxa2xx_pcm_pointer(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct pxa2xx_runtime_data *prtd = runtime->private_data; + + dma_addr_t ptr = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? + DSADR(prtd->dma_ch) : DTADR(prtd->dma_ch); + snd_pcm_uframes_t x = bytes_to_frames(runtime, ptr - runtime->dma_addr); + + if (x == runtime->buffer_size) + x = 0; + return x; +} + +static int pxa2xx_pcm_open(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct pxa2xx_runtime_data *prtd; + int ret; + + snd_soc_set_runtime_hwparams(substream, &pxa2xx_pcm_hardware); + + /* + * For mysterious reasons (and despite what the manual says) + * playback samples are lost if the DMA count is not a multiple + * of the DMA burst size. Let's add a rule to enforce that. + */ + ret = snd_pcm_hw_constraint_step(runtime, 0, + SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32); + if (ret) + goto out; + + ret = snd_pcm_hw_constraint_step(runtime, 0, + SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32); + if (ret) + goto out; + + prtd = kzalloc(sizeof(struct pxa2xx_runtime_data), GFP_KERNEL); + if (prtd == NULL) { + ret = -ENOMEM; + goto out; + } + + prtd->dma_desc_array = + dma_alloc_writecombine(substream->pcm->card->dev, PAGE_SIZE, + &prtd->dma_desc_array_phys, GFP_KERNEL); + if (!prtd->dma_desc_array) { + ret = -ENOMEM; + goto err1; + } + + runtime->private_data = prtd; + return 0; + + err1: + kfree(prtd); + out: + return ret; +} + +static int pxa2xx_pcm_close(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct pxa2xx_runtime_data *prtd = runtime->private_data; + + dma_free_writecombine(substream->pcm->card->dev, PAGE_SIZE, + prtd->dma_desc_array, prtd->dma_desc_array_phys); + kfree(prtd); + return 0; +} + +static int pxa2xx_pcm_mmap(struct snd_pcm_substream *substream, + struct vm_area_struct *vma) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + return dma_mmap_writecombine(substream->pcm->card->dev, vma, + runtime->dma_area, + runtime->dma_addr, + runtime->dma_bytes); +} + +struct snd_pcm_ops pxa2xx_pcm_ops = { + .open = pxa2xx_pcm_open, + .close = pxa2xx_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = pxa2xx_pcm_hw_params, + .hw_free = pxa2xx_pcm_hw_free, + .prepare = pxa2xx_pcm_prepare, + .trigger = pxa2xx_pcm_trigger, + .pointer = pxa2xx_pcm_pointer, + .mmap = pxa2xx_pcm_mmap, +}; + +static int pxa2xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) +{ + struct snd_pcm_substream *substream = pcm->streams[stream].substream; + struct snd_dma_buffer *buf = &substream->dma_buffer; + size_t size = pxa2xx_pcm_hardware.buffer_bytes_max; + buf->dev.type = SNDRV_DMA_TYPE_DEV; + buf->dev.dev = pcm->card->dev; + buf->private_data = NULL; + buf->area = dma_alloc_writecombine(pcm->card->dev, size, + &buf->addr, GFP_KERNEL); + if (!buf->area) + return -ENOMEM; + buf->bytes = size; + return 0; +} + +static void pxa2xx_pcm_free_dma_buffers(struct snd_pcm *pcm) +{ + struct snd_pcm_substream *substream; + struct snd_dma_buffer *buf; + int stream; + + for (stream = 0; stream < 2; stream++) { + substream = pcm->streams[stream].substream; + if (!substream) + continue; + + buf = &substream->dma_buffer; + if (!buf->area) + continue; + + dma_free_writecombine(pcm->card->dev, buf->bytes, + buf->area, buf->addr); + buf->area = NULL; + } +} + +static u64 pxa2xx_pcm_dmamask = DMA_32BIT_MASK; + +int pxa2xx_pcm_new(struct snd_card *card, struct snd_soc_codec_dai *dai, + struct snd_pcm *pcm) +{ + int ret = 0; + + if (!card->dev->dma_mask) + card->dev->dma_mask = &pxa2xx_pcm_dmamask; + if (!card->dev->coherent_dma_mask) + card->dev->coherent_dma_mask = DMA_32BIT_MASK; + + if (dai->playback.channels_min) { + ret = pxa2xx_pcm_preallocate_dma_buffer(pcm, + SNDRV_PCM_STREAM_PLAYBACK); + if (ret) + goto out; + } + + if (dai->capture.channels_min) { + ret = pxa2xx_pcm_preallocate_dma_buffer(pcm, + SNDRV_PCM_STREAM_CAPTURE); + if (ret) + goto out; + } + out: + return ret; +} + +struct snd_soc_platform pxa2xx_soc_platform = { + .name = "pxa2xx-audio", + .pcm_ops = &pxa2xx_pcm_ops, + .pcm_new = pxa2xx_pcm_new, + .pcm_free = pxa2xx_pcm_free_dma_buffers, +}; + +EXPORT_SYMBOL_GPL(pxa2xx_soc_platform); + +MODULE_AUTHOR("Nicolas Pitre"); +MODULE_DESCRIPTION("Intel PXA2xx PCM DMA module"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/pxa/pxa2xx-pcm.h b/sound/soc/pxa/pxa2xx-pcm.h new file mode 100644 index 00000000000..0b55f070da2 --- /dev/null +++ b/sound/soc/pxa/pxa2xx-pcm.h @@ -0,0 +1,48 @@ +/* + * linux/sound/arm/pxa2xx-pcm.h -- ALSA PCM interface for the Intel PXA2xx chip + * + * Author: Nicolas Pitre + * Created: Nov 30, 2004 + * Copyright: MontaVista Software, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _PXA2XX_PCM_H +#define _PXA2XX_PCM_H + +struct pxa2xx_pcm_dma_params { + char *name; /* stream identifier */ + u32 dcmd; /* DMA descriptor dcmd field */ + volatile u32 *drcmr; /* the DMA request channel to use */ + u32 dev_addr; /* device physical address for DMA */ +}; + +struct pxa2xx_gpio { + u32 sys; + u32 rx; + u32 tx; + u32 clk; + u32 frm; +}; + +/* pxa2xx DAI ID's */ +#define PXA2XX_DAI_AC97_HIFI 0 +#define PXA2XX_DAI_AC97_AUX 1 +#define PXA2XX_DAI_AC97_MIC 2 +#define PXA2XX_DAI_I2S 0 +#define PXA2XX_DAI_SSP1 0 +#define PXA2XX_DAI_SSP2 1 +#define PXA2XX_DAI_SSP3 2 + +extern struct snd_soc_cpu_dai pxa_ac97_dai[3]; +extern struct snd_soc_cpu_dai pxa_i2s_dai; +extern struct snd_soc_cpu_dai pxa_ssp_dai[3]; + +/* platform data */ +extern struct snd_soc_platform pxa2xx_soc_platform; +extern struct snd_ac97_bus_ops pxa2xx_ac97_ops; + +#endif -- cgit v1.2.3 From 3e7cc3d3d1c435f83533b8bf2cf1833855be2901 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Thu, 12 Oct 2006 14:28:10 +0200 Subject: [ALSA] ASoC pxa2xx I2S support This patch adds pxa2xx I2S ASoC audio support. Features:- o Supports playback/capture o 16 bit PCM o 8k - 96k sample rates o Supports master and slave mode. From: Liam Girdwood Signed-off-by: Richard Purdie Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/pxa/pxa2xx-i2s.c | 306 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 306 insertions(+) create mode 100644 sound/soc/pxa/pxa2xx-i2s.c (limited to 'sound') diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c new file mode 100644 index 00000000000..c3b7a4bb7bd --- /dev/null +++ b/sound/soc/pxa/pxa2xx-i2s.c @@ -0,0 +1,306 @@ +/* + * pxa2xx-i2s.c -- ALSA Soc Audio Layer + * + * Copyright 2005 Wolfson Microelectronics PLC. + * Author: Liam Girdwood + * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision history + * 12th Aug 2005 Initial version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "pxa2xx-pcm.h" + +/* used to disable sysclk if external crystal is used */ +static int extclk; +module_param(extclk, int, 0); +MODULE_PARM_DESC(extclk, "set to 1 to disable pxa2xx i2s sysclk"); + +struct pxa_i2s_port { + u32 sadiv; + u32 sacr0; + u32 sacr1; + u32 saimr; + int master; +}; +static struct pxa_i2s_port pxa_i2s; + +#define PXA_I2S_DAIFMT \ + (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_NB_NF) + +#define PXA_I2S_DIR \ + (SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE) + +#define PXA_I2S_RATES \ + (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \ + SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) + +/* priv is divider */ +static struct snd_soc_dai_mode pxa2xx_i2s_modes[] = { + /* pxa2xx I2S frame and clock master modes */ + {PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, SND_SOC_DAITDM_LRDW(0,0), + SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_8000, PXA_I2S_DIR, + SND_SOC_DAI_BFS_DIV, 256, SND_SOC_FSBD(4), 0x48}, + {PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, SND_SOC_DAITDM_LRDW(0,0), + SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_11025, PXA_I2S_DIR, + SND_SOC_DAI_BFS_DIV, 256, SND_SOC_FSBD(4), 0x34}, + {PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, SND_SOC_DAITDM_LRDW(0,0), + SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_16000, PXA_I2S_DIR, + SND_SOC_DAI_BFS_DIV, 256, SND_SOC_FSBD(4), 0x24}, + {PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, SND_SOC_DAITDM_LRDW(0,0), + SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_22050, PXA_I2S_DIR, + SND_SOC_DAI_BFS_DIV, 256, SND_SOC_FSBD(4), 0x1a}, + {PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, SND_SOC_DAITDM_LRDW(0,0), + SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_44100, PXA_I2S_DIR, + SND_SOC_DAI_BFS_DIV, 256, SND_SOC_FSBD(4), 0xd}, + {PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, SND_SOC_DAITDM_LRDW(0,0), + SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_48000, PXA_I2S_DIR, + SND_SOC_DAI_BFS_DIV, 256, SND_SOC_FSBD(4), 0xc}, + + /* pxa2xx I2S frame master and clock slave mode */ + {PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBM_CFS, SND_SOC_DAITDM_LRDW(0,0), + SNDRV_PCM_FMTBIT_S16_LE, PXA_I2S_RATES, PXA_I2S_DIR, 0, + SND_SOC_FS_ALL, SND_SOC_FSB(64), 0x48}, + +}; + +static struct pxa2xx_pcm_dma_params pxa2xx_i2s_pcm_stereo_out = { + .name = "I2S PCM Stereo out", + .dev_addr = __PREG(SADR), + .drcmr = &DRCMRTXSADR, + .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | + DCMD_BURST32 | DCMD_WIDTH4, +}; + +static struct pxa2xx_pcm_dma_params pxa2xx_i2s_pcm_stereo_in = { + .name = "I2S PCM Stereo in", + .dev_addr = __PREG(SADR), + .drcmr = &DRCMRRXSADR, + .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | + DCMD_BURST32 | DCMD_WIDTH4, +}; + +static struct pxa2xx_gpio gpio_bus[] = { + { /* I2S SoC Slave */ + .rx = GPIO29_SDATA_IN_I2S_MD, + .tx = GPIO30_SDATA_OUT_I2S_MD, + .clk = GPIO28_BITCLK_IN_I2S_MD, + .frm = GPIO31_SYNC_I2S_MD, + }, + { /* I2S SoC Master */ +#ifdef CONFIG_PXA27x + .sys = GPIO113_I2S_SYSCLK_MD, +#else + .sys = GPIO32_SYSCLK_I2S_MD, +#endif + .rx = GPIO29_SDATA_IN_I2S_MD, + .tx = GPIO30_SDATA_OUT_I2S_MD, + .clk = GPIO28_BITCLK_OUT_I2S_MD, + .frm = GPIO31_SYNC_I2S_MD, + }, +}; + +static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + + if (!rtd->cpu_dai->active) { + SACR0 |= SACR0_RST; + SACR0 = 0; + } + + return 0; +} + +/* wait for I2S controller to be ready */ +static int pxa_i2s_wait(void) +{ + int i; + + /* flush the Rx FIFO */ + for(i = 0; i < 16; i++) + SADR; + return 0; +} + +static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + + pxa_i2s.master = 0; + if (rtd->cpu_dai->dai_runtime.fmt & SND_SOC_DAIFMT_CBS_CFS) + pxa_i2s.master = 1; + + if (pxa_i2s.master && !extclk) + pxa_gpio_mode(gpio_bus[pxa_i2s.master].sys); + + pxa_gpio_mode(gpio_bus[pxa_i2s.master].rx); + pxa_gpio_mode(gpio_bus[pxa_i2s.master].tx); + pxa_gpio_mode(gpio_bus[pxa_i2s.master].frm); + pxa_gpio_mode(gpio_bus[pxa_i2s.master].clk); + pxa_set_cken(CKEN8_I2S, 1); + pxa_i2s_wait(); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + rtd->cpu_dai->dma_data = &pxa2xx_i2s_pcm_stereo_out; + else + rtd->cpu_dai->dma_data = &pxa2xx_i2s_pcm_stereo_in; + + /* is port used by another stream */ + if (!(SACR0 & SACR0_ENB)) { + + SACR0 = 0; + SACR1 = 0; + if (pxa_i2s.master) + SACR0 |= SACR0_BCKD; + + SACR0 |= SACR0_RFTH(14) | SACR0_TFTH(1); + + if (rtd->cpu_dai->dai_runtime.fmt & SND_SOC_DAIFMT_LEFT_J) + SACR1 |= SACR1_AMSL; + } + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + SAIMR |= SAIMR_TFS; + else + SAIMR |= SAIMR_RFS; + + SADIV = rtd->cpu_dai->dai_runtime.priv; + return 0; +} + +static int pxa2xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd) +{ + int ret = 0; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + SACR0 |= SACR0_ENB; + break; + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static void pxa2xx_i2s_shutdown(struct snd_pcm_substream *substream) +{ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + SACR1 |= SACR1_DRPL; + SAIMR &= ~SAIMR_TFS; + } else { + SACR1 |= SACR1_DREC; + SAIMR &= ~SAIMR_RFS; + } + + if (SACR1 & (SACR1_DREC | SACR1_DRPL)) { + SACR0 &= ~SACR0_ENB; + pxa_i2s_wait(); + pxa_set_cken(CKEN8_I2S, 0); + } +} + +#ifdef CONFIG_PM +static int pxa2xx_i2s_suspend(struct platform_device *dev, + struct snd_soc_cpu_dai *dai) +{ + if (!dai->active) + return 0; + + /* store registers */ + pxa_i2s.sacr0 = SACR0; + pxa_i2s.sacr1 = SACR1; + pxa_i2s.saimr = SAIMR; + pxa_i2s.sadiv = SADIV; + + /* deactivate link */ + SACR0 &= ~SACR0_ENB; + pxa_i2s_wait(); + return 0; +} + +static int pxa2xx_i2s_resume(struct platform_device *pdev, + struct snd_soc_cpu_dai *dai) +{ + if (!dai->active) + return 0; + + pxa_i2s_wait(); + + SACR0 = pxa_i2s.sacr0 &= ~SACR0_ENB; + SACR1 = pxa_i2s.sacr1; + SAIMR = pxa_i2s.saimr; + SADIV = pxa_i2s.sadiv; + SACR0 |= SACR0_ENB; + + return 0; +} + +#else +#define pxa2xx_i2s_suspend NULL +#define pxa2xx_i2s_resume NULL +#endif + +/* pxa2xx I2S sysclock is always 256 FS */ +static unsigned int pxa_i2s_config_sysclk(struct snd_soc_cpu_dai *iface, + struct snd_soc_clock_info *info, unsigned int clk) +{ + return info->rate << 8; +} + +struct snd_soc_cpu_dai pxa_i2s_dai = { + .name = "pxa2xx-i2s", + .id = 0, + .type = SND_SOC_DAI_I2S, + .suspend = pxa2xx_i2s_suspend, + .resume = pxa2xx_i2s_resume, + .config_sysclk = pxa_i2s_config_sysclk, + .playback = { + .channels_min = 2, + .channels_max = 2,}, + .capture = { + .channels_min = 2, + .channels_max = 2,}, + .ops = { + .startup = pxa2xx_i2s_startup, + .shutdown = pxa2xx_i2s_shutdown, + .trigger = pxa2xx_i2s_trigger, + .hw_params = pxa2xx_i2s_hw_params,}, + .caps = { + .num_modes = ARRAY_SIZE(pxa2xx_i2s_modes), + .mode = pxa2xx_i2s_modes,}, +}; + +EXPORT_SYMBOL_GPL(pxa_i2s_dai); + +/* Module information */ +MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com"); +MODULE_DESCRIPTION("pxa2xx I2S SoC Interface"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 75b41027662e29822746342865fa8abd941d2604 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Thu, 12 Oct 2006 14:29:03 +0200 Subject: [ALSA] ASoC pxa2xx AC97 support This patch adds pxa2xx AC97 ASoC audio support. It's based on sound/arm/pxa-ac97 by Nicolas Pitre with the following differences. o Modified driver structure to use ASoC core PCM callbacks. o Removed AC97 configuration function (all handled in ASoC core) o Added and exported ASoC DAI configuration table. o Added DMA support for AUX DAC and Mic ADC o Separated out AC97 reset into cold and warm reset functions. From: Liam Girdwood Signed-off-by: Nicolas Pitre Signed-off-by: Richard Purdie Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/pxa/pxa2xx-ac97.c | 437 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 437 insertions(+) create mode 100644 sound/soc/pxa/pxa2xx-ac97.c (limited to 'sound') diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c new file mode 100644 index 00000000000..28b1985edc0 --- /dev/null +++ b/sound/soc/pxa/pxa2xx-ac97.c @@ -0,0 +1,437 @@ +/* + * linux/sound/pxa2xx-ac97.c -- AC97 support for the Intel PXA2xx chip. + * + * Author: Nicolas Pitre + * Created: Dec 02, 2004 + * Copyright: MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "pxa2xx-pcm.h" + +static DEFINE_MUTEX(car_mutex); +static DECLARE_WAIT_QUEUE_HEAD(gsr_wq); +static volatile long gsr_bits; + +#define AC97_DIR \ + (SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE) + +#define AC97_RATES \ + (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \ + SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) + +/* may need to expand this */ +static struct snd_soc_dai_mode pxa2xx_ac97_modes[] = { + { + .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, + .pcmrate = AC97_RATES, + .pcmdir = AC97_DIR, + }, +}; + +/* + * Beware PXA27x bugs: + * + * o Slot 12 read from modem space will hang controller. + * o CDONE, SDONE interrupt fails after any slot 12 IO. + * + * We therefore have an hybrid approach for waiting on SDONE (interrupt or + * 1 jiffy timeout if interrupt never comes). + */ + +static unsigned short pxa2xx_ac97_read(struct snd_ac97 *ac97, + unsigned short reg) +{ + unsigned short val = -1; + volatile u32 *reg_addr; + + mutex_lock(&car_mutex); + + /* set up primary or secondary codec/modem space */ +#ifdef CONFIG_PXA27x + reg_addr = ac97->num ? &SAC_REG_BASE : &PAC_REG_BASE; +#else + if (reg == AC97_GPIO_STATUS) + reg_addr = ac97->num ? &SMC_REG_BASE : &PMC_REG_BASE; + else + reg_addr = ac97->num ? &SAC_REG_BASE : &PAC_REG_BASE; +#endif + reg_addr += (reg >> 1); + +#ifndef CONFIG_PXA27x + if (reg == AC97_GPIO_STATUS) { + /* read from controller cache */ + val = *reg_addr; + goto out; + } +#endif + + /* start read access across the ac97 link */ + GSR = GSR_CDONE | GSR_SDONE; + gsr_bits = 0; + val = *reg_addr; + + wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_SDONE, 1); + if (!((GSR | gsr_bits) & GSR_SDONE)) { + printk(KERN_ERR "%s: read error (ac97_reg=%x GSR=%#lx)\n", + __FUNCTION__, reg, GSR | gsr_bits); + val = -1; + goto out; + } + + /* valid data now */ + GSR = GSR_CDONE | GSR_SDONE; + gsr_bits = 0; + val = *reg_addr; + /* but we've just started another cycle... */ + wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_SDONE, 1); + +out: mutex_unlock(&car_mutex); + return val; +} + +static void pxa2xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg, + unsigned short val) +{ + volatile u32 *reg_addr; + + mutex_lock(&car_mutex); + + /* set up primary or secondary codec/modem space */ +#ifdef CONFIG_PXA27x + reg_addr = ac97->num ? &SAC_REG_BASE : &PAC_REG_BASE; +#else + if (reg == AC97_GPIO_STATUS) + reg_addr = ac97->num ? &SMC_REG_BASE : &PMC_REG_BASE; + else + reg_addr = ac97->num ? &SAC_REG_BASE : &PAC_REG_BASE; +#endif + reg_addr += (reg >> 1); + + GSR = GSR_CDONE | GSR_SDONE; + gsr_bits = 0; + *reg_addr = val; + wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_CDONE, 1); + if (!((GSR | gsr_bits) & GSR_CDONE)) + printk(KERN_ERR "%s: write error (ac97_reg=%x GSR=%#lx)\n", + __FUNCTION__, reg, GSR | gsr_bits); + + mutex_unlock(&car_mutex); +} + +static void pxa2xx_ac97_warm_reset(struct snd_ac97 *ac97) +{ + gsr_bits = 0; + +#ifdef CONFIG_PXA27x + /* warm reset broken on Bulverde, + so manually keep AC97 reset high */ + pxa_gpio_mode(113 | GPIO_OUT | GPIO_DFLT_HIGH); + udelay(10); + GCR |= GCR_WARM_RST; + pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT); + udelay(500); +#else + GCR |= GCR_WARM_RST | GCR_PRIRDY_IEN | GCR_SECRDY_IEN; + wait_event_timeout(gsr_wq, gsr_bits & (GSR_PCR | GSR_SCR), 1); +#endif + + if (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR))) + printk(KERN_INFO "%s: warm reset timeout (GSR=%#lx)\n", + __FUNCTION__, gsr_bits); + + GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN); + GCR |= GCR_SDONE_IE|GCR_CDONE_IE; +} + +static void pxa2xx_ac97_cold_reset(struct snd_ac97 *ac97) +{ + GCR &= GCR_COLD_RST; /* clear everything but nCRST */ + GCR &= ~GCR_COLD_RST; /* then assert nCRST */ + + gsr_bits = 0; +#ifdef CONFIG_PXA27x + /* PXA27x Developers Manual section 13.5.2.2.1 */ + pxa_set_cken(1 << 31, 1); + udelay(5); + pxa_set_cken(1 << 31, 0); + GCR = GCR_COLD_RST; + udelay(50); +#else + GCR = GCR_COLD_RST; + GCR |= GCR_CDONE_IE|GCR_SDONE_IE; + wait_event_timeout(gsr_wq, gsr_bits & (GSR_PCR | GSR_SCR), 1); +#endif + + if (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR))) + printk(KERN_INFO "%s: cold reset timeout (GSR=%#lx)\n", + __FUNCTION__, gsr_bits); + + GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN); + GCR |= GCR_SDONE_IE|GCR_CDONE_IE; +} + +static irqreturn_t pxa2xx_ac97_irq(int irq, void *dev_id) +{ + long status; + + status = GSR; + if (status) { + GSR = status; + gsr_bits |= status; + wake_up(&gsr_wq); + +#ifdef CONFIG_PXA27x + /* Although we don't use those we still need to clear them + since they tend to spuriously trigger when MMC is used + (hardware bug? go figure)... */ + MISR = MISR_EOC; + PISR = PISR_EOC; + MCSR = MCSR_EOC; +#endif + + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +struct snd_ac97_bus_ops soc_ac97_ops = { + .read = pxa2xx_ac97_read, + .write = pxa2xx_ac97_write, + .warm_reset = pxa2xx_ac97_warm_reset, + .reset = pxa2xx_ac97_cold_reset, +}; + +static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_stereo_out = { + .name = "AC97 PCM Stereo out", + .dev_addr = __PREG(PCDR), + .drcmr = &DRCMRTXPCDR, + .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | + DCMD_BURST32 | DCMD_WIDTH4, +}; + +static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_stereo_in = { + .name = "AC97 PCM Stereo in", + .dev_addr = __PREG(PCDR), + .drcmr = &DRCMRRXPCDR, + .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | + DCMD_BURST32 | DCMD_WIDTH4, +}; + +static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_aux_mono_out = { + .name = "AC97 Aux PCM (Slot 5) Mono out", + .dev_addr = __PREG(MODR), + .drcmr = &DRCMRTXMODR, + .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | + DCMD_BURST16 | DCMD_WIDTH2, +}; + +static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_aux_mono_in = { + .name = "AC97 Aux PCM (Slot 5) Mono in", + .dev_addr = __PREG(MODR), + .drcmr = &DRCMRRXMODR, + .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | + DCMD_BURST16 | DCMD_WIDTH2, +}; + +static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_mic_mono_in = { + .name = "AC97 Mic PCM (Slot 6) Mono in", + .dev_addr = __PREG(MCDR), + .drcmr = &DRCMRRXMCDR, + .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | + DCMD_BURST16 | DCMD_WIDTH2, +}; + +#ifdef CONFIG_PM +static int pxa2xx_ac97_suspend(struct platform_device *pdev, + struct snd_soc_cpu_dai *dai) +{ + GCR |= GCR_ACLINK_OFF; + pxa_set_cken(CKEN2_AC97, 0); + return 0; +} + +static int pxa2xx_ac97_resume(struct platform_device *pdev, + struct snd_soc_cpu_dai *dai) +{ + pxa_gpio_mode(GPIO31_SYNC_AC97_MD); + pxa_gpio_mode(GPIO30_SDATA_OUT_AC97_MD); + pxa_gpio_mode(GPIO28_BITCLK_AC97_MD); + pxa_gpio_mode(GPIO29_SDATA_IN_AC97_MD); +#ifdef CONFIG_PXA27x + /* Use GPIO 113 as AC97 Reset on Bulverde */ + pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT); +#endif + pxa_set_cken(CKEN2_AC97, 1); + return 0; +} + +#else +#define pxa2xx_ac97_suspend NULL +#define pxa2xx_ac97_resume NULL +#endif + +static int pxa2xx_ac97_probe(struct platform_device *pdev) +{ + int ret; + + ret = request_irq(IRQ_AC97, pxa2xx_ac97_irq, IRQF_DISABLED, "AC97", NULL); + if (ret < 0) + goto err; + + pxa_gpio_mode(GPIO31_SYNC_AC97_MD); + pxa_gpio_mode(GPIO30_SDATA_OUT_AC97_MD); + pxa_gpio_mode(GPIO28_BITCLK_AC97_MD); + pxa_gpio_mode(GPIO29_SDATA_IN_AC97_MD); +#ifdef CONFIG_PXA27x + /* Use GPIO 113 as AC97 Reset on Bulverde */ + pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT); +#endif + pxa_set_cken(CKEN2_AC97, 1); + return 0; + + err: + if (CKEN & CKEN2_AC97) { + GCR |= GCR_ACLINK_OFF; + free_irq(IRQ_AC97, NULL); + pxa_set_cken(CKEN2_AC97, 0); + } + return ret; +} + +static void pxa2xx_ac97_remove(struct platform_device *pdev) +{ + GCR |= GCR_ACLINK_OFF; + free_irq(IRQ_AC97, NULL); + pxa_set_cken(CKEN2_AC97, 0); +} + +static int pxa2xx_ac97_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + rtd->cpu_dai->dma_data = &pxa2xx_ac97_pcm_stereo_out; + else + rtd->cpu_dai->dma_data = &pxa2xx_ac97_pcm_stereo_in; + + return 0; +} + +static int pxa2xx_ac97_hw_aux_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + rtd->cpu_dai->dma_data = &pxa2xx_ac97_pcm_aux_mono_out; + else + rtd->cpu_dai->dma_data = &pxa2xx_ac97_pcm_aux_mono_in; + + return 0; +} + +static int pxa2xx_ac97_hw_mic_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + return -ENODEV; + else + rtd->cpu_dai->dma_data = &pxa2xx_ac97_pcm_mic_mono_in; + + return 0; +} + +/* + * There is only 1 physical AC97 interface for pxa2xx, but it + * has extra fifo's that can be used for aux DACs and ADCs. + */ +struct snd_soc_cpu_dai pxa_ac97_dai[] = { +{ + .name = "pxa2xx-ac97", + .id = 0, + .type = SND_SOC_DAI_AC97, + .probe = pxa2xx_ac97_probe, + .remove = pxa2xx_ac97_remove, + .suspend = pxa2xx_ac97_suspend, + .resume = pxa2xx_ac97_resume, + .playback = { + .stream_name = "AC97 Playback", + .channels_min = 2, + .channels_max = 2,}, + .capture = { + .stream_name = "AC97 Capture", + .channels_min = 2, + .channels_max = 2,}, + .ops = { + .hw_params = pxa2xx_ac97_hw_params,}, + .caps = { + .num_modes = ARRAY_SIZE(pxa2xx_ac97_modes), + .mode = pxa2xx_ac97_modes,}, +}, +{ + .name = "pxa2xx-ac97-aux", + .id = 1, + .type = SND_SOC_DAI_AC97, + .playback = { + .stream_name = "AC97 Aux Playback", + .channels_min = 1, + .channels_max = 1,}, + .capture = { + .stream_name = "AC97 Aux Capture", + .channels_min = 1, + .channels_max = 1,}, + .ops = { + .hw_params = pxa2xx_ac97_hw_aux_params,}, + .caps = { + .num_modes = ARRAY_SIZE(pxa2xx_ac97_modes), + .mode = pxa2xx_ac97_modes,}, +}, +{ + .name = "pxa2xx-ac97-mic", + .id = 2, + .type = SND_SOC_DAI_AC97, + .capture = { + .stream_name = "AC97 Mic Capture", + .channels_min = 1, + .channels_max = 1,}, + .ops = { + .hw_params = pxa2xx_ac97_hw_mic_params,}, + .caps = { + .num_modes = ARRAY_SIZE(pxa2xx_ac97_modes), + .mode = pxa2xx_ac97_modes,},}, +}; + +EXPORT_SYMBOL_GPL(pxa_ac97_dai); +EXPORT_SYMBOL_GPL(soc_ac97_ops); + +MODULE_AUTHOR("Nicolas Pitre"); +MODULE_DESCRIPTION("AC97 driver for the Intel PXA2xx chip"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From a1eb4b3caf3abd0d1a8474f07d29959e1879bb29 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Thu, 12 Oct 2006 14:31:16 +0200 Subject: [ALSA] ASoC pxa2xx Corgi machine support This patch adds Alsa audio support to the Sharp Zaurus SL-C7x0/C860 (Corgi) machines. From: Liam Girdwood Signed-off-by: Graeme Gregory Signed-off-by: Richard Purdie Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/pxa/corgi.c | 361 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 361 insertions(+) create mode 100644 sound/soc/pxa/corgi.c (limited to 'sound') diff --git a/sound/soc/pxa/corgi.c b/sound/soc/pxa/corgi.c new file mode 100644 index 00000000000..2b1c6e94d1e --- /dev/null +++ b/sound/soc/pxa/corgi.c @@ -0,0 +1,361 @@ +/* + * corgi.c -- SoC audio for Corgi + * + * Copyright 2005 Wolfson Microelectronics PLC. + * Copyright 2005 Openedhand Ltd. + * + * Authors: Liam Girdwood + * Richard Purdie + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision history + * 30th Nov 2005 Initial version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "../codecs/wm8731.h" +#include "pxa2xx-pcm.h" + +#define CORGI_HP 0 +#define CORGI_MIC 1 +#define CORGI_LINE 2 +#define CORGI_HEADSET 3 +#define CORGI_HP_OFF 4 +#define CORGI_SPK_ON 0 +#define CORGI_SPK_OFF 1 + + /* audio clock in Hz - rounded from 12.235MHz */ +#define CORGI_AUDIO_CLOCK 12288000 + +static int corgi_jack_func; +static int corgi_spk_func; + +static void corgi_ext_control(struct snd_soc_codec *codec) +{ + int spk = 0, mic = 0, line = 0, hp = 0, hs = 0; + + /* set up jack connection */ + switch (corgi_jack_func) { + case CORGI_HP: + hp = 1; + /* set = unmute headphone */ + set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L); + set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R); + break; + case CORGI_MIC: + mic = 1; + /* reset = mute headphone */ + reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L); + reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R); + break; + case CORGI_LINE: + line = 1; + reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L); + reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R); + break; + case CORGI_HEADSET: + hs = 1; + mic = 1; + reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L); + set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R); + break; + } + + if (corgi_spk_func == CORGI_SPK_ON) + spk = 1; + + /* set the enpoints to their new connetion states */ + snd_soc_dapm_set_endpoint(codec, "Ext Spk", spk); + snd_soc_dapm_set_endpoint(codec, "Mic Jack", mic); + snd_soc_dapm_set_endpoint(codec, "Line Jack", line); + snd_soc_dapm_set_endpoint(codec, "Headphone Jack", hp); + snd_soc_dapm_set_endpoint(codec, "Headset Jack", hs); + + /* signal a DAPM event */ + snd_soc_dapm_sync_endpoints(codec); +} + +static int corgi_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_codec *codec = rtd->socdev->codec; + + /* check the jack status at stream startup */ + corgi_ext_control(codec); + return 0; +} + +/* we need to unmute the HP at shutdown as the mute burns power on corgi */ +static int corgi_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_codec *codec = rtd->socdev->codec; + + /* set = unmute headphone */ + set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L); + set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R); + return 0; +} + +static struct snd_soc_ops corgi_ops = { + .startup = corgi_startup, + .shutdown = corgi_shutdown, +}; + +static int corgi_get_jack(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = corgi_jack_func; + return 0; +} + +static int corgi_set_jack(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + + if (corgi_jack_func == ucontrol->value.integer.value[0]) + return 0; + + corgi_jack_func = ucontrol->value.integer.value[0]; + corgi_ext_control(codec); + return 1; +} + +static int corgi_get_spk(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = corgi_spk_func; + return 0; +} + +static int corgi_set_spk(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + + if (corgi_spk_func == ucontrol->value.integer.value[0]) + return 0; + + corgi_spk_func = ucontrol->value.integer.value[0]; + corgi_ext_control(codec); + return 1; +} + +static int corgi_amp_event(struct snd_soc_dapm_widget *w, int event) +{ + if (SND_SOC_DAPM_EVENT_ON(event)) + set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_APM_ON); + else + reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_APM_ON); + + return 0; +} + +static int corgi_mic_event(struct snd_soc_dapm_widget *w, int event) +{ + if (SND_SOC_DAPM_EVENT_ON(event)) + set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MIC_BIAS); + else + reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MIC_BIAS); + + return 0; +} + +/* corgi machine dapm widgets */ +static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = { +SND_SOC_DAPM_HP("Headphone Jack", NULL), +SND_SOC_DAPM_MIC("Mic Jack", corgi_mic_event), +SND_SOC_DAPM_SPK("Ext Spk", corgi_amp_event), +SND_SOC_DAPM_LINE("Line Jack", NULL), +SND_SOC_DAPM_HP("Headset Jack", NULL), +}; + +/* Corgi machine audio map (connections to the codec pins) */ +static const char *audio_map[][3] = { + + /* headset Jack - in = micin, out = LHPOUT*/ + {"Headset Jack", NULL, "LHPOUT"}, + + /* headphone connected to LHPOUT1, RHPOUT1 */ + {"Headphone Jack", NULL, "LHPOUT"}, + {"Headphone Jack", NULL, "RHPOUT"}, + + /* speaker connected to LOUT, ROUT */ + {"Ext Spk", NULL, "ROUT"}, + {"Ext Spk", NULL, "LOUT"}, + + /* mic is connected to MICIN (via right channel of headphone jack) */ + {"MICIN", NULL, "Mic Jack"}, + + /* Same as the above but no mic bias for line signals */ + {"MICIN", NULL, "Line Jack"}, + + {NULL, NULL, NULL}, +}; + +static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset", + "Off"}; +static const char *spk_function[] = {"On", "Off"}; +static const struct soc_enum corgi_enum[] = { + SOC_ENUM_SINGLE_EXT(5, jack_function), + SOC_ENUM_SINGLE_EXT(2, spk_function), +}; + +static const struct snd_kcontrol_new wm8731_corgi_controls[] = { + SOC_ENUM_EXT("Jack Function", corgi_enum[0], corgi_get_jack, + corgi_set_jack), + SOC_ENUM_EXT("Speaker Function", corgi_enum[1], corgi_get_spk, + corgi_set_spk), +}; + +/* + * Logic for a wm8731 as connected on a Sharp SL-C7x0 Device + */ +static int corgi_wm8731_init(struct snd_soc_codec *codec) +{ + int i, err; + + snd_soc_dapm_set_endpoint(codec, "LLINEIN", 0); + snd_soc_dapm_set_endpoint(codec, "RLINEIN", 0); + + /* Add corgi specific controls */ + for (i = 0; i < ARRAY_SIZE(wm8731_corgi_controls); i++) { + err = snd_ctl_add(codec->card, + snd_soc_cnew(&wm8731_corgi_controls[i],codec, NULL)); + if (err < 0) + return err; + } + + /* Add corgi specific widgets */ + for(i = 0; i < ARRAY_SIZE(wm8731_dapm_widgets); i++) { + snd_soc_dapm_new_control(codec, &wm8731_dapm_widgets[i]); + } + + /* Set up corgi specific audio path audio_map */ + for(i = 0; audio_map[i][0] != NULL; i++) { + snd_soc_dapm_connect_input(codec, audio_map[i][0], + audio_map[i][1], audio_map[i][2]); + } + + snd_soc_dapm_sync_endpoints(codec); + return 0; +} + +static unsigned int corgi_config_sysclk(struct snd_soc_pcm_runtime *rtd, + struct snd_soc_clock_info *info) +{ + if (info->bclk_master & SND_SOC_DAIFMT_CBS_CFS) { + /* pxa2xx is i2s master */ + switch (info->rate) { + case 44100: + case 88200: + /* configure codec digital filters for 44.1, 88.2 */ + rtd->codec_dai->config_sysclk(rtd->codec_dai, info, + 11289600); + break; + default: + /* configure codec digital filters for all other rates */ + rtd->codec_dai->config_sysclk(rtd->codec_dai, info, + CORGI_AUDIO_CLOCK); + break; + } + /* config pxa i2s as master */ + return rtd->cpu_dai->config_sysclk(rtd->cpu_dai, info, + CORGI_AUDIO_CLOCK); + } else { + /* codec is i2s master - + * only configure codec DAI clock and filters */ + return rtd->codec_dai->config_sysclk(rtd->codec_dai, info, + CORGI_AUDIO_CLOCK); + } +} + +/* corgi digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link corgi_dai = { + .name = "WM8731", + .stream_name = "WM8731", + .cpu_dai = &pxa_i2s_dai, + .codec_dai = &wm8731_dai, + .init = corgi_wm8731_init, + .config_sysclk = corgi_config_sysclk, +}; + +/* corgi audio machine driver */ +static struct snd_soc_machine snd_soc_machine_corgi = { + .name = "Corgi", + .dai_link = &corgi_dai, + .num_links = 1, + .ops = &corgi_ops, +}; + +/* corgi audio private data */ +static struct wm8731_setup_data corgi_wm8731_setup = { + .i2c_address = 0x1b, +}; + +/* corgi audio subsystem */ +static struct snd_soc_device corgi_snd_devdata = { + .machine = &snd_soc_machine_corgi, + .platform = &pxa2xx_soc_platform, + .codec_dev = &soc_codec_dev_wm8731, + .codec_data = &corgi_wm8731_setup, +}; + +static struct platform_device *corgi_snd_device; + +static int __init corgi_init(void) +{ + int ret; + + if (!(machine_is_corgi() || machine_is_shepherd() || machine_is_husky())) + return -ENODEV; + + corgi_snd_device = platform_device_alloc("soc-audio", -1); + if (!corgi_snd_device) + return -ENOMEM; + + platform_set_drvdata(corgi_snd_device, &corgi_snd_devdata); + corgi_snd_devdata.dev = &corgi_snd_device->dev; + ret = platform_device_add(corgi_snd_device); + + if (ret) + platform_device_put(corgi_snd_device); + + return ret; +} + +static void __exit corgi_exit(void) +{ + platform_device_unregister(corgi_snd_device); +} + +module_init(corgi_init); +module_exit(corgi_exit); + +/* Module information */ +MODULE_AUTHOR("Richard Purdie"); +MODULE_DESCRIPTION("ALSA SoC Corgi"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 7fb290d03af69bfca5876573ac0eada40bd4e292 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Thu, 12 Oct 2006 14:32:13 +0200 Subject: [ALSA] ASoC pxa2xx Spitz machine support This patch adds Alsa audio support to the Sharp Zaurus SL-C1000/SL-C3x00 (Akita/Spitz) machines. From: Liam Girdwood Signed-off-by: Richard Purdie Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/pxa/spitz.c | 374 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 374 insertions(+) create mode 100644 sound/soc/pxa/spitz.c (limited to 'sound') diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c new file mode 100644 index 00000000000..17c8e61efe6 --- /dev/null +++ b/sound/soc/pxa/spitz.c @@ -0,0 +1,374 @@ +/* + * spitz.c -- SoC audio for Sharp SL-Cxx00 models Spitz, Borzoi and Akita + * + * Copyright 2005 Wolfson Microelectronics PLC. + * Copyright 2005 Openedhand Ltd. + * + * Authors: Liam Girdwood + * Richard Purdie + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision history + * 30th Nov 2005 Initial version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include "../codecs/wm8750.h" +#include "pxa2xx-pcm.h" + +#define SPITZ_HP 0 +#define SPITZ_MIC 1 +#define SPITZ_LINE 2 +#define SPITZ_HEADSET 3 +#define SPITZ_HP_OFF 4 +#define SPITZ_SPK_ON 0 +#define SPITZ_SPK_OFF 1 + + /* audio clock in Hz - rounded from 12.235MHz */ +#define SPITZ_AUDIO_CLOCK 12288000 + +static int spitz_jack_func; +static int spitz_spk_func; + +static void spitz_ext_control(struct snd_soc_codec *codec) +{ + if (spitz_spk_func == SPITZ_SPK_ON) + snd_soc_dapm_set_endpoint(codec, "Ext Spk", 1); + else + snd_soc_dapm_set_endpoint(codec, "Ext Spk", 0); + + /* set up jack connection */ + switch (spitz_jack_func) { + case SPITZ_HP: + /* enable and unmute hp jack, disable mic bias */ + snd_soc_dapm_set_endpoint(codec, "Headset Jack", 0); + snd_soc_dapm_set_endpoint(codec, "Mic Jack", 0); + snd_soc_dapm_set_endpoint(codec, "Line Jack", 0); + snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 1); + set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L); + set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R); + break; + case SPITZ_MIC: + /* enable mic jack and bias, mute hp */ + snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 0); + snd_soc_dapm_set_endpoint(codec, "Headset Jack", 0); + snd_soc_dapm_set_endpoint(codec, "Line Jack", 0); + snd_soc_dapm_set_endpoint(codec, "Mic Jack", 1); + reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L); + reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R); + break; + case SPITZ_LINE: + /* enable line jack, disable mic bias and mute hp */ + snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 0); + snd_soc_dapm_set_endpoint(codec, "Headset Jack", 0); + snd_soc_dapm_set_endpoint(codec, "Mic Jack", 0); + snd_soc_dapm_set_endpoint(codec, "Line Jack", 1); + reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L); + reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R); + break; + case SPITZ_HEADSET: + /* enable and unmute headset jack enable mic bias, mute L hp */ + snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 0); + snd_soc_dapm_set_endpoint(codec, "Mic Jack", 1); + snd_soc_dapm_set_endpoint(codec, "Line Jack", 0); + snd_soc_dapm_set_endpoint(codec, "Headset Jack", 1); + reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L); + set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R); + break; + case SPITZ_HP_OFF: + + /* jack removed, everything off */ + snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 0); + snd_soc_dapm_set_endpoint(codec, "Headset Jack", 0); + snd_soc_dapm_set_endpoint(codec, "Mic Jack", 0); + snd_soc_dapm_set_endpoint(codec, "Line Jack", 0); + reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L); + reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R); + break; + } + snd_soc_dapm_sync_endpoints(codec); +} + +static int spitz_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_codec *codec = rtd->socdev->codec; + + /* check the jack status at stream startup */ + spitz_ext_control(codec); + return 0; +} + +static struct snd_soc_ops spitz_ops = { + .startup = spitz_startup, +}; + +static int spitz_get_jack(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = spitz_jack_func; + return 0; +} + +static int spitz_set_jack(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + + if (spitz_jack_func == ucontrol->value.integer.value[0]) + return 0; + + spitz_jack_func = ucontrol->value.integer.value[0]; + spitz_ext_control(codec); + return 1; +} + +static int spitz_get_spk(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = spitz_spk_func; + return 0; +} + +static int spitz_set_spk(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + + if (spitz_spk_func == ucontrol->value.integer.value[0]) + return 0; + + spitz_spk_func = ucontrol->value.integer.value[0]; + spitz_ext_control(codec); + return 1; +} + +static int spitz_mic_bias(struct snd_soc_dapm_widget *w, int event) +{ + if (machine_is_borzoi() || machine_is_spitz()) { + if (SND_SOC_DAPM_EVENT_ON(event)) + set_scoop_gpio(&spitzscoop2_device.dev, + SPITZ_SCP2_MIC_BIAS); + else + reset_scoop_gpio(&spitzscoop2_device.dev, + SPITZ_SCP2_MIC_BIAS); + } + + if (machine_is_akita()) { + if (SND_SOC_DAPM_EVENT_ON(event)) + akita_set_ioexp(&akitaioexp_device.dev, + AKITA_IOEXP_MIC_BIAS); + else + akita_reset_ioexp(&akitaioexp_device.dev, + AKITA_IOEXP_MIC_BIAS); + } + return 0; +} + +/* spitz machine dapm widgets */ +static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Mic Jack", spitz_mic_bias), + SND_SOC_DAPM_SPK("Ext Spk", NULL), + SND_SOC_DAPM_LINE("Line Jack", NULL), + + /* headset is a mic and mono headphone */ + SND_SOC_DAPM_HP("Headset Jack", NULL), +}; + +/* Spitz machine audio_map */ +static const char *audio_map[][3] = { + + /* headphone connected to LOUT1, ROUT1 */ + {"Headphone Jack", NULL, "LOUT1"}, + {"Headphone Jack", NULL, "ROUT1"}, + + /* headset connected to ROUT1 and LINPUT1 with bias (def below) */ + {"Headset Jack", NULL, "ROUT1"}, + + /* ext speaker connected to LOUT2, ROUT2 */ + {"Ext Spk", NULL , "ROUT2"}, + {"Ext Spk", NULL , "LOUT2"}, + + /* mic is connected to input 1 - with bias */ + {"LINPUT1", NULL, "Mic Bias"}, + {"Mic Bias", NULL, "Mic Jack"}, + + /* line is connected to input 1 - no bias */ + {"LINPUT1", NULL, "Line Jack"}, + + {NULL, NULL, NULL}, +}; + +static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset", + "Off"}; +static const char *spk_function[] = {"On", "Off"}; +static const struct soc_enum spitz_enum[] = { + SOC_ENUM_SINGLE_EXT(5, jack_function), + SOC_ENUM_SINGLE_EXT(2, spk_function), +}; + +static const struct snd_kcontrol_new wm8750_spitz_controls[] = { + SOC_ENUM_EXT("Jack Function", spitz_enum[0], spitz_get_jack, + spitz_set_jack), + SOC_ENUM_EXT("Speaker Function", spitz_enum[1], spitz_get_spk, + spitz_set_spk), +}; + +/* + * Logic for a wm8750 as connected on a Sharp SL-Cxx00 Device + */ +static int spitz_wm8750_init(struct snd_soc_codec *codec) +{ + int i, err; + + /* NC codec pins */ + snd_soc_dapm_set_endpoint(codec, "RINPUT1", 0); + snd_soc_dapm_set_endpoint(codec, "LINPUT2", 0); + snd_soc_dapm_set_endpoint(codec, "RINPUT2", 0); + snd_soc_dapm_set_endpoint(codec, "LINPUT3", 0); + snd_soc_dapm_set_endpoint(codec, "RINPUT3", 0); + snd_soc_dapm_set_endpoint(codec, "OUT3", 0); + snd_soc_dapm_set_endpoint(codec, "MONO", 0); + + /* Add spitz specific controls */ + for (i = 0; i < ARRAY_SIZE(wm8750_spitz_controls); i++) { + err = snd_ctl_add(codec->card, + snd_soc_cnew(&wm8750_spitz_controls[i], codec, NULL)); + if (err < 0) + return err; + } + + /* Add spitz specific widgets */ + for (i = 0; i < ARRAY_SIZE(wm8750_dapm_widgets); i++) { + snd_soc_dapm_new_control(codec, &wm8750_dapm_widgets[i]); + } + + /* Set up spitz specific audio path audio_map */ + for (i = 0; audio_map[i][0] != NULL; i++) { + snd_soc_dapm_connect_input(codec, audio_map[i][0], + audio_map[i][1], audio_map[i][2]); + } + + snd_soc_dapm_sync_endpoints(codec); + return 0; +} + +static unsigned int spitz_config_sysclk(struct snd_soc_pcm_runtime *rtd, + struct snd_soc_clock_info *info) +{ + if (info->bclk_master & SND_SOC_DAIFMT_CBS_CFS) { + /* pxa2xx is i2s master */ + switch (info->rate) { + case 11025: + case 22050: + case 44100: + case 88200: + /* configure codec digital filters + * for 11.025, 22.05, 44.1, 88.2 */ + rtd->codec_dai->config_sysclk(rtd->codec_dai, info, + 11289600); + break; + default: + /* configure codec digital filters for all other rates */ + rtd->codec_dai->config_sysclk(rtd->codec_dai, info, + SPITZ_AUDIO_CLOCK); + break; + } + /* configure pxa2xx i2s interface clocks as master */ + return rtd->cpu_dai->config_sysclk(rtd->cpu_dai, info, + SPITZ_AUDIO_CLOCK); + } else { + /* codec is i2s master - only configure codec DAI clock */ + return rtd->codec_dai->config_sysclk(rtd->codec_dai, info, + SPITZ_AUDIO_CLOCK); + } +} + +/* spitz digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link spitz_dai = { + .name = "wm8750", + .stream_name = "WM8750", + .cpu_dai = &pxa_i2s_dai, + .codec_dai = &wm8750_dai, + .init = spitz_wm8750_init, + .config_sysclk = spitz_config_sysclk, +}; + +/* spitz audio machine driver */ +static struct snd_soc_machine snd_soc_machine_spitz = { + .name = "Spitz", + .dai_link = &spitz_dai, + .num_links = 1, + .ops = &spitz_ops, +}; + +/* spitz audio private data */ +static struct wm8750_setup_data spitz_wm8750_setup = { + .i2c_address = 0x1b, +}; + +/* spitz audio subsystem */ +static struct snd_soc_device spitz_snd_devdata = { + .machine = &snd_soc_machine_spitz, + .platform = &pxa2xx_soc_platform, + .codec_dev = &soc_codec_dev_wm8750, + .codec_data = &spitz_wm8750_setup, +}; + +static struct platform_device *spitz_snd_device; + +static int __init spitz_init(void) +{ + int ret; + + if (!(machine_is_spitz() || machine_is_borzoi() || machine_is_akita())) + return -ENODEV; + + spitz_snd_device = platform_device_alloc("soc-audio", -1); + if (!spitz_snd_device) + return -ENOMEM; + + platform_set_drvdata(spitz_snd_device, &spitz_snd_devdata); + spitz_snd_devdata.dev = &spitz_snd_device->dev; + ret = platform_device_add(spitz_snd_device); + + if (ret) + platform_device_put(spitz_snd_device); + + return ret; +} + +static void __exit spitz_exit(void) +{ + platform_device_unregister(spitz_snd_device); +} + +module_init(spitz_init); +module_exit(spitz_exit); + +MODULE_AUTHOR("Richard Purdie"); +MODULE_DESCRIPTION("ALSA SoC Spitz"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 1b49cb987030c09ca763c1dabd5c5e33f669e530 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Thu, 12 Oct 2006 14:33:09 +0200 Subject: [ALSA] ASoC pxa2xx Tosa machine support This patch adds Alsa audio support to the Sharp Zaurus SL-C6000 (Tosa) machine. From: Liam Girdwood Signed-off-by: Dirk Opfer Signed-off-by: Richard Purdie Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/pxa/tosa.c | 287 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 287 insertions(+) create mode 100644 sound/soc/pxa/tosa.c (limited to 'sound') diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c new file mode 100644 index 00000000000..8c3c6b0534d --- /dev/null +++ b/sound/soc/pxa/tosa.c @@ -0,0 +1,287 @@ +/* + * tosa.c -- SoC audio for Tosa + * + * Copyright 2005 Wolfson Microelectronics PLC. + * Copyright 2005 Openedhand Ltd. + * + * Authors: Liam Girdwood + * Richard Purdie + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision history + * 30th Nov 2005 Initial version. + * + * GPIO's + * 1 - Jack Insertion + * 5 - Hookswitch (headset answer/hang up switch) + * + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "../codecs/wm9712.h" +#include "pxa2xx-pcm.h" + +static struct snd_soc_machine tosa; + +#define TOSA_HP 0 +#define TOSA_MIC_INT 1 +#define TOSA_HEADSET 2 +#define TOSA_HP_OFF 3 +#define TOSA_SPK_ON 0 +#define TOSA_SPK_OFF 1 + +static int tosa_jack_func; +static int tosa_spk_func; + +static void tosa_ext_control(struct snd_soc_codec *codec) +{ + int spk = 0, mic_int = 0, hp = 0, hs = 0; + + /* set up jack connection */ + switch (tosa_jack_func) { + case TOSA_HP: + hp = 1; + break; + case TOSA_MIC_INT: + mic_int = 1; + break; + case TOSA_HEADSET: + hs = 1; + break; + } + + if (tosa_spk_func == TOSA_SPK_ON) + spk = 1; + + snd_soc_dapm_set_endpoint(codec, "Speaker", spk); + snd_soc_dapm_set_endpoint(codec, "Mic (Internal)", mic_int); + snd_soc_dapm_set_endpoint(codec, "Headphone Jack", hp); + snd_soc_dapm_set_endpoint(codec, "Headset Jack", hs); + snd_soc_dapm_sync_endpoints(codec); +} + +static int tosa_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_codec *codec = rtd->socdev->codec; + + /* check the jack status at stream startup */ + tosa_ext_control(codec); + return 0; +} + +static struct snd_soc_ops tosa_ops = { + .startup = tosa_startup, +}; + +static int tosa_get_jack(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = tosa_jack_func; + return 0; +} + +static int tosa_set_jack(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + + if (tosa_jack_func == ucontrol->value.integer.value[0]) + return 0; + + tosa_jack_func = ucontrol->value.integer.value[0]; + tosa_ext_control(codec); + return 1; +} + +static int tosa_get_spk(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = tosa_spk_func; + return 0; +} + +static int tosa_set_spk(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + + if (tosa_spk_func == ucontrol->value.integer.value[0]) + return 0; + + tosa_spk_func = ucontrol->value.integer.value[0]; + tosa_ext_control(codec); + return 1; +} + +/* tosa dapm event handlers */ +static int tosa_hp_event(struct snd_soc_dapm_widget *w, int event) +{ + if (SND_SOC_DAPM_EVENT_ON(event)) + set_tc6393_gpio(&tc6393_device.dev,TOSA_TC6393_L_MUTE); + else + reset_tc6393_gpio(&tc6393_device.dev,TOSA_TC6393_L_MUTE); + return 0; +} + +/* tosa machine dapm widgets */ +static const struct snd_soc_dapm_widget tosa_dapm_widgets[] = { +SND_SOC_DAPM_HP("Headphone Jack", tosa_hp_event), +SND_SOC_DAPM_HP("Headset Jack", NULL), +SND_SOC_DAPM_MIC("Mic (Internal)", NULL), +SND_SOC_DAPM_SPK("Speaker", NULL), +}; + +/* tosa audio map */ +static const char *audio_map[][3] = { + + /* headphone connected to HPOUTL, HPOUTR */ + {"Headphone Jack", NULL, "HPOUTL"}, + {"Headphone Jack", NULL, "HPOUTR"}, + + /* ext speaker connected to LOUT2, ROUT2 */ + {"Speaker", NULL, "LOUT2"}, + {"Speaker", NULL, "ROUT2"}, + + /* internal mic is connected to mic1, mic2 differential - with bias */ + {"MIC1", NULL, "Mic Bias"}, + {"MIC2", NULL, "Mic Bias"}, + {"Mic Bias", NULL, "Mic (Internal)"}, + + /* headset is connected to HPOUTR, and LINEINR with bias */ + {"Headset Jack", NULL, "HPOUTR"}, + {"LINEINR", NULL, "Mic Bias"}, + {"Mic Bias", NULL, "Headset Jack"}, + + {NULL, NULL, NULL}, +}; + +static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset", + "Off"}; +static const char *spk_function[] = {"On", "Off"}; +static const struct soc_enum tosa_enum[] = { + SOC_ENUM_SINGLE_EXT(5, jack_function), + SOC_ENUM_SINGLE_EXT(2, spk_function), +}; + +static const struct snd_kcontrol_new tosa_controls[] = { + SOC_ENUM_EXT("Jack Function", tosa_enum[0], tosa_get_jack, + tosa_set_jack), + SOC_ENUM_EXT("Speaker Function", tosa_enum[1], tosa_get_spk, + tosa_set_spk), +}; + +static int tosa_ac97_init(struct snd_soc_codec *codec) +{ + int i, err; + + snd_soc_dapm_set_endpoint(codec, "OUT3", 0); + snd_soc_dapm_set_endpoint(codec, "MONOOUT", 0); + + /* add tosa specific controls */ + for (i = 0; i < ARRAY_SIZE(tosa_controls); i++) { + err = snd_ctl_add(codec->card, + snd_soc_cnew(&tosa_controls[i],codec, NULL)); + if (err < 0) + return err; + } + + /* add tosa specific widgets */ + for (i = 0; i < ARRAY_SIZE(tosa_dapm_widgets); i++) { + snd_soc_dapm_new_control(codec, &tosa_dapm_widgets[i]); + } + + /* set up tosa specific audio path audio_map */ + for (i = 0; audio_map[i][0] != NULL; i++) { + snd_soc_dapm_connect_input(codec, audio_map[i][0], + audio_map[i][1], audio_map[i][2]); + } + + snd_soc_dapm_sync_endpoints(codec); + return 0; +} + +static struct snd_soc_dai_link tosa_dai[] = { +{ + .name = "AC97", + .stream_name = "AC97 HiFi", + .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI], + .codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI], + .init = tosa_ac97_init, +}, +{ + .name = "AC97 Aux", + .stream_name = "AC97 Aux", + .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX], + .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX], +}, +}; + +static struct snd_soc_machine tosa = { + .name = "Tosa", + .dai_link = tosa_dai, + .num_links = ARRAY_SIZE(tosa_dai), + .ops = &tosa_ops, +}; + +static struct snd_soc_device tosa_snd_devdata = { + .machine = &tosa, + .platform = &pxa2xx_soc_platform, + .codec_dev = &soc_codec_dev_wm9712, +}; + +static struct platform_device *tosa_snd_device; + +static int __init tosa_init(void) +{ + int ret; + + if (!machine_is_tosa()) + return -ENODEV; + + tosa_snd_device = platform_device_alloc("soc-audio", -1); + if (!tosa_snd_device) + return -ENOMEM; + + platform_set_drvdata(tosa_snd_device, &tosa_snd_devdata); + tosa_snd_devdata.dev = &tosa_snd_device->dev; + ret = platform_device_add(tosa_snd_device); + + if (ret) + platform_device_put(tosa_snd_device); + + return ret; +} + +static void __exit tosa_exit(void) +{ + platform_device_unregister(tosa_snd_device); +} + +module_init(tosa_init); +module_exit(tosa_exit); + +/* Module information */ +MODULE_AUTHOR("Richard Purdie"); +MODULE_DESCRIPTION("ALSA SoC Tosa"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 6e24dd9310b66d6f500a81ee320a8babec529573 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Thu, 12 Oct 2006 14:33:45 +0200 Subject: [ALSA] ASoC pxa2xx Poodle machine support This patch adds Alsa audio support to the Sharp Zaurus SL-C5600 (Poodle) machine. From: Liam Girdwood Signed-off-by: Richard Purdie Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/pxa/poodle.c | 329 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 329 insertions(+) create mode 100644 sound/soc/pxa/poodle.c (limited to 'sound') diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c new file mode 100644 index 00000000000..ee933608682 --- /dev/null +++ b/sound/soc/pxa/poodle.c @@ -0,0 +1,329 @@ +/* + * poodle.c -- SoC audio for Poodle + * + * Copyright 2005 Wolfson Microelectronics PLC. + * Copyright 2005 Openedhand Ltd. + * + * Authors: Liam Girdwood + * Richard Purdie + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "../codecs/wm8731.h" +#include "pxa2xx-pcm.h" + +#define POODLE_HP 1 +#define POODLE_HP_OFF 0 +#define POODLE_SPK_ON 1 +#define POODLE_SPK_OFF 0 + + /* audio clock in Hz - rounded from 12.235MHz */ +#define POODLE_AUDIO_CLOCK 12288000 + +static int poodle_jack_func; +static int poodle_spk_func; + +static void poodle_ext_control(struct snd_soc_codec *codec) +{ + int spk = 0; + + /* set up jack connection */ + if (poodle_jack_func == POODLE_HP) { + /* set = unmute headphone */ + locomo_gpio_write(&poodle_locomo_device.dev, + POODLE_LOCOMO_GPIO_MUTE_L, 1); + locomo_gpio_write(&poodle_locomo_device.dev, + POODLE_LOCOMO_GPIO_MUTE_R, 1); + snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 1); + } else { + locomo_gpio_write(&poodle_locomo_device.dev, + POODLE_LOCOMO_GPIO_MUTE_L, 0); + locomo_gpio_write(&poodle_locomo_device.dev, + POODLE_LOCOMO_GPIO_MUTE_R, 0); + snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 0); + } + + if (poodle_spk_func == POODLE_SPK_ON) + spk = 1; + + /* set the enpoints to their new connetion states */ + snd_soc_dapm_set_endpoint(codec, "Ext Spk", spk); + + /* signal a DAPM event */ + snd_soc_dapm_sync_endpoints(codec); +} + +static int poodle_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_codec *codec = rtd->socdev->codec; + + /* check the jack status at stream startup */ + poodle_ext_control(codec); + return 0; +} + +/* we need to unmute the HP at shutdown as the mute burns power on poodle */ +static int poodle_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_codec *codec = rtd->socdev->codec; + + /* set = unmute headphone */ + locomo_gpio_write(&poodle_locomo_device.dev, + POODLE_LOCOMO_GPIO_MUTE_L, 1); + locomo_gpio_write(&poodle_locomo_device.dev, + POODLE_LOCOMO_GPIO_MUTE_R, 1); + return 0; +} + +static struct snd_soc_ops poodle_ops = { + .startup = poodle_startup, + .shutdown = poodle_shutdown, +}; + +static int poodle_get_jack(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = poodle_jack_func; + return 0; +} + +static int poodle_set_jack(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + + if (poodle_jack_func == ucontrol->value.integer.value[0]) + return 0; + + poodle_jack_func = ucontrol->value.integer.value[0]; + poodle_ext_control(codec); + return 1; +} + +static int poodle_get_spk(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = poodle_spk_func; + return 0; +} + +static int poodle_set_spk(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + + if (poodle_spk_func == ucontrol->value.integer.value[0]) + return 0; + + poodle_spk_func = ucontrol->value.integer.value[0]; + poodle_ext_control(codec); + return 1; +} + +static int poodle_amp_event(struct snd_soc_dapm_widget *w, int event) +{ + if (SND_SOC_DAPM_EVENT_ON(event)) + locomo_gpio_write(&poodle_locomo_device.dev, + POODLE_LOCOMO_GPIO_AMP_ON, 0); + else + locomo_gpio_write(&poodle_locomo_device.dev, + POODLE_LOCOMO_GPIO_AMP_ON, 1); + + return 0; +} + +/* poodle machine dapm widgets */ +static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = { +SND_SOC_DAPM_HP("Headphone Jack", NULL), +SND_SOC_DAPM_SPK("Ext Spk", poodle_amp_event), +}; + +/* Corgi machine audio_mapnections to the codec pins */ +static const char *audio_map[][3] = { + + /* headphone connected to LHPOUT1, RHPOUT1 */ + {"Headphone Jack", NULL, "LHPOUT"}, + {"Headphone Jack", NULL, "RHPOUT"}, + + /* speaker connected to LOUT, ROUT */ + {"Ext Spk", NULL, "ROUT"}, + {"Ext Spk", NULL, "LOUT"}, + + {NULL, NULL, NULL}, +}; + +static const char *jack_function[] = {"Off", "Headphone"}; +static const char *spk_function[] = {"Off", "On"}; +static const struct soc_enum poodle_enum[] = { + SOC_ENUM_SINGLE_EXT(2, jack_function), + SOC_ENUM_SINGLE_EXT(2, spk_function), +}; + +static const snd_kcontrol_new_t wm8731_poodle_controls[] = { + SOC_ENUM_EXT("Jack Function", poodle_enum[0], poodle_get_jack, + poodle_set_jack), + SOC_ENUM_EXT("Speaker Function", poodle_enum[1], poodle_get_spk, + poodle_set_spk), +}; + +/* + * Logic for a wm8731 as connected on a Sharp SL-C7x0 Device + */ +static int poodle_wm8731_init(struct snd_soc_codec *codec) +{ + int i, err; + + snd_soc_dapm_set_endpoint(codec, "LLINEIN", 0); + snd_soc_dapm_set_endpoint(codec, "RLINEIN", 0); + snd_soc_dapm_set_endpoint(codec, "MICIN", 1); + + /* Add poodle specific controls */ + for (i = 0; i < ARRAY_SIZE(wm8731_poodle_controls); i++) { + err = snd_ctl_add(codec->card, + snd_soc_cnew(&wm8731_poodle_controls[i],codec, NULL)); + if (err < 0) + return err; + } + + /* Add poodle specific widgets */ + for (i = 0; i < ARRAY_SIZE(wm8731_dapm_widgets); i++) { + snd_soc_dapm_new_control(codec, &wm8731_dapm_widgets[i]); + } + + /* Set up poodle specific audio path audio_map */ + for (i = 0; audio_map[i][0] != NULL; i++) { + snd_soc_dapm_connect_input(codec, audio_map[i][0], + audio_map[i][1], audio_map[i][2]); + } + + snd_soc_dapm_sync_endpoints(codec); + return 0; +} + +static unsigned int poodle_config_sysclk(struct snd_soc_pcm_runtime *rtd, + struct snd_soc_clock_info *info) +{ + if (info->bclk_master & SND_SOC_DAIFMT_CBS_CFS) { + /* pxa2xx is i2s master */ + switch (info->rate) { + case 44100: + case 88200: + /* configure codec digital filters for 44.1, 88.2 */ + rtd->codec_dai->config_sysclk(rtd->codec_dai, info, + 11289600); + break; + default: + /* configure codec digital filters for all other rates */ + rtd->codec_dai->config_sysclk(rtd->codec_dai, info, + POODLE_AUDIO_CLOCK); + break; + } + return rtd->cpu_dai->config_sysclk(rtd->cpu_dai, info, + POODLE_AUDIO_CLOCK); + } else { + /* codec is i2s master - + * only configure codec DAI clock and filters */ + return rtd->codec_dai->config_sysclk(rtd->codec_dai, info, + POODLE_AUDIO_CLOCK); + } +} + +/* poodle digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link poodle_dai = { + .name = "WM8731", + .stream_name = "WM8731", + .cpu_dai = &pxa_i2s_dai, + .codec_dai = &wm8731_dai, + .init = poodle_wm8731_init, + .config_sysclk = poodle_config_sysclk, +}; + +/* poodle audio machine driver */ +static struct snd_soc_machine snd_soc_machine_poodle = { + .name = "Poodle", + .dai_link = &poodle_dai, + .num_links = 1, + .ops = &poodle_ops, +}; + +/* poodle audio private data */ +static struct wm8731_setup_data poodle_wm8731_setup = { + .i2c_address = 0x1b, +}; + +/* poodle audio subsystem */ +static struct snd_soc_device poodle_snd_devdata = { + .machine = &snd_soc_machine_poodle, + .platform = &pxa2xx_soc_platform, + .codec_dev = &soc_codec_dev_wm8731, + .codec_data = &poodle_wm8731_setup, +}; + +static struct platform_device *poodle_snd_device; + +static int __init poodle_init(void) +{ + int ret; + + if (!machine_is_poodle()) + return -ENODEV; + + locomo_gpio_set_dir(&poodle_locomo_device.dev, + POODLE_LOCOMO_GPIO_AMP_ON, 0); + /* should we mute HP at startup - burning power ?*/ + locomo_gpio_set_dir(&poodle_locomo_device.dev, + POODLE_LOCOMO_GPIO_MUTE_L, 0); + locomo_gpio_set_dir(&poodle_locomo_device.dev, + POODLE_LOCOMO_GPIO_MUTE_R, 0); + + poodle_snd_device = platform_device_alloc("soc-audio", -1); + if (!poodle_snd_device) + return -ENOMEM; + + platform_set_drvdata(poodle_snd_device, &poodle_snd_devdata); + poodle_snd_devdata.dev = &poodle_snd_device->dev; + ret = platform_device_add(poodle_snd_device); + + if (ret) + platform_device_put(poodle_snd_device); + + return ret; +} + +static void __exit poodle_exit(void) +{ + platform_device_unregister(poodle_snd_device); +} + +module_init(poodle_init); +module_exit(poodle_exit); + +/* Module information */ +MODULE_AUTHOR("Richard Purdie"); +MODULE_DESCRIPTION("ALSA SoC Poodle"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 734c2d4bb7cfccaab79923331efc7422e4e76a8a Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Thu, 12 Oct 2006 14:34:32 +0200 Subject: [ALSA] ASoC pxa2xx build support This patch builds ASoC pxa2xx support for Corgi, Spitz, Tosa and Poodle Zaurus machines. From: Liam Girdwood Signed-off-by: Richard Purdie Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/Kconfig | 1 + sound/soc/Makefile | 2 +- sound/soc/pxa/Kconfig | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++ sound/soc/pxa/Makefile | 20 +++++++++++++++++ 4 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 sound/soc/pxa/Kconfig create mode 100644 sound/soc/pxa/Makefile (limited to 'sound') diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index e7dab5bdc6b..ec821a57f84 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -23,6 +23,7 @@ config SND_SOC menu "SoC Platforms" depends on SND_SOC source "sound/soc/at91/Kconfig" +source "sound/soc/pxa/Kconfig" endmenu # Supported codecs diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 3e12a1654c4..98e6f49dafc 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -1,4 +1,4 @@ snd-soc-core-objs := soc-core.o soc-dapm.o obj-$(CONFIG_SND_SOC) += snd-soc-core.o -obj-$(CONFIG_SND_SOC) += codecs/ at91/ +obj-$(CONFIG_SND_SOC) += codecs/ at91/ pxa/ diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig new file mode 100644 index 00000000000..a07598cdab3 --- /dev/null +++ b/sound/soc/pxa/Kconfig @@ -0,0 +1,60 @@ +menu "SoC Audio for the Intel PXA2xx" + +config SND_PXA2XX_SOC + tristate "SoC Audio for the Intel PXA2xx chip" + depends on ARCH_PXA && SND + select SND_PCM + help + Say Y or M if you want to add support for codecs attached to + the PXA2xx AC97, I2S or SSP interface. You will also need + to select the audio interfaces to support below. + +config SND_PXA2XX_AC97 + tristate + select SND_AC97_CODEC + +config SND_PXA2XX_SOC_AC97 + tristate + select SND_AC97_BUS + select SND_SOC_AC97_BUS + +config SND_PXA2XX_SOC_I2S + tristate + +config SND_PXA2XX_SOC_CORGI + tristate "SoC Audio support for Sharp Zaurus SL-C7x0" + depends on SND_PXA2XX_SOC && PXA_SHARP_C7xx + select SND_PXA2XX_SOC_I2S + select SND_SOC_WM8731 + help + Say Y if you want to add support for SoC audio on Sharp + Zaurus SL-C7x0 models (Corgi, Shepherd, Husky). + +config SND_PXA2XX_SOC_SPITZ + tristate "SoC Audio support for Sharp Zaurus SL-Cxx00" + depends on SND_PXA2XX_SOC && PXA_SHARP_Cxx00 + select SND_PXA2XX_SOC_I2S + select SND_SOC_WM8750 + help + Say Y if you want to add support for SoC audio on Sharp + Zaurus SL-Cxx00 models (Spitz, Borzoi and Akita). + +config SND_PXA2XX_SOC_POODLE + tristate "SoC Audio support for Poodle" + depends on SND_PXA2XX_SOC && MACH_POODLE + select SND_PXA2XX_SOC_I2S + select SND_SOC_WM8731 + help + Say Y if you want to add support for SoC audio on Sharp + Zaurus SL-5600 model (Poodle). + +config SND_PXA2XX_SOC_TOSA + tristate "SoC AC97 Audio support for Tosa" + depends on SND_PXA2XX_SOC && MACH_TOSA + select SND_PXA2XX_SOC_AC97 + select SND_SOC_WM9712 + help + Say Y if you want to add support for SoC audio on Sharp + Zaurus SL-C6000x models (Tosa). + +endmenu diff --git a/sound/soc/pxa/Makefile b/sound/soc/pxa/Makefile new file mode 100644 index 00000000000..78e0d6b07d1 --- /dev/null +++ b/sound/soc/pxa/Makefile @@ -0,0 +1,20 @@ +# PXA Platform Support +snd-soc-pxa2xx-objs := pxa2xx-pcm.o +snd-soc-pxa2xx-ac97-objs := pxa2xx-ac97.o +snd-soc-pxa2xx-i2s-objs := pxa2xx-i2s.o + +obj-$(CONFIG_SND_PXA2XX_SOC) += snd-soc-pxa2xx.o +obj-$(CONFIG_SND_PXA2XX_SOC_AC97) += snd-soc-pxa2xx-ac97.o +obj-$(CONFIG_SND_PXA2XX_SOC_I2S) += snd-soc-pxa2xx-i2s.o + +# PXA Machine Support +snd-soc-corgi-objs := corgi.o +snd-soc-poodle-objs := poodle.o +snd-soc-tosa-objs := tosa.o +snd-soc-spitz-objs := spitz.o + +obj-$(CONFIG_SND_PXA2XX_SOC_CORGI) += snd-soc-corgi.o +obj-$(CONFIG_SND_PXA2XX_SOC_POODLE) += snd-soc-poodle.o +obj-$(CONFIG_SND_PXA2XX_SOC_TOSA) += snd-soc-tosa.o +obj-$(CONFIG_SND_PXA2XX_SOC_SPITZ) += snd-soc-spitz.o + -- cgit v1.2.3 From c07584c83287ae5a13cc836f69a1d824ad068c66 Mon Sep 17 00:00:00 2001 From: Tobin Davis Date: Fri, 13 Oct 2006 12:32:16 +0200 Subject: [ALSA] hda-codec - Add support for Medion laptops This patch adds audio support for Medion's line of laptops, based on code shipped with the laptops. Microphone support is still being explored. Signed-off-by: Tobin Davis Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 54 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 4e0c3c1b908..0b14bd17181 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -112,6 +112,7 @@ enum { ALC883_6ST_DIG, ALC888_DEMO_BOARD, ALC883_ACER, + ALC883_MEDION, ALC883_AUTO, ALC883_MODEL_LAST, }; @@ -4309,7 +4310,7 @@ static struct hda_verb alc882_init_verbs[] = { static struct hda_verb alc882_eapd_verbs[] = { /* change to EAPD mode */ {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, - {0x20, AC_VERB_SET_PROC_COEF, 0x3060}, + {0x20, AC_VERB_SET_PROC_COEF, 0x3070}, { } }; @@ -4875,6 +4876,41 @@ static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = { { } /* end */ }; +static snd_kcontrol_new_t alc883_fivestack_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x16, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), + HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), + + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 1, + .info = alc883_mux_enum_info, + .get = alc883_mux_enum_get, + .put = alc883_mux_enum_put, + }, + { } /* end */ +}; + static struct snd_kcontrol_new alc883_chmode_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -5082,6 +5118,8 @@ static struct hda_board_config alc883_cfg_tbl[] = { .config = ALC883_ACER }, { .pci_subvendor = 0x1025, .pci_subdevice = 0x009f, .config = ALC883_ACER }, + { .pci_subvendor = 0x161f, .pci_subdevice = 0x2054, + .modelname = "medion", .config = ALC883_MEDION } { .modelname = "auto", .config = ALC883_AUTO }, {} }; @@ -5169,6 +5207,20 @@ static struct alc_config_preset alc883_presets[] = { .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_capture_source, }, + [ALC883_MEDION] = { + .mixers = { alc883_fivestack_mixer, + alc883_chmode_mixer }, + .init_verbs = { alc883_init_verbs, + alc882_eapd_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc883_adc_nids), + .adc_nids = alc883_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes), + .channel_mode = alc883_sixstack_modes, + .input_mux = &alc883_capture_source, + } + }; -- cgit v1.2.3 From 527541f9a8a83eedb4d732657dbfdcd2c4ca8bb4 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 13 Oct 2006 12:33:56 +0200 Subject: [ALSA] ASoC DAI capabilities labelling This patch suggested by Takashi changes the DAI capabilities definitions in pxa-i2s.c, at91rm9200-i2s.c, wm8731.c, wm8750.c and wm9712.c to use a label = value style. Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/at91/at91rm9200-i2s.c | 52 +++++-- sound/soc/codecs/wm8731.c | 184 ++++++++++++++++------- sound/soc/codecs/wm8750.c | 316 +++++++++++++++++++++++++++++----------- sound/soc/codecs/wm9712.c | 7 +- sound/soc/pxa/pxa2xx-i2s.c | 91 +++++++++--- 5 files changed, 483 insertions(+), 167 deletions(-) (limited to 'sound') diff --git a/sound/soc/at91/at91rm9200-i2s.c b/sound/soc/at91/at91rm9200-i2s.c index 044a774b430..91f1daa44f1 100644 --- a/sound/soc/at91/at91rm9200-i2s.c +++ b/sound/soc/at91/at91rm9200-i2s.c @@ -51,24 +51,52 @@ static struct snd_soc_dai_mode at91rm9200_i2s[] = { /* 8k: BCLK = (MCLK/10) = (60MHz/50) = 1.2MHz */ - { AT91RM9200_I2S_DAIFMT, SND_SOC_DAITDM_LRDW(0,0), - SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_8000, AT91RM9200_I2S_DIR, - SND_SOC_DAI_BFS_DIV, 1500, SND_SOC_FSBD(10), (25 << 16 | 74) }, + { + .fmt = AT91RM9200_I2S_DAIFMT, + .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, + .pcmrate = SNDRV_PCM_RATE_8000, + .pcmdir = AT91RM9200_I2S_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 1500, + .bfs = SND_SOC_FSBD(10), + .priv = (25 << 16 | 74), + }, /* 16k: BCLK = (MCLK/3) ~= (60MHz/14) = 4.285714MHz */ - { AT91RM9200_I2S_DAIFMT, SND_SOC_DAITDM_LRDW(0,0), - SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_16000, AT91RM9200_I2S_DIR, - SND_SOC_DAI_BFS_DIV, 750, SND_SOC_FSBD(3) , (7 << 16 | 133) }, + { + .fmt = AT91RM9200_I2S_DAIFMT, + .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, + .pcmrate = SNDRV_PCM_RATE_16000, + .pcmdir = AT91RM9200_I2S_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 750, + .bfs = SND_SOC_FSBD(3), + .flags (7 << 16 | 133), + }, /* 24k: BCLK = (MCLK/10) = (60MHz/50) = 1.2MHz */ - { AT91RM9200_I2S_DAIFMT, SND_SOC_DAITDM_LRDW(0,0), - SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_22050, AT91RM9200_I2S_DIR, - SND_SOC_DAI_BFS_DIV, 500, SND_SOC_FSBD(10), (25 << 16 | 24) }, + { + .fmt = AT91RM9200_I2S_DAIFMT, + .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, + .pcmrate = SNDRV_PCM_RATE_22050, + .pcmdir = AT91RM9200_I2S_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 500, + .bfs = SND_SOC_FSBD(10), + .priv = (25 << 16 | 24), + }, /* 48kHz: BCLK = (MCLK/5) ~= (60MHz/26) = 2.3076923MHz */ - { AT91RM9200_I2S_DAIFMT, SND_SOC_DAITDM_LRDW(0,0), - SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_48000, AT91RM9200_I2S_DIR, - SND_SOC_DAI_BFS_DIV, 250, SND_SOC_FSBD(5), (13 << 16 | 23) }, + { + .fmt = AT91RM9200_I2S_DAIFMT, + .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, + .pcmrate = SNDRV_PCM_RATE_48000, + .pcmdir = AT91RM9200_I2S_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 250, + .bfs SND_SOC_FSBD(5), + .priv = (13 << 16 | 23), + }, }; diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index cd0ece650f3..03a6bb9b877 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -85,74 +85,160 @@ static const u16 wm8731_reg[WM8731_CACHEREGNUM] = { static struct snd_soc_dai_mode wm8731_modes[] = { /* codec frame and clock master modes */ /* 8k */ - {WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, SND_SOC_DAITDM_LRDW(0,0), - WM8731_HIFI_BITS, SNDRV_PCM_RATE_8000, WM8731_DIR, 0, - 1536, SND_SOC_FSB(64)}, - {WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, SND_SOC_DAITDM_LRDW(0,0), - WM8731_HIFI_BITS, SNDRV_PCM_RATE_8000, WM8731_DIR, 0, - 2304, SND_SOC_FSB(64)}, - {WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, SND_SOC_DAITDM_LRDW(0,0), - WM8731_HIFI_BITS, SNDRV_PCM_RATE_8000, WM8731_DIR, 0, - 1408, SND_SOC_FSB(64)}, - {WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, SND_SOC_DAITDM_LRDW(0,0), - WM8731_HIFI_BITS, SNDRV_PCM_RATE_8000, WM8731_DIR, 0, - 2112, SND_SOC_FSB(64)}, + { + .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + .pcmfmt = WM8731_HIFI_BITS, + .pcmrate = SNDRV_PCM_RATE_8000, + .pcmdir = WM8731_DIR, + .fs = 1536, + .bfs = SND_SOC_FSB(64), + }, + { + .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + .pcmfmt = WM8731_HIFI_BITS, + .pcmrate = SNDRV_PCM_RATE_8000, + .pcmdir = WM8731_DIR, + .fs = 2304, + .bfs = SND_SOC_FSB(64), + }, + { + .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + .pcmfmt = WM8731_HIFI_BITS, + .pcmrate = SNDRV_PCM_RATE_8000, + .pcmdir = WM8731_DIR, + .fs = 1408, + .bfs = SND_SOC_FSB(64), + }, + { + .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + .pcmfmt = WM8731_HIFI_BITS, + .pcmrate = SNDRV_PCM_RATE_8000, + .pcmdir = WM8731_DIR, + .fs = 2112, + .bfs = SND_SOC_FSB(64), + }, /* 32k */ - {WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, SND_SOC_DAITDM_LRDW(0,0), - WM8731_HIFI_BITS, SNDRV_PCM_RATE_32000, WM8731_DIR, 0, - 384, SND_SOC_FSB(64)}, - {WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, SND_SOC_DAITDM_LRDW(0,0), - WM8731_HIFI_BITS, SNDRV_PCM_RATE_32000, WM8731_DIR, 0, - 576, SND_SOC_FSB(64)}, + { + .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + .pcmfmt = WM8731_HIFI_BITS, + .pcmrate = SNDRV_PCM_RATE_32000, + .pcmdir = WM8731_DIR, + .fs = 384, + .bfs = SND_SOC_FSB(64), + }, + { + .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + .pcmfmt = WM8731_HIFI_BITS, + .pcmrate = SNDRV_PCM_RATE_32000, + .pcmdir = WM8731_DIR, + .fs = 576, + .bfs = SND_SOC_FSB(64), + }, /* 44.1k & 48k */ - {WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, SND_SOC_DAITDM_LRDW(0,0), - WM8731_HIFI_BITS, SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, - WM8731_DIR, 0, 256, SND_SOC_FSB(64)}, - {WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, SND_SOC_DAITDM_LRDW(0,0), - WM8731_HIFI_BITS, SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, - WM8731_DIR, 0, 384, SND_SOC_FSB(64)}, + { + .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + .pcmfmt = WM8731_HIFI_BITS, + .pcmrate = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, + .pcmdir = WM8731_DIR, + .fs = 256, + .bfs = SND_SOC_FSB(64), + }, + { + .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + .pcmfmt = WM8731_HIFI_BITS, + .pcmrate = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, + .pcmdir = WM8731_DIR, + .fs = 384, + .bfs = SND_SOC_FSB(64), + }, /* 88.2 & 96k */ - {WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, SND_SOC_DAITDM_LRDW(0,0), - WM8731_HIFI_BITS, SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000, - WM8731_DIR, 0, 128, SND_SOC_FSB(64)}, - {WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, SND_SOC_DAITDM_LRDW(0,0), - WM8731_HIFI_BITS, SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000, - WM8731_DIR, 0, 192, SND_SOC_FSB(64)}, - + { + .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + .pcmfmt = WM8731_HIFI_BITS, + .pcmrate = SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000, + .pcmdir = WM8731_DIR, + .fs = 128, + .bfs = SND_SOC_FSB(64), + + }, + { + .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + .pcmfmt = WM8731_HIFI_BITS, + .pcmrate = SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000, + .pcmdir = WM8731_DIR, + .fs = 192, + .bfs = SND_SOC_FSB(64), + }, /* USB codec frame and clock master modes */ /* 8k */ - {WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, SND_SOC_DAITDM_LRDW(0,0), - WM8731_HIFI_BITS, SNDRV_PCM_RATE_8000, WM8731_DIR, - SND_SOC_DAI_BFS_DIV, 1500, SND_SOC_FSBD(1)}, + { + .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + .pcmfmt = WM8731_HIFI_BITS, + .pcmrate = SNDRV_PCM_RATE_8000, + .pcmdir = WM8731_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 1500, + .bfs = SND_SOC_FSBD(1), + }, /* 44.1k */ - {WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, SND_SOC_DAITDM_LRDW(0,0), - WM8731_HIFI_BITS, SNDRV_PCM_RATE_44100, WM8731_DIR, - SND_SOC_DAI_BFS_DIV, 272, SND_SOC_FSBD(1)}, + { + .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + .pcmfmt = WM8731_HIFI_BITS, + .pcmrate = SNDRV_PCM_RATE_44100, + .pcmdir = WM8731_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 272, + .bfs = SND_SOC_FSBD(1), + }, /* 48k */ - {WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, SND_SOC_DAITDM_LRDW(0,0), - WM8731_HIFI_BITS, SNDRV_PCM_RATE_48000, WM8731_DIR, - SND_SOC_DAI_BFS_DIV, 250, SND_SOC_FSBD(1)}, + { + .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + .pcmfmt = WM8731_HIFI_BITS, + .pcmrate = SNDRV_PCM_RATE_48000, + .pcmdir = WM8731_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 250, + .bfs = SND_SOC_FSBD(1), + }, /* 88.2k */ - {WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, SND_SOC_DAITDM_LRDW(0,0), - WM8731_HIFI_BITS, SNDRV_PCM_RATE_88200, WM8731_DIR, - SND_SOC_DAI_BFS_DIV, 136, SND_SOC_FSBD(1)}, + { + .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + .pcmfmt = WM8731_HIFI_BITS, + .pcmrate = SNDRV_PCM_RATE_88200, + .pcmdir = WM8731_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 136, + .bfs = SND_SOC_FSBD(1), + }, /* 96k */ - {WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, SND_SOC_DAITDM_LRDW(0,0), - WM8731_HIFI_BITS, SNDRV_PCM_RATE_96000, WM8731_DIR, - SND_SOC_DAI_BFS_DIV, 125, SND_SOC_FSBD(1)}, + { + .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + .pcmfmt = WM8731_HIFI_BITS, + .pcmrate = SNDRV_PCM_RATE_96000, + .pcmdir = WM8731_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 125, + .bfs = SND_SOC_FSBD(1), + }, /* codec frame and clock slave modes */ - {WM8731_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, SND_SOC_DAITDM_LRDW(0,0), - WM8731_HIFI_BITS, WM8731_RATES, WM8731_DIR, SND_SOC_DAI_BFS_DIV, - SND_SOC_FS_ALL, SND_SOC_FSBD_ALL}, + { + .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, + .pcmfmt = WM8731_HIFI_BITS, + .pcmrate = WM8731_RATES, + .pcmdir = WM8731_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = SND_SOC_FS_ALL, + .bfs = SND_SOC_FSBD_ALL, + }, }; /* diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index 6a8b2799b3b..b07a6ed6aa6 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c @@ -97,102 +97,254 @@ static const u16 wm8750_reg[] = { static struct snd_soc_dai_mode wm8750_modes[] = { /* common codec frame and clock master modes */ /* 8k */ - {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_8000, - WM8750_DIR, SND_SOC_DAI_BFS_DIV, 1536, WM8750_HIFI_FSB}, - {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_8000, - WM8750_DIR, SND_SOC_DAI_BFS_DIV, 1408, WM8750_HIFI_FSB}, - {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_8000, - WM8750_DIR, SND_SOC_DAI_BFS_DIV, 2304, WM8750_HIFI_FSB}, - {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_8000, - WM8750_DIR, SND_SOC_DAI_BFS_DIV, 2112, WM8750_HIFI_FSB}, - {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_8000, - WM8750_DIR, SND_SOC_DAI_BFS_DIV, 1500, WM8750_HIFI_FSB}, + { + .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + .pcmfmt = WM8750_HIFI_BITS, + .pcmrate = SNDRV_PCM_RATE_8000, + .pcmdir = WM8750_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 1536, + .bfs = WM8750_HIFI_FSB, + }, + { + .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + .pcmfmt = WM8750_HIFI_BITS, + .pcmrate = SNDRV_PCM_RATE_8000, + .pcmdir = WM8750_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 1408, + .bfs = WM8750_HIFI_FSB, + }, + { + .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + .pcmfmt = WM8750_HIFI_BITS, + .pcmrate = SNDRV_PCM_RATE_8000, + .pcmdir = WM8750_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 2304, + .bfs = WM8750_HIFI_FSB, + }, + { + .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + .pcmfmt = WM8750_HIFI_BITS, + .pcmrate = SNDRV_PCM_RATE_8000, + .pcmdir = WM8750_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 2112, + .bfs = WM8750_HIFI_FSB, + }, + { + .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + .pcmfmt = WM8750_HIFI_BITS, + .pcmrate = SNDRV_PCM_RATE_8000, + .pcmdir = WM8750_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 1500, + .bfs = WM8750_HIFI_FSB, + }, /* 11.025k */ - {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_11025, - WM8750_DIR, SND_SOC_DAI_BFS_DIV, 1024, WM8750_HIFI_FSB}, - {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_11025, - WM8750_DIR, SND_SOC_DAI_BFS_DIV, 1536, WM8750_HIFI_FSB}, - {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_11025, - WM8750_DIR, SND_SOC_DAI_BFS_DIV, 1088, WM8750_HIFI_FSB}, + { + .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + .pcmfmt = WM8750_HIFI_BITS, + .pcmrate = SNDRV_PCM_RATE_11025, + .pcmdir = WM8750_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 1024, + .bfs = WM8750_HIFI_FSB, + }, + { + .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + .pcmfmt = WM8750_HIFI_BITS, + .pcmrate = SNDRV_PCM_RATE_11025, + .pcmdir = WM8750_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 1536, + .bfs = WM8750_HIFI_FSB, + }, + { + .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + .pcmfmt = WM8750_HIFI_BITS, + .pcmrate = SNDRV_PCM_RATE_11025, + .pcmdir = WM8750_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 1088, + .bfs = WM8750_HIFI_FSB, + }, /* 16k */ - {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_16000, - WM8750_DIR, SND_SOC_DAI_BFS_DIV, 768, WM8750_HIFI_FSB}, - {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_16000, - WM8750_DIR, SND_SOC_DAI_BFS_DIV, 1152, WM8750_HIFI_FSB}, - {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_16000, - WM8750_DIR, SND_SOC_DAI_BFS_DIV, 750, WM8750_HIFI_FSB}, + { + .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + .pcmfmt = WM8750_HIFI_BITS, + .pcmrate = SNDRV_PCM_RATE_16000, + .pcmdir = WM8750_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 768, + .bfs = WM8750_HIFI_FSB, + }, + { + .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + .pcmfmt = WM8750_HIFI_BITS, + .pcmrate = SNDRV_PCM_RATE_16000, + .pcmdir = WM8750_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 1152, + .bfs = WM8750_HIFI_FSB + }, + { + .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + .pcmfmt = WM8750_HIFI_BITS, + .pcmrate = SNDRV_PCM_RATE_16000, + .pcmdir = WM8750_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 750, + .bfs = WM8750_HIFI_FSB, + }, /* 22.05k */ - {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_22050, - WM8750_DIR, SND_SOC_DAI_BFS_DIV, 512, WM8750_HIFI_FSB}, - {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_22050, - WM8750_DIR, SND_SOC_DAI_BFS_DIV, 768, WM8750_HIFI_FSB}, - {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_22050, - WM8750_DIR, SND_SOC_DAI_BFS_DIV, 544, WM8750_HIFI_FSB}, + { + .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + .pcmfmt = WM8750_HIFI_BITS, + .pcmrate = SNDRV_PCM_RATE_22050, + .pcmdir = WM8750_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 512, + .bfs = WM8750_HIFI_FSB, + }, + { + .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + .pcmfmt = WM8750_HIFI_BITS, + .pcmrate = SNDRV_PCM_RATE_22050, + .pcmdir = WM8750_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 768, + .bfs = WM8750_HIFI_FSB, + }, + { + .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + .pcmfmt = WM8750_HIFI_BITS, + .pcmrate = SNDRV_PCM_RATE_22050, + .pcmdir = WM8750_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 544, + .bfs = WM8750_HIFI_FSB, + }, /* 32k */ - {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_16000, - WM8750_DIR, SND_SOC_DAI_BFS_DIV, 384, WM8750_HIFI_FSB}, - {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_16000, - WM8750_DIR, SND_SOC_DAI_BFS_DIV, 576, WM8750_HIFI_FSB}, - {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_16000, - WM8750_DIR, SND_SOC_DAI_BFS_DIV, 375, WM8750_HIFI_FSB}, + { + .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + .pcmfmt = WM8750_HIFI_BITS, + .pcmrate = SNDRV_PCM_RATE_32000, + .pcmdir = WM8750_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 384, + .bfs = WM8750_HIFI_FSB, + }, + { + .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + .pcmfmt = WM8750_HIFI_BITS, + .pcmrate = SNDRV_PCM_RATE_32000, + .pcmdir = WM8750_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 576, + .bfs = WM8750_HIFI_FSB, + }, + { + .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + .pcmfmt = WM8750_HIFI_BITS, + .pcmrate = SNDRV_PCM_RATE_32000, + .pcmdir = WM8750_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 375, + .bfs = WM8750_HIFI_FSB, + }, /* 44.1k & 48k */ - {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_44100 | - SNDRV_PCM_RATE_48000, WM8750_DIR, SND_SOC_DAI_BFS_DIV, 256, - WM8750_HIFI_FSB}, - {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_44100 | - SNDRV_PCM_RATE_48000, WM8750_DIR, SND_SOC_DAI_BFS_DIV, 384, - WM8750_HIFI_FSB}, - {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_44100, - WM8750_DIR, SND_SOC_DAI_BFS_DIV, 272, WM8750_HIFI_FSB}, - {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_48000, - WM8750_DIR, SND_SOC_DAI_BFS_DIV, 250, WM8750_HIFI_FSB}, + { + .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + .pcmfmt = WM8750_HIFI_BITS, + .pcmrate = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, + .pcmdir = WM8750_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 256, + .bfs = WM8750_HIFI_FSB, + }, + { + .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + .pcmfmt = WM8750_HIFI_BITS, + .pcmrate = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, + .pcmdir = WM8750_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 384, + .bfs = WM8750_HIFI_FSB, + }, + { + .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + .pcmfmt = WM8750_HIFI_BITS, + .pcmrate = SNDRV_PCM_RATE_44100, + .pcmdir = WM8750_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 272, + .bfs = WM8750_HIFI_FSB, + }, + { + .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + .pcmfmt = WM8750_HIFI_BITS, + .pcmrate = SNDRV_PCM_RATE_48000, + .pcmdir = WM8750_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 250, + .bfs = WM8750_HIFI_FSB, + }, /* 88.2k & 96k */ - {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_88200 | - SNDRV_PCM_RATE_96000, WM8750_DIR, SND_SOC_DAI_BFS_DIV, 128, - WM8750_HIFI_FSB}, - {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_88200 | - SNDRV_PCM_RATE_96000, WM8750_DIR, SND_SOC_DAI_BFS_DIV, 192, - WM8750_HIFI_FSB}, - {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_88200, - WM8750_DIR, SND_SOC_DAI_BFS_DIV, 136, WM8750_HIFI_FSB}, - {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_96000, - WM8750_DIR, SND_SOC_DAI_BFS_DIV, 125, WM8750_HIFI_FSB}, + { + .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + .pcmfmt = WM8750_HIFI_BITS, + .pcmrate = SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000, + .pcmdir = WM8750_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 128, + .bfs = WM8750_HIFI_FSB, + }, + { + .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + .pcmfmt = WM8750_HIFI_BITS, + .pcmrate = SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000, + .pcmdir = WM8750_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 192, + .bfs = WM8750_HIFI_FSB, + }, + { + .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + .pcmfmt = WM8750_HIFI_BITS, + .pcmrate = SNDRV_PCM_RATE_88200, + .pcmdir = WM8750_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 136, + .bfs = WM8750_HIFI_FSB, + }, + { + .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + .pcmfmt = WM8750_HIFI_BITS, + .pcmrate = SNDRV_PCM_RATE_96000, + .pcmdir = WM8750_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 125, + .bfs = WM8750_HIFI_FSB, + }, /* codec frame and clock slave modes */ - {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, SND_SOC_DAITDM_LRDW(0,0), - WM8750_HIFI_BITS, WM8750_HIFI_RATES, WM8750_DIR, - SND_SOC_DAI_BFS_DIV, SND_SOC_FS_ALL, SND_SOC_FSBD_ALL}, + { + .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, + .pcmfmt = WM8750_HIFI_BITS, + .pcmrate = WM8750_HIFI_RATES, + .pcmdir = WM8750_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = SND_SOC_FS_ALL, + .bfs = SND_SOC_FSBD_ALL, + }, }; /* diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index 4850550e2e3..c6b7de42646 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -44,8 +44,11 @@ static int ac97_write(struct snd_soc_codec *codec, /* may need to expand this */ static struct snd_soc_dai_mode ac97_modes[] = { - {0, 0, SNDRV_PCM_FMTBIT_S16_LE, AC97_RATES}, - {0, 0, SNDRV_PCM_FMTBIT_S18_3LE, AC97_RATES}, + { + .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE, + .pcmrate = AC97_RATES, + .pcmdir = AC97_DIR, + }, }; /* diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c index c3b7a4bb7bd..db2310f87fb 100644 --- a/sound/soc/pxa/pxa2xx-i2s.c +++ b/sound/soc/pxa/pxa2xx-i2s.c @@ -58,30 +58,77 @@ static struct pxa_i2s_port pxa_i2s; /* priv is divider */ static struct snd_soc_dai_mode pxa2xx_i2s_modes[] = { /* pxa2xx I2S frame and clock master modes */ - {PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, SND_SOC_DAITDM_LRDW(0,0), - SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_8000, PXA_I2S_DIR, - SND_SOC_DAI_BFS_DIV, 256, SND_SOC_FSBD(4), 0x48}, - {PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, SND_SOC_DAITDM_LRDW(0,0), - SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_11025, PXA_I2S_DIR, - SND_SOC_DAI_BFS_DIV, 256, SND_SOC_FSBD(4), 0x34}, - {PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, SND_SOC_DAITDM_LRDW(0,0), - SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_16000, PXA_I2S_DIR, - SND_SOC_DAI_BFS_DIV, 256, SND_SOC_FSBD(4), 0x24}, - {PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, SND_SOC_DAITDM_LRDW(0,0), - SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_22050, PXA_I2S_DIR, - SND_SOC_DAI_BFS_DIV, 256, SND_SOC_FSBD(4), 0x1a}, - {PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, SND_SOC_DAITDM_LRDW(0,0), - SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_44100, PXA_I2S_DIR, - SND_SOC_DAI_BFS_DIV, 256, SND_SOC_FSBD(4), 0xd}, - {PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, SND_SOC_DAITDM_LRDW(0,0), - SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_48000, PXA_I2S_DIR, - SND_SOC_DAI_BFS_DIV, 256, SND_SOC_FSBD(4), 0xc}, + { + .fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, + .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, + .pcmrate = SNDRV_PCM_RATE_8000, + .pcmdir = PXA_I2S_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 256, + .bfs = SND_SOC_FSBD(4), + .priv = 0x48, + }, + { + .fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, + .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, + .pcmrate = SNDRV_PCM_RATE_11025, + .pcmdir = PXA_I2S_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 256, + .bfs = SND_SOC_FSBD(4), + .priv = 0x34, + }, + { + .fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, + .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, + .pcmrate = SNDRV_PCM_RATE_16000, + .pcmdir = PXA_I2S_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 256, + .bfs = SND_SOC_FSBD(4), + .priv = 0x24, + }, + { + .fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, + .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, + .pcmrate = SNDRV_PCM_RATE_22050, + .pcmdir = PXA_I2S_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 256, + .bfs = SND_SOC_FSBD(4), + .priv = 0x1a, + }, + { + .fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, + .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, + .pcmrate = SNDRV_PCM_RATE_44100, + .pcmdir = PXA_I2S_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 256, + .bfs = SND_SOC_FSBD(4), + .priv = 0xd, + }, + { + .fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, + .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, + .pcmrate = SNDRV_PCM_RATE_48000, + .pcmdir = PXA_I2S_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 256, + .bfs = SND_SOC_FSBD(4), + .priv = 0xc, + }, /* pxa2xx I2S frame master and clock slave mode */ - {PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBM_CFS, SND_SOC_DAITDM_LRDW(0,0), - SNDRV_PCM_FMTBIT_S16_LE, PXA_I2S_RATES, PXA_I2S_DIR, 0, - SND_SOC_FS_ALL, SND_SOC_FSB(64), 0x48}, - + { + .fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBM_CFS, + .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, + .pcmrate = PXA_I2S_RATES, + .pcmdir = PXA_I2S_DIR, + .fs = SND_SOC_FS_ALL, + .bfs = SND_SOC_FSB(64), + .priv = 0x48, + }, }; static struct pxa2xx_pcm_dma_params pxa2xx_i2s_pcm_stereo_out = { -- cgit v1.2.3 From 35f60839b6158f72d2be0dd2764ad772e1d44e8a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 13 Oct 2006 12:46:10 +0200 Subject: [ALSA] hda-codec - Add missing comma Added a missing comma in the medion patch. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 0b14bd17181..1420db43423 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -5119,7 +5119,7 @@ static struct hda_board_config alc883_cfg_tbl[] = { { .pci_subvendor = 0x1025, .pci_subdevice = 0x009f, .config = ALC883_ACER }, { .pci_subvendor = 0x161f, .pci_subdevice = 0x2054, - .modelname = "medion", .config = ALC883_MEDION } + .modelname = "medion", .config = ALC883_MEDION }, { .modelname = "auto", .config = ALC883_AUTO }, {} }; -- cgit v1.2.3 From b5c5fd24b9d34e4670cb339e546bfae7ad316354 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 13 Oct 2006 19:13:41 +0200 Subject: [ALSA] ASoC debug output build breakage This patch fixes a build failure when ASoC debug is enabled. Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/soc-core.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index eba0a101253..8d6ff047d7a 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -575,10 +575,11 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) } dbg("asoc: %s <-> %s info:\n", rtd->codec_dai->name, rtd->cpu_dai->name); - dbg("asoc: rate mask 0x%x \nasoc: min ch %d max ch %d\n" - "asoc: min rate %d max rate %d\n", - runtime->hw.rates, runtime->hw.channels_min, - runtime->hw.channels_max, runtime->hw.rate_min, runtime->hw.rate_max); + dbg("asoc: rate mask 0x%x\n", runtime->hw.rates); + dbg("asoc: min ch %d max ch %d\n", runtime->hw.channels_min, + runtime->hw.channels_max); + dbg("asoc: min rate %d max rate %d\n", runtime->hw.rate_min, + runtime->hw.rate_max); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) -- cgit v1.2.3 From b3b9c1cbb35125f7e43a323ebe89e7a74e3c1ac2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 13 Oct 2006 20:09:59 +0200 Subject: [ALSA] Remove trailing whitespaces from soc/* files Remove trailing whitespaces from soc/* files added by the conversion to C99-style initialization. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/at91/at91rm9200-i2s.c | 34 +++---- sound/soc/codecs/wm8731.c | 94 +++++++++--------- sound/soc/codecs/wm8750.c | 210 ++++++++++++++++++++-------------------- sound/soc/pxa/pxa2xx-i2s.c | 58 +++++------ 4 files changed, 198 insertions(+), 198 deletions(-) (limited to 'sound') diff --git a/sound/soc/at91/at91rm9200-i2s.c b/sound/soc/at91/at91rm9200-i2s.c index 91f1daa44f1..8c4d3b99905 100644 --- a/sound/soc/at91/at91rm9200-i2s.c +++ b/sound/soc/at91/at91rm9200-i2s.c @@ -52,9 +52,9 @@ static struct snd_soc_dai_mode at91rm9200_i2s[] = { /* 8k: BCLK = (MCLK/10) = (60MHz/50) = 1.2MHz */ { - .fmt = AT91RM9200_I2S_DAIFMT, - .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, - .pcmrate = SNDRV_PCM_RATE_8000, + .fmt = AT91RM9200_I2S_DAIFMT, + .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, + .pcmrate = SNDRV_PCM_RATE_8000, .pcmdir = AT91RM9200_I2S_DIR, .flags = SND_SOC_DAI_BFS_DIV, .fs = 1500, @@ -63,38 +63,38 @@ static struct snd_soc_dai_mode at91rm9200_i2s[] = { }, /* 16k: BCLK = (MCLK/3) ~= (60MHz/14) = 4.285714MHz */ - { + { .fmt = AT91RM9200_I2S_DAIFMT, .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, .pcmrate = SNDRV_PCM_RATE_16000, .pcmdir = AT91RM9200_I2S_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 750, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 750, .bfs = SND_SOC_FSBD(3), .flags (7 << 16 | 133), }, /* 24k: BCLK = (MCLK/10) = (60MHz/50) = 1.2MHz */ - { + { .fmt = AT91RM9200_I2S_DAIFMT, - .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, - .pcmrate = SNDRV_PCM_RATE_22050, + .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, + .pcmrate = SNDRV_PCM_RATE_22050, .pcmdir = AT91RM9200_I2S_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 500, - .bfs = SND_SOC_FSBD(10), + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 500, + .bfs = SND_SOC_FSBD(10), .priv = (25 << 16 | 24), }, /* 48kHz: BCLK = (MCLK/5) ~= (60MHz/26) = 2.3076923MHz */ - { + { .fmt = AT91RM9200_I2S_DAIFMT, .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, - .pcmrate = SNDRV_PCM_RATE_48000, + .pcmrate = SNDRV_PCM_RATE_48000, .pcmdir = AT91RM9200_I2S_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 250, - .bfs SND_SOC_FSBD(5), + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 250, + .bfs SND_SOC_FSBD(5), .priv = (13 << 16 | 23), }, }; diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 03a6bb9b877..9adbd2d401c 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -87,89 +87,89 @@ static struct snd_soc_dai_mode wm8731_modes[] = { /* 8k */ { .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8731_HIFI_BITS, - .pcmrate = SNDRV_PCM_RATE_8000, + .pcmfmt = WM8731_HIFI_BITS, + .pcmrate = SNDRV_PCM_RATE_8000, .pcmdir = WM8731_DIR, - .fs = 1536, + .fs = 1536, .bfs = SND_SOC_FSB(64), }, { .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8731_HIFI_BITS, - .pcmrate = SNDRV_PCM_RATE_8000, + .pcmfmt = WM8731_HIFI_BITS, + .pcmrate = SNDRV_PCM_RATE_8000, .pcmdir = WM8731_DIR, - .fs = 2304, + .fs = 2304, .bfs = SND_SOC_FSB(64), }, { .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8731_HIFI_BITS, - .pcmrate = SNDRV_PCM_RATE_8000, + .pcmfmt = WM8731_HIFI_BITS, + .pcmrate = SNDRV_PCM_RATE_8000, .pcmdir = WM8731_DIR, - .fs = 1408, + .fs = 1408, .bfs = SND_SOC_FSB(64), }, { .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8731_HIFI_BITS, - .pcmrate = SNDRV_PCM_RATE_8000, + .pcmfmt = WM8731_HIFI_BITS, + .pcmrate = SNDRV_PCM_RATE_8000, .pcmdir = WM8731_DIR, - .fs = 2112, + .fs = 2112, .bfs = SND_SOC_FSB(64), }, /* 32k */ { .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8731_HIFI_BITS, + .pcmfmt = WM8731_HIFI_BITS, .pcmrate = SNDRV_PCM_RATE_32000, .pcmdir = WM8731_DIR, - .fs = 384, + .fs = 384, .bfs = SND_SOC_FSB(64), }, { .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8731_HIFI_BITS, - .pcmrate = SNDRV_PCM_RATE_32000, + .pcmfmt = WM8731_HIFI_BITS, + .pcmrate = SNDRV_PCM_RATE_32000, .pcmdir = WM8731_DIR, - .fs = 576, + .fs = 576, .bfs = SND_SOC_FSB(64), }, /* 44.1k & 48k */ { .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8731_HIFI_BITS, + .pcmfmt = WM8731_HIFI_BITS, .pcmrate = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, .pcmdir = WM8731_DIR, - .fs = 256, + .fs = 256, .bfs = SND_SOC_FSB(64), }, { .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8731_HIFI_BITS, + .pcmfmt = WM8731_HIFI_BITS, .pcmrate = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, .pcmdir = WM8731_DIR, - .fs = 384, + .fs = 384, .bfs = SND_SOC_FSB(64), }, /* 88.2 & 96k */ { .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8731_HIFI_BITS, + .pcmfmt = WM8731_HIFI_BITS, .pcmrate = SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000, .pcmdir = WM8731_DIR, - .fs = 128, + .fs = 128, .bfs = SND_SOC_FSB(64), }, { .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8731_HIFI_BITS, + .pcmfmt = WM8731_HIFI_BITS, .pcmrate = SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000, .pcmdir = WM8731_DIR, - .fs = 192, + .fs = 192, .bfs = SND_SOC_FSB(64), }, @@ -177,66 +177,66 @@ static struct snd_soc_dai_mode wm8731_modes[] = { /* 8k */ { .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8731_HIFI_BITS, - .pcmrate = SNDRV_PCM_RATE_8000, + .pcmfmt = WM8731_HIFI_BITS, + .pcmrate = SNDRV_PCM_RATE_8000, .pcmdir = WM8731_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 1500, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 1500, .bfs = SND_SOC_FSBD(1), }, /* 44.1k */ { .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8731_HIFI_BITS, - .pcmrate = SNDRV_PCM_RATE_44100, + .pcmfmt = WM8731_HIFI_BITS, + .pcmrate = SNDRV_PCM_RATE_44100, .pcmdir = WM8731_DIR, .flags = SND_SOC_DAI_BFS_DIV, - .fs = 272, + .fs = 272, .bfs = SND_SOC_FSBD(1), }, /* 48k */ { .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8731_HIFI_BITS, - .pcmrate = SNDRV_PCM_RATE_48000, + .pcmfmt = WM8731_HIFI_BITS, + .pcmrate = SNDRV_PCM_RATE_48000, .pcmdir = WM8731_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 250, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 250, .bfs = SND_SOC_FSBD(1), }, /* 88.2k */ { - .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8731_HIFI_BITS, - .pcmrate = SNDRV_PCM_RATE_88200, + .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + .pcmfmt = WM8731_HIFI_BITS, + .pcmrate = SNDRV_PCM_RATE_88200, .pcmdir = WM8731_DIR, .flags = SND_SOC_DAI_BFS_DIV, - .fs = 136, + .fs = 136, .bfs = SND_SOC_FSBD(1), }, /* 96k */ { .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8731_HIFI_BITS, - .pcmrate = SNDRV_PCM_RATE_96000, + .pcmfmt = WM8731_HIFI_BITS, + .pcmrate = SNDRV_PCM_RATE_96000, .pcmdir = WM8731_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 125, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 125, .bfs = SND_SOC_FSBD(1), }, /* codec frame and clock slave modes */ { .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, - .pcmfmt = WM8731_HIFI_BITS, - .pcmrate = WM8731_RATES, + .pcmfmt = WM8731_HIFI_BITS, + .pcmrate = WM8731_RATES, .pcmdir = WM8731_DIR, .flags = SND_SOC_DAI_BFS_DIV, - .fs = SND_SOC_FS_ALL, + .fs = SND_SOC_FS_ALL, .bfs = SND_SOC_FSBD_ALL, }, }; diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index b07a6ed6aa6..243da712d9c 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c @@ -99,250 +99,250 @@ static struct snd_soc_dai_mode wm8750_modes[] = { /* 8k */ { .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8750_HIFI_BITS, + .pcmfmt = WM8750_HIFI_BITS, .pcmrate = SNDRV_PCM_RATE_8000, - .pcmdir = WM8750_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 1536, + .pcmdir = WM8750_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 1536, .bfs = WM8750_HIFI_FSB, }, { .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8750_HIFI_BITS, + .pcmfmt = WM8750_HIFI_BITS, .pcmrate = SNDRV_PCM_RATE_8000, - .pcmdir = WM8750_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 1408, + .pcmdir = WM8750_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 1408, .bfs = WM8750_HIFI_FSB, }, { .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8750_HIFI_BITS, + .pcmfmt = WM8750_HIFI_BITS, .pcmrate = SNDRV_PCM_RATE_8000, - .pcmdir = WM8750_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 2304, + .pcmdir = WM8750_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 2304, .bfs = WM8750_HIFI_FSB, }, { .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8750_HIFI_BITS, + .pcmfmt = WM8750_HIFI_BITS, .pcmrate = SNDRV_PCM_RATE_8000, - .pcmdir = WM8750_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 2112, + .pcmdir = WM8750_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 2112, .bfs = WM8750_HIFI_FSB, }, { .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8750_HIFI_BITS, + .pcmfmt = WM8750_HIFI_BITS, .pcmrate = SNDRV_PCM_RATE_8000, - .pcmdir = WM8750_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 1500, + .pcmdir = WM8750_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 1500, .bfs = WM8750_HIFI_FSB, }, /* 11.025k */ { .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8750_HIFI_BITS, + .pcmfmt = WM8750_HIFI_BITS, .pcmrate = SNDRV_PCM_RATE_11025, - .pcmdir = WM8750_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 1024, + .pcmdir = WM8750_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 1024, .bfs = WM8750_HIFI_FSB, }, { .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8750_HIFI_BITS, + .pcmfmt = WM8750_HIFI_BITS, .pcmrate = SNDRV_PCM_RATE_11025, - .pcmdir = WM8750_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 1536, + .pcmdir = WM8750_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 1536, .bfs = WM8750_HIFI_FSB, }, { .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8750_HIFI_BITS, + .pcmfmt = WM8750_HIFI_BITS, .pcmrate = SNDRV_PCM_RATE_11025, - .pcmdir = WM8750_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 1088, + .pcmdir = WM8750_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 1088, .bfs = WM8750_HIFI_FSB, }, /* 16k */ { .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8750_HIFI_BITS, + .pcmfmt = WM8750_HIFI_BITS, .pcmrate = SNDRV_PCM_RATE_16000, - .pcmdir = WM8750_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 768, + .pcmdir = WM8750_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 768, .bfs = WM8750_HIFI_FSB, }, { .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8750_HIFI_BITS, + .pcmfmt = WM8750_HIFI_BITS, .pcmrate = SNDRV_PCM_RATE_16000, - .pcmdir = WM8750_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 1152, + .pcmdir = WM8750_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 1152, .bfs = WM8750_HIFI_FSB }, { .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8750_HIFI_BITS, + .pcmfmt = WM8750_HIFI_BITS, .pcmrate = SNDRV_PCM_RATE_16000, - .pcmdir = WM8750_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 750, + .pcmdir = WM8750_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 750, .bfs = WM8750_HIFI_FSB, }, /* 22.05k */ { .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8750_HIFI_BITS, + .pcmfmt = WM8750_HIFI_BITS, .pcmrate = SNDRV_PCM_RATE_22050, - .pcmdir = WM8750_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 512, + .pcmdir = WM8750_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 512, .bfs = WM8750_HIFI_FSB, }, { .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8750_HIFI_BITS, + .pcmfmt = WM8750_HIFI_BITS, .pcmrate = SNDRV_PCM_RATE_22050, - .pcmdir = WM8750_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 768, + .pcmdir = WM8750_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 768, .bfs = WM8750_HIFI_FSB, }, { .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8750_HIFI_BITS, + .pcmfmt = WM8750_HIFI_BITS, .pcmrate = SNDRV_PCM_RATE_22050, - .pcmdir = WM8750_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 544, + .pcmdir = WM8750_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 544, .bfs = WM8750_HIFI_FSB, }, /* 32k */ { .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8750_HIFI_BITS, + .pcmfmt = WM8750_HIFI_BITS, .pcmrate = SNDRV_PCM_RATE_32000, - .pcmdir = WM8750_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 384, + .pcmdir = WM8750_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 384, .bfs = WM8750_HIFI_FSB, }, { .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8750_HIFI_BITS, + .pcmfmt = WM8750_HIFI_BITS, .pcmrate = SNDRV_PCM_RATE_32000, - .pcmdir = WM8750_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 576, + .pcmdir = WM8750_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 576, .bfs = WM8750_HIFI_FSB, }, { .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8750_HIFI_BITS, + .pcmfmt = WM8750_HIFI_BITS, .pcmrate = SNDRV_PCM_RATE_32000, - .pcmdir = WM8750_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 375, + .pcmdir = WM8750_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 375, .bfs = WM8750_HIFI_FSB, }, /* 44.1k & 48k */ { .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8750_HIFI_BITS, - .pcmrate = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, - .pcmdir = WM8750_DIR, - .flags = SND_SOC_DAI_BFS_DIV, + .pcmfmt = WM8750_HIFI_BITS, + .pcmrate = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, + .pcmdir = WM8750_DIR, + .flags = SND_SOC_DAI_BFS_DIV, .fs = 256, .bfs = WM8750_HIFI_FSB, }, { .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8750_HIFI_BITS, - .pcmrate = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, - .pcmdir = WM8750_DIR, - .flags = SND_SOC_DAI_BFS_DIV, + .pcmfmt = WM8750_HIFI_BITS, + .pcmrate = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, + .pcmdir = WM8750_DIR, + .flags = SND_SOC_DAI_BFS_DIV, .fs = 384, .bfs = WM8750_HIFI_FSB, }, { .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8750_HIFI_BITS, + .pcmfmt = WM8750_HIFI_BITS, .pcmrate = SNDRV_PCM_RATE_44100, - .pcmdir = WM8750_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 272, + .pcmdir = WM8750_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 272, .bfs = WM8750_HIFI_FSB, }, { .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8750_HIFI_BITS, + .pcmfmt = WM8750_HIFI_BITS, .pcmrate = SNDRV_PCM_RATE_48000, - .pcmdir = WM8750_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 250, + .pcmdir = WM8750_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 250, .bfs = WM8750_HIFI_FSB, }, /* 88.2k & 96k */ { .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8750_HIFI_BITS, - .pcmrate = SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000, - .pcmdir = WM8750_DIR, - .flags = SND_SOC_DAI_BFS_DIV, + .pcmfmt = WM8750_HIFI_BITS, + .pcmrate = SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000, + .pcmdir = WM8750_DIR, + .flags = SND_SOC_DAI_BFS_DIV, .fs = 128, .bfs = WM8750_HIFI_FSB, }, { .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8750_HIFI_BITS, - .pcmrate = SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000, - .pcmdir = WM8750_DIR, - .flags = SND_SOC_DAI_BFS_DIV, + .pcmfmt = WM8750_HIFI_BITS, + .pcmrate = SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000, + .pcmdir = WM8750_DIR, + .flags = SND_SOC_DAI_BFS_DIV, .fs = 192, .bfs = WM8750_HIFI_FSB, }, { .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8750_HIFI_BITS, + .pcmfmt = WM8750_HIFI_BITS, .pcmrate = SNDRV_PCM_RATE_88200, - .pcmdir = WM8750_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 136, + .pcmdir = WM8750_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 136, .bfs = WM8750_HIFI_FSB, }, { .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8750_HIFI_BITS, + .pcmfmt = WM8750_HIFI_BITS, .pcmrate = SNDRV_PCM_RATE_96000, - .pcmdir = WM8750_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 125, + .pcmdir = WM8750_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 125, .bfs = WM8750_HIFI_FSB, }, /* codec frame and clock slave modes */ { - .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, - .pcmfmt = WM8750_HIFI_BITS, - .pcmrate = WM8750_HIFI_RATES, + .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, + .pcmfmt = WM8750_HIFI_BITS, + .pcmrate = WM8750_HIFI_RATES, .pcmdir = WM8750_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = SND_SOC_FS_ALL, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = SND_SOC_FS_ALL, .bfs = SND_SOC_FSBD_ALL, }, }; diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c index db2310f87fb..99f1da32744 100644 --- a/sound/soc/pxa/pxa2xx-i2s.c +++ b/sound/soc/pxa/pxa2xx-i2s.c @@ -60,61 +60,61 @@ static struct snd_soc_dai_mode pxa2xx_i2s_modes[] = { /* pxa2xx I2S frame and clock master modes */ { .fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, - .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, - .pcmrate = SNDRV_PCM_RATE_8000, + .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, + .pcmrate = SNDRV_PCM_RATE_8000, .pcmdir = PXA_I2S_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 256, - .bfs = SND_SOC_FSBD(4), + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 256, + .bfs = SND_SOC_FSBD(4), .priv = 0x48, }, { .fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, - .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, - .pcmrate = SNDRV_PCM_RATE_11025, + .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, + .pcmrate = SNDRV_PCM_RATE_11025, .pcmdir = PXA_I2S_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 256, - .bfs = SND_SOC_FSBD(4), + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 256, + .bfs = SND_SOC_FSBD(4), .priv = 0x34, }, { .fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, - .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, - .pcmrate = SNDRV_PCM_RATE_16000, + .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, + .pcmrate = SNDRV_PCM_RATE_16000, .pcmdir = PXA_I2S_DIR, .flags = SND_SOC_DAI_BFS_DIV, - .fs = 256, - .bfs = SND_SOC_FSBD(4), + .fs = 256, + .bfs = SND_SOC_FSBD(4), .priv = 0x24, }, { .fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, - .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, + .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, .pcmrate = SNDRV_PCM_RATE_22050, .pcmdir = PXA_I2S_DIR, .flags = SND_SOC_DAI_BFS_DIV, - .fs = 256, - .bfs = SND_SOC_FSBD(4), + .fs = 256, + .bfs = SND_SOC_FSBD(4), .priv = 0x1a, }, { .fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, - .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, - .pcmrate = SNDRV_PCM_RATE_44100, + .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, + .pcmrate = SNDRV_PCM_RATE_44100, .pcmdir = PXA_I2S_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 256, - .bfs = SND_SOC_FSBD(4), + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 256, + .bfs = SND_SOC_FSBD(4), .priv = 0xd, }, { .fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, - .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, - .pcmrate = SNDRV_PCM_RATE_48000, + .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, + .pcmrate = SNDRV_PCM_RATE_48000, .pcmdir = PXA_I2S_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 256, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 256, .bfs = SND_SOC_FSBD(4), .priv = 0xc, }, @@ -122,11 +122,11 @@ static struct snd_soc_dai_mode pxa2xx_i2s_modes[] = { /* pxa2xx I2S frame master and clock slave mode */ { .fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBM_CFS, - .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, + .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, .pcmrate = PXA_I2S_RATES, .pcmdir = PXA_I2S_DIR, - .fs = SND_SOC_FS_ALL, - .bfs = SND_SOC_FSB(64), + .fs = SND_SOC_FS_ALL, + .bfs = SND_SOC_FSB(64), .priv = 0x48, }, }; -- cgit v1.2.3 From 3cee5a60ce18034a63f70ba2bdd54f85018ce960 Mon Sep 17 00:00:00 2001 From: Remy Bruno Date: Mon, 16 Oct 2006 12:46:32 +0200 Subject: [ALSA] hdspm: Add support for AES32 Add support for AES32. Difference between MADI and AES32 is done through revision. Master support is not finished for now (RME so-called DDS feature is not supported yet) Signed-off-by: Remy Bruno Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/rme9652/hdspm.c | 1320 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 1098 insertions(+), 222 deletions(-) (limited to 'sound') diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 0547f6f04bd..3d3a4ce3a35 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -6,6 +6,8 @@ * code based on hdsp.c Paul Davis * Marcus Andersson * Thomas Charbonnel + * Modified 2006-06-01 for AES32 support by Remy Bruno + * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -77,7 +79,8 @@ MODULE_PARM_DESC(enable_monitor, MODULE_AUTHOR ("Winfried Ritsch , Paul Davis , " - "Marcus Andersson, Thomas Charbonnel "); + "Marcus Andersson, Thomas Charbonnel , " + "Remy Bruno "); MODULE_DESCRIPTION("RME HDSPM"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); @@ -107,7 +110,12 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); /* --- Read registers. --- These are defined as byte-offsets from the iobase value */ #define HDSPM_statusRegister 0 -#define HDSPM_statusRegister2 96 +/*#define HDSPM_statusRegister2 96 */ +/* after RME Windows driver sources, status2 is 4-byte word # 48 = word at + * offset 192, for AES32 *and* MADI + * => need to check that offset 192 is working on MADI */ +#define HDSPM_statusRegister2 192 +#define HDSPM_timecodeRegister 128 #define HDSPM_midiDataIn0 360 #define HDSPM_midiDataIn1 364 @@ -140,37 +148,50 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); #define HDSPM_Frequency0 (1<<6) /* 0=44.1kHz/88.2kHz 1=48kHz/96kHz */ #define HDSPM_Frequency1 (1<<7) /* 0=32kHz/64kHz */ #define HDSPM_DoubleSpeed (1<<8) /* 0=normal speed, 1=double speed */ -#define HDSPM_QuadSpeed (1<<31) /* quad speed bit, not implemented now */ +#define HDSPM_QuadSpeed (1<<31) /* quad speed bit */ +#define HDSPM_Professional (1<<9) /* Professional */ /* AES32 ONLY */ #define HDSPM_TX_64ch (1<<10) /* Output 64channel MODE=1, - 56channelMODE=0 */ + 56channelMODE=0 */ /* MADI ONLY*/ +#define HDSPM_Emphasis (1<<10) /* Emphasis */ /* AES32 ONLY */ #define HDSPM_AutoInp (1<<11) /* Auto Input (takeover) == Safe Mode, - 0=off, 1=on */ + 0=off, 1=on */ /* MADI ONLY */ +#define HDSPM_Dolby (1<<11) /* Dolby = "NonAudio" ?? */ /* AES32 ONLY */ -#define HDSPM_InputSelect0 (1<<14) /* Input select 0= optical, 1=coax */ +#define HDSPM_InputSelect0 (1<<14) /* Input select 0= optical, 1=coax */ /* MADI ONLY*/ #define HDSPM_InputSelect1 (1<<15) /* should be 0 */ #define HDSPM_SyncRef0 (1<<16) /* 0=WOrd, 1=MADI */ -#define HDSPM_SyncRef1 (1<<17) /* should be 0 */ +#define HDSPM_SyncRef1 (1<<17) /* for AES32: SyncRefN codes the AES # */ +#define HDSPM_SyncRef2 (1<<13) +#define HDSPM_SyncRef3 (1<<25) +#define HDSPM_SMUX (1<<18) /* Frame ??? */ /* MADI ONY */ #define HDSPM_clr_tms (1<<19) /* clear track marker, do not use AES additional bits in lower 5 Audiodatabits ??? */ +#define HDSPM_taxi_reset (1<<20) /* ??? */ /* MADI ONLY ? */ +#define HDSPM_WCK48 (1<<20) /* Frame ??? = HDSPM_SMUX */ /* AES32 ONLY */ #define HDSPM_Midi0InterruptEnable (1<<22) #define HDSPM_Midi1InterruptEnable (1<<23) #define HDSPM_LineOut (1<<24) /* Analog Out on channel 63/64 on=1, mute=0 */ +#define HDSPM_DS_DoubleWire (1<<26) /* AES32 ONLY */ +#define HDSPM_QS_DoubleWire (1<<27) /* AES32 ONLY */ +#define HDSPM_QS_QuadWire (1<<28) /* AES32 ONLY */ + +#define HDSPM_wclk_sel (1<<30) /* --- bit helper defines */ #define HDSPM_LatencyMask (HDSPM_Latency0|HDSPM_Latency1|HDSPM_Latency2) -#define HDSPM_FrequencyMask (HDSPM_Frequency0|HDSPM_Frequency1) +#define HDSPM_FrequencyMask (HDSPM_Frequency0|HDSPM_Frequency1|HDSPM_DoubleSpeed|HDSPM_QuadSpeed) #define HDSPM_InputMask (HDSPM_InputSelect0|HDSPM_InputSelect1) #define HDSPM_InputOptical 0 #define HDSPM_InputCoaxial (HDSPM_InputSelect0) -#define HDSPM_SyncRefMask (HDSPM_SyncRef0|HDSPM_SyncRef1) +#define HDSPM_SyncRefMask (HDSPM_SyncRef0|HDSPM_SyncRef1|HDSPM_SyncRef2|HDSPM_SyncRef3) #define HDSPM_SyncRef_Word 0 #define HDSPM_SyncRef_MADI (HDSPM_SyncRef0) @@ -183,6 +204,9 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); #define HDSPM_Frequency64KHz (HDSPM_DoubleSpeed|HDSPM_Frequency0) #define HDSPM_Frequency88_2KHz (HDSPM_DoubleSpeed|HDSPM_Frequency1) #define HDSPM_Frequency96KHz (HDSPM_DoubleSpeed|HDSPM_Frequency1|HDSPM_Frequency0) +#define HDSPM_Frequency128KHz (HDSPM_QuadSpeed|HDSPM_Frequency0) +#define HDSPM_Frequency176_4KHz (HDSPM_QuadSpeed|HDSPM_Frequency1) +#define HDSPM_Frequency192KHz (HDSPM_QuadSpeed|HDSPM_Frequency1|HDSPM_Frequency0) /* --- for internal discrimination */ #define HDSPM_CLOCK_SOURCE_AUTOSYNC 0 /* Sample Clock Sources */ @@ -229,7 +253,8 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); #define HDSPM_BIGENDIAN_MODE (1<<9) #define HDSPM_RD_MULTIPLE (1<<10) -/* --- Status Register bits --- */ +/* --- Status Register bits --- */ /* MADI ONLY */ /* Bits defined here and + that do not conflict with specific bits for AES32 seem to be valid also for the AES32 */ #define HDSPM_audioIRQPending (1<<0) /* IRQ is high and pending */ #define HDSPM_RX_64ch (1<<1) /* Input 64chan. MODE=1, 56chn. MODE=0 */ #define HDSPM_AB_int (1<<2) /* InputChannel Opt=0, Coax=1 (like inp0) */ @@ -263,7 +288,7 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); #define HDSPM_madiFreq176_4 (HDSPM_madiFreq3) #define HDSPM_madiFreq192 (HDSPM_madiFreq3|HDSPM_madiFreq0) -/* Status2 Register bits */ +/* Status2 Register bits */ /* MADI ONLY */ #define HDSPM_version0 (1<<0) /* not realy defined but I guess */ #define HDSPM_version1 (1<<1) /* in former cards it was ??? */ @@ -297,6 +322,56 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); #define HDSPM_SelSyncRef_MADI (HDSPM_SelSyncRef0) #define HDSPM_SelSyncRef_NVALID (HDSPM_SelSyncRef0|HDSPM_SelSyncRef1|HDSPM_SelSyncRef2) +/* + For AES32, bits for status, status2 and timecode are different +*/ +/* status */ +#define HDSPM_AES32_wcLock 0x0200000 +#define HDSPM_AES32_wcFreq_bit 22 +/* (status >> HDSPM_AES32_wcFreq_bit) & 0xF gives WC frequency (cf function + HDSPM_bit2freq */ +#define HDSPM_AES32_syncref_bit 16 +/* (status >> HDSPM_AES32_syncref_bit) & 0xF gives sync source */ + +#define HDSPM_AES32_AUTOSYNC_FROM_WORD 0 +#define HDSPM_AES32_AUTOSYNC_FROM_AES1 1 +#define HDSPM_AES32_AUTOSYNC_FROM_AES2 2 +#define HDSPM_AES32_AUTOSYNC_FROM_AES3 3 +#define HDSPM_AES32_AUTOSYNC_FROM_AES4 4 +#define HDSPM_AES32_AUTOSYNC_FROM_AES5 5 +#define HDSPM_AES32_AUTOSYNC_FROM_AES6 6 +#define HDSPM_AES32_AUTOSYNC_FROM_AES7 7 +#define HDSPM_AES32_AUTOSYNC_FROM_AES8 8 +#define HDSPM_AES32_AUTOSYNC_FROM_NONE -1 + +/* status2 */ +/* HDSPM_LockAES_bit is given by HDSPM_LockAES >> (AES# - 1) */ +#define HDSPM_LockAES 0x80 +#define HDSPM_LockAES1 0x80 +#define HDSPM_LockAES2 0x40 +#define HDSPM_LockAES3 0x20 +#define HDSPM_LockAES4 0x10 +#define HDSPM_LockAES5 0x8 +#define HDSPM_LockAES6 0x4 +#define HDSPM_LockAES7 0x2 +#define HDSPM_LockAES8 0x1 +/* + Timecode + After windows driver sources, bits 4*i to 4*i+3 give the input frequency on + AES i+1 + bits 3210 + 0001 32kHz + 0010 44.1kHz + 0011 48kHz + 0100 64kHz + 0101 88.2kHz + 0110 96kHz + 0111 128kHz + 1000 176.4kHz + 1001 192kHz + NB: Timecode register doesn't seem to work on AES32 card revision 230 +*/ + /* Mixer Values */ #define UNITY_GAIN 32768 /* = 65536/2 */ #define MINUS_INFINITY_GAIN 0 @@ -314,10 +389,14 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); size is the same regardless of the number of channels, and also the latency to use. for one direction !!! + => need to mupltiply by 2!! */ -#define HDSPM_DMA_AREA_BYTES (HDSPM_MAX_CHANNELS * HDSPM_CHANNEL_BUFFER_BYTES) +#define HDSPM_DMA_AREA_BYTES (2 * HDSPM_MAX_CHANNELS * HDSPM_CHANNEL_BUFFER_BYTES) #define HDSPM_DMA_AREA_KILOBYTES (HDSPM_DMA_AREA_BYTES/1024) +/* revisions >= 230 indicate AES32 card */ +#define HDSPM_AESREVISION 230 + struct hdspm_midi { struct hdspm *hdspm; int id; @@ -336,7 +415,9 @@ struct hdspm { struct snd_pcm_substream *playback_substream; /* and/or capture stream */ char *card_name; /* for procinfo */ - unsigned short firmware_rev; /* dont know if relevant */ + unsigned short firmware_rev; /* dont know if relevant (yes if AES32)*/ + + unsigned char is_aes32; /* indicates if card is AES32 */ int precise_ptr; /* use precise pointers, to be tested */ int monitor_outs; /* set up monitoring outs init flag */ @@ -453,6 +534,15 @@ static int snd_hdspm_set_defaults(struct hdspm * hdspm); static void hdspm_set_sgbuf(struct hdspm * hdspm, struct snd_sg_buf *sgbuf, unsigned int reg, int channels); +static inline int HDSPM_bit2freq(int n) +{ + static int bit2freq_tab[] = { 0, 32000, 44100, 48000, 64000, 88200, + 96000, 128000, 176400, 192000 }; + if (n < 1 || n > 9) + return 0; + return bit2freq_tab[n]; +} + /* Write/read to/from HDSPM with Adresses in Bytes not words but only 32Bit writes are allowed */ @@ -544,86 +634,105 @@ static inline int snd_hdspm_use_is_exclusive(struct hdspm * hdspm) /* check for external sample rate */ static inline int hdspm_external_sample_rate(struct hdspm * hdspm) { - unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2); - unsigned int status = hdspm_read(hdspm, HDSPM_statusRegister); - unsigned int rate_bits; - int rate = 0; + if (hdspm->is_aes32) { + unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2); + unsigned int status = hdspm_read(hdspm, HDSPM_statusRegister); + unsigned int timecode = hdspm_read(hdspm, HDSPM_timecodeRegister); + + int syncref = hdspm_autosync_ref(hdspm); + + if (syncref == HDSPM_AES32_AUTOSYNC_FROM_WORD && + status & HDSPM_AES32_wcLock) + return HDSPM_bit2freq((status >> HDSPM_AES32_wcFreq_bit) & 0xF); + if (syncref >= HDSPM_AES32_AUTOSYNC_FROM_AES1 && + syncref <= HDSPM_AES32_AUTOSYNC_FROM_AES8 && + status2 & (HDSPM_LockAES >> + (syncref - HDSPM_AES32_AUTOSYNC_FROM_AES1))) + return HDSPM_bit2freq((timecode >> + (4*(syncref-HDSPM_AES32_AUTOSYNC_FROM_AES1))) & 0xF); + return 0; + } else { + unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2); + unsigned int status = hdspm_read(hdspm, HDSPM_statusRegister); + unsigned int rate_bits; + int rate = 0; - /* if wordclock has synced freq and wordclock is valid */ - if ((status2 & HDSPM_wcLock) != 0 && - (status & HDSPM_SelSyncRef0) == 0) { + /* if wordclock has synced freq and wordclock is valid */ + if ((status2 & HDSPM_wcLock) != 0 && + (status & HDSPM_SelSyncRef0) == 0) { - rate_bits = status2 & HDSPM_wcFreqMask; + rate_bits = status2 & HDSPM_wcFreqMask; - switch (rate_bits) { - case HDSPM_wcFreq32: - rate = 32000; - break; - case HDSPM_wcFreq44_1: - rate = 44100; - break; - case HDSPM_wcFreq48: - rate = 48000; - break; - case HDSPM_wcFreq64: - rate = 64000; - break; - case HDSPM_wcFreq88_2: - rate = 88200; - break; - case HDSPM_wcFreq96: - rate = 96000; - break; - /* Quadspeed Bit missing ???? */ - default: - rate = 0; - break; + switch (rate_bits) { + case HDSPM_wcFreq32: + rate = 32000; + break; + case HDSPM_wcFreq44_1: + rate = 44100; + break; + case HDSPM_wcFreq48: + rate = 48000; + break; + case HDSPM_wcFreq64: + rate = 64000; + break; + case HDSPM_wcFreq88_2: + rate = 88200; + break; + case HDSPM_wcFreq96: + rate = 96000; + break; + /* Quadspeed Bit missing ???? */ + default: + rate = 0; + break; + } } - } - /* if rate detected and Syncref is Word than have it, word has priority to MADI */ - if (rate != 0 - && (status2 & HDSPM_SelSyncRefMask) == HDSPM_SelSyncRef_WORD) - return rate; + /* if rate detected and Syncref is Word than have it, word has priority to MADI */ + if (rate != 0 && + (status2 & HDSPM_SelSyncRefMask) == HDSPM_SelSyncRef_WORD) + return rate; - /* maby a madi input (which is taken if sel sync is madi) */ - if (status & HDSPM_madiLock) { - rate_bits = status & HDSPM_madiFreqMask; + /* maby a madi input (which is taken if sel sync is madi) */ + if (status & HDSPM_madiLock) { + rate_bits = status & HDSPM_madiFreqMask; - switch (rate_bits) { - case HDSPM_madiFreq32: - rate = 32000; - break; - case HDSPM_madiFreq44_1: - rate = 44100; - break; - case HDSPM_madiFreq48: - rate = 48000; - break; - case HDSPM_madiFreq64: - rate = 64000; - break; - case HDSPM_madiFreq88_2: - rate = 88200; - break; - case HDSPM_madiFreq96: - rate = 96000; - break; - case HDSPM_madiFreq128: - rate = 128000; - break; - case HDSPM_madiFreq176_4: - rate = 176400; - break; - case HDSPM_madiFreq192: - rate = 192000; - break; - default: - rate = 0; - break; + switch (rate_bits) { + case HDSPM_madiFreq32: + rate = 32000; + break; + case HDSPM_madiFreq44_1: + rate = 44100; + break; + case HDSPM_madiFreq48: + rate = 48000; + break; + case HDSPM_madiFreq64: + rate = 64000; + break; + case HDSPM_madiFreq88_2: + rate = 88200; + break; + case HDSPM_madiFreq96: + rate = 96000; + break; + case HDSPM_madiFreq128: + rate = 128000; + break; + case HDSPM_madiFreq176_4: + rate = 176400; + break; + case HDSPM_madiFreq192: + rate = 192000; + break; + default: + rate = 0; + break; + } } + return rate; } - return rate; } /* Latency function */ @@ -676,7 +785,8 @@ static inline void hdspm_silence_playback(struct hdspm * hdspm) int n = hdspm->period_bytes; void *buf = hdspm->playback_buffer; - snd_assert(buf != NULL, return); + if (buf == NULL) + return; for (i = 0; i < HDSPM_MAX_CHANNELS; i++) { memset(buf, 0, n); @@ -716,6 +826,7 @@ static int hdspm_set_rate(struct hdspm * hdspm, int rate, int called_internally) int current_rate; int rate_bits; int not_set = 0; + int is_single, is_double, is_quad; /* ASSUMPTION: hdspm->lock is either set, or there is no need for it (e.g. during module initialization). @@ -766,43 +877,56 @@ static int hdspm_set_rate(struct hdspm * hdspm, int rate, int called_internally) changes in the read/write routines. */ + is_single = (current_rate <= 48000); + is_double = (current_rate > 48000 && current_rate <= 96000); + is_quad = (current_rate > 96000); + switch (rate) { case 32000: - if (current_rate > 48000) { + if (!is_single) reject_if_open = 1; - } rate_bits = HDSPM_Frequency32KHz; break; case 44100: - if (current_rate > 48000) { + if (!is_single) reject_if_open = 1; - } rate_bits = HDSPM_Frequency44_1KHz; break; case 48000: - if (current_rate > 48000) { + if (!is_single) reject_if_open = 1; - } rate_bits = HDSPM_Frequency48KHz; break; case 64000: - if (current_rate <= 48000) { + if (!is_double) reject_if_open = 1; - } rate_bits = HDSPM_Frequency64KHz; break; case 88200: - if (current_rate <= 48000) { + if (!is_double) reject_if_open = 1; - } rate_bits = HDSPM_Frequency88_2KHz; break; case 96000: - if (current_rate <= 48000) { + if (!is_double) reject_if_open = 1; - } rate_bits = HDSPM_Frequency96KHz; break; + case 128000: + if (!is_quad) + reject_if_open = 1; + rate_bits = HDSPM_Frequency128KHz; + break; + case 176400: + if (!is_quad) + reject_if_open = 1; + rate_bits = HDSPM_Frequency176_4KHz; + break; + case 192000: + if (!is_quad) + reject_if_open = 1; + rate_bits = HDSPM_Frequency192KHz; + break; default: return -EINVAL; } @@ -819,7 +943,7 @@ static int hdspm_set_rate(struct hdspm * hdspm, int rate, int called_internally) hdspm->control_register |= rate_bits; hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); - if (rate > 64000) + if (rate > 96000 /* 64000*/) hdspm->channel_map = channel_map_madi_qs; else if (rate > 48000) hdspm->channel_map = channel_map_madi_ds; @@ -1455,11 +1579,27 @@ static int hdspm_pref_sync_ref(struct hdspm * hdspm) /* Notice that this looks at the requested sync source, not the one actually in use. */ - switch (hdspm->control_register & HDSPM_SyncRefMask) { - case HDSPM_SyncRef_Word: - return HDSPM_SYNC_FROM_WORD; - case HDSPM_SyncRef_MADI: - return HDSPM_SYNC_FROM_MADI; + if (hdspm->is_aes32) { + switch (hdspm->control_register & HDSPM_SyncRefMask) { + /* number gives AES index, except for 0 which + corresponds to WordClock */ + case 0: return 0; + case HDSPM_SyncRef0: return 1; + case HDSPM_SyncRef1: return 2; + case HDSPM_SyncRef1+HDSPM_SyncRef0: return 3; + case HDSPM_SyncRef2: return 4; + case HDSPM_SyncRef2+HDSPM_SyncRef0: return 5; + case HDSPM_SyncRef2+HDSPM_SyncRef1: return 6; + case HDSPM_SyncRef2+HDSPM_SyncRef1+HDSPM_SyncRef0: return 7; + case HDSPM_SyncRef3: return 8; + } + } else { + switch (hdspm->control_register & HDSPM_SyncRefMask) { + case HDSPM_SyncRef_Word: + return HDSPM_SYNC_FROM_WORD; + case HDSPM_SyncRef_MADI: + return HDSPM_SYNC_FROM_MADI; + } } return HDSPM_SYNC_FROM_WORD; @@ -1469,15 +1609,49 @@ static int hdspm_set_pref_sync_ref(struct hdspm * hdspm, int pref) { hdspm->control_register &= ~HDSPM_SyncRefMask; - switch (pref) { - case HDSPM_SYNC_FROM_MADI: - hdspm->control_register |= HDSPM_SyncRef_MADI; - break; - case HDSPM_SYNC_FROM_WORD: - hdspm->control_register |= HDSPM_SyncRef_Word; - break; - default: - return -1; + if (hdspm->is_aes32) { + switch (pref) { + case 0: + hdspm->control_register |= 0; + break; + case 1: + hdspm->control_register |= HDSPM_SyncRef0; + break; + case 2: + hdspm->control_register |= HDSPM_SyncRef1; + break; + case 3: + hdspm->control_register |= HDSPM_SyncRef1+HDSPM_SyncRef0; + break; + case 4: + hdspm->control_register |= HDSPM_SyncRef2; + break; + case 5: + hdspm->control_register |= HDSPM_SyncRef2+HDSPM_SyncRef0; + break; + case 6: + hdspm->control_register |= HDSPM_SyncRef2+HDSPM_SyncRef1; + break; + case 7: + hdspm->control_register |= HDSPM_SyncRef2+HDSPM_SyncRef1+HDSPM_SyncRef0; + break; + case 8: + hdspm->control_register |= HDSPM_SyncRef3; + break; + default: + return -1; + } + } else { + switch (pref) { + case HDSPM_SYNC_FROM_MADI: + hdspm->control_register |= HDSPM_SyncRef_MADI; + break; + case HDSPM_SYNC_FROM_WORD: + hdspm->control_register |= HDSPM_SyncRef_Word; + break; + default: + return -1; + } } hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); return 0; @@ -1486,18 +1660,36 @@ static int hdspm_set_pref_sync_ref(struct hdspm * hdspm, int pref) static int snd_hdspm_info_pref_sync_ref(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { "Word", "MADI" }; + struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; + if (hdspm->is_aes32) { + static char *texts[] = { "Word", "AES1", "AES2", "AES3", + "AES4", "AES5", "AES6", "AES7", "AES8" }; - uinfo->value.enumerated.items = 2; + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = - uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); + uinfo->value.enumerated.items = 9; + + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = + uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, + texts[uinfo->value.enumerated.item]); + } else { + static char *texts[] = { "Word", "MADI" }; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + + uinfo->value.enumerated.items = 2; + + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = + uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, + texts[uinfo->value.enumerated.item]); + } return 0; } @@ -1517,7 +1709,7 @@ static int snd_hdspm_put_pref_sync_ref(struct snd_kcontrol *kcontrol, int change, max; unsigned int val; - max = 2; + max = hdspm->is_aes32 ? 9 : 2; if (!snd_hdspm_use_is_exclusive(hdspm)) return -EBUSY; @@ -1542,40 +1734,64 @@ static int snd_hdspm_put_pref_sync_ref(struct snd_kcontrol *kcontrol, static int hdspm_autosync_ref(struct hdspm * hdspm) { - /* This looks at the autosync selected sync reference */ - unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2); - - switch (status2 & HDSPM_SelSyncRefMask) { - - case HDSPM_SelSyncRef_WORD: - return HDSPM_AUTOSYNC_FROM_WORD; - - case HDSPM_SelSyncRef_MADI: - return HDSPM_AUTOSYNC_FROM_MADI; - - case HDSPM_SelSyncRef_NVALID: - return HDSPM_AUTOSYNC_FROM_NONE; + if (hdspm->is_aes32) { + unsigned int status = hdspm_read(hdspm, HDSPM_statusRegister); + unsigned int syncref = (status >> HDSPM_AES32_syncref_bit) & 0xF; + if (syncref == 0) + return HDSPM_AES32_AUTOSYNC_FROM_WORD; + if (syncref <= 8) + return syncref; + return HDSPM_AES32_AUTOSYNC_FROM_NONE; + } else { + /* This looks at the autosync selected sync reference */ + unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2); + + switch (status2 & HDSPM_SelSyncRefMask) { + case HDSPM_SelSyncRef_WORD: + return HDSPM_AUTOSYNC_FROM_WORD; + case HDSPM_SelSyncRef_MADI: + return HDSPM_AUTOSYNC_FROM_MADI; + case HDSPM_SelSyncRef_NVALID: + return HDSPM_AUTOSYNC_FROM_NONE; + default: + return 0; + } - default: return 0; } - - return 0; } static int snd_hdspm_info_autosync_ref(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { "WordClock", "MADI", "None" }; + struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 3; - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = - uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); + if (hdspm->is_aes32) { + static char *texts[] = { "WordClock", "AES1", "AES2", "AES3", + "AES4", "AES5", "AES6", "AES7", "AES8", "None"}; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 10; + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = + uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, + texts[uinfo->value.enumerated.item]); + } + else + { + static char *texts[] = { "WordClock", "MADI", "None" }; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 3; + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = + uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, + texts[uinfo->value.enumerated.item]); + } return 0; } @@ -1787,45 +2003,376 @@ static int snd_hdspm_put_c_tms(struct snd_kcontrol *kcontrol, .put = snd_hdspm_put_safe_mode \ } -static int hdspm_safe_mode(struct hdspm * hdspm) +static int hdspm_safe_mode(struct hdspm * hdspm) +{ + return (hdspm->control_register & HDSPM_AutoInp) ? 1 : 0; +} + +static int hdspm_set_safe_mode(struct hdspm * hdspm, int out) +{ + if (out) + hdspm->control_register |= HDSPM_AutoInp; + else + hdspm->control_register &= ~HDSPM_AutoInp; + hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); + + return 0; +} + +static int snd_hdspm_info_safe_mode(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int snd_hdspm_get_safe_mode(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); + + spin_lock_irq(&hdspm->lock); + ucontrol->value.integer.value[0] = hdspm_safe_mode(hdspm); + spin_unlock_irq(&hdspm->lock); + return 0; +} + +static int snd_hdspm_put_safe_mode(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); + int change; + unsigned int val; + + if (!snd_hdspm_use_is_exclusive(hdspm)) + return -EBUSY; + val = ucontrol->value.integer.value[0] & 1; + spin_lock_irq(&hdspm->lock); + change = (int) val != hdspm_safe_mode(hdspm); + hdspm_set_safe_mode(hdspm, val); + spin_unlock_irq(&hdspm->lock); + return change; +} + +#define HDSPM_EMPHASIS(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .index = xindex, \ + .info = snd_hdspm_info_emphasis, \ + .get = snd_hdspm_get_emphasis, \ + .put = snd_hdspm_put_emphasis \ +} + +static int hdspm_emphasis(struct hdspm * hdspm) +{ + return (hdspm->control_register & HDSPM_Emphasis) ? 1 : 0; +} + +static int hdspm_set_emphasis(struct hdspm * hdspm, int emp) +{ + if (emp) + hdspm->control_register |= HDSPM_Emphasis; + else + hdspm->control_register &= ~HDSPM_Emphasis; + hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); + + return 0; +} + +static int snd_hdspm_info_emphasis(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int snd_hdspm_get_emphasis(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); + + spin_lock_irq(&hdspm->lock); + ucontrol->value.enumerated.item[0] = hdspm_emphasis(hdspm); + spin_unlock_irq(&hdspm->lock); + return 0; +} + +static int snd_hdspm_put_emphasis(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); + int change; + unsigned int val; + + if (!snd_hdspm_use_is_exclusive(hdspm)) + return -EBUSY; + val = ucontrol->value.integer.value[0] & 1; + spin_lock_irq(&hdspm->lock); + change = (int) val != hdspm_emphasis(hdspm); + hdspm_set_emphasis(hdspm, val); + spin_unlock_irq(&hdspm->lock); + return change; +} + +#define HDSPM_DOLBY(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .index = xindex, \ + .info = snd_hdspm_info_dolby, \ + .get = snd_hdspm_get_dolby, \ + .put = snd_hdspm_put_dolby \ +} + +static int hdspm_dolby(struct hdspm * hdspm) +{ + return (hdspm->control_register & HDSPM_Dolby) ? 1 : 0; +} + +static int hdspm_set_dolby(struct hdspm * hdspm, int dol) +{ + if (dol) + hdspm->control_register |= HDSPM_Dolby; + else + hdspm->control_register &= ~HDSPM_Dolby; + hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); + + return 0; +} + +static int snd_hdspm_info_dolby(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int snd_hdspm_get_dolby(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); + + spin_lock_irq(&hdspm->lock); + ucontrol->value.enumerated.item[0] = hdspm_dolby(hdspm); + spin_unlock_irq(&hdspm->lock); + return 0; +} + +static int snd_hdspm_put_dolby(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); + int change; + unsigned int val; + + if (!snd_hdspm_use_is_exclusive(hdspm)) + return -EBUSY; + val = ucontrol->value.integer.value[0] & 1; + spin_lock_irq(&hdspm->lock); + change = (int) val != hdspm_dolby(hdspm); + hdspm_set_dolby(hdspm, val); + spin_unlock_irq(&hdspm->lock); + return change; +} + +#define HDSPM_PROFESSIONAL(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .index = xindex, \ + .info = snd_hdspm_info_professional, \ + .get = snd_hdspm_get_professional, \ + .put = snd_hdspm_put_professional \ +} + +static int hdspm_professional(struct hdspm * hdspm) +{ + return (hdspm->control_register & HDSPM_Professional) ? 1 : 0; +} + +static int hdspm_set_professional(struct hdspm * hdspm, int dol) +{ + if (dol) + hdspm->control_register |= HDSPM_Professional; + else + hdspm->control_register &= ~HDSPM_Professional; + hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); + + return 0; +} + +static int snd_hdspm_info_professional(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int snd_hdspm_get_professional(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); + + spin_lock_irq(&hdspm->lock); + ucontrol->value.enumerated.item[0] = hdspm_professional(hdspm); + spin_unlock_irq(&hdspm->lock); + return 0; +} + +static int snd_hdspm_put_professional(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); + int change; + unsigned int val; + + if (!snd_hdspm_use_is_exclusive(hdspm)) + return -EBUSY; + val = ucontrol->value.integer.value[0] & 1; + spin_lock_irq(&hdspm->lock); + change = (int) val != hdspm_professional(hdspm); + hdspm_set_professional(hdspm, val); + spin_unlock_irq(&hdspm->lock); + return change; +} + +#define HDSPM_INPUT_SELECT(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .index = xindex, \ + .info = snd_hdspm_info_input_select, \ + .get = snd_hdspm_get_input_select, \ + .put = snd_hdspm_put_input_select \ +} + +static int hdspm_input_select(struct hdspm * hdspm) +{ + return (hdspm->control_register & HDSPM_InputSelect0) ? 1 : 0; +} + +static int hdspm_set_input_select(struct hdspm * hdspm, int out) +{ + if (out) + hdspm->control_register |= HDSPM_InputSelect0; + else + hdspm->control_register &= ~HDSPM_InputSelect0; + hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); + + return 0; +} + +static int snd_hdspm_info_input_select(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + static char *texts[] = { "optical", "coaxial" }; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 2; + + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = + uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, + texts[uinfo->value.enumerated.item]); + + return 0; +} + +static int snd_hdspm_get_input_select(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); + + spin_lock_irq(&hdspm->lock); + ucontrol->value.enumerated.item[0] = hdspm_input_select(hdspm); + spin_unlock_irq(&hdspm->lock); + return 0; +} + +static int snd_hdspm_put_input_select(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); + int change; + unsigned int val; + + if (!snd_hdspm_use_is_exclusive(hdspm)) + return -EBUSY; + val = ucontrol->value.integer.value[0] & 1; + spin_lock_irq(&hdspm->lock); + change = (int) val != hdspm_input_select(hdspm); + hdspm_set_input_select(hdspm, val); + spin_unlock_irq(&hdspm->lock); + return change; +} + +#define HDSPM_DS_WIRE(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .index = xindex, \ + .info = snd_hdspm_info_ds_wire, \ + .get = snd_hdspm_get_ds_wire, \ + .put = snd_hdspm_put_ds_wire \ +} + +static int hdspm_ds_wire(struct hdspm * hdspm) { - return (hdspm->control_register & HDSPM_AutoInp) ? 1 : 0; + return (hdspm->control_register & HDSPM_DS_DoubleWire) ? 1 : 0; } -static int hdspm_set_safe_mode(struct hdspm * hdspm, int out) +static int hdspm_set_ds_wire(struct hdspm * hdspm, int ds) { - if (out) - hdspm->control_register |= HDSPM_AutoInp; + if (ds) + hdspm->control_register |= HDSPM_DS_DoubleWire; else - hdspm->control_register &= ~HDSPM_AutoInp; + hdspm->control_register &= ~HDSPM_DS_DoubleWire; hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); return 0; } -static int snd_hdspm_info_safe_mode(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) +static int snd_hdspm_info_ds_wire(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) { - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + static char *texts[] = { "Single", "Double" }; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; + uinfo->value.enumerated.items = 2; + + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = + uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, + texts[uinfo->value.enumerated.item]); + return 0; } -static int snd_hdspm_get_safe_mode(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int snd_hdspm_get_ds_wire(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); spin_lock_irq(&hdspm->lock); - ucontrol->value.integer.value[0] = hdspm_safe_mode(hdspm); + ucontrol->value.enumerated.item[0] = hdspm_ds_wire(hdspm); spin_unlock_irq(&hdspm->lock); return 0; } -static int snd_hdspm_put_safe_mode(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int snd_hdspm_put_ds_wire(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); int change; @@ -1835,45 +2382,56 @@ static int snd_hdspm_put_safe_mode(struct snd_kcontrol *kcontrol, return -EBUSY; val = ucontrol->value.integer.value[0] & 1; spin_lock_irq(&hdspm->lock); - change = (int) val != hdspm_safe_mode(hdspm); - hdspm_set_safe_mode(hdspm, val); + change = (int) val != hdspm_ds_wire(hdspm); + hdspm_set_ds_wire(hdspm, val); spin_unlock_irq(&hdspm->lock); return change; } -#define HDSPM_INPUT_SELECT(xname, xindex) \ +#define HDSPM_QS_WIRE(xname, xindex) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ .name = xname, \ .index = xindex, \ - .info = snd_hdspm_info_input_select, \ - .get = snd_hdspm_get_input_select, \ - .put = snd_hdspm_put_input_select \ + .info = snd_hdspm_info_qs_wire, \ + .get = snd_hdspm_get_qs_wire, \ + .put = snd_hdspm_put_qs_wire \ } -static int hdspm_input_select(struct hdspm * hdspm) +static int hdspm_qs_wire(struct hdspm * hdspm) { - return (hdspm->control_register & HDSPM_InputSelect0) ? 1 : 0; + if (hdspm->control_register & HDSPM_QS_DoubleWire) + return 1; + if (hdspm->control_register & HDSPM_QS_QuadWire) + return 2; + return 0; } -static int hdspm_set_input_select(struct hdspm * hdspm, int out) +static int hdspm_set_qs_wire(struct hdspm * hdspm, int mode) { - if (out) - hdspm->control_register |= HDSPM_InputSelect0; - else - hdspm->control_register &= ~HDSPM_InputSelect0; + hdspm->control_register &= ~(HDSPM_QS_DoubleWire | HDSPM_QS_QuadWire); + switch (mode) { + case 0: + break; + case 1: + hdspm->control_register |= HDSPM_QS_DoubleWire; + break; + case 2: + hdspm->control_register |= HDSPM_QS_QuadWire; + break; + } hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); return 0; } -static int snd_hdspm_info_input_select(struct snd_kcontrol *kcontrol, +static int snd_hdspm_info_qs_wire(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { "optical", "coaxial" }; + static char *texts[] = { "Single", "Double", "Quad" }; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; - uinfo->value.enumerated.items = 2; + uinfo->value.enumerated.items = 3; if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) uinfo->value.enumerated.item = @@ -1884,30 +2442,34 @@ static int snd_hdspm_info_input_select(struct snd_kcontrol *kcontrol, return 0; } -static int snd_hdspm_get_input_select(struct snd_kcontrol *kcontrol, +static int snd_hdspm_get_qs_wire(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); spin_lock_irq(&hdspm->lock); - ucontrol->value.enumerated.item[0] = hdspm_input_select(hdspm); + ucontrol->value.enumerated.item[0] = hdspm_qs_wire(hdspm); spin_unlock_irq(&hdspm->lock); return 0; } -static int snd_hdspm_put_input_select(struct snd_kcontrol *kcontrol, +static int snd_hdspm_put_qs_wire(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); int change; - unsigned int val; + int val; if (!snd_hdspm_use_is_exclusive(hdspm)) return -EBUSY; - val = ucontrol->value.integer.value[0] & 1; + val = ucontrol->value.integer.value[0]; + if (val < 0) + val = 0; + if (val > 2) + val = 2; spin_lock_irq(&hdspm->lock); - change = (int) val != hdspm_input_select(hdspm); - hdspm_set_input_select(hdspm, val); + change = (int) val != hdspm_qs_wire(hdspm); + hdspm_set_qs_wire(hdspm, val); spin_unlock_irq(&hdspm->lock); return change; } @@ -2135,14 +2697,24 @@ static int snd_hdspm_info_sync_check(struct snd_kcontrol *kcontrol, static int hdspm_wc_sync_check(struct hdspm * hdspm) { - int status2 = hdspm_read(hdspm, HDSPM_statusRegister2); - if (status2 & HDSPM_wcLock) { - if (status2 & HDSPM_wcSync) + if (hdspm->is_aes32) { + int status = hdspm_read(hdspm, HDSPM_statusRegister); + if (status & HDSPM_AES32_wcLock) { + /* I don't know how to differenciate sync from lock. + Doing as if sync for now */ return 2; - else - return 1; + } + return 0; + } else { + int status2 = hdspm_read(hdspm, HDSPM_statusRegister2); + if (status2 & HDSPM_wcLock) { + if (status2 & HDSPM_wcSync) + return 2; + else + return 1; + } + return 0; } - return 0; } static int snd_hdspm_get_wc_sync_check(struct snd_kcontrol *kcontrol, @@ -2188,9 +2760,43 @@ static int snd_hdspm_get_madisync_sync_check(struct snd_kcontrol *kcontrol, } +#define HDSPM_AES_SYNC_CHECK(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .index = xindex, \ + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ + .info = snd_hdspm_info_sync_check, \ + .get = snd_hdspm_get_aes_sync_check \ +} + +static int hdspm_aes_sync_check(struct hdspm * hdspm, int idx) +{ + int status2 = hdspm_read(hdspm, HDSPM_statusRegister2); + if (status2 & (HDSPM_LockAES >> idx)) { + /* I don't know how to differenciate sync from lock. + Doing as if sync for now */ + return 2; + } + return 0; +} + +static int snd_hdspm_get_aes_sync_check(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int offset; + struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); + + offset = ucontrol->id.index - 1; + if (offset < 0 || offset >= 8) + return -EINVAL; + + ucontrol->value.enumerated.item[0] = + hdspm_aes_sync_check(hdspm, offset); + return 0; +} -static struct snd_kcontrol_new snd_hdspm_controls[] = { +static struct snd_kcontrol_new snd_hdspm_controls_madi[] = { HDSPM_MIXER("Mixer", 0), /* 'Sample Clock Source' complies with the alsa control naming scheme */ @@ -2211,6 +2817,29 @@ static struct snd_kcontrol_new snd_hdspm_controls[] = { HDSPM_INPUT_SELECT("Input Select", 0), }; +static struct snd_kcontrol_new snd_hdspm_controls_aes32[] = { + + HDSPM_MIXER("Mixer", 0), +/* 'Sample Clock Source' complies with the alsa control naming scheme */ + HDSPM_CLOCK_SOURCE("Sample Clock Source", 0), + + HDSPM_SYSTEM_CLOCK_MODE("System Clock Mode", 0), + HDSPM_PREF_SYNC_REF("Preferred Sync Reference", 0), + HDSPM_AUTOSYNC_REF("AutoSync Reference", 0), + HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0), +/* 'External Rate' complies with the alsa control naming scheme */ + HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 0), + HDSPM_WC_SYNC_CHECK("Word Clock Lock Status", 0), +/* HDSPM_AES_SYNC_CHECK("AES Lock Status", 0),*/ /* created in snd_hdspm_create_controls() */ + HDSPM_LINE_OUT("Line Out", 0), + HDSPM_EMPHASIS("Emphasis", 0), + HDSPM_DOLBY("Non Audio", 0), + HDSPM_PROFESSIONAL("Professional", 0), + HDSPM_C_TMS("Clear Track Marker", 0), + HDSPM_DS_WIRE("Double Speed Wire Mode", 0), + HDSPM_QS_WIRE("Quad Speed Wire Mode", 0), +}; + static struct snd_kcontrol_new snd_hdspm_playback_mixer = HDSPM_PLAYBACK_MIXER; @@ -2245,20 +2874,40 @@ static int snd_hdspm_create_controls(struct snd_card *card, struct hdspm * hdspm struct snd_kcontrol *kctl; /* add control list first */ - - for (idx = 0; idx < ARRAY_SIZE(snd_hdspm_controls); idx++) { - if ((err = - snd_ctl_add(card, kctl = - snd_ctl_new1(&snd_hdspm_controls[idx], - hdspm))) < 0) { - return err; + if (hdspm->is_aes32) { + struct snd_kcontrol_new aes_sync_ctl = + HDSPM_AES_SYNC_CHECK("AES Lock Status", 0); + + for (idx = 0; idx < ARRAY_SIZE(snd_hdspm_controls_aes32); + idx++) { + err = snd_ctl_add(card, + snd_ctl_new1(&snd_hdspm_controls_aes32[idx], + hdspm)); + if (err < 0) + return err; + } + for (idx = 1; idx <= 8; idx++) { + aes_sync_ctl.index = idx; + err = snd_ctl_add(card, + snd_ctl_new1(&aes_sync_ctl, hdspm)); + if (err < 0) + return err; + } + } else { + for (idx = 0; idx < ARRAY_SIZE(snd_hdspm_controls_madi); + idx++) { + err = snd_ctl_add(card, + snd_ctl_new1(&snd_hdspm_controls_madi[idx], + hdspm)); + if (err < 0) + return err; } } /* Channel playback mixer as default control - Note: the whole matrix would be 128*HDSPM_MIXER_CHANNELS Faders, thats too big for any alsamixer - they are accesible via special IOCTL on hwdep - and the mixer 2dimensional mixer control */ +Note: the whole matrix would be 128*HDSPM_MIXER_CHANNELS Faders, thats too big for any alsamixer +they are accesible via special IOCTL on hwdep +and the mixer 2dimensional mixer control */ snd_hdspm_playback_mixer.name = "Chn"; limit = HDSPM_MAX_CHANNELS; @@ -2289,7 +2938,8 @@ static int snd_hdspm_create_controls(struct snd_card *card, struct hdspm * hdspm ------------------------------------------------------------*/ static void -snd_hdspm_proc_read(struct snd_info_entry * entry, struct snd_info_buffer *buffer) +snd_hdspm_proc_read_madi(struct snd_info_entry * entry, + struct snd_info_buffer *buffer) { struct hdspm *hdspm = (struct hdspm *) entry->private_data; unsigned int status; @@ -2420,11 +3070,10 @@ snd_hdspm_proc_read(struct snd_info_entry * entry, struct snd_info_buffer *buffe clock_source = "Error"; } snd_iprintf(buffer, "Sample Clock Source: %s\n", clock_source); - if (!(hdspm->control_register & HDSPM_ClockModeMaster)) { + if (!(hdspm->control_register & HDSPM_ClockModeMaster)) system_clock_mode = "Slave"; - } else { + else system_clock_mode = "Master"; - } snd_iprintf(buffer, "System Clock Mode: %s\n", system_clock_mode); switch (hdspm_pref_sync_ref(hdspm)) { @@ -2484,13 +3133,213 @@ snd_hdspm_proc_read(struct snd_info_entry * entry, struct snd_info_buffer *buffe snd_iprintf(buffer, "\n"); } +static void +snd_hdspm_proc_read_aes32(struct snd_info_entry * entry, + struct snd_info_buffer *buffer) +{ + struct hdspm *hdspm = (struct hdspm *) entry->private_data; + unsigned int status; + unsigned int status2; + unsigned int timecode; + int pref_syncref; + char *autosync_ref; + char *system_clock_mode; + char *clock_source; + int x; + + status = hdspm_read(hdspm, HDSPM_statusRegister); + status2 = hdspm_read(hdspm, HDSPM_statusRegister2); + timecode = hdspm_read(hdspm, HDSPM_timecodeRegister); + + snd_iprintf(buffer, "%s (Card #%d) Rev.%x\n", + hdspm->card_name, hdspm->card->number + 1, + hdspm->firmware_rev); + + snd_iprintf(buffer, "IRQ: %d Registers bus: 0x%lx VM: 0x%lx\n", + hdspm->irq, hdspm->port, (unsigned long)hdspm->iobase); + + snd_iprintf(buffer, "--- System ---\n"); + + snd_iprintf(buffer, + "IRQ Pending: Audio=%d, MIDI0=%d, MIDI1=%d, IRQcount=%d\n", + status & HDSPM_audioIRQPending, + (status & HDSPM_midi0IRQPending) ? 1 : 0, + (status & HDSPM_midi1IRQPending) ? 1 : 0, + hdspm->irq_count); + snd_iprintf(buffer, + "HW pointer: id = %d, rawptr = %d (%d->%d) estimated= %ld (bytes)\n", + ((status & HDSPM_BufferID) ? 1 : 0), + (status & HDSPM_BufferPositionMask), + (status & HDSPM_BufferPositionMask) % (2 * + (int)hdspm-> + period_bytes), + ((status & HDSPM_BufferPositionMask) - + 64) % (2 * (int)hdspm->period_bytes), + (long) hdspm_hw_pointer(hdspm) * 4); + + snd_iprintf(buffer, + "MIDI FIFO: Out1=0x%x, Out2=0x%x, In1=0x%x, In2=0x%x \n", + hdspm_read(hdspm, HDSPM_midiStatusOut0) & 0xFF, + hdspm_read(hdspm, HDSPM_midiStatusOut1) & 0xFF, + hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xFF, + hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xFF); + snd_iprintf(buffer, + "Register: ctrl1=0x%x, ctrl2=0x%x, status1=0x%x, status2=0x%x, timecode=0x%x\n", + hdspm->control_register, hdspm->control2_register, + status, status2, timecode); + + snd_iprintf(buffer, "--- Settings ---\n"); + + x = 1 << (6 + + hdspm_decode_latency(hdspm-> + control_register & + HDSPM_LatencyMask)); + + snd_iprintf(buffer, + "Size (Latency): %d samples (2 periods of %lu bytes)\n", + x, (unsigned long) hdspm->period_bytes); + + snd_iprintf(buffer, "Line out: %s, Precise Pointer: %s\n", + (hdspm-> + control_register & HDSPM_LineOut) ? "on " : "off", + (hdspm->precise_ptr) ? "on" : "off"); + + snd_iprintf(buffer, + "ClearTrackMarker %s, Emphasis %s, Dolby %s\n", + (hdspm-> + control_register & HDSPM_clr_tms) ? "on" : "off", + (hdspm-> + control_register & HDSPM_Emphasis) ? "on" : "off", + (hdspm-> + control_register & HDSPM_Dolby) ? "on" : "off"); + + switch (hdspm_clock_source(hdspm)) { + case HDSPM_CLOCK_SOURCE_AUTOSYNC: + clock_source = "AutoSync"; + break; + case HDSPM_CLOCK_SOURCE_INTERNAL_32KHZ: + clock_source = "Internal 32 kHz"; + break; + case HDSPM_CLOCK_SOURCE_INTERNAL_44_1KHZ: + clock_source = "Internal 44.1 kHz"; + break; + case HDSPM_CLOCK_SOURCE_INTERNAL_48KHZ: + clock_source = "Internal 48 kHz"; + break; + case HDSPM_CLOCK_SOURCE_INTERNAL_64KHZ: + clock_source = "Internal 64 kHz"; + break; + case HDSPM_CLOCK_SOURCE_INTERNAL_88_2KHZ: + clock_source = "Internal 88.2 kHz"; + break; + case HDSPM_CLOCK_SOURCE_INTERNAL_96KHZ: + clock_source = "Internal 96 kHz"; + break; + case HDSPM_CLOCK_SOURCE_INTERNAL_128KHZ: + clock_source = "Internal 128 kHz"; + break; + case HDSPM_CLOCK_SOURCE_INTERNAL_176_4KHZ: + clock_source = "Internal 176.4 kHz"; + break; + case HDSPM_CLOCK_SOURCE_INTERNAL_192KHZ: + clock_source = "Internal 192 kHz"; + break; + default: + clock_source = "Error"; + } + snd_iprintf(buffer, "Sample Clock Source: %s\n", clock_source); + if (!(hdspm->control_register & HDSPM_ClockModeMaster)) + system_clock_mode = "Slave"; + else + system_clock_mode = "Master"; + snd_iprintf(buffer, "System Clock Mode: %s\n", system_clock_mode); + + pref_syncref = hdspm_pref_sync_ref(hdspm); + if (pref_syncref == 0) + snd_iprintf(buffer, "Preferred Sync Reference: Word Clock\n"); + else + snd_iprintf(buffer, "Preferred Sync Reference: AES%d\n", + pref_syncref); + + snd_iprintf(buffer, "System Clock Frequency: %d\n", + hdspm->system_sample_rate); + + snd_iprintf(buffer, "Double speed: %s\n", + hdspm->control_register & HDSPM_DS_DoubleWire? + "Double wire" : "Single wire"); + snd_iprintf(buffer, "Quad speed: %s\n", + hdspm->control_register & HDSPM_QS_DoubleWire? + "Double wire" : + hdspm->control_register & HDSPM_QS_QuadWire? + "Quad wire" : "Single wire"); + + snd_iprintf(buffer, "--- Status:\n"); + + snd_iprintf(buffer, "Word: %s Frequency: %d\n", + (status & HDSPM_AES32_wcLock)? "Sync " : "No Lock", + HDSPM_bit2freq((status >> HDSPM_AES32_wcFreq_bit) & 0xF)); + + for (x = 0; x < 8; x++) { + snd_iprintf(buffer, "AES%d: %s Frequency: %d\n", + x+1, + (status2 & (HDSPM_LockAES >> x))? "Sync ": "No Lock", + HDSPM_bit2freq((timecode >> (4*x)) & 0xF)); + } + + switch (hdspm_autosync_ref(hdspm)) { + case HDSPM_AES32_AUTOSYNC_FROM_NONE: autosync_ref="None"; break; + case HDSPM_AES32_AUTOSYNC_FROM_WORD: autosync_ref="Word Clock"; break; + case HDSPM_AES32_AUTOSYNC_FROM_AES1: autosync_ref="AES1"; break; + case HDSPM_AES32_AUTOSYNC_FROM_AES2: autosync_ref="AES2"; break; + case HDSPM_AES32_AUTOSYNC_FROM_AES3: autosync_ref="AES3"; break; + case HDSPM_AES32_AUTOSYNC_FROM_AES4: autosync_ref="AES4"; break; + case HDSPM_AES32_AUTOSYNC_FROM_AES5: autosync_ref="AES5"; break; + case HDSPM_AES32_AUTOSYNC_FROM_AES6: autosync_ref="AES6"; break; + case HDSPM_AES32_AUTOSYNC_FROM_AES7: autosync_ref="AES7"; break; + case HDSPM_AES32_AUTOSYNC_FROM_AES8: autosync_ref="AES8"; break; + default: autosync_ref = "---"; break; + } + snd_iprintf(buffer, "AutoSync ref = %s\n", autosync_ref); + + snd_iprintf(buffer, "\n"); +} + +#ifdef CONFIG_SND_DEBUG +static void +snd_hdspm_proc_read_debug(struct snd_info_entry * entry, + struct snd_info_buffer *buffer) +{ + struct hdspm *hdspm = (struct hdspm *)entry->private_data; + + int j,i; + + for (i = 0; i < 256 /* 1024*64 */; i += j) + { + snd_iprintf(buffer, "0x%08X: ", i); + for (j = 0; j < 16; j += 4) + snd_iprintf(buffer, "%08X ", hdspm_read(hdspm, i + j)); + snd_iprintf(buffer, "\n"); + } +} +#endif + + + static void __devinit snd_hdspm_proc_init(struct hdspm * hdspm) { struct snd_info_entry *entry; if (!snd_card_proc_new(hdspm->card, "hdspm", &entry)) snd_info_set_text_ops(entry, hdspm, - snd_hdspm_proc_read); + hdspm->is_aes32 ? + snd_hdspm_proc_read_aes32 : + snd_hdspm_proc_read_madi); +#ifdef CONFIG_SND_DEBUG + /* debug file to read all hdspm registers */ + if (!snd_card_proc_new(hdspm->card, "debug", &entry)) + snd_info_set_text_ops(entry, hdspm, + snd_hdspm_proc_read_debug); +#endif } /*------------------------------------------------------------ @@ -2507,13 +3356,20 @@ static int snd_hdspm_set_defaults(struct hdspm * hdspm) /* set defaults: */ - hdspm->control_register = HDSPM_ClockModeMaster | /* Master Cloack Mode on */ - hdspm_encode_latency(7) | /* latency maximum = 8192 samples */ - HDSPM_InputCoaxial | /* Input Coax not Optical */ - HDSPM_SyncRef_MADI | /* Madi is syncclock */ - HDSPM_LineOut | /* Analog output in */ - HDSPM_TX_64ch | /* transmit in 64ch mode */ - HDSPM_AutoInp; /* AutoInput chossing (takeover) */ + if (hdspm->is_aes32) + hdspm->control_register = HDSPM_ClockModeMaster | /* Master Cloack Mode on */ + hdspm_encode_latency(7) | /* latency maximum = 8192 samples */ + HDSPM_SyncRef0 | /* AES1 is syncclock */ + HDSPM_LineOut | /* Analog output in */ + HDSPM_Professional; /* Professional mode */ + else + hdspm->control_register = HDSPM_ClockModeMaster | /* Master Cloack Mode on */ + hdspm_encode_latency(7) | /* latency maximum = 8192 samples */ + HDSPM_InputCoaxial | /* Input Coax not Optical */ + HDSPM_SyncRef_MADI | /* Madi is syncclock */ + HDSPM_LineOut | /* Analog output in */ + HDSPM_TX_64ch | /* transmit in 64ch mode */ + HDSPM_AutoInp; /* AutoInput chossing (takeover) */ /* ! HDSPM_Frequency0|HDSPM_Frequency1 = 44.1khz */ /* ! HDSPM_DoubleSpeed HDSPM_QuadSpeed = normal speed */ @@ -2822,6 +3678,8 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream, hdspm->playback_buffer = (unsigned char *) substream->runtime->dma_area; + snd_printdd("Allocated sample buffer for playback at 0x%08X\n", + hdspm->playback_buffer); } else { hdspm_set_sgbuf(hdspm, sgbuf, HDSPM_pageAddressBufferIn, params_channels(params)); @@ -2831,7 +3689,15 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream, hdspm->capture_buffer = (unsigned char *) substream->runtime->dma_area; + snd_printdd("Allocated sample buffer for capture at 0x%08X\n", + hdspm->capture_buffer); } + /* + snd_printdd("Allocated sample buffer for %s at 0x%08X\n", + substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? + "playback" : "capture", + snd_pcm_sgbuf_get_addr(sgbuf, 0)); + */ return 0; } @@ -2982,9 +3848,10 @@ static struct snd_pcm_hardware snd_hdspm_playback_subinfo = { SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 | - SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000), + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000 ), .rate_min = 32000, - .rate_max = 96000, + .rate_max = 192000, .channels_min = 1, .channels_max = HDSPM_MAX_CHANNELS, .buffer_bytes_max = @@ -3006,9 +3873,10 @@ static struct snd_pcm_hardware snd_hdspm_capture_subinfo = { SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 | - SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000), + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000), .rate_min = 32000, - .rate_max = 96000, + .rate_max = 192000, .channels_min = 1, .channels_max = HDSPM_MAX_CHANNELS, .buffer_bytes_max = @@ -3315,7 +4183,8 @@ static int __devinit snd_hdspm_preallocate_memory(struct hdspm * hdspm) pcm = hdspm->pcm; - wanted = HDSPM_DMA_AREA_BYTES + 4096; /* dont know why, but it works */ +/* wanted = HDSPM_DMA_AREA_BYTES + 4096;*/ /* dont know why, but it works */ + wanted = HDSPM_DMA_AREA_BYTES; if ((err = snd_pcm_lib_preallocate_pages_for_all(pcm, @@ -3467,9 +4336,16 @@ static int __devinit snd_hdspm_create(struct snd_card *card, struct hdspm * hdsp pci_read_config_word(hdspm->pci, PCI_CLASS_REVISION, &hdspm->firmware_rev); - strcpy(card->driver, "HDSPM"); + hdspm->is_aes32 = (hdspm->firmware_rev >= HDSPM_AESREVISION); + strcpy(card->mixername, "Xilinx FPGA"); - hdspm->card_name = "RME HDSPM MADI"; + if (hdspm->is_aes32) { + strcpy(card->driver, "HDSPAES32"); + hdspm->card_name = "RME HDSPM AES32"; + } else { + strcpy(card->driver, "HDSPM"); + hdspm->card_name = "RME HDSPM MADI"; + } if ((err = pci_enable_device(pci)) < 0) return err; -- cgit v1.2.3 From cbcc2c4c07bd34586c7fd8d7513d3a397d39ce3c Mon Sep 17 00:00:00 2001 From: Jerome Demange Date: Mon, 16 Oct 2006 21:08:57 +0200 Subject: [ALSA] ac97 - enables sound output through speakers on MSI S250 laptop Signed-off-by: Jerome Demange Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/ac97/ac97_patch.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index e813968e0cf..123de550d1f 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -2264,7 +2264,8 @@ int patch_alc655(struct snd_ac97 * ac97) if (ac97->subsystem_vendor == 0x1462 && (ac97->subsystem_device == 0x0131 || /* MSI S270 laptop */ ac97->subsystem_device == 0x0161 || /* LG K1 Express */ - ac97->subsystem_device == 0x0351)) /* MSI L725 laptop */ + ac97->subsystem_device == 0x0351 || /* MSI L725 laptop */ + ac97->subsystem_device == 0x0061)) /* MSI S250 laptop */ val &= ~(1 << 1); /* Pin 47 is EAPD (for internal speaker) */ else val |= (1 << 1); /* Pin 47 is spdif input pin */ -- cgit v1.2.3 From 12e74f7d430655f541b85018ea62bcd669094bd7 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Mon, 16 Oct 2006 21:19:48 +0200 Subject: [ALSA] ASoC - Fix build warnings in soc-core.c This patch fixes some build warnings in soc-core.c Changes:- o Check the return value of soc_ac97_dev_register() o Check return value of calls to device_create_file() Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/soc-core.c | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 8d6ff047d7a..2ce0c8251dc 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1438,12 +1438,18 @@ int snd_soc_register_card(struct snd_soc_device *socdev) { struct snd_soc_codec *codec = socdev->codec; struct snd_soc_machine *machine = socdev->machine; - int ret = 0, i, ac97 = 0; + int ret = 0, i, ac97 = 0, err = 0; mutex_lock(&codec->mutex); for(i = 0; i < machine->num_links; i++) { - if (socdev->machine->dai_link[i].init) - socdev->machine->dai_link[i].init(codec); + if (socdev->machine->dai_link[i].init) { + err = socdev->machine->dai_link[i].init(codec); + if (err < 0) { + printk(KERN_ERR "asoc: failed to init %s\n", + socdev->machine->dai_link[i].stream_name); + continue; + } + } if (socdev->machine->dai_link[i].cpu_dai->type == SND_SOC_DAI_AC97) ac97 = 1; } @@ -1456,17 +1462,28 @@ int snd_soc_register_card(struct snd_soc_device *socdev) if (ret < 0) { printk(KERN_ERR "asoc: failed to register soundcard for codec %s\n", codec->name); - mutex_unlock(&codec->mutex); - return ret; + goto out; } #ifdef CONFIG_SND_SOC_AC97_BUS - if (ac97) - soc_ac97_dev_register(codec); + if (ac97) { + ret = soc_ac97_dev_register(codec); + if (ret < 0) { + printk(KERN_ERR "asoc: AC97 device register failed\n"); + snd_card_free(codec->card); + goto out; + } + } #endif - snd_soc_dapm_sys_add(socdev->dev); - device_create_file(socdev->dev, &dev_attr_codec_reg); + err = snd_soc_dapm_sys_add(socdev->dev); + if (err < 0) + printk(KERN_WARNING "asoc: failed to add dapm sysfs entries\n"); + + err = device_create_file(socdev->dev, &dev_attr_codec_reg); + if (err < 0) + printk(KERN_WARNING "asoc: failed to add codec sysfs entries\n"); +out: mutex_unlock(&codec->mutex); return ret; } -- cgit v1.2.3 From a53d1aece388d940831846f642810e47526883e8 Mon Sep 17 00:00:00 2001 From: Tobin Davis Date: Tue, 17 Oct 2006 12:00:28 +0200 Subject: [ALSA] hda-codec - Add toshiba model to ALC861 codec This patch adds support for Toshiba laptops. Code is from RealTek's alsa-driver-1.0.12-4.05b tree. Signed-off-by: Tobin Davis Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 77 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 75 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 1420db43423..62c75388457 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -91,6 +91,7 @@ enum { ALC861_3ST_DIG, ALC861_6ST_DIG, ALC861_UNIWILL_M31, + ALC861_TOSHIBA, ALC861_AUTO, ALC861_MODEL_LAST, }; @@ -6206,7 +6207,29 @@ static struct snd_kcontrol_new alc861_3ST_mixer[] = { .private_value = ARRAY_SIZE(alc861_threestack_modes), }, { } /* end */ -}; +}; + +static snd_kcontrol_new_t alc861_toshiba_mixer[] = { + /* output mixer control */ + HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT), + + /*Capture mixer control */ + HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Source", + .count = 1, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, + }, + + { } /* end */ +}; + static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = { /* output mixer control */ HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT), @@ -6489,6 +6512,39 @@ static struct hda_verb alc861_auto_init_verbs[] = { { } }; +static struct hda_verb alc861_toshiba_init_verbs[] = { + {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + + { } +}; + +/* toggle speaker-output according to the hp-jack state */ +static void alc861_toshiba_automute(struct hda_codec *codec) +{ + unsigned int present; + + present = snd_hda_codec_read(codec, 0x0f, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + snd_hda_codec_amp_update(codec, 0x16, 0, HDA_INPUT, 0, + 0x80, present ? 0x80 : 0); + snd_hda_codec_amp_update(codec, 0x16, 1, HDA_INPUT, 0, + 0x80, present ? 0x80 : 0); + snd_hda_codec_amp_update(codec, 0x1a, 0, HDA_INPUT, 3, + 0x80, present ? 0 : 0x80); + snd_hda_codec_amp_update(codec, 0x1a, 1, HDA_INPUT, 3, + 0x80, present ? 0 : 0x80); +} + +static void alc861_toshiba_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + /* Looks like the unsol event is incompatible with the standard + * definition. 6bit tag is placed at 26 bit! + */ + if ((res >> 26) == ALC880_HP_EVENT) + alc861_toshiba_automute(codec); +} + /* pcm configuration: identiacal with ALC880 */ #define alc861_pcm_analog_playback alc880_pcm_analog_playback #define alc861_pcm_analog_capture alc880_pcm_analog_capture @@ -6774,6 +6830,11 @@ static struct hda_board_config alc861_cfg_tbl[] = { { .modelname = "uniwill-m31", .config = ALC861_UNIWILL_M31}, { .pci_subvendor = 0x1584, .pci_subdevice = 0x9072, .config = ALC861_UNIWILL_M31 }, + { .modelname = "toshiba", .config = ALC861_TOSHIBA }, + { .pci_subvendor = 0x1043, .pci_subdevice = 0x1338, + .config = ALC861_TOSHIBA }, + { .pci_subvendor = 0x1179, .pci_subdevice = 0xff10, + .config = ALC861_TOSHIBA }, { .modelname = "auto", .config = ALC861_AUTO }, {} }; @@ -6841,7 +6902,19 @@ static struct alc_config_preset alc861_presets[] = { .adc_nids = alc861_adc_nids, .input_mux = &alc861_capture_source, }, - + [ALC861_TOSHIBA] = { + .mixers = { alc861_toshiba_mixer }, + .init_verbs = { alc861_base_init_verbs, alc861_toshiba_init_verbs }, + .num_dacs = ARRAY_SIZE(alc861_dac_nids), + .dac_nids = alc861_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), + .channel_mode = alc883_3ST_2ch_modes, + .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), + .adc_nids = alc861_adc_nids, + .input_mux = &alc861_capture_source, + .unsol_event = alc861_toshiba_unsol_event, + .init_hook = alc861_toshiba_automute, + }, }; -- cgit v1.2.3 From ccc656ce5f6627032bd44e660071bb71e65a231a Mon Sep 17 00:00:00 2001 From: Kailang Yang Date: Tue, 17 Oct 2006 12:32:26 +0200 Subject: [ALSA] hda-codec - Add new modesl for Realtek codecs Changes from Realtek driver: - New models hippo and hippo_1 for ALC262 - New models tagra-dig and tagra-2ch-dig for ALC883 - New id for ALC660 codec chip Signed-off-by: Kailang Yang Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 536 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 530 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 62c75388457..04749d2f7bd 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -32,6 +32,10 @@ #include "hda_codec.h" #include "hda_local.h" +#define ALC880_FRONT_EVENT 0x01 +#define ALC880_DCVOL_EVENT 0x02 +#define ALC880_HP_EVENT 0x04 +#define ALC880_MIC_EVENT 0x08 /* ALC880 board config type */ enum { @@ -49,6 +53,8 @@ enum { ALC880_ASUS_W1V, ALC880_ASUS_DIG2, ALC880_UNIWILL_DIG, + ALC880_UNIWILL, + ALC880_UNIWILL_P53, ALC880_CLEVO, ALC880_TCL_S700, ALC880_LG, @@ -77,6 +83,8 @@ enum { /* ALC262 models */ enum { ALC262_BASIC, + ALC262_HIPPO, + ALC262_HIPPO_1, ALC262_FUJITSU, ALC262_HP_BPC, ALC262_BENQ_ED8, @@ -111,6 +119,8 @@ enum { ALC883_3ST_6ch_DIG, ALC883_3ST_6ch, ALC883_6ST_DIG, + ALC883_TARGA_DIG, + ALC883_TARGA_2ch_DIG, ALC888_DEMO_BOARD, ALC883_ACER, ALC883_MEDION, @@ -1017,6 +1027,46 @@ static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = { { } /* end */ }; +/* Uniwill */ +static struct snd_kcontrol_new alc880_uniwill_mixer[] = { + HDA_CODEC_VOLUME("HPhone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("HPhone Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("iSpeaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("iSpeaker Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), + HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc_ch_mode_info, + .get = alc_ch_mode_get, + .put = alc_ch_mode_put, + }, + { } /* end */ +}; + +static struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = { + HDA_CODEC_VOLUME("HPhone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("HPhone Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("iSpeaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("iSpeaker Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; + /* * build control elements */ @@ -1250,6 +1300,154 @@ static struct hda_verb alc880_pin_6stack_init_verbs[] = { { } }; +/* + * Uniwill pin configuration: + * HP = 0x14, InternalSpeaker = 0x15, mic = 0x18, internal mic = 0x19, + * line = 0x1a + */ +static struct hda_verb alc880_uniwill_init_verbs[] = { + {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, */ + /* {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */ + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + + { } +}; + +/* +* Uniwill P53 +* HP = 0x14, InternalSpeaker = 0x15, mic = 0x19, + */ +static struct hda_verb alc880_uniwill_p53_init_verbs[] = { + {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_DCVOL_EVENT}, + + { } +}; + +/* toggle speaker-output according to the hp-jack state */ +static void alc880_uniwill_automute(struct hda_codec *codec) +{ + unsigned int present; + + present = snd_hda_codec_read(codec, 0x14, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, + 0x80, present ? 0x80 : 0); + snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, + 0x80, present ? 0x80 : 0); + snd_hda_codec_amp_update(codec, 0x16, 0, HDA_OUTPUT, 0, + 0x80, present ? 0x80 : 0); + snd_hda_codec_amp_update(codec, 0x16, 1, HDA_OUTPUT, 0, + 0x80, present ? 0x80 : 0); + + present = snd_hda_codec_read(codec, 0x18, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + snd_hda_codec_write(codec, 0x0b, 0, AC_VERB_SET_AMP_GAIN_MUTE, + 0x7000 | (0x01 << 8) | (present ? 0x80 : 0)); +} + +static void alc880_uniwill_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + /* Looks like the unsol event is incompatible with the standard + * definition. 4bit tag is placed at 28 bit! + */ + if ((res >> 28) == ALC880_HP_EVENT || + (res >> 28) == ALC880_MIC_EVENT) + alc880_uniwill_automute(codec); +} + +static void alc880_uniwill_p53_hp_automute(struct hda_codec *codec) +{ + unsigned int present; + + present = snd_hda_codec_read(codec, 0x14, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + + snd_hda_codec_amp_update(codec, 0x15, 0, HDA_INPUT, 0, + 0x80, present ? 0x80 : 0); + snd_hda_codec_amp_update(codec, 0x15, 1, HDA_INPUT, 0, + 0x80, present ? 0x80 : 0); +} + +static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec) +{ + unsigned int present; + + present = snd_hda_codec_read(codec, 0x21, 0, + AC_VERB_GET_VOLUME_KNOB_CONTROL, 0) & 0x7f; + + snd_hda_codec_amp_update(codec, 0x0c, 0, HDA_OUTPUT, 0, + 0x7f, present); + snd_hda_codec_amp_update(codec, 0x0c, 1, HDA_OUTPUT, 0, + 0x7f, present); + + snd_hda_codec_amp_update(codec, 0x0d, 0, HDA_OUTPUT, 0, + 0x7f, present); + snd_hda_codec_amp_update(codec, 0x0d, 1, HDA_OUTPUT, 0, + 0x7f, present); + +} +static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + /* Looks like the unsol event is incompatible with the standard + * definition. 4bit tag is placed at 28 bit! + */ + if ((res >> 28) == ALC880_HP_EVENT) + alc880_uniwill_p53_hp_automute(codec); + if ((res >> 28) == ALC880_DCVOL_EVENT) + alc880_uniwill_p53_dcvol_automute(codec); +} + /* FIXME! */ /* * F1734 pin configuration: @@ -2262,7 +2460,10 @@ static struct hda_board_config alc880_cfg_tbl[] = { { .pci_subvendor = 0x1558, .pci_subdevice = 0x5401, .config = ALC880_ASUS_DIG2 }, { .modelname = "uniwill", .config = ALC880_UNIWILL_DIG }, - { .pci_subvendor = 0x1584, .pci_subdevice = 0x9050, .config = ALC880_UNIWILL_DIG }, + { .pci_subvendor = 0x1584, .pci_subdevice = 0x9050, .config = ALC880_UNIWILL_DIG }, + { .pci_subvendor = 0x1584, .pci_subdevice = 0x9070, .config = ALC880_UNIWILL }, + { .pci_subvendor = 0x1734, .pci_subdevice = 0x10ac, .config = ALC880_UNIWILL }, + { .pci_subvendor = 0x1584, .pci_subdevice = 0x9077, .config = ALC880_UNIWILL_P53 }, { .modelname = "F1734", .config = ALC880_F1734 }, { .pci_subvendor = 0x1734, .pci_subdevice = 0x107c, .config = ALC880_F1734 }, @@ -2440,7 +2641,8 @@ static struct alc_config_preset alc880_presets[] = { }, [ALC880_UNIWILL_DIG] = { .mixers = { alc880_asus_mixer, alc880_pcbeep_mixer }, - .init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_init_verbs }, + .init_verbs = { alc880_volume_init_verbs, + alc880_pin_asus_init_verbs }, .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), .dac_nids = alc880_asus_dac_nids, .dig_out_nid = ALC880_DIGOUT_NID, @@ -2449,6 +2651,32 @@ static struct alc_config_preset alc880_presets[] = { .need_dac_fix = 1, .input_mux = &alc880_capture_source, }, + [ALC880_UNIWILL] = { + .mixers = { alc880_uniwill_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_uniwill_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), + .dac_nids = alc880_asus_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), + .channel_mode = alc880_threestack_modes, + .need_dac_fix = 1, + .input_mux = &alc880_capture_source, + .unsol_event = alc880_uniwill_unsol_event, + .init_hook = alc880_uniwill_automute, + }, + [ALC880_UNIWILL_P53] = { + .mixers = { alc880_uniwill_p53_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_uniwill_p53_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), + .dac_nids = alc880_asus_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc880_w810_modes), + .channel_mode = alc880_w810_modes, + .input_mux = &alc880_capture_source, + .unsol_event = alc880_uniwill_p53_unsol_event, + .init_hook = alc880_uniwill_p53_hp_automute, + }, [ALC880_CLEVO] = { .mixers = { alc880_three_stack_mixer }, .init_verbs = { alc880_volume_init_verbs, @@ -4912,6 +5140,62 @@ static snd_kcontrol_new_t alc883_fivestack_mixer[] = { { } /* end */ }; +static struct snd_kcontrol_new alc883_tagra_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 2, + .info = alc883_mux_enum_info, + .get = alc883_mux_enum_get, + .put = alc883_mux_enum_put, + }, + { } /* end */ +}; + +static struct snd_kcontrol_new alc883_tagra_2ch_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 2, + .info = alc883_mux_enum_info, + .get = alc883_mux_enum_get, + .put = alc883_mux_enum_put, + }, + { } /* end */ +}; + static struct snd_kcontrol_new alc883_chmode_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -5000,6 +5284,45 @@ static struct hda_verb alc883_init_verbs[] = { { } }; +static struct hda_verb alc883_tagra_verbs[] = { + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + + {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */ + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */ + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ + + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + {0x01, AC_VERB_SET_GPIO_MASK, 0x03}, + {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03}, + {0x01, AC_VERB_SET_GPIO_DATA, 0x03}, + + { } /* end */ +}; + +/* toggle speaker-output according to the hp-jack state */ +static void alc883_tagra_automute(struct hda_codec *codec) +{ + unsigned int present; + + present = snd_hda_codec_read(codec, 0x14, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + snd_hda_codec_amp_update(codec, 0x1b, 0, HDA_OUTPUT, 0, + 0x80, present ? 0x80 : 0); + snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0, + 0x80, present ? 0x80 : 0); + snd_hda_codec_write(codec, 1, 0, AC_VERB_SET_GPIO_DATA, present ? 1 : 3); +} + +static void alc883_tagra_unsol_event(struct hda_codec *codec, unsigned int res) +{ + if ((res >> 26) == ALC880_HP_EVENT) + alc883_tagra_automute(codec); +} + /* * generic initialization of ADC, input mixers and output mixers */ @@ -5101,9 +5424,9 @@ static struct hda_board_config alc883_cfg_tbl[] = { .config = ALC883_3ST_6ch_DIG }, /* ECS to Intel*/ { .modelname = "3stack-6ch", .config = ALC883_3ST_6ch }, { .pci_subvendor = 0x108e, .pci_subdevice = 0x534d, - .config = ALC883_3ST_6ch }, - { .pci_subvendor = 0x8086, .pci_subdevice = 0xd601, - .config = ALC883_3ST_6ch }, /* D102GGC */ + .config = ALC883_3ST_6ch }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xd601, + .config = ALC883_3ST_6ch }, /* D102GGC */ { .modelname = "6stack-dig", .config = ALC883_6ST_DIG }, { .pci_subvendor = 0x1462, .pci_subdevice = 0x6668, .config = ALC883_6ST_DIG }, /* MSI */ @@ -5111,6 +5434,32 @@ static struct hda_board_config alc883_cfg_tbl[] = { .config = ALC883_6ST_DIG }, /* MSI K9A Platinum (MS-7280) */ { .pci_subvendor = 0x105b, .pci_subdevice = 0x6668, .config = ALC883_6ST_DIG }, /* Foxconn */ + { .pci_subvendor = 0x1462, .pci_subdevice = 0x7187, + .config = ALC883_6ST_DIG }, /* MSI */ + { .modelname = "targa-dig", .config = ALC883_TARGA_DIG }, + { .pci_subvendor = 0x1462, .pci_subdevice = 0x4314, + .config = ALC883_TARGA_DIG }, /* MSI */ + { .pci_subvendor = 0x1462, .pci_subdevice = 0x3fcc, + .config = ALC883_TARGA_DIG }, /* MSI */ + { .pci_subvendor = 0x1462, .pci_subdevice = 0x3fc1, + .config = ALC883_TARGA_DIG }, /* MSI */ + { .pci_subvendor = 0x1462, .pci_subdevice = 0x3fc3, + .config = ALC883_TARGA_DIG }, /* MSI */ + { .pci_subvendor = 0x1462, .pci_subdevice = 0x4314, + .config = ALC883_TARGA_DIG }, /* MSI */ + { .pci_subvendor = 0x1462, .pci_subdevice = 0x4319, + .config = ALC883_TARGA_DIG }, /* MSI */ + { .pci_subvendor = 0x1462, .pci_subdevice = 0x3ef9, + .config = ALC883_TARGA_DIG }, /* MSI */ + { .pci_subvendor = 0x1462, .pci_subdevice = 0x4324, + .config = ALC883_TARGA_DIG }, /* MSI */ + { .modelname = "targa-2ch-dig", .config = ALC883_TARGA_2ch_DIG }, + { .pci_subvendor = 0x1462, .pci_subdevice = 0x0579, + .config = ALC883_TARGA_2ch_DIG }, /* MSI */ + { .pci_subvendor = 0x1462, .pci_subdevice = 0xa422, + .config = ALC883_TARGA_2ch_DIG }, /* MSI */ + { .pci_subvendor = 0x1462, .pci_subdevice = 0x3b7f, + .config = ALC883_TARGA_2ch_DIG }, /* MSI */ { .modelname = "6stack-dig-demo", .config = ALC888_DEMO_BOARD }, { .modelname = "acer", .config = ALC883_ACER }, { .pci_subvendor = 0x1025, .pci_subdevice = 0/*0x0102*/, @@ -5178,6 +5527,35 @@ static struct alc_config_preset alc883_presets[] = { .channel_mode = alc883_sixstack_modes, .input_mux = &alc883_capture_source, }, + [ALC883_TARGA_DIG] = { + .mixers = { alc883_tagra_mixer, alc883_chmode_mixer }, + .init_verbs = { alc883_init_verbs, alc883_tagra_verbs}, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .dig_out_nid = ALC883_DIGOUT_NID, + .num_adc_nids = ARRAY_SIZE(alc883_adc_nids), + .adc_nids = alc883_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes), + .channel_mode = alc883_3ST_6ch_modes, + .need_dac_fix = 1, + .input_mux = &alc883_capture_source, + .unsol_event = alc883_tagra_unsol_event, + .init_hook = alc883_tagra_automute, + }, + [ALC883_TARGA_2ch_DIG] = { + .mixers = { alc883_tagra_2ch_mixer}, + .init_verbs = { alc883_init_verbs, alc883_tagra_verbs}, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .dig_out_nid = ALC883_DIGOUT_NID, + .num_adc_nids = ARRAY_SIZE(alc883_adc_nids), + .adc_nids = alc883_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), + .channel_mode = alc883_3ST_2ch_modes, + .input_mux = &alc883_capture_source, + .unsol_event = alc883_tagra_unsol_event, + .init_hook = alc883_tagra_automute, + }, [ALC888_DEMO_BOARD] = { .mixers = { alc883_base_mixer, alc883_chmode_mixer }, .init_verbs = { alc883_init_verbs }, @@ -5408,6 +5786,24 @@ static struct snd_kcontrol_new alc262_base_mixer[] = { { } /* end */ }; +static struct snd_kcontrol_new alc262_hippo1_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), + /* HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT), + HDA_CODEC_MUTE("PC Beelp Playback Switch", 0x0b, 0x05, HDA_INPUT), */ + /*HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),*/ + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + { } /* end */ +}; + static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT), @@ -5512,6 +5908,103 @@ static struct hda_verb alc262_init_verbs[] = { { } }; +static struct hda_verb alc262_hippo_unsol_verbs[] = { + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {} +}; + +static struct hda_verb alc262_hippo1_unsol_verbs[] = { + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, + + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {} +}; + +/* mute/unmute internal speaker according to the hp jack and mute state */ +static void alc262_hippo_automute(struct hda_codec *codec, int force) +{ + struct alc_spec *spec = codec->spec; + unsigned int mute; + + if (force || ! spec->sense_updated) { + unsigned int present; + /* need to execute and sync at first */ + snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0); + present = snd_hda_codec_read(codec, 0x15, 0, + AC_VERB_GET_PIN_SENSE, 0); + spec->jack_present = (present & 0x80000000) != 0; + spec->sense_updated = 1; + } + if (spec->jack_present) { + /* mute internal speaker */ + snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, + 0x80, 0x80); + snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, + 0x80, 0x80); + } else { + /* unmute internal speaker if necessary */ + mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0); + snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, + 0x80, mute & 0x80); + mute = snd_hda_codec_amp_read(codec, 0x15, 1, HDA_OUTPUT, 0); + snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, + 0x80, mute & 0x80); + } +} + +/* unsolicited event for HP jack sensing */ +static void alc262_hippo_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) != ALC880_HP_EVENT) + return; + alc262_hippo_automute(codec, 1); +} + +static void alc262_hippo1_automute(struct hda_codec *codec, int force) +{ + struct alc_spec *spec = codec->spec; + unsigned int mute; + + if (force || ! spec->sense_updated) { + unsigned int present; + /* need to execute and sync at first */ + snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0); + present = snd_hda_codec_read(codec, 0x1b, 0, + AC_VERB_GET_PIN_SENSE, 0); + spec->jack_present = (present & 0x80000000) != 0; + spec->sense_updated = 1; + } + if (spec->jack_present) { + /* mute internal speaker */ + snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, + 0x80, 0x80); + snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, + 0x80, 0x80); + } else { + /* unmute internal speaker if necessary */ + mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0); + snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, + 0x80, mute & 0x80); + mute = snd_hda_codec_amp_read(codec, 0x1b, 1, HDA_OUTPUT, 0); + snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, + 0x80, mute & 0x80); + } +} + +/* unsolicited event for HP jack sensing */ +static void alc262_hippo1_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) != ALC880_HP_EVENT) + return; + alc262_hippo1_automute(codec, 1); +} + /* * fujitsu model * 0x14 = headphone/spdif-out, 0x15 = internal speaker @@ -5921,6 +6414,12 @@ static void alc262_auto_init(struct hda_codec *codec) */ static struct hda_board_config alc262_cfg_tbl[] = { { .modelname = "basic", .config = ALC262_BASIC }, + { .modelname = "hippo", + .pci_subvendor =0x1002, .pci_subdevice = 0x437b, + .config = ALC262_HIPPO}, + { .modelname = "hippo_1", + .pci_subvendor =0x17ff, .pci_subdevice = 0x058f, + .config = ALC262_HIPPO_1}, { .modelname = "fujitsu", .config = ALC262_FUJITSU }, { .pci_subvendor = 0x10cf, .pci_subdevice = 0x1397, .config = ALC262_FUJITSU }, @@ -5953,6 +6452,30 @@ static struct alc_config_preset alc262_presets[] = { .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, }, + [ALC262_HIPPO] = { + .mixers = { alc262_base_mixer }, + .init_verbs = { alc262_init_verbs, alc262_hippo_unsol_verbs}, + .num_dacs = ARRAY_SIZE(alc262_dac_nids), + .dac_nids = alc262_dac_nids, + .hp_nid = 0x03, + .dig_out_nid = ALC262_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc262_modes), + .channel_mode = alc262_modes, + .input_mux = &alc262_capture_source, + .unsol_event = alc262_hippo_unsol_event, + }, + [ALC262_HIPPO_1] = { + .mixers = { alc262_hippo1_mixer }, + .init_verbs = { alc262_init_verbs, alc262_hippo1_unsol_verbs}, + .num_dacs = ARRAY_SIZE(alc262_dac_nids), + .dac_nids = alc262_dac_nids, + .hp_nid = 0x02, + .dig_out_nid = ALC262_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc262_modes), + .channel_mode = alc262_modes, + .input_mux = &alc262_capture_source, + .unsol_event = alc262_hippo1_unsol_event, + }, [ALC262_FUJITSU] = { .mixers = { alc262_fujitsu_mixer }, .init_verbs = { alc262_init_verbs, alc262_fujitsu_unsol_verbs }, @@ -6983,7 +7506,8 @@ struct hda_codec_preset snd_hda_preset_realtek[] = { { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc883 }, { .id = 0x10ec0861, .rev = 0x100300, .name = "ALC861", .patch = patch_alc861 }, - { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660", + { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660", .patch = patch_alc861 }, + { .id = 0x10ec0660, .name = "ALC660", .patch = patch_alc861 }, {} /* terminator */ }; -- cgit v1.2.3 From d7923b2a816625dc4208d89471da6bdcab188cdb Mon Sep 17 00:00:00 2001 From: Remy Bruno Date: Tue, 17 Oct 2006 12:41:56 +0200 Subject: [ALSA] hdsp - Add DDS register support for RME9632 rev >= 152 Add DDS register support for RME9632 rev >= 152. This register sets the sample rate for these cards and is required in addition to the standard control register. It corresponds to a quartz divisor. Signed-off-by: Remy Bruno Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/rme9652/hdsp.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'sound') diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index 849ffe4aa5c..89b3c7ff503 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -80,6 +80,7 @@ MODULE_SUPPORTED_DEVICE("{{RME Hammerfall-DSP}," /* Write registers. These are defined as byte-offsets from the iobase value. */ #define HDSP_resetPointer 0 +#define HDSP_freqReg 0 #define HDSP_outputBufferAddress 32 #define HDSP_inputBufferAddress 36 #define HDSP_controlRegister 64 @@ -469,6 +470,7 @@ struct hdsp { struct pci_dev *pci; struct snd_kcontrol *spdif_ctl; unsigned short mixer_matrix[HDSP_MATRIX_MIXER_SIZE]; + unsigned int dds_value; /* last value written to freq register */ }; /* These tables map the ALSA channels 1..N to the channels that we @@ -940,6 +942,11 @@ static snd_pcm_uframes_t hdsp_hw_pointer(struct hdsp *hdsp) static void hdsp_reset_hw_pointer(struct hdsp *hdsp) { hdsp_write (hdsp, HDSP_resetPointer, 0); + if (hdsp->io_type == H9632 && hdsp->firmware_rev >= 152) + /* HDSP_resetPointer = HDSP_freqReg, which is strange and + * requires (?) to write again DDS value after a reset pointer + * (at least, it works like this) */ + hdsp_write (hdsp, HDSP_freqReg, hdsp->dds_value); } static void hdsp_start_audio(struct hdsp *s) @@ -984,6 +991,30 @@ static int hdsp_set_interrupt_interval(struct hdsp *s, unsigned int frames) return 0; } +static void hdsp_set_dds_value(struct hdsp *hdsp, int rate) +{ + u64 n; + u32 r; + + if (rate >= 112000) + rate /= 4; + else if (rate >= 56000) + rate /= 2; + + /* RME says n = 104857600000000, but in the windows MADI driver, I see: +// return 104857600000000 / rate; // 100 MHz + return 110100480000000 / rate; // 105 MHz + */ + n = 104857600000000ULL; /* = 2^20 * 10^8 */ + div64_32(&n, rate, &r); + /* n should be less than 2^32 for being written to FREQ register */ + snd_assert((n >> 32) == 0); + /* HDSP_freqReg and HDSP_resetPointer are the same, so keep the DDS + value to write it after a reset */ + hdsp->dds_value = n; + hdsp_write(hdsp, HDSP_freqReg, hdsp->dds_value); +} + static int hdsp_set_rate(struct hdsp *hdsp, int rate, int called_internally) { int reject_if_open = 0; @@ -1092,6 +1123,10 @@ static int hdsp_set_rate(struct hdsp *hdsp, int rate, int called_internally) hdsp->control_register |= rate_bits; hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); + /* For HDSP9632 rev 152, need to set DDS value in FREQ register */ + if (hdsp->io_type == H9632 && hdsp->firmware_rev >= 152) + hdsp_set_dds_value(hdsp, rate); + if (rate >= 128000) { hdsp->channel_map = channel_map_H9632_qs; } else if (rate > 48000) { @@ -4945,6 +4980,7 @@ static int __devinit snd_hdsp_create(struct snd_card *card, hdsp->irq = pci->irq; hdsp->precise_ptr = 0; hdsp->use_midi_tasklet = 1; + hdsp->dds_value = 0; if ((err = snd_hdsp_initialize_memory(hdsp)) < 0) return err; -- cgit v1.2.3 From 543a0fbe18d0b44f3d037fe6b59458fa0c0d5e4b Mon Sep 17 00:00:00 2001 From: Frank Mandarino Date: Thu, 19 Oct 2006 18:22:53 +0200 Subject: [ALSA] ASoC AT91 DAI modes update This patch by Frank Mandarino updates the AT91RM9200 I2S DAI audio modes as follows:- o fixes a typo in the 16k mode o removes experimental 24k mode o adds a 32k mode. Signed-off-by: Frank Mandarino Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/at91/at91rm9200-i2s.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/soc/at91/at91rm9200-i2s.c b/sound/soc/at91/at91rm9200-i2s.c index 8c4d3b99905..2eee427b1e5 100644 --- a/sound/soc/at91/at91rm9200-i2s.c +++ b/sound/soc/at91/at91rm9200-i2s.c @@ -71,22 +71,22 @@ static struct snd_soc_dai_mode at91rm9200_i2s[] = { .flags = SND_SOC_DAI_BFS_DIV, .fs = 750, .bfs = SND_SOC_FSBD(3), - .flags (7 << 16 | 133), + .priv = (7 << 16 | 133), }, - /* 24k: BCLK = (MCLK/10) = (60MHz/50) = 1.2MHz */ + /* 32k: BCLK = (MCLK/3) ~= (60MHz/14) = 4.285714MHz */ { .fmt = AT91RM9200_I2S_DAIFMT, .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, - .pcmrate = SNDRV_PCM_RATE_22050, + .pcmrate = SNDRV_PCM_RATE_32000, .pcmdir = AT91RM9200_I2S_DIR, .flags = SND_SOC_DAI_BFS_DIV, - .fs = 500, - .bfs = SND_SOC_FSBD(10), - .priv = (25 << 16 | 24), + .fs = 375, + .bfs = SND_SOC_FSBD(3), + .priv = (7 << 16 | 66), }, - /* 48kHz: BCLK = (MCLK/5) ~= (60MHz/26) = 2.3076923MHz */ + /* 48k: BCLK = (MCLK/5) ~= (60MHz/26) = 2.3076923MHz */ { .fmt = AT91RM9200_I2S_DAIFMT, .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, -- cgit v1.2.3 From a71a468a50f1385855e28864e26251b02df829bb Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Thu, 19 Oct 2006 20:35:56 +0200 Subject: [ALSA] ASoC: Add support for BCLK based on (Rate * Chn * Word Size) This patch adds support for the DAI BCLK to be generated by multiplying Rate * Channels * Word Size (RCW). This now gives 3 options for BCLK clocking and synchronisation :- 1. BCLK = Rate * x 2. BCLK = MCLK / x 3. BCLK = Rate * Chn * Word Size. (New) Changes:- o Add support for RCW generation of BCLK o Update Documentation to include RCW. o Update DAI documentation for label = value DAI modes. o Add RCW support to wm8731, wm8750 and pxa2xx-i2s drivers. Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/codecs/wm8731.c | 33 ++++--- sound/soc/codecs/wm8750.c | 15 ++-- sound/soc/pxa/pxa2xx-i2s.c | 3 +- sound/soc/soc-core.c | 215 +++++++++++++++++++++++++++++++++++---------- 4 files changed, 196 insertions(+), 70 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 9adbd2d401c..412291241ec 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -90,32 +90,36 @@ static struct snd_soc_dai_mode wm8731_modes[] = { .pcmfmt = WM8731_HIFI_BITS, .pcmrate = SNDRV_PCM_RATE_8000, .pcmdir = WM8731_DIR, + .flags = SND_SOC_DAI_BFS_RATE, .fs = 1536, - .bfs = SND_SOC_FSB(64), + .bfs = 64, }, { .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, .pcmfmt = WM8731_HIFI_BITS, .pcmrate = SNDRV_PCM_RATE_8000, .pcmdir = WM8731_DIR, + .flags = SND_SOC_DAI_BFS_RATE, .fs = 2304, - .bfs = SND_SOC_FSB(64), + .bfs = 64, }, { .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, .pcmfmt = WM8731_HIFI_BITS, .pcmrate = SNDRV_PCM_RATE_8000, .pcmdir = WM8731_DIR, + .flags = SND_SOC_DAI_BFS_RATE, .fs = 1408, - .bfs = SND_SOC_FSB(64), + .bfs = 64, }, { .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, .pcmfmt = WM8731_HIFI_BITS, .pcmrate = SNDRV_PCM_RATE_8000, .pcmdir = WM8731_DIR, + .flags = SND_SOC_DAI_BFS_RATE, .fs = 2112, - .bfs = SND_SOC_FSB(64), + .bfs = 64, }, /* 32k */ @@ -124,16 +128,18 @@ static struct snd_soc_dai_mode wm8731_modes[] = { .pcmfmt = WM8731_HIFI_BITS, .pcmrate = SNDRV_PCM_RATE_32000, .pcmdir = WM8731_DIR, + .flags = SND_SOC_DAI_BFS_RATE, .fs = 384, - .bfs = SND_SOC_FSB(64), + .bfs = 64, }, { .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, .pcmfmt = WM8731_HIFI_BITS, .pcmrate = SNDRV_PCM_RATE_32000, .pcmdir = WM8731_DIR, + .flags = SND_SOC_DAI_BFS_RATE, .fs = 576, - .bfs = SND_SOC_FSB(64), + .bfs = 64, }, /* 44.1k & 48k */ @@ -142,16 +148,18 @@ static struct snd_soc_dai_mode wm8731_modes[] = { .pcmfmt = WM8731_HIFI_BITS, .pcmrate = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, .pcmdir = WM8731_DIR, + .flags = SND_SOC_DAI_BFS_RATE, .fs = 256, - .bfs = SND_SOC_FSB(64), + .bfs = 64, }, { .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, .pcmfmt = WM8731_HIFI_BITS, .pcmrate = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, .pcmdir = WM8731_DIR, + .flags = SND_SOC_DAI_BFS_RATE, .fs = 384, - .bfs = SND_SOC_FSB(64), + .bfs = 64, }, /* 88.2 & 96k */ @@ -160,17 +168,18 @@ static struct snd_soc_dai_mode wm8731_modes[] = { .pcmfmt = WM8731_HIFI_BITS, .pcmrate = SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000, .pcmdir = WM8731_DIR, + .flags = SND_SOC_DAI_BFS_RATE, .fs = 128, - .bfs = SND_SOC_FSB(64), - + .bfs = 64, }, { .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, .pcmfmt = WM8731_HIFI_BITS, .pcmrate = SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000, .pcmdir = WM8731_DIR, + .flags = SND_SOC_DAI_BFS_RATE, .fs = 192, - .bfs = SND_SOC_FSB(64), + .bfs = 64, }, /* USB codec frame and clock master modes */ @@ -237,7 +246,7 @@ static struct snd_soc_dai_mode wm8731_modes[] = { .pcmdir = WM8731_DIR, .flags = SND_SOC_DAI_BFS_DIV, .fs = SND_SOC_FS_ALL, - .bfs = SND_SOC_FSBD_ALL, + .bfs = SND_SOC_FSB_ALL, }, }; diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index 243da712d9c..c5d13a9454d 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c @@ -343,7 +343,7 @@ static struct snd_soc_dai_mode wm8750_modes[] = { .pcmdir = WM8750_DIR, .flags = SND_SOC_DAI_BFS_DIV, .fs = SND_SOC_FS_ALL, - .bfs = SND_SOC_FSBD_ALL, + .bfs = SND_SOC_FSB_ALL, }, }; @@ -829,6 +829,9 @@ static inline int get_coeff(int mclk, int rate) if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk) return i; } + + printk(KERN_ERR "wm8750: could not get coeff for mclk %d @ rate %d\n", + mclk, rate); return -EINVAL; } @@ -836,13 +839,7 @@ static inline int get_coeff(int mclk, int rate) static unsigned int wm8750_config_sysclk(struct snd_soc_codec_dai *dai, struct snd_soc_clock_info *info, unsigned int clk) { - dai->mclk = 0; - - /* check that the calculated FS and rate actually match a clock from - * the machine driver */ - if (info->fs * info->rate == clk) - dai->mclk = clk; - + dai->mclk = clk; return dai->mclk; } @@ -859,7 +856,7 @@ static int wm8750_pcm_prepare(struct snd_pcm_substream *substream) if (i < 0) return i; - bfs = SND_SOC_FSB_REAL(rtd->codec_dai->dai_runtime.bfs); + bfs = SND_SOC_FSBD_REAL(rtd->codec_dai->dai_runtime.bfs); /* set master/slave audio interface */ switch (rtd->codec_dai->dai_runtime.fmt & SND_SOC_DAIFMT_CLOCK_MASK) { diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c index 99f1da32744..98b167fe68e 100644 --- a/sound/soc/pxa/pxa2xx-i2s.c +++ b/sound/soc/pxa/pxa2xx-i2s.c @@ -126,7 +126,8 @@ static struct snd_soc_dai_mode pxa2xx_i2s_modes[] = { .pcmrate = PXA_I2S_RATES, .pcmdir = PXA_I2S_DIR, .fs = SND_SOC_FS_ALL, - .bfs = SND_SOC_FSB(64), + .flags = SND_SOC_DAI_BFS_RATE, + .bfs = 64, .priv = 0x48, }, }; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 2ce0c8251dc..6da1616bf77 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -51,6 +51,8 @@ #define dbgc(format, arg...) #endif +#define CODEC_CPU(codec, cpu) ((codec << 4) | cpu) + static DEFINE_MUTEX(pcm_mutex); static DEFINE_MUTEX(io_mutex); static struct workqueue_struct *soc_workq; @@ -150,11 +152,11 @@ static unsigned inline int soc_get_mclk(struct snd_soc_pcm_runtime *rtd, } /* changes a bitclk multiplier mask to a divider mask */ -static u16 soc_bfs_mult_to_div(u16 bfs, int rate, unsigned int mclk, +static u64 soc_bfs_rcw_to_div(u64 bfs, int rate, unsigned int mclk, unsigned int pcmfmt, unsigned int chn) { int i, j; - u16 bfs_ = 0; + u64 bfs_ = 0; int size = snd_pcm_format_physical_width(pcmfmt), min = 0; if (size <= 0) @@ -162,17 +164,14 @@ static u16 soc_bfs_mult_to_div(u16 bfs, int rate, unsigned int mclk, /* the minimum bit clock that has enough bandwidth */ min = size * rate * chn; - dbgc("mult --> div min bclk %d with mclk %d\n", min, mclk); + dbgc("rcw --> div min bclk %d with mclk %d\n", min, mclk); - for (i = 0; i < 16; i++) { + for (i = 0; i < 64; i++) { if ((bfs >> i) & 0x1) { - j = rate * SND_SOC_FSB_REAL(1<= min) { - bfs_ |= SND_SOC_FSBD(mclk/j); - dbgc("mult --> div support mult %d\n", - SND_SOC_FSB_REAL(1< div support mult %d\n", + SND_SOC_FSBD_REAL(1<> i) & 0x1) { - j = mclk / (SND_SOC_FSBD_REAL(1<= min) { - bfs_ |= SND_SOC_FSB(j/rate); - dbgc("div --> mult support div %d\n", - SND_SOC_FSBD_REAL(1< rcw support div %d\n", + SND_SOC_FSBW_REAL(1< rcw min bclk %d with mclk %d\n", min, mclk); + + if (bfs_ < min) + return 0; + else { + bfs_ = SND_SOC_FSBW(bfs_/min); + dbgc("rate --> rcw support div %d\n", SND_SOC_FSBW_REAL(bfs_)); + return bfs_; + } +} + +/* changes a bitclk multiplier mask to a divider mask */ +static u64 soc_bfs_rate_to_div(u64 bfs, int rate, unsigned int mclk, + unsigned int pcmfmt, unsigned int chn) +{ + unsigned int bfs_ = rate * bfs; + int size = snd_pcm_format_physical_width(pcmfmt), min = 0; + + if (size <= 0) + return 0; + + /* the minimum bit clock that has enough bandwidth */ + min = size * rate * chn; + dbgc("rate --> div min bclk %d with mclk %d\n", min, mclk); + + if (bfs_ < min) + return 0; + else { + bfs_ = SND_SOC_FSBW(mclk/bfs_); + dbgc("rate --> div support div %d\n", SND_SOC_FSBD_REAL(bfs_)); + return bfs_; + } +} + /* Matches codec DAI and SoC CPU DAI hardware parameters */ static int soc_hw_match_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) @@ -217,9 +262,10 @@ static int soc_hw_match_params(struct snd_pcm_substream *substream, struct snd_soc_dai_mode *codec_dai_mode = NULL; struct snd_soc_dai_mode *cpu_dai_mode = NULL; struct snd_soc_clock_info clk_info; - unsigned int fs, mclk, codec_bfs, cpu_bfs, rate = params_rate(params), + unsigned int fs, mclk, rate = params_rate(params), chn, j, k, cpu_bclk, codec_bclk, pcmrate; u16 fmt = 0; + u64 codec_bfs, cpu_bfs; dbg("asoc: match version %s\n", SND_SOC_VERSION); clk_info.rate = rate; @@ -309,44 +355,98 @@ static int soc_hw_match_params(struct snd_pcm_substream *substream, * used in the codec and cpu DAI modes. We always choose the * lowest possible clocks to reduce power. */ - if (codec_dai_mode->flags & cpu_dai_mode->flags & - SND_SOC_DAI_BFS_DIV) { + switch (CODEC_CPU(codec_dai_mode->flags, cpu_dai_mode->flags)) { + case CODEC_CPU(SND_SOC_DAI_BFS_DIV, SND_SOC_DAI_BFS_DIV): /* cpu & codec bfs dividers */ rtd->cpu_dai->dai_runtime.bfs = rtd->codec_dai->dai_runtime.bfs = 1 << (fls(codec_dai_mode->bfs & cpu_dai_mode->bfs) - 1); - } else if (codec_dai_mode->flags & SND_SOC_DAI_BFS_DIV) { - /* normalise bfs codec divider & cpu mult */ - codec_bfs = soc_bfs_div_to_mult(codec_dai_mode->bfs, rate, + break; + case CODEC_CPU(SND_SOC_DAI_BFS_DIV, SND_SOC_DAI_BFS_RCW): + /* normalise bfs codec divider & cpu rcw mult */ + codec_bfs = soc_bfs_div_to_rcw(codec_dai_mode->bfs, rate, mclk, rtd->codec_dai->dai_runtime.pcmfmt, chn); rtd->cpu_dai->dai_runtime.bfs = 1 << (ffs(codec_bfs & cpu_dai_mode->bfs) - 1); - cpu_bfs = soc_bfs_mult_to_div(cpu_dai_mode->bfs, rate, mclk, + cpu_bfs = soc_bfs_rcw_to_div(cpu_dai_mode->bfs, rate, mclk, rtd->codec_dai->dai_runtime.pcmfmt, chn); rtd->codec_dai->dai_runtime.bfs = 1 << (fls(codec_dai_mode->bfs & cpu_bfs) - 1); - } else if (cpu_dai_mode->flags & SND_SOC_DAI_BFS_DIV) { - /* normalise bfs codec mult & cpu divider */ - codec_bfs = soc_bfs_mult_to_div(codec_dai_mode->bfs, rate, + break; + case CODEC_CPU(SND_SOC_DAI_BFS_RCW, SND_SOC_DAI_BFS_DIV): + /* normalise bfs codec rcw mult & cpu divider */ + codec_bfs = soc_bfs_rcw_to_div(codec_dai_mode->bfs, rate, mclk, rtd->codec_dai->dai_runtime.pcmfmt, chn); rtd->cpu_dai->dai_runtime.bfs = 1 << (fls(codec_bfs & cpu_dai_mode->bfs) -1); - cpu_bfs = soc_bfs_div_to_mult(cpu_dai_mode->bfs, rate, mclk, + cpu_bfs = soc_bfs_div_to_rcw(cpu_dai_mode->bfs, rate, mclk, rtd->codec_dai->dai_runtime.pcmfmt, chn); rtd->codec_dai->dai_runtime.bfs = 1 << (ffs(codec_dai_mode->bfs & cpu_bfs) -1); - } else { - /* codec & cpu bfs rate multipliers */ + break; + case CODEC_CPU(SND_SOC_DAI_BFS_RCW, SND_SOC_DAI_BFS_RCW): + /* codec & cpu bfs rate rcw multipliers */ rtd->cpu_dai->dai_runtime.bfs = rtd->codec_dai->dai_runtime.bfs = 1 << (ffs(codec_dai_mode->bfs & cpu_dai_mode->bfs) -1); + break; + case CODEC_CPU(SND_SOC_DAI_BFS_DIV, SND_SOC_DAI_BFS_RATE): + /* normalise cpu bfs rate const multiplier & codec div */ + cpu_bfs = soc_bfs_rate_to_div(cpu_dai_mode->bfs, rate, + mclk, rtd->codec_dai->dai_runtime.pcmfmt, chn); + if(codec_dai_mode->bfs & cpu_bfs) { + rtd->codec_dai->dai_runtime.bfs = cpu_bfs; + rtd->cpu_dai->dai_runtime.bfs = cpu_dai_mode->bfs; + } else + rtd->cpu_dai->dai_runtime.bfs = 0; + break; + case CODEC_CPU(SND_SOC_DAI_BFS_RCW, SND_SOC_DAI_BFS_RATE): + /* normalise cpu bfs rate const multiplier & codec rcw mult */ + cpu_bfs = soc_bfs_rate_to_rcw(cpu_dai_mode->bfs, rate, + mclk, rtd->codec_dai->dai_runtime.pcmfmt, chn); + if(codec_dai_mode->bfs & cpu_bfs) { + rtd->codec_dai->dai_runtime.bfs = cpu_bfs; + rtd->cpu_dai->dai_runtime.bfs = cpu_dai_mode->bfs; + } else + rtd->cpu_dai->dai_runtime.bfs = 0; + break; + case CODEC_CPU(SND_SOC_DAI_BFS_RATE, SND_SOC_DAI_BFS_RCW): + /* normalise cpu bfs rate rcw multiplier & codec const mult */ + codec_bfs = soc_bfs_rate_to_rcw(codec_dai_mode->bfs, rate, + mclk, rtd->codec_dai->dai_runtime.pcmfmt, chn); + if(cpu_dai_mode->bfs & codec_bfs) { + rtd->cpu_dai->dai_runtime.bfs = codec_bfs; + rtd->codec_dai->dai_runtime.bfs = codec_dai_mode->bfs; + } else + rtd->cpu_dai->dai_runtime.bfs = 0; + break; + case CODEC_CPU(SND_SOC_DAI_BFS_RATE, SND_SOC_DAI_BFS_DIV): + /* normalise cpu bfs div & codec const mult */ + codec_bfs = soc_bfs_rate_to_div(codec_dai_mode->bfs, rate, + mclk, rtd->codec_dai->dai_runtime.pcmfmt, chn); + if(codec_dai_mode->bfs & codec_bfs) { + rtd->cpu_dai->dai_runtime.bfs = codec_bfs; + rtd->codec_dai->dai_runtime.bfs = codec_dai_mode->bfs; + } else + rtd->cpu_dai->dai_runtime.bfs = 0; + break; + case CODEC_CPU(SND_SOC_DAI_BFS_RATE, SND_SOC_DAI_BFS_RATE): + /* cpu & codec constant mult */ + if(codec_dai_mode->bfs == cpu_dai_mode->bfs) + rtd->cpu_dai->dai_runtime.bfs = + rtd->codec_dai->dai_runtime.bfs = + codec_dai_mode->bfs; + else + rtd->cpu_dai->dai_runtime.bfs = + rtd->codec_dai->dai_runtime.bfs = 0; + break; } /* make sure the bit clock speed is acceptable */ if (!rtd->cpu_dai->dai_runtime.bfs || !rtd->codec_dai->dai_runtime.bfs) { dbgc("asoc: DAI[%d:%d] failed to match BFS\n", j, k); - dbgc("asoc: cpu_dai %x codec %x\n", + dbgc("asoc: cpu_dai %llu codec %llu\n", rtd->cpu_dai->dai_runtime.bfs, rtd->codec_dai->dai_runtime.bfs); dbgc("asoc: mclk %d hwfmt %x\n", mclk, fmt); @@ -378,26 +478,41 @@ found: dbg("asoc: codec fs %d mclk %d bfs div %d bclk %d\n", rtd->codec_dai->dai_runtime.fs, mclk, SND_SOC_FSBD_REAL(rtd->codec_dai->dai_runtime.bfs), codec_bclk); - } else { - codec_bclk = params_rate(params) * - SND_SOC_FSB_REAL(rtd->codec_dai->dai_runtime.bfs); - dbg("asoc: codec fs %d mclk %d bfs mult %d bclk %d\n", + } else if(rtd->codec_dai->dai_runtime.flags == SND_SOC_DAI_BFS_RATE) { + codec_bclk = params_rate(params) * rtd->codec_dai->dai_runtime.bfs; + dbg("asoc: codec fs %d mclk %d bfs rate mult %llu bclk %d\n", rtd->codec_dai->dai_runtime.fs, mclk, - SND_SOC_FSB_REAL(rtd->codec_dai->dai_runtime.bfs), codec_bclk); - } + rtd->codec_dai->dai_runtime.bfs, codec_bclk); + } else if (rtd->cpu_dai->dai_runtime.flags == SND_SOC_DAI_BFS_RCW) { + codec_bclk = params_rate(params) * params_channels(params) * + snd_pcm_format_physical_width(rtd->codec_dai->dai_runtime.pcmfmt) * + SND_SOC_FSBW_REAL(rtd->codec_dai->dai_runtime.bfs); + dbg("asoc: codec fs %d mclk %d bfs rcw mult %d bclk %d\n", + rtd->codec_dai->dai_runtime.fs, mclk, + SND_SOC_FSBW_REAL(rtd->codec_dai->dai_runtime.bfs), codec_bclk); + } else + codec_bclk = 0; + if (rtd->cpu_dai->dai_runtime.flags == SND_SOC_DAI_BFS_DIV) { cpu_bclk = (rtd->cpu_dai->dai_runtime.fs * params_rate(params)) / SND_SOC_FSBD_REAL(rtd->cpu_dai->dai_runtime.bfs); dbg("asoc: cpu fs %d mclk %d bfs div %d bclk %d\n", rtd->cpu_dai->dai_runtime.fs, mclk, SND_SOC_FSBD_REAL(rtd->cpu_dai->dai_runtime.bfs), cpu_bclk); - } else { - cpu_bclk = params_rate(params) * - SND_SOC_FSB_REAL(rtd->cpu_dai->dai_runtime.bfs); - dbg("asoc: cpu fs %d mclk %d bfs mult %d bclk %d\n", + } else if (rtd->cpu_dai->dai_runtime.flags == SND_SOC_DAI_BFS_RATE) { + cpu_bclk = params_rate(params) * rtd->cpu_dai->dai_runtime.bfs; + dbg("asoc: cpu fs %d mclk %d bfs rate mult %llu bclk %d\n", rtd->cpu_dai->dai_runtime.fs, mclk, - SND_SOC_FSB_REAL(rtd->cpu_dai->dai_runtime.bfs), cpu_bclk); - } + rtd->cpu_dai->dai_runtime.bfs, cpu_bclk); + } else if (rtd->cpu_dai->dai_runtime.flags == SND_SOC_DAI_BFS_RCW) { + cpu_bclk = params_rate(params) * params_channels(params) * + snd_pcm_format_physical_width(rtd->cpu_dai->dai_runtime.pcmfmt) * + SND_SOC_FSBW_REAL(rtd->cpu_dai->dai_runtime.bfs); + dbg("asoc: cpu fs %d mclk %d bfs mult rcw %d bclk %d\n", + rtd->cpu_dai->dai_runtime.fs, mclk, + SND_SOC_FSBW_REAL(rtd->cpu_dai->dai_runtime.bfs), cpu_bclk); + } else + cpu_bclk = 0; /* * Check we have matching bitclocks. If we don't then it means the @@ -405,7 +520,7 @@ found: * machine sysclock function) is wrong compared with the supported DAI * modes for the codec or cpu DAI. */ - if (cpu_bclk != codec_bclk){ + if (cpu_bclk != codec_bclk && cpu_bclk){ printk(KERN_ERR "asoc: codec and cpu bitclocks differ, audio may be wrong speed\n" ); @@ -723,14 +838,18 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) mutex_lock(&pcm_mutex); if (platform->pcm_ops->prepare) { ret = platform->pcm_ops->prepare(substream); - if (ret < 0) + if (ret < 0) { + printk(KERN_ERR "asoc: platform prepare error\n"); goto out; + } } if (rtd->codec_dai->ops.prepare) { ret = rtd->codec_dai->ops.prepare(substream); - if (ret < 0) + if (ret < 0) { + printk(KERN_ERR "asoc: codec DAI prepare error\n"); goto out; + } } if (rtd->cpu_dai->ops.prepare) -- cgit v1.2.3 From 7cdbff945e9e3bb592dee2f66afbcc2255747f8f Mon Sep 17 00:00:00 2001 From: Mariusz Domanski Date: Mon, 23 Oct 2006 13:42:56 +0200 Subject: [ALSA] hda-codec - Add asus model to ALC861 codec This patch adds support for Asus laptops (for example: Asus A6Rp-AP002). Signed-off-by: Mariusz Domanski Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 165 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 163 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 04749d2f7bd..990714e2bcb 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -100,6 +100,7 @@ enum { ALC861_6ST_DIG, ALC861_UNIWILL_M31, ALC861_TOSHIBA, + ALC861_ASUS, ALC861_AUTO, ALC861_MODEL_LAST, }; @@ -6654,6 +6655,44 @@ static struct hda_channel_mode alc861_uniwill_m31_modes[2] = { { 4, alc861_uniwill_m31_ch4_init }, }; +/* Set mic1 and line-in as input and unmute the mixer */ +static struct hda_verb alc861_asus_ch2_init[] = { + /* set pin widget 1Ah (line in) for input */ + { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + /* set pin widget 18h (mic1/2) for input, for mic also enable the vref */ + { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + + { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c }, +#if 0 + { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/ + { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/ +#endif + { } /* end */ +}; +/* Set mic1 nad line-in as output and mute mixer */ +static struct hda_verb alc861_asus_ch6_init[] = { + /* set pin widget 1Ah (line in) for output (Back Surround)*/ + { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + /* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */ + /* set pin widget 18h (mic1) for output (CLFE)*/ + { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + /* { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */ + { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 }, + { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 }, + + { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 }, +#if 0 + { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/ + { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/ +#endif + { } /* end */ +}; + +static struct hda_channel_mode alc861_asus_modes[2] = { + { 2, alc861_asus_ch2_init }, + { 6, alc861_asus_ch6_init }, +}; + /* patch-ALC861 */ static struct snd_kcontrol_new alc861_base_mixer[] = { @@ -6794,6 +6833,49 @@ static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = { }, { } /* end */ }; + +static struct snd_kcontrol_new alc861_asus_mixer[] = { + /* output mixer control */ + HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), + + /* Input mixer control */ + HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT), /* was HDA_INPUT (why?) */ + + /* Capture mixer control */ + HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Source", + .count = 1, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc_ch_mode_info, + .get = alc_ch_mode_get, + .put = alc_ch_mode_put, + .private_value = ARRAY_SIZE(alc861_asus_modes), + }, + { } +}; + /* * generic initialization of ADC, input mixers and output mixers @@ -6983,6 +7065,68 @@ static struct hda_verb alc861_uniwill_m31_init_verbs[] = { { } }; +static struct hda_verb alc861_asus_init_verbs[] = { + /* + * Unmute ADC0 and set the default input to mic-in + */ + /* port-A for surround (rear panel) | according to codec#0 this is the HP jack*/ + { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* was 0x00 */ + /* route front PCM to HP */ + { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x01 }, + /* port-B for mic-in (rear panel) with vref */ + { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + /* port-C for line-in (rear panel) */ + { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + /* port-D for Front */ + { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 }, + /* port-E for HP out (front panel) */ + { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, /* this has to be set to VREF80 */ + /* route front PCM to HP */ + { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x01 }, + /* port-F for mic-in (front panel) with vref */ + { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + /* port-G for CLFE (rear panel) */ + { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + /* port-H for side (rear panel) */ + { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + /* CD-in */ + { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + /* route front mic to ADC1*/ + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + /* Unmute DAC0~3 & spdif out*/ + {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Unmute Mixer 14 (mic) 1c (Line in)*/ + {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + /* Unmute Stereo Mixer 15 */ + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c }, /* Output 0~12 step */ + + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, /* hp used DAC 3 (Front) */ + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + { } +}; + + /* * generic initialization of ADC, input mixers and output mixers */ @@ -7354,10 +7498,13 @@ static struct hda_board_config alc861_cfg_tbl[] = { { .pci_subvendor = 0x1584, .pci_subdevice = 0x9072, .config = ALC861_UNIWILL_M31 }, { .modelname = "toshiba", .config = ALC861_TOSHIBA }, - { .pci_subvendor = 0x1043, .pci_subdevice = 0x1338, - .config = ALC861_TOSHIBA }, { .pci_subvendor = 0x1179, .pci_subdevice = 0xff10, .config = ALC861_TOSHIBA }, + { .modelname = "asus", .config = ALC861_ASUS}, + { .pci_subvendor = 0x1043, .pci_subdevice = 0x1393, + .config = ALC861_ASUS }, + { .pci_subvendor = 0x1043, .pci_subdevice = 0x1338, + .config = ALC861_ASUS }, { .modelname = "auto", .config = ALC861_AUTO }, {} }; @@ -7438,6 +7585,20 @@ static struct alc_config_preset alc861_presets[] = { .unsol_event = alc861_toshiba_unsol_event, .init_hook = alc861_toshiba_automute, }, + [ALC861_ASUS] = { + .mixers = { alc861_asus_mixer }, + .init_verbs = { alc861_asus_init_verbs }, + .num_dacs = ARRAY_SIZE(alc861_dac_nids), + .dac_nids = alc861_dac_nids, + .dig_out_nid = ALC861_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc861_asus_modes), + .channel_mode = alc861_asus_modes, + .need_dac_fix = 1, + .hp_nid = 0x06, + .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), + .adc_nids = alc861_adc_nids, + .input_mux = &alc861_capture_source, + }, }; -- cgit v1.2.3 From f1a63a38d2a885cc7e38c67b699171a7c5666d88 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 24 Oct 2006 18:25:29 +0200 Subject: [ALSA] ac97 - Suppress power-saving mode on non-supporting drivers Don't enable power-saving mode on drivers that don't support it. The supporting drivers set AC97_SCAP_POWER_SAVE to scaps at creation of ac97 instance. Currently enable on the following drivers: intel8x0, intel8x0m, atiixp, atiixp-modem, via82xx and via82xx-modem. Also, a bit clean up of power-saving stuff: - Don't create an own workq - Remove superfluous ifdefs Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/ac97/ac97_codec.c | 41 +++++++++++++++++++++-------------------- sound/pci/atiixp.c | 2 +- sound/pci/atiixp_modem.c | 2 +- sound/pci/intel8x0.c | 2 +- sound/pci/intel8x0m.c | 2 +- sound/pci/via82xx.c | 2 +- sound/pci/via82xx_modem.c | 2 +- 7 files changed, 27 insertions(+), 26 deletions(-) (limited to 'sound') diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index d2994cb4c8c..9da4977c0a0 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -194,6 +194,13 @@ static const struct ac97_codec_id snd_ac97_codec_ids[] = { static void update_power_regs(struct snd_ac97 *ac97); +#ifdef CONFIG_SND_AC97_POWER_SAVE +#define ac97_is_power_save_mode(ac97) \ + ((ac97->scaps & AC97_SCAP_POWER_SAVE) && power_save) +#else +#define ac97_is_power_save_mode(ac97) 0 +#endif + /* * I/O routines @@ -982,8 +989,7 @@ static int snd_ac97_free(struct snd_ac97 *ac97) { if (ac97) { #ifdef CONFIG_SND_AC97_POWER_SAVE - if (ac97->power_workq) - destroy_workqueue(ac97->power_workq); + cancel_delayed_work(&ac97->power_work); #endif snd_ac97_proc_done(ac97); if (ac97->bus) @@ -1989,7 +1995,6 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template, mutex_init(&ac97->reg_mutex); mutex_init(&ac97->page_mutex); #ifdef CONFIG_SND_AC97_POWER_SAVE - ac97->power_workq = create_workqueue("ac97"); INIT_DELAYED_WORK(&ac97->power_work, do_update_power); #endif @@ -2275,15 +2280,13 @@ static void snd_ac97_powerdown(struct snd_ac97 *ac97) udelay(100); power |= AC97_PD_PR2 | AC97_PD_PR3; /* Analog Mixer powerdown */ snd_ac97_write(ac97, AC97_POWERDOWN, power); -#ifdef CONFIG_SND_AC97_POWER_SAVE - if (power_save) { + if (ac97_is_power_save_mode(ac97)) { udelay(100); /* AC-link powerdown, internal Clk disable */ /* FIXME: this may cause click noises on some boards */ power |= AC97_PD_PR4 | AC97_PD_PR5; snd_ac97_write(ac97, AC97_POWERDOWN, power); } -#endif } @@ -2337,14 +2340,16 @@ int snd_ac97_update_power(struct snd_ac97 *ac97, int reg, int powerup) } } - if (power_save && !powerup && ac97->power_workq) + if (ac97_is_power_save_mode(ac97) && !powerup) /* adjust power-down bits after two seconds delay * (for avoiding loud click noises for many (OSS) apps * that open/close frequently) */ - queue_delayed_work(ac97->power_workq, &ac97->power_work, HZ*2); - else + schedule_delayed_work(&ac97->power_work, HZ*2); + else { + cancel_delayed_work(&ac97->power_work); update_power_regs(ac97); + } return 0; } @@ -2357,19 +2362,15 @@ static void update_power_regs(struct snd_ac97 *ac97) unsigned int power_up, bits; int i; + power_up = (1 << PWIDX_FRONT) | (1 << PWIDX_ADC); + power_up |= (1 << PWIDX_MIC); + if (ac97->scaps & AC97_SCAP_SURROUND_DAC) + power_up |= (1 << PWIDX_SURR); + if (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC) + power_up |= (1 << PWIDX_CLFE); #ifdef CONFIG_SND_AC97_POWER_SAVE - if (power_save) + if (ac97_is_power_save_mode(ac97)) power_up = ac97->power_up; - else { -#endif - power_up = (1 << PWIDX_FRONT) | (1 << PWIDX_ADC); - power_up |= (1 << PWIDX_MIC); - if (ac97->scaps & AC97_SCAP_SURROUND_DAC) - power_up |= (1 << PWIDX_SURR); - if (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC) - power_up |= (1 << PWIDX_CLFE); -#ifdef CONFIG_SND_AC97_POWER_SAVE - } #endif if (power_up) { if (ac97->regs[AC97_POWERDOWN] & AC97_PD_PR2) { diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c index 476c3433073..86710df71a8 100644 --- a/sound/pci/atiixp.c +++ b/sound/pci/atiixp.c @@ -1396,7 +1396,7 @@ static int __devinit snd_atiixp_mixer_new(struct atiixp *chip, int clock, ac97.private_data = chip; ac97.pci = chip->pci; ac97.num = i; - ac97.scaps = AC97_SCAP_SKIP_MODEM; + ac97.scaps = AC97_SCAP_SKIP_MODEM | AC97_SCAP_POWER_SAVE; if (! chip->spdif_over_aclink) ac97.scaps |= AC97_SCAP_NO_SPDIF; if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97[i])) < 0) { diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c index cc2e6b9d407..904023fe4f2 100644 --- a/sound/pci/atiixp_modem.c +++ b/sound/pci/atiixp_modem.c @@ -1090,7 +1090,7 @@ static int __devinit snd_atiixp_mixer_new(struct atiixp_modem *chip, int clock) ac97.private_data = chip; ac97.pci = chip->pci; ac97.num = i; - ac97.scaps = AC97_SCAP_SKIP_AUDIO; + ac97.scaps = AC97_SCAP_SKIP_AUDIO | AC97_SCAP_POWER_SAVE; if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97[i])) < 0) { chip->ac97[i] = NULL; /* to be sure */ snd_printdd("atiixp-modem: codec %d not available for modem\n", i); diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 28d5d9deb89..f8aef131be7 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -2057,7 +2057,7 @@ static int __devinit snd_intel8x0_mixer(struct intel8x0 *chip, int ac97_clock, memset(&ac97, 0, sizeof(ac97)); ac97.private_data = chip; ac97.private_free = snd_intel8x0_mixer_free_ac97; - ac97.scaps = AC97_SCAP_SKIP_MODEM; + ac97.scaps = AC97_SCAP_SKIP_MODEM | AC97_SCAP_POWER_SAVE; if (chip->xbox) ac97.scaps |= AC97_SCAP_DETECT_BY_VENDOR; if (chip->device_type != DEVICE_ALI) { diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c index 936c3cf1693..c155e1f3a0e 100644 --- a/sound/pci/intel8x0m.c +++ b/sound/pci/intel8x0m.c @@ -830,7 +830,7 @@ static int __devinit snd_intel8x0_mixer(struct intel8x0m *chip, int ac97_clock) memset(&ac97, 0, sizeof(ac97)); ac97.private_data = chip; ac97.private_free = snd_intel8x0_mixer_free_ac97; - ac97.scaps = AC97_SCAP_SKIP_AUDIO; + ac97.scaps = AC97_SCAP_SKIP_AUDIO | AC97_SCAP_POWER_SAVE; glob_sta = igetdword(chip, ICHREG(GLOB_STA)); diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index a572b018807..0440df7de37 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -1823,7 +1823,7 @@ static int __devinit snd_via82xx_mixer_new(struct via82xx *chip, const char *qui ac97.private_data = chip; ac97.private_free = snd_via82xx_mixer_free_ac97; ac97.pci = chip->pci; - ac97.scaps = AC97_SCAP_SKIP_MODEM; + ac97.scaps = AC97_SCAP_SKIP_MODEM | AC97_SCAP_POWER_SAVE; if ((err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97)) < 0) return err; diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c index 17d6b847585..b338e15db0d 100644 --- a/sound/pci/via82xx_modem.c +++ b/sound/pci/via82xx_modem.c @@ -900,7 +900,7 @@ static int __devinit snd_via82xx_mixer_new(struct via82xx_modem *chip) ac97.private_data = chip; ac97.private_free = snd_via82xx_mixer_free_ac97; ac97.pci = chip->pci; - ac97.scaps = AC97_SCAP_SKIP_AUDIO; + ac97.scaps = AC97_SCAP_SKIP_AUDIO | AC97_SCAP_POWER_SAVE; ac97.num = chip->ac97_secondary; if ((err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97)) < 0) -- cgit v1.2.3 From 06bf2f495aabfdbe9d5db7b910fa75dd7f72131a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 24 Oct 2006 19:49:39 +0200 Subject: [ALSA] hda-codec - Fix model for Lenovo A60 desktop Add a proper model entry (3stack) for Lenovo A60 desktop with AD1986a codec to fix noise problems. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_analog.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 076365bc10e..5e63123f70b 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -800,6 +800,8 @@ static struct hda_board_config ad1986a_cfg_tbl[] = { .config = AD1986A_3STACK }, /* ASUS P5RD2-VM / P5GPL-X SE */ { .pci_subvendor = 0x1043, .pci_subdevice = 0x81cb, .config = AD1986A_3STACK }, /* ASUS M2NPV-VM */ + { .pci_subvendor = 0x17aa, .pci_subdevice = 0x1017, + .config = AD1986A_3STACK }, /* Lenovo A60 desktop */ { .modelname = "laptop", .config = AD1986A_LAPTOP }, { .pci_subvendor = 0x144d, .pci_subdevice = 0xc01e, .config = AD1986A_LAPTOP }, /* FSC V2060 */ -- cgit v1.2.3 From 8b65727bf07abc0b3fdac4fcf2f90c5882d65f4f Mon Sep 17 00:00:00 2001 From: Matt Porter Date: Thu, 26 Oct 2006 17:12:59 +0200 Subject: [ALSA] hda: add dig mic support for sigmatel codecs Adds support for digital microphone pin widgets on SigmaTel codecs. Enables support only on the 9205 codecs for now. Signed-off-by: Matt Porter Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_sigmatel.c | 130 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 125 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index fe51ef3e49d..8f52372d66a 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -44,7 +44,7 @@ #define STAC_922X_MODELS 4 /* number of 922x models */ #define STAC_D965_3ST 4 #define STAC_D965_5ST 5 -#define STAC_927X_MODELS 6 /* number of 922x models */ +#define STAC_927X_MODELS 6 /* number of 927x models */ struct sigmatel_spec { struct snd_kcontrol_new *mixers[4]; @@ -67,6 +67,9 @@ struct sigmatel_spec { unsigned int num_adcs; hda_nid_t *mux_nids; unsigned int num_muxes; + hda_nid_t *dmic_nids; + unsigned int num_dmics; + hda_nid_t dmux_nid; hda_nid_t dig_in_nid; /* pin widgets */ @@ -80,6 +83,8 @@ struct sigmatel_spec { struct snd_kcontrol_new *mixer; /* capture source */ + struct hda_input_mux *dinput_mux; + unsigned int cur_dmux; struct hda_input_mux *input_mux; unsigned int cur_mux[3]; @@ -92,6 +97,7 @@ struct sigmatel_spec { struct auto_pin_cfg autocfg; unsigned int num_kctl_alloc, num_kctl_used; struct snd_kcontrol_new *kctl_alloc; + struct hda_input_mux private_dimux; struct hda_input_mux private_imux; }; @@ -131,6 +137,10 @@ static hda_nid_t stac9205_mux_nids[2] = { 0x19, 0x1a }; +static hda_nid_t stac9205_dmic_nids[3] = { + 0x17, 0x18, 0 +}; + static hda_nid_t stac9200_pin_nids[8] = { 0x08, 0x09, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, @@ -154,6 +164,34 @@ static hda_nid_t stac9205_pin_nids[12] = { }; +static int stac92xx_dmux_enum_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct sigmatel_spec *spec = codec->spec; + return snd_hda_input_mux_info(spec->dinput_mux, uinfo); +} + +static int stac92xx_dmux_enum_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct sigmatel_spec *spec = codec->spec; + + ucontrol->value.enumerated.item[0] = spec->cur_dmux; + return 0; +} + +static int stac92xx_dmux_enum_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct sigmatel_spec *spec = codec->spec; + + return snd_hda_input_mux_put(codec, spec->dinput_mux, ucontrol, + spec->dmux_nid, &spec->cur_dmux); +} + static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); @@ -279,6 +317,14 @@ static snd_kcontrol_new_t stac927x_mixer[] = { }; static snd_kcontrol_new_t stac9205_mixer[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Digital Input Source", + .count = 1, + .info = stac92xx_dmux_enum_info, + .get = stac92xx_dmux_enum_get, + .put = stac92xx_dmux_enum_put, + }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Input Source", @@ -585,8 +631,8 @@ static struct hda_board_config stac927x_cfg_tbl[] = { static unsigned int ref9205_pin_configs[12] = { 0x40000100, 0x40000100, 0x01016011, 0x01014010, - 0x01813122, 0x01a19021, 0x40000100, 0x40000100, - 0x40000100, 0x40000100, 0x01441030, 0x01c41030 + 0x01813122, 0x01a19021, 0x40000100, 0x40000100, + 0x90a000f0, 0x90a000f0, 0x01441030, 0x01c41030 }; static unsigned int *stac9205_brd_tbl[] = { @@ -1154,6 +1200,58 @@ static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec, return 0; } +/* labels for dmic mux inputs */ +const char *stac92xx_dmic_labels[5] = { + "Analog Inputs", "Digital Mic 1", "Digital Mic 2", + "Digital Mic 3", "Digital Mic 4" +}; + +/* create playback/capture controls for input pins on dmic capable codecs */ +static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec, + const struct auto_pin_cfg *cfg) +{ + struct sigmatel_spec *spec = codec->spec; + struct hda_input_mux *dimux = &spec->private_dimux; + hda_nid_t con_lst[HDA_MAX_NUM_INPUTS]; + int i, j; + + dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0]; + dimux->items[dimux->num_items].index = 0; + dimux->num_items++; + + for (i = 0; i < spec->num_dmics; i++) { + int index; + int num_cons; + unsigned int def_conf; + + def_conf = snd_hda_codec_read(codec, + spec->dmic_nids[i], + 0, + AC_VERB_GET_CONFIG_DEFAULT, + 0); + if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) + continue; + + num_cons = snd_hda_get_connections(codec, + spec->dmux_nid, + con_lst, + HDA_MAX_NUM_INPUTS); + for (j = 0; j < num_cons; j++) + if (con_lst[j] == spec->dmic_nids[i]) { + index = j; + goto found; + } + continue; +found: + dimux->items[dimux->num_items].label = + stac92xx_dmic_labels[dimux->num_items]; + dimux->items[dimux->num_items].index = index; + dimux->num_items++; + } + + return 0; +} + /* create playback/capture controls for input pins */ static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { @@ -1238,7 +1336,9 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out struct sigmatel_spec *spec = codec->spec; int err; - if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0) + if ((err = snd_hda_parse_pin_def_config(codec, + &spec->autocfg, + spec->dmic_nids)) < 0) return err; if (! spec->autocfg.line_outs) return 0; /* can't find valid pin config */ @@ -1254,6 +1354,11 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out (err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0) return err; + if (spec->num_dmics > 0) + if ((err = stac92xx_auto_create_dmic_input_ctls(codec, + &spec->autocfg)) < 0) + return err; + spec->multiout.max_channels = spec->multiout.num_dacs * 2; if (spec->multiout.max_channels > 2) spec->surr_switch = 1; @@ -1267,6 +1372,7 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out spec->mixers[spec->num_mixers++] = spec->kctl_alloc; spec->input_mux = &spec->private_imux; + spec->dinput_mux = &spec->private_dimux; return 1; } @@ -1366,6 +1472,7 @@ static int stac9200_parse_auto_config(struct hda_codec *codec) spec->mixers[spec->num_mixers++] = spec->kctl_alloc; spec->input_mux = &spec->private_imux; + spec->dinput_mux = &spec->private_dimux; return 1; } @@ -1448,6 +1555,11 @@ static int stac92xx_init(struct hda_codec *codec) stac92xx_auto_set_pinctl(codec, nid, pinctl); } } + if (spec->num_dmics > 0) + for (i = 0; i < spec->num_dmics; i++) + stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i], + AC_PINCTL_IN_EN); + if (cfg->dig_out_pin) stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin, AC_PINCTL_OUT_EN); @@ -1618,6 +1730,7 @@ static int patch_stac9200(struct hda_codec *codec) spec->adc_nids = stac9200_adc_nids; spec->mux_nids = stac9200_mux_nids; spec->num_muxes = 1; + spec->num_dmics = 0; spec->init = stac9200_core_init; spec->mixer = stac9200_mixer; @@ -1663,6 +1776,7 @@ static int patch_stac922x(struct hda_codec *codec) spec->adc_nids = stac922x_adc_nids; spec->mux_nids = stac922x_mux_nids; spec->num_muxes = 2; + spec->num_dmics = 0; spec->init = stac922x_core_init; spec->mixer = stac922x_mixer; @@ -1714,6 +1828,7 @@ static int patch_stac927x(struct hda_codec *codec) spec->adc_nids = stac927x_adc_nids; spec->mux_nids = stac927x_mux_nids; spec->num_muxes = 3; + spec->num_dmics = 0; spec->init = d965_core_init; spec->mixer = stac9227_mixer; break; @@ -1721,6 +1836,7 @@ static int patch_stac927x(struct hda_codec *codec) spec->adc_nids = stac927x_adc_nids; spec->mux_nids = stac927x_mux_nids; spec->num_muxes = 3; + spec->num_dmics = 0; spec->init = d965_core_init; spec->mixer = stac9227_mixer; break; @@ -1728,6 +1844,7 @@ static int patch_stac927x(struct hda_codec *codec) spec->adc_nids = stac927x_adc_nids; spec->mux_nids = stac927x_mux_nids; spec->num_muxes = 3; + spec->num_dmics = 0; spec->init = stac927x_core_init; spec->mixer = stac927x_mixer; } @@ -1773,7 +1890,10 @@ static int patch_stac9205(struct hda_codec *codec) spec->adc_nids = stac9205_adc_nids; spec->mux_nids = stac9205_mux_nids; - spec->num_muxes = 3; + spec->num_muxes = 2; + spec->dmic_nids = stac9205_dmic_nids; + spec->num_dmics = 2; + spec->dmux_nid = 0x1d; spec->init = stac9205_core_init; spec->mixer = stac9205_mixer; -- cgit v1.2.3 From 219e281f4627a395aaceff0e4a257cd18608e145 Mon Sep 17 00:00:00 2001 From: Hubert Kahlert Date: Tue, 31 Oct 2006 15:31:27 +0100 Subject: [ALSA] Fix mask to stop AT91 SSC clock on shutdown This patch by Frank Mandarino and Hubert Kahlert fixes a bug in the AT91 SSC (i2s) shutdown code that would erroneously disable other AT91 peripheral clocks. Signed-off-by: Hubert Kahlert Signed-off-by: Frank Mandarino Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/at91/at91rm9200-i2s.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/at91/at91rm9200-i2s.c b/sound/soc/at91/at91rm9200-i2s.c index 2eee427b1e5..e3e6345fc8b 100644 --- a/sound/soc/at91/at91rm9200-i2s.c +++ b/sound/soc/at91/at91rm9200-i2s.c @@ -373,7 +373,7 @@ static void at91rm9200_i2s_shutdown(struct snd_pcm_substream *substream) if (!ssc_p->dir_mask) { /* Shutdown the SSC clock. */ DBG("Stopping pid %d clock\n", ssc_p->pid); - at91_sys_write(AT91_PMC_PCDR, ssc_p->pid); + at91_sys_write(AT91_PMC_PCDR, 1<pid); if (ssc_p->initialized) free_irq(ssc_p->pid, ssc_p); -- cgit v1.2.3 From de66d53e46f39de6ea3261609fdb92900bb34a42 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 6 Nov 2006 09:18:34 +0100 Subject: [ALSA] sb16: add request_firmware() Load the CSP programs using request_firmware(), if possible, instead of using the built-in firmware blobs. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela --- sound/isa/Kconfig | 1 + sound/isa/sb/sb16_csp.c | 61 ++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 54 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig index 57371f1a441..565ed2add38 100644 --- a/sound/isa/Kconfig +++ b/sound/isa/Kconfig @@ -358,6 +358,7 @@ config SND_SBAWE config SND_SB16_CSP bool "Sound Blaster 16/AWE CSP support" depends on (SND_SB16 || SND_SBAWE) && (BROKEN || !PPC) + select FW_LOADER help Say Y here to include support for the CSP core. This special coprocessor can do variable tasks like various compression and diff --git a/sound/isa/sb/sb16_csp.c b/sound/isa/sb/sb16_csp.c index fcd638090a9..3d9d7e0107c 100644 --- a/sound/isa/sb/sb16_csp.c +++ b/sound/isa/sb/sb16_csp.c @@ -161,10 +161,13 @@ int snd_sb_csp_new(struct snd_sb *chip, int device, struct snd_hwdep ** rhwdep) */ static void snd_sb_csp_free(struct snd_hwdep *hwdep) { + int i; struct snd_sb_csp *p = hwdep->private_data; if (p) { if (p->running & SNDRV_SB_CSP_ST_RUNNING) snd_sb_csp_stop(p); + for (i = 0; i < ARRAY_SIZE(p->csp_programs); ++i) + release_firmware(p->csp_programs[i]); kfree(p); } } @@ -687,8 +690,50 @@ static int snd_sb_csp_load_user(struct snd_sb_csp * p, const unsigned char __use return err; } +#define FIRMWARE_IN_THE_KERNEL + +#ifdef FIRMWARE_IN_THE_KERNEL #include "sb16_csp_codecs.h" +static const struct firmware snd_sb_csp_static_programs[] = { + { .data = mulaw_main, .size = sizeof mulaw_main }, + { .data = alaw_main, .size = sizeof alaw_main }, + { .data = ima_adpcm_init, .size = sizeof ima_adpcm_init }, + { .data = ima_adpcm_playback, .size = sizeof ima_adpcm_playback }, + { .data = ima_adpcm_capture, .size = sizeof ima_adpcm_capture }, +}; +#endif + +static int snd_sb_csp_firmware_load(struct snd_sb_csp *p, int index, int flags) +{ + static const char *const names[] = { + "sb16/mulaw_main.csp", + "sb16/alaw_main.csp", + "sb16/ima_adpcm_init.csp", + "sb16/ima_adpcm_playback.csp", + "sb16/ima_adpcm_capture.csp", + }; + const struct firmware *program; + int err; + + BUILD_BUG_ON(ARRAY_SIZE(names) != CSP_PROGRAM_COUNT); + program = p->csp_programs[index]; + if (!program) { + err = request_firmware(&program, names[index], + p->chip->card->dev); + if (err >= 0) + p->csp_programs[index] = program; + else { +#ifdef FIRMWARE_IN_THE_KERNEL + program = &snd_sb_csp_static_programs[index]; +#else + return err; +#endif + } + } + return snd_sb_csp_load(p, program->data, program->size, flags); +} + /* * autoload hardware codec if necessary * return 0 if CSP is loaded and ready to run (p->running != 0) @@ -708,27 +753,27 @@ static int snd_sb_csp_autoload(struct snd_sb_csp * p, int pcm_sfmt, int play_rec } else { switch (pcm_sfmt) { case SNDRV_PCM_FORMAT_MU_LAW: - err = snd_sb_csp_load(p, &mulaw_main[0], sizeof(mulaw_main), 0); + err = snd_sb_csp_firmware_load(p, CSP_PROGRAM_MULAW, 0); p->acc_format = SNDRV_PCM_FMTBIT_MU_LAW; p->mode = SNDRV_SB_CSP_MODE_DSP_READ | SNDRV_SB_CSP_MODE_DSP_WRITE; break; case SNDRV_PCM_FORMAT_A_LAW: - err = snd_sb_csp_load(p, &alaw_main[0], sizeof(alaw_main), 0); + err = snd_sb_csp_firmware_load(p, CSP_PROGRAM_ALAW, 0); p->acc_format = SNDRV_PCM_FMTBIT_A_LAW; p->mode = SNDRV_SB_CSP_MODE_DSP_READ | SNDRV_SB_CSP_MODE_DSP_WRITE; break; case SNDRV_PCM_FORMAT_IMA_ADPCM: - err = snd_sb_csp_load(p, &ima_adpcm_init[0], sizeof(ima_adpcm_init), - SNDRV_SB_CSP_LOAD_INITBLOCK); + err = snd_sb_csp_firmware_load(p, CSP_PROGRAM_ADPCM_INIT, + SNDRV_SB_CSP_LOAD_INITBLOCK); if (err) break; if (play_rec_mode == SNDRV_SB_CSP_MODE_DSP_WRITE) { - err = snd_sb_csp_load(p, &ima_adpcm_playback[0], - sizeof(ima_adpcm_playback), 0); + err = snd_sb_csp_firmware_load + (p, CSP_PROGRAM_ADPCM_PLAYBACK, 0); p->mode = SNDRV_SB_CSP_MODE_DSP_WRITE; } else { - err = snd_sb_csp_load(p, &ima_adpcm_capture[0], - sizeof(ima_adpcm_capture), 0); + err = snd_sb_csp_firmware_load + (p, CSP_PROGRAM_ADPCM_CAPTURE, 0); p->mode = SNDRV_SB_CSP_MODE_DSP_READ; } p->acc_format = SNDRV_PCM_FMTBIT_IMA_ADPCM; -- cgit v1.2.3 From 59540fe85924ecb7b9760ab422cffaea0c3ce43a Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 6 Nov 2006 09:20:04 +0100 Subject: [ALSA] wavefront: simplify YSS225 register initialization Instead of using a somewhat algorithmic approach of initializing the YSS225's registers, just use a simple series of port/value pairs. This makes it easier to later replace or entirely remove the register data blob. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela --- sound/isa/wavefront/wavefront.c | 1 + sound/isa/wavefront/wavefront_fx.c | 789 +---------- sound/isa/wavefront/yss225.c | 2739 ++++++++++++++++++++++++++++++++++++ 3 files changed, 2761 insertions(+), 768 deletions(-) create mode 100644 sound/isa/wavefront/yss225.c (limited to 'sound') diff --git a/sound/isa/wavefront/wavefront.c b/sound/isa/wavefront/wavefront.c index 85db535aea9..e2fdd5fd39d 100644 --- a/sound/isa/wavefront/wavefront.c +++ b/sound/isa/wavefront/wavefront.c @@ -402,6 +402,7 @@ static struct snd_card *snd_wavefront_card_new(int dev) init_waitqueue_head(&acard->wavefront.interrupt_sleeper); spin_lock_init(&acard->wavefront.midi.open); spin_lock_init(&acard->wavefront.midi.virtual); + acard->wavefront.card = card; card->private_free = snd_wavefront_free; return card; diff --git a/sound/isa/wavefront/wavefront_fx.c b/sound/isa/wavefront/wavefront_fx.c index 4f0846feb73..2e03dc504d4 100644 --- a/sound/isa/wavefront/wavefront_fx.c +++ b/sound/isa/wavefront/wavefront_fx.c @@ -32,325 +32,9 @@ #define FX_MSB_TRANSFER 0x02 /* transfer after DSP MSB byte written */ #define FX_AUTO_INCR 0x04 /* auto-increment DSP address after transfer */ -/* weird stuff, derived from port I/O tracing with dosemu */ - -static unsigned char page_zero[] __devinitdata = { -0x01, 0x7c, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf5, 0x00, -0x11, 0x00, 0x20, 0x00, 0x32, 0x00, 0x40, 0x00, 0x13, 0x00, 0x00, -0x00, 0x14, 0x02, 0x76, 0x00, 0x60, 0x00, 0x80, 0x02, 0x00, 0x00, -0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x19, -0x01, 0x1a, 0x01, 0x20, 0x01, 0x40, 0x01, 0x17, 0x00, 0x00, 0x01, -0x80, 0x01, 0x20, 0x00, 0x10, 0x01, 0xa0, 0x03, 0xd1, 0x00, 0x00, -0x01, 0xf2, 0x02, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0xf4, 0x02, -0xe0, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, -0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x50, 0x00, 0x00, 0x00, -0x40, 0x00, 0x00, 0x00, 0x71, 0x02, 0x00, 0x00, 0x60, 0x00, 0x00, -0x00, 0x92, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb3, 0x02, -0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, 0x40, -0x00, 0x80, 0x00, 0xf5, 0x00, 0x20, 0x00, 0x70, 0x00, 0xa0, 0x02, -0x11, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, -0x02, 0x00, 0x00, 0x20, 0x00, 0x10, 0x00, 0x17, 0x00, 0x1b, 0x00, -0x1d, 0x02, 0xdf -}; - -static unsigned char page_one[] __devinitdata = { -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x19, 0x00, -0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xd8, 0x00, 0x00, -0x02, 0x20, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x01, -0xc0, 0x01, 0xfa, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x40, 0x02, 0x60, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xc0, 0x02, 0x80, 0x00, -0x00, 0x02, 0xfb, 0x02, 0xa0, 0x00, 0x00, 0x00, 0x1b, 0x02, 0xd7, -0x00, 0x00, 0x02, 0xf7, 0x03, 0x20, 0x03, 0x00, 0x00, 0x00, 0x00, -0x1c, 0x03, 0x3c, 0x00, 0x00, 0x03, 0x3f, 0x00, 0x00, 0x03, 0xc0, -0x00, 0x00, 0x03, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x03, 0x5d, 0x00, -0x00, 0x03, 0xc0, 0x00, 0x00, 0x03, 0x7d, 0x00, 0x00, 0x03, 0xc0, -0x00, 0x00, 0x03, 0x9e, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x03, -0xbe, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, -0xdb, 0x00, 0x00, 0x02, 0xdb, 0x00, 0x00, 0x02, 0xe0, 0x00, 0x00, -0x02, 0xfb, 0x00, 0x00, 0x02, 0xc0, 0x02, 0x40, 0x02, 0xfb, 0x02, -0x60, 0x00, 0x1b -}; - -static unsigned char page_two[] __devinitdata = { -0xc4, 0x00, 0x44, 0x07, 0x44, 0x00, 0x40, 0x25, 0x01, 0x06, 0xc4, -0x07, 0x40, 0x25, 0x01, 0x00, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x07, -0x05, 0x05, 0x05, 0x04, 0x07, 0x05, 0x04, 0x07, 0x05, 0x44, 0x46, -0x44, 0x46, 0x46, 0x07, 0x05, 0x44, 0x46, 0x05, 0x46, 0x05, 0x46, -0x05, 0x46, 0x05, 0x44, 0x46, 0x05, 0x07, 0x44, 0x46, 0x05, 0x07, -0x44, 0x46, 0x05, 0x07, 0x44, 0x46, 0x05, 0x07, 0x44, 0x05, 0x05, -0x05, 0x44, 0x05, 0x05, 0x05, 0x46, 0x05, 0x46, 0x05, 0x46, 0x05, -0x46, 0x05, 0x46, 0x07, 0x46, 0x07, 0x44 -}; - -static unsigned char page_three[] __devinitdata = { -0x07, 0x40, 0x00, 0x00, 0x00, 0x47, 0x00, 0x40, 0x00, 0x40, 0x06, -0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, -0xc0, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00, -0x60, 0x00, 0x70, 0x00, 0x40, 0x00, 0x40, 0x00, 0x42, 0x00, 0x40, -0x00, 0x02, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, -0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, -0x00, 0x42, 0x00, 0x40, 0x00, 0x42, 0x00, 0x02, 0x00, 0x02, 0x00, -0x02, 0x00, 0x42, 0x00, 0xc0, 0x00, 0x40 -}; - -static unsigned char page_four[] __devinitdata = { -0x63, 0x03, 0x26, 0x02, 0x2c, 0x00, 0x24, 0x00, 0x2e, 0x02, 0x02, -0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, -0x20, 0x00, 0x60, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, -0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x60, 0x00, -0x20, 0x00, 0x60, 0x00, 0x20, 0x00, 0x60, 0x00, 0x20, 0x00, 0x60, -0x00, 0x20, 0x00, 0x60, 0x00, 0x20, 0x00, 0x60, 0x00, 0x20, 0x00, -0x20, 0x00, 0x22, 0x02, 0x22, 0x02, 0x20, 0x00, 0x60, 0x00, 0x22, -0x02, 0x62, 0x02, 0x20, 0x01, 0x21, 0x01 -}; - -static unsigned char page_six[] __devinitdata = { -0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x04, 0x00, 0x00, 0x06, 0x00, -0x00, 0x08, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x0e, -0x00, 0x00, 0x10, 0x00, 0x00, 0x12, 0x00, 0x00, 0x14, 0x00, 0x00, -0x16, 0x00, 0x00, 0x18, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x1c, 0x00, -0x00, 0x1e, 0x00, 0x00, 0x20, 0x00, 0x00, 0x22, 0x00, 0x00, 0x24, -0x00, 0x00, 0x26, 0x00, 0x00, 0x28, 0x00, 0x00, 0x2a, 0x00, 0x00, -0x2c, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x30, 0x00, 0x00, 0x32, 0x00, -0x00, 0x34, 0x00, 0x00, 0x36, 0x00, 0x00, 0x38, 0x00, 0x00, 0x3a, -0x00, 0x00, 0x3c, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x40, 0x00, 0x00, -0x42, 0x03, 0x00, 0x44, 0x01, 0x00, 0x46, 0x0a, 0x21, 0x48, 0x0d, -0x23, 0x4a, 0x23, 0x1b, 0x4c, 0x37, 0x8f, 0x4e, 0x45, 0x77, 0x50, -0x52, 0xe2, 0x52, 0x1c, 0x92, 0x54, 0x1c, 0x52, 0x56, 0x07, 0x00, -0x58, 0x2f, 0xc6, 0x5a, 0x0b, 0x00, 0x5c, 0x30, 0x06, 0x5e, 0x17, -0x00, 0x60, 0x3d, 0xda, 0x62, 0x29, 0x00, 0x64, 0x3e, 0x41, 0x66, -0x39, 0x00, 0x68, 0x4c, 0x48, 0x6a, 0x49, 0x00, 0x6c, 0x4c, 0x6c, -0x6e, 0x11, 0xd2, 0x70, 0x16, 0x0c, 0x72, 0x00, 0x00, 0x74, 0x00, -0x80, 0x76, 0x0f, 0x00, 0x78, 0x00, 0x80, 0x7a, 0x13, 0x00, 0x7c, -0x80, 0x00, 0x7e, 0x80, 0x80 -}; - -static unsigned char page_seven[] __devinitdata = { -0x0f, 0xff, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00, -0x00, 0x00, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, -0x08, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0f, -0xff, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x0f, 0xff, -0x0f, 0xff, 0x0f, 0xff, 0x02, 0xe9, 0x06, 0x8c, 0x06, 0x8c, 0x0f, -0xff, 0x1a, 0x75, 0x0d, 0x8b, 0x04, 0xe9, 0x0b, 0x16, 0x1a, 0x38, -0x0d, 0xc8, 0x04, 0x6f, 0x0b, 0x91, 0x0f, 0xff, 0x06, 0x40, 0x06, -0x40, 0x02, 0x8f, 0x0f, 0xff, 0x06, 0x62, 0x06, 0x62, 0x02, 0x7b, -0x0f, 0xff, 0x06, 0x97, 0x06, 0x97, 0x02, 0x52, 0x0f, 0xff, 0x06, -0xf6, 0x06, 0xf6, 0x02, 0x19, 0x05, 0x55, 0x05, 0x55, 0x05, 0x55, -0x05, 0x55, 0x05, 0x55, 0x05, 0x55, 0x05, 0x55, 0x05, 0x55, 0x14, -0xda, 0x0d, 0x93, 0x04, 0xda, 0x05, 0x93, 0x14, 0xda, 0x0d, 0x93, -0x04, 0xda, 0x05, 0x93, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x02, 0x00 -}; - -static unsigned char page_zero_v2[] __devinitdata = { -0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -static unsigned char page_one_v2[] __devinitdata = { -0x01, 0xc0, 0x01, 0xfa, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -static unsigned char page_two_v2[] __devinitdata = { -0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00 -}; -static unsigned char page_three_v2[] __devinitdata = { -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00 -}; -static unsigned char page_four_v2[] __devinitdata = { -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00 -}; - -static unsigned char page_seven_v2[] __devinitdata = { -0x0f, 0xff, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -static unsigned char mod_v2[] __devinitdata = { -0x01, 0x00, 0x02, 0x00, 0x01, 0x01, 0x02, 0x00, 0x01, 0x02, 0x02, -0x00, 0x01, 0x03, 0x02, 0x00, 0x01, 0x04, 0x02, 0x00, 0x01, 0x05, -0x02, 0x00, 0x01, 0x06, 0x02, 0x00, 0x01, 0x07, 0x02, 0x00, 0xb0, -0x20, 0xb1, 0x20, 0xb2, 0x20, 0xb3, 0x20, 0xb4, 0x20, 0xb5, 0x20, -0xb6, 0x20, 0xb7, 0x20, 0xf0, 0x20, 0xf1, 0x20, 0xf2, 0x20, 0xf3, -0x20, 0xf4, 0x20, 0xf5, 0x20, 0xf6, 0x20, 0xf7, 0x20, 0x10, 0xff, -0x11, 0xff, 0x12, 0xff, 0x13, 0xff, 0x14, 0xff, 0x15, 0xff, 0x16, -0xff, 0x17, 0xff, 0x20, 0xff, 0x21, 0xff, 0x22, 0xff, 0x23, 0xff, -0x24, 0xff, 0x25, 0xff, 0x26, 0xff, 0x27, 0xff, 0x30, 0x00, 0x31, -0x00, 0x32, 0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00, 0x36, 0x00, -0x37, 0x00, 0x40, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00, 0x44, -0x00, 0x45, 0x00, 0x46, 0x00, 0x47, 0x00, 0x50, 0x00, 0x51, 0x00, -0x52, 0x00, 0x53, 0x00, 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, -0x00, 0x60, 0x00, 0x61, 0x00, 0x62, 0x00, 0x63, 0x00, 0x64, 0x00, -0x65, 0x00, 0x66, 0x00, 0x67, 0x00, 0x70, 0xc0, 0x71, 0xc0, 0x72, -0xc0, 0x73, 0xc0, 0x74, 0xc0, 0x75, 0xc0, 0x76, 0xc0, 0x77, 0xc0, -0x80, 0x00, 0x81, 0x00, 0x82, 0x00, 0x83, 0x00, 0x84, 0x00, 0x85, -0x00, 0x86, 0x00, 0x87, 0x00, 0x90, 0x00, 0x91, 0x00, 0x92, 0x00, -0x93, 0x00, 0x94, 0x00, 0x95, 0x00, 0x96, 0x00, 0x97, 0x00, 0xa0, -0x00, 0xa1, 0x00, 0xa2, 0x00, 0xa3, 0x00, 0xa4, 0x00, 0xa5, 0x00, -0xa6, 0x00, 0xa7, 0x00, 0xc0, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc3, -0x00, 0xc4, 0x00, 0xc5, 0x00, 0xc6, 0x00, 0xc7, 0x00, 0xd0, 0x00, -0xd1, 0x00, 0xd2, 0x00, 0xd3, 0x00, 0xd4, 0x00, 0xd5, 0x00, 0xd6, -0x00, 0xd7, 0x00, 0xe0, 0x00, 0xe1, 0x00, 0xe2, 0x00, 0xe3, 0x00, -0xe4, 0x00, 0xe5, 0x00, 0xe6, 0x00, 0xe7, 0x00, 0x01, 0x00, 0x02, -0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x02, 0x02, 0x01, 0x01, 0x03, -0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x05, 0x02, 0x01, 0x01, -0x06, 0x02, 0x01, 0x01, 0x07, 0x02, 0x01 -}; -static unsigned char coefficients[] __devinitdata = { -0x07, 0x46, 0x00, 0x00, 0x07, 0x49, 0x00, 0x00, 0x00, 0x4b, 0x03, -0x11, 0x00, 0x4d, 0x01, 0x32, 0x07, 0x46, 0x00, 0x00, 0x07, 0x49, -0x00, 0x00, 0x07, 0x40, 0x00, 0x00, 0x07, 0x41, 0x00, 0x00, 0x01, -0x40, 0x02, 0x40, 0x01, 0x41, 0x02, 0x60, 0x07, 0x40, 0x00, 0x00, -0x07, 0x41, 0x00, 0x00, 0x07, 0x47, 0x00, 0x00, 0x07, 0x4a, 0x00, -0x00, 0x00, 0x47, 0x01, 0x00, 0x00, 0x4a, 0x01, 0x20, 0x07, 0x47, -0x00, 0x00, 0x07, 0x4a, 0x00, 0x00, 0x07, 0x7c, 0x00, 0x00, 0x07, -0x7e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x1c, 0x07, 0x7c, 0x00, 0x00, -0x07, 0x7e, 0x00, 0x00, 0x07, 0x44, 0x00, 0x00, 0x00, 0x44, 0x01, -0x00, 0x07, 0x44, 0x00, 0x00, 0x07, 0x42, 0x00, 0x00, 0x07, 0x43, -0x00, 0x00, 0x00, 0x42, 0x01, 0x1a, 0x00, 0x43, 0x01, 0x20, 0x07, -0x42, 0x00, 0x00, 0x07, 0x43, 0x00, 0x00, 0x07, 0x40, 0x00, 0x00, -0x07, 0x41, 0x00, 0x00, 0x01, 0x40, 0x02, 0x40, 0x01, 0x41, 0x02, -0x60, 0x07, 0x40, 0x00, 0x00, 0x07, 0x41, 0x00, 0x00, 0x07, 0x44, -0x0f, 0xff, 0x07, 0x42, 0x00, 0x00, 0x07, 0x43, 0x00, 0x00, 0x07, -0x40, 0x00, 0x00, 0x07, 0x41, 0x00, 0x00, 0x07, 0x51, 0x06, 0x40, -0x07, 0x50, 0x06, 0x40, 0x07, 0x4f, 0x03, 0x81, 0x07, 0x53, 0x1a, -0x76, 0x07, 0x54, 0x0d, 0x8b, 0x07, 0x55, 0x04, 0xe9, 0x07, 0x56, -0x0b, 0x17, 0x07, 0x57, 0x1a, 0x38, 0x07, 0x58, 0x0d, 0xc9, 0x07, -0x59, 0x04, 0x6f, 0x07, 0x5a, 0x0b, 0x91, 0x07, 0x73, 0x14, 0xda, -0x07, 0x74, 0x0d, 0x93, 0x07, 0x75, 0x04, 0xd9, 0x07, 0x76, 0x05, -0x93, 0x07, 0x77, 0x14, 0xda, 0x07, 0x78, 0x0d, 0x93, 0x07, 0x79, -0x04, 0xd9, 0x07, 0x7a, 0x05, 0x93, 0x07, 0x5e, 0x03, 0x68, 0x07, -0x5c, 0x04, 0x31, 0x07, 0x5d, 0x04, 0x31, 0x07, 0x62, 0x03, 0x52, -0x07, 0x60, 0x04, 0x76, 0x07, 0x61, 0x04, 0x76, 0x07, 0x66, 0x03, -0x2e, 0x07, 0x64, 0x04, 0xda, 0x07, 0x65, 0x04, 0xda, 0x07, 0x6a, -0x02, 0xf6, 0x07, 0x68, 0x05, 0x62, 0x07, 0x69, 0x05, 0x62, 0x06, -0x46, 0x0a, 0x22, 0x06, 0x48, 0x0d, 0x24, 0x06, 0x6e, 0x11, 0xd3, -0x06, 0x70, 0x15, 0xcb, 0x06, 0x52, 0x20, 0x93, 0x06, 0x54, 0x20, -0x54, 0x06, 0x4a, 0x27, 0x1d, 0x06, 0x58, 0x2f, 0xc8, 0x06, 0x5c, -0x30, 0x07, 0x06, 0x4c, 0x37, 0x90, 0x06, 0x60, 0x3d, 0xdb, 0x06, -0x64, 0x3e, 0x42, 0x06, 0x4e, 0x45, 0x78, 0x06, 0x68, 0x4c, 0x48, -0x06, 0x6c, 0x4c, 0x6c, 0x06, 0x50, 0x52, 0xe2, 0x06, 0x42, 0x02, -0xba -}; -static unsigned char coefficients2[] __devinitdata = { -0x07, 0x46, 0x00, 0x00, 0x07, 0x49, 0x00, 0x00, 0x07, 0x45, 0x0f, -0xff, 0x07, 0x48, 0x0f, 0xff, 0x07, 0x7b, 0x04, 0xcc, 0x07, 0x7d, -0x04, 0xcc, 0x07, 0x7c, 0x00, 0x00, 0x07, 0x7e, 0x00, 0x00, 0x07, -0x46, 0x00, 0x00, 0x07, 0x49, 0x00, 0x00, 0x07, 0x47, 0x00, 0x00, -0x07, 0x4a, 0x00, 0x00, 0x07, 0x4c, 0x00, 0x00, 0x07, 0x4e, 0x00, 0x00 -}; -static unsigned char coefficients3[] __devinitdata = { -0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x28, 0x00, 0x51, 0x00, -0x51, 0x00, 0x7a, 0x00, 0x7a, 0x00, 0xa3, 0x00, 0xa3, 0x00, 0xcc, -0x00, 0xcc, 0x00, 0xf5, 0x00, 0xf5, 0x01, 0x1e, 0x01, 0x1e, 0x01, -0x47, 0x01, 0x47, 0x01, 0x70, 0x01, 0x70, 0x01, 0x99, 0x01, 0x99, -0x01, 0xc2, 0x01, 0xc2, 0x01, 0xeb, 0x01, 0xeb, 0x02, 0x14, 0x02, -0x14, 0x02, 0x3d, 0x02, 0x3d, 0x02, 0x66, 0x02, 0x66, 0x02, 0x8f, -0x02, 0x8f, 0x02, 0xb8, 0x02, 0xb8, 0x02, 0xe1, 0x02, 0xe1, 0x03, -0x0a, 0x03, 0x0a, 0x03, 0x33, 0x03, 0x33, 0x03, 0x5c, 0x03, 0x5c, -0x03, 0x85, 0x03, 0x85, 0x03, 0xae, 0x03, 0xae, 0x03, 0xd7, 0x03, -0xd7, 0x04, 0x00, 0x04, 0x00, 0x04, 0x28, 0x04, 0x28, 0x04, 0x51, -0x04, 0x51, 0x04, 0x7a, 0x04, 0x7a, 0x04, 0xa3, 0x04, 0xa3, 0x04, -0xcc, 0x04, 0xcc, 0x04, 0xf5, 0x04, 0xf5, 0x05, 0x1e, 0x05, 0x1e, -0x05, 0x47, 0x05, 0x47, 0x05, 0x70, 0x05, 0x70, 0x05, 0x99, 0x05, -0x99, 0x05, 0xc2, 0x05, 0xc2, 0x05, 0xeb, 0x05, 0xeb, 0x06, 0x14, -0x06, 0x14, 0x06, 0x3d, 0x06, 0x3d, 0x06, 0x66, 0x06, 0x66, 0x06, -0x8f, 0x06, 0x8f, 0x06, 0xb8, 0x06, 0xb8, 0x06, 0xe1, 0x06, 0xe1, -0x07, 0x0a, 0x07, 0x0a, 0x07, 0x33, 0x07, 0x33, 0x07, 0x5c, 0x07, -0x5c, 0x07, 0x85, 0x07, 0x85, 0x07, 0xae, 0x07, 0xae, 0x07, 0xd7, -0x07, 0xd7, 0x08, 0x00, 0x08, 0x00, 0x08, 0x28, 0x08, 0x28, 0x08, -0x51, 0x08, 0x51, 0x08, 0x7a, 0x08, 0x7a, 0x08, 0xa3, 0x08, 0xa3, -0x08, 0xcc, 0x08, 0xcc, 0x08, 0xf5, 0x08, 0xf5, 0x09, 0x1e, 0x09, -0x1e, 0x09, 0x47, 0x09, 0x47, 0x09, 0x70, 0x09, 0x70, 0x09, 0x99, -0x09, 0x99, 0x09, 0xc2, 0x09, 0xc2, 0x09, 0xeb, 0x09, 0xeb, 0x0a, -0x14, 0x0a, 0x14, 0x0a, 0x3d, 0x0a, 0x3d, 0x0a, 0x66, 0x0a, 0x66, -0x0a, 0x8f, 0x0a, 0x8f, 0x0a, 0xb8, 0x0a, 0xb8, 0x0a, 0xe1, 0x0a, -0xe1, 0x0b, 0x0a, 0x0b, 0x0a, 0x0b, 0x33, 0x0b, 0x33, 0x0b, 0x5c, -0x0b, 0x5c, 0x0b, 0x85, 0x0b, 0x85, 0x0b, 0xae, 0x0b, 0xae, 0x0b, -0xd7, 0x0b, 0xd7, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x28, 0x0c, 0x28, -0x0c, 0x51, 0x0c, 0x51, 0x0c, 0x7a, 0x0c, 0x7a, 0x0c, 0xa3, 0x0c, -0xa3, 0x0c, 0xcc, 0x0c, 0xcc, 0x0c, 0xf5, 0x0c, 0xf5, 0x0d, 0x1e, -0x0d, 0x1e, 0x0d, 0x47, 0x0d, 0x47, 0x0d, 0x70, 0x0d, 0x70, 0x0d, -0x99, 0x0d, 0x99, 0x0d, 0xc2, 0x0d, 0xc2, 0x0d, 0xeb, 0x0d, 0xeb, -0x0e, 0x14, 0x0e, 0x14, 0x0e, 0x3d, 0x0e, 0x3d, 0x0e, 0x66, 0x0e, -0x66, 0x0e, 0x8f, 0x0e, 0x8f, 0x0e, 0xb8, 0x0e, 0xb8, 0x0e, 0xe1, -0x0e, 0xe1, 0x0f, 0x0a, 0x0f, 0x0a, 0x0f, 0x33, 0x0f, 0x33, 0x0f, -0x5c, 0x0f, 0x5c, 0x0f, 0x85, 0x0f, 0x85, 0x0f, 0xae, 0x0f, 0xae, -0x0f, 0xd7, 0x0f, 0xd7, 0x0f, 0xff, 0x0f, 0xff -}; +#define WAIT_IDLE 0xff + +#include "yss225.c" static int wavefront_fx_idle (snd_wavefront_t *dev) @@ -555,465 +239,34 @@ snd_wavefront_fx_ioctl (struct snd_hwdep *sdev, struct file *file, of the port I/O done, using the Yamaha faxback document as a guide to add more logic to the code. Its really pretty weird. - There was an alternative approach of just dumping the whole I/O + This is the approach of just dumping the whole I/O sequence as a series of port/value pairs and a simple loop - that output it. However, I hope that eventually I'll get more - control over what this code does, and so I tried to stick with - a somewhat "algorithmic" approach. + that outputs it. */ - int __devinit snd_wavefront_fx_start (snd_wavefront_t *dev) - { - unsigned int i, j; + unsigned int i; - /* Set all bits for all channels on the MOD unit to zero */ - /* XXX But why do this twice ? */ - - for (j = 0; j < 2; j++) { - for (i = 0x10; i <= 0xff; i++) { - - if (!wavefront_fx_idle (dev)) { - return (-1); - } - - outb (i, dev->fx_mod_addr); - outb (0x0, dev->fx_mod_data); - } - } + if (dev->fx_initialized) + return 0; - if (!wavefront_fx_idle (dev)) return (-1); - outb (0x02, dev->fx_op); /* mute on */ - - if (!wavefront_fx_idle (dev)) return (-1); - outb (0x07, dev->fx_dsp_page); - outb (0x44, dev->fx_dsp_addr); - outb (0x00, dev->fx_dsp_msb); - outb (0x00, dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - outb (0x07, dev->fx_dsp_page); - outb (0x42, dev->fx_dsp_addr); - outb (0x00, dev->fx_dsp_msb); - outb (0x00, dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - outb (0x07, dev->fx_dsp_page); - outb (0x43, dev->fx_dsp_addr); - outb (0x00, dev->fx_dsp_msb); - outb (0x00, dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - outb (0x07, dev->fx_dsp_page); - outb (0x7c, dev->fx_dsp_addr); - outb (0x00, dev->fx_dsp_msb); - outb (0x00, dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - outb (0x07, dev->fx_dsp_page); - outb (0x7e, dev->fx_dsp_addr); - outb (0x00, dev->fx_dsp_msb); - outb (0x00, dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - outb (0x07, dev->fx_dsp_page); - outb (0x46, dev->fx_dsp_addr); - outb (0x00, dev->fx_dsp_msb); - outb (0x00, dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - outb (0x07, dev->fx_dsp_page); - outb (0x49, dev->fx_dsp_addr); - outb (0x00, dev->fx_dsp_msb); - outb (0x00, dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - outb (0x07, dev->fx_dsp_page); - outb (0x47, dev->fx_dsp_addr); - outb (0x00, dev->fx_dsp_msb); - outb (0x00, dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - outb (0x07, dev->fx_dsp_page); - outb (0x4a, dev->fx_dsp_addr); - outb (0x00, dev->fx_dsp_msb); - outb (0x00, dev->fx_dsp_lsb); - - /* either because of stupidity by TB's programmers, or because it - actually does something, rezero the MOD page. - */ - for (i = 0x10; i <= 0xff; i++) { - - if (!wavefront_fx_idle (dev)) { - return (-1); + for (i = 0; i < ARRAY_SIZE(yss225_registers); ++i) { + if (yss225_registers[i].addr >= 8 && + yss225_registers[i].addr < 16) { + outb(yss225_registers[i].data, + yss225_registers[i].addr + dev->base); + } else if (yss225_registers[i].addr == WAIT_IDLE) { + if (!wavefront_fx_idle(dev)) + return -1; + } else { + snd_printk(KERN_ERR "invalid address" + " in register data\n"); + return -1; } - - outb (i, dev->fx_mod_addr); - outb (0x0, dev->fx_mod_data); - } - /* load page zero */ - - outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr); - outb (0x00, dev->fx_dsp_page); - outb (0x00, dev->fx_dsp_addr); - - for (i = 0; i < sizeof (page_zero); i += 2) { - outb (page_zero[i], dev->fx_dsp_msb); - outb (page_zero[i+1], dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - } - - /* Now load page one */ - - outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr); - outb (0x01, dev->fx_dsp_page); - outb (0x00, dev->fx_dsp_addr); - - for (i = 0; i < sizeof (page_one); i += 2) { - outb (page_one[i], dev->fx_dsp_msb); - outb (page_one[i+1], dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - } - - outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr); - outb (0x02, dev->fx_dsp_page); - outb (0x00, dev->fx_dsp_addr); - - for (i = 0; i < sizeof (page_two); i++) { - outb (page_two[i], dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - } - - outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr); - outb (0x03, dev->fx_dsp_page); - outb (0x00, dev->fx_dsp_addr); - - for (i = 0; i < sizeof (page_three); i++) { - outb (page_three[i], dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - } - - outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr); - outb (0x04, dev->fx_dsp_page); - outb (0x00, dev->fx_dsp_addr); - - for (i = 0; i < sizeof (page_four); i++) { - outb (page_four[i], dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); } - /* Load memory area (page six) */ - - outb (FX_LSB_TRANSFER, dev->fx_lcr); - outb (0x06, dev->fx_dsp_page); - - for (i = 0; i < sizeof (page_six); i += 3) { - outb (page_six[i], dev->fx_dsp_addr); - outb (page_six[i+1], dev->fx_dsp_msb); - outb (page_six[i+2], dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - } - - outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr); - outb (0x07, dev->fx_dsp_page); - outb (0x00, dev->fx_dsp_addr); - - for (i = 0; i < sizeof (page_seven); i += 2) { - outb (page_seven[i], dev->fx_dsp_msb); - outb (page_seven[i+1], dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - } - - /* Now setup the MOD area. We do this algorithmically in order to - save a little data space. It could be done in the same fashion - as the "pages". - */ - - for (i = 0x00; i <= 0x0f; i++) { - outb (0x01, dev->fx_mod_addr); - outb (i, dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); - outb (0x02, dev->fx_mod_addr); - outb (0x00, dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); - } - - for (i = 0xb0; i <= 0xbf; i++) { - outb (i, dev->fx_mod_addr); - outb (0x20, dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); - } - - for (i = 0xf0; i <= 0xff; i++) { - outb (i, dev->fx_mod_addr); - outb (0x20, dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); - } - - for (i = 0x10; i <= 0x1d; i++) { - outb (i, dev->fx_mod_addr); - outb (0xff, dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); - } - - outb (0x1e, dev->fx_mod_addr); - outb (0x40, dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); - - for (i = 0x1f; i <= 0x2d; i++) { - outb (i, dev->fx_mod_addr); - outb (0xff, dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); - } - - outb (0x2e, dev->fx_mod_addr); - outb (0x00, dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); - - for (i = 0x2f; i <= 0x3e; i++) { - outb (i, dev->fx_mod_addr); - outb (0x00, dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); - } - - outb (0x3f, dev->fx_mod_addr); - outb (0x20, dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); - - for (i = 0x40; i <= 0x4d; i++) { - outb (i, dev->fx_mod_addr); - outb (0x00, dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); - } - - outb (0x4e, dev->fx_mod_addr); - outb (0x0e, dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); - outb (0x4f, dev->fx_mod_addr); - outb (0x0e, dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); - - - for (i = 0x50; i <= 0x6b; i++) { - outb (i, dev->fx_mod_addr); - outb (0x00, dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); - } - - outb (0x6c, dev->fx_mod_addr); - outb (0x40, dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); - - outb (0x6d, dev->fx_mod_addr); - outb (0x00, dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); - - outb (0x6e, dev->fx_mod_addr); - outb (0x40, dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); - - outb (0x6f, dev->fx_mod_addr); - outb (0x40, dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); - - for (i = 0x70; i <= 0x7f; i++) { - outb (i, dev->fx_mod_addr); - outb (0xc0, dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); - } - - for (i = 0x80; i <= 0xaf; i++) { - outb (i, dev->fx_mod_addr); - outb (0x00, dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); - } - - for (i = 0xc0; i <= 0xdd; i++) { - outb (i, dev->fx_mod_addr); - outb (0x00, dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); - } - - outb (0xde, dev->fx_mod_addr); - outb (0x10, dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); - outb (0xdf, dev->fx_mod_addr); - outb (0x10, dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); - - for (i = 0xe0; i <= 0xef; i++) { - outb (i, dev->fx_mod_addr); - outb (0x00, dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); - } - - for (i = 0x00; i <= 0x0f; i++) { - outb (0x01, dev->fx_mod_addr); - outb (i, dev->fx_mod_data); - outb (0x02, dev->fx_mod_addr); - outb (0x01, dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); - } - - outb (0x02, dev->fx_op); /* mute on */ - - /* Now set the coefficients and so forth for the programs above */ - - for (i = 0; i < sizeof (coefficients); i += 4) { - outb (coefficients[i], dev->fx_dsp_page); - outb (coefficients[i+1], dev->fx_dsp_addr); - outb (coefficients[i+2], dev->fx_dsp_msb); - outb (coefficients[i+3], dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - } - - /* Some settings (?) that are too small to bundle into loops */ - - if (!wavefront_fx_idle (dev)) return (-1); - outb (0x1e, dev->fx_mod_addr); - outb (0x14, dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); - outb (0xde, dev->fx_mod_addr); - outb (0x20, dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); - outb (0xdf, dev->fx_mod_addr); - outb (0x20, dev->fx_mod_data); - - /* some more coefficients */ - - if (!wavefront_fx_idle (dev)) return (-1); - outb (0x06, dev->fx_dsp_page); - outb (0x78, dev->fx_dsp_addr); - outb (0x00, dev->fx_dsp_msb); - outb (0x40, dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - outb (0x07, dev->fx_dsp_page); - outb (0x03, dev->fx_dsp_addr); - outb (0x0f, dev->fx_dsp_msb); - outb (0xff, dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - outb (0x07, dev->fx_dsp_page); - outb (0x0b, dev->fx_dsp_addr); - outb (0x0f, dev->fx_dsp_msb); - outb (0xff, dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - outb (0x07, dev->fx_dsp_page); - outb (0x02, dev->fx_dsp_addr); - outb (0x00, dev->fx_dsp_msb); - outb (0x00, dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - outb (0x07, dev->fx_dsp_page); - outb (0x0a, dev->fx_dsp_addr); - outb (0x00, dev->fx_dsp_msb); - outb (0x00, dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - outb (0x07, dev->fx_dsp_page); - outb (0x46, dev->fx_dsp_addr); - outb (0x00, dev->fx_dsp_msb); - outb (0x00, dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - outb (0x07, dev->fx_dsp_page); - outb (0x49, dev->fx_dsp_addr); - outb (0x00, dev->fx_dsp_msb); - outb (0x00, dev->fx_dsp_lsb); - - /* Now, for some strange reason, lets reload every page - and all the coefficients over again. I have *NO* idea - why this is done. I do know that no sound is produced - is this phase is omitted. - */ - - outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr); - outb (0x00, dev->fx_dsp_page); - outb (0x10, dev->fx_dsp_addr); - - for (i = 0; i < sizeof (page_zero_v2); i += 2) { - outb (page_zero_v2[i], dev->fx_dsp_msb); - outb (page_zero_v2[i+1], dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - } - - outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr); - outb (0x01, dev->fx_dsp_page); - outb (0x10, dev->fx_dsp_addr); - - for (i = 0; i < sizeof (page_one_v2); i += 2) { - outb (page_one_v2[i], dev->fx_dsp_msb); - outb (page_one_v2[i+1], dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - } - - if (!wavefront_fx_idle (dev)) return (-1); - if (!wavefront_fx_idle (dev)) return (-1); - - outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr); - outb (0x02, dev->fx_dsp_page); - outb (0x10, dev->fx_dsp_addr); - - for (i = 0; i < sizeof (page_two_v2); i++) { - outb (page_two_v2[i], dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - } - outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr); - outb (0x03, dev->fx_dsp_page); - outb (0x10, dev->fx_dsp_addr); - - for (i = 0; i < sizeof (page_three_v2); i++) { - outb (page_three_v2[i], dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - } - - outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr); - outb (0x04, dev->fx_dsp_page); - outb (0x10, dev->fx_dsp_addr); - - for (i = 0; i < sizeof (page_four_v2); i++) { - outb (page_four_v2[i], dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - } - - outb (FX_LSB_TRANSFER, dev->fx_lcr); - outb (0x06, dev->fx_dsp_page); - - /* Page six v.2 is algorithmic */ - - for (i = 0x10; i <= 0x3e; i += 2) { - outb (i, dev->fx_dsp_addr); - outb (0x00, dev->fx_dsp_msb); - outb (0x00, dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - } - - outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr); - outb (0x07, dev->fx_dsp_page); - outb (0x10, dev->fx_dsp_addr); - - for (i = 0; i < sizeof (page_seven_v2); i += 2) { - outb (page_seven_v2[i], dev->fx_dsp_msb); - outb (page_seven_v2[i+1], dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - } - - for (i = 0x00; i < sizeof(mod_v2); i += 2) { - outb (mod_v2[i], dev->fx_mod_addr); - outb (mod_v2[i+1], dev->fx_mod_data); - if (!wavefront_fx_idle (dev)) return (-1); - } - - for (i = 0; i < sizeof (coefficients2); i += 4) { - outb (coefficients2[i], dev->fx_dsp_page); - outb (coefficients2[i+1], dev->fx_dsp_addr); - outb (coefficients2[i+2], dev->fx_dsp_msb); - outb (coefficients2[i+3], dev->fx_dsp_lsb); - if (!wavefront_fx_idle (dev)) return (-1); - } - - for (i = 0; i < sizeof (coefficients3); i += 2) { - int x; - - outb (0x07, dev->fx_dsp_page); - x = (i % 4) ? 0x4e : 0x4c; - outb (x, dev->fx_dsp_addr); - outb (coefficients3[i], dev->fx_dsp_msb); - outb (coefficients3[i+1], dev->fx_dsp_lsb); - } - - outb (0x00, dev->fx_op); /* mute off */ - if (!wavefront_fx_idle (dev)) return (-1); - + dev->fx_initialized = 1; return (0); } diff --git a/sound/isa/wavefront/yss225.c b/sound/isa/wavefront/yss225.c new file mode 100644 index 00000000000..9f6be3ff8ec --- /dev/null +++ b/sound/isa/wavefront/yss225.c @@ -0,0 +1,2739 @@ +/* + * Copyright (c) 1998-2002 by Paul Davis + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* weird stuff, derived from port I/O tracing with dosemu */ + +static const struct { + unsigned char addr; + unsigned char data; +} yss225_registers[] __devinitdata = { +/* Set all bits for all channels on the MOD unit to zero */ +{ WAIT_IDLE }, { 0xe, 0x10 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x11 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x12 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x13 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x14 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x15 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x16 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x17 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x18 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x19 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x1a }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x1b }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x1c }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x1d }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x1e }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x1f }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x20 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x21 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x22 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x23 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x24 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x25 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x26 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x27 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x28 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x29 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x2a }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x2b }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x2c }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x2d }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x2e }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x2f }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x30 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x31 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x32 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x33 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x34 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x35 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x36 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x37 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x38 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x39 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x3a }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x3b }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x3c }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x3d }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x3e }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x3f }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x40 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x41 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x42 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x43 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x44 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x45 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x46 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x47 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x48 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x49 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x4a }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x4b }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x4c }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x4d }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x4e }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x4f }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x50 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x51 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x52 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x53 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x54 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x55 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x56 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x57 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x58 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x59 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x5a }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x5b }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x5c }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x5d }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x5e }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x5f }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x60 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x61 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x62 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x63 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x64 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x65 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x66 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x67 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x68 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x69 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x6a }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x6b }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x6c }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x6d }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x6e }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x6f }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x70 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x71 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x72 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x73 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x74 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x75 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x76 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x77 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x78 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x79 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x7a }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x7b }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x7c }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x7d }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x7e }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x7f }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x80 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x81 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x82 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x83 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x84 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x85 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x86 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x87 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x88 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x89 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x8a }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x8b }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x8c }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x8d }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x8e }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x8f }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x90 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x91 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x92 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x93 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x94 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x95 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x96 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x97 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x98 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x99 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x9a }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x9b }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x9c }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x9d }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x9e }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x9f }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa0 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa1 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa2 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa3 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa4 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa5 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa6 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa7 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa8 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa9 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xaa }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xab }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xac }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xad }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xae }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xaf }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb0 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb1 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb2 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb3 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb4 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb5 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb6 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb7 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb8 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb9 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xba }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xbb }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xbc }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xbd }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xbe }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xbf }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc0 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc1 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc2 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc3 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc4 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc5 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc6 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc7 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc8 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc9 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xca }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xcb }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xcc }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xcd }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xce }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xcf }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd0 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd1 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd2 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd3 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd4 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd5 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd6 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd7 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd8 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd9 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xda }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xdb }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xdc }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xdd }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xde }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xdf }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe0 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe1 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe2 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe3 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe4 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe5 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe6 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe7 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe8 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe9 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xea }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xeb }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xec }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xed }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xee }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xef }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf0 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf1 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf2 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf3 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf4 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf5 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf6 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf7 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf8 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf9 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xfa }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xfb }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xfc }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xfd }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xfe }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xff }, { 0xf, 0x00 }, + +/* XXX But why do this twice? */ +{ WAIT_IDLE }, { 0xe, 0x10 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x11 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x12 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x13 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x14 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x15 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x16 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x17 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x18 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x19 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x1a }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x1b }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x1c }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x1d }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x1e }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x1f }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x20 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x21 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x22 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x23 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x24 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x25 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x26 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x27 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x28 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x29 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x2a }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x2b }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x2c }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x2d }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x2e }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x2f }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x30 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x31 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x32 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x33 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x34 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x35 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x36 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x37 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x38 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x39 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x3a }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x3b }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x3c }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x3d }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x3e }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x3f }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x40 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x41 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x42 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x43 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x44 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x45 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x46 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x47 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x48 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x49 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x4a }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x4b }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x4c }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x4d }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x4e }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x4f }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x50 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x51 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x52 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x53 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x54 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x55 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x56 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x57 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x58 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x59 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x5a }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x5b }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x5c }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x5d }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x5e }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x5f }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x60 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x61 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x62 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x63 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x64 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x65 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x66 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x67 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x68 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x69 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x6a }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x6b }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x6c }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x6d }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x6e }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x6f }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x70 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x71 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x72 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x73 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x74 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x75 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x76 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x77 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x78 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x79 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x7a }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x7b }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x7c }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x7d }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x7e }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x7f }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x80 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x81 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x82 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x83 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x84 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x85 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x86 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x87 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x88 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x89 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x8a }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x8b }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x8c }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x8d }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x8e }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x8f }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x90 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x91 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x92 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x93 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x94 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x95 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x96 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x97 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x98 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x99 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x9a }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x9b }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x9c }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x9d }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x9e }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x9f }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa0 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa1 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa2 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa3 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa4 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa5 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa6 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa7 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa8 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa9 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xaa }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xab }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xac }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xad }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xae }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xaf }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb0 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb1 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb2 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb3 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb4 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb5 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb6 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb7 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb8 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb9 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xba }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xbb }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xbc }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xbd }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xbe }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xbf }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc0 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc1 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc2 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc3 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc4 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc5 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc6 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc7 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc8 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc9 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xca }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xcb }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xcc }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xcd }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xce }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xcf }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd0 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd1 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd2 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd3 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd4 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd5 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd6 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd7 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd8 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd9 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xda }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xdb }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xdc }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xdd }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xde }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xdf }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe0 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe1 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe2 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe3 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe4 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe5 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe6 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe7 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe8 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe9 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xea }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xeb }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xec }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xed }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xee }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xef }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf0 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf1 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf2 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf3 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf4 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf5 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf6 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf7 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf8 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf9 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xfa }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xfb }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xfc }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xfd }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xfe }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xff }, { 0xf, 0x00 }, + +/* mute on */ +{ WAIT_IDLE }, { 0x8, 0x02 }, + +{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x44 }, { 0xd, 0x00 }, { 0xc, 0x00 }, +{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x42 }, { 0xd, 0x00 }, { 0xc, 0x00 }, +{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x43 }, { 0xd, 0x00 }, { 0xc, 0x00 }, +{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x7c }, { 0xd, 0x00 }, { 0xc, 0x00 }, +{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x7e }, { 0xd, 0x00 }, { 0xc, 0x00 }, +{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x46 }, { 0xd, 0x00 }, { 0xc, 0x00 }, +{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x49 }, { 0xd, 0x00 }, { 0xc, 0x00 }, +{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x47 }, { 0xd, 0x00 }, { 0xc, 0x00 }, +{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x4a }, { 0xd, 0x00 }, { 0xc, 0x00 }, + +/* either because of stupidity by TB's programmers, or because it + actually does something, rezero the MOD page. */ +{ WAIT_IDLE }, { 0xe, 0x10 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x11 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x12 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x13 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x14 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x15 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x16 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x17 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x18 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x19 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x1a }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x1b }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x1c }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x1d }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x1e }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x1f }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x20 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x21 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x22 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x23 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x24 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x25 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x26 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x27 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x28 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x29 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x2a }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x2b }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x2c }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x2d }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x2e }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x2f }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x30 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x31 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x32 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x33 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x34 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x35 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x36 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x37 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x38 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x39 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x3a }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x3b }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x3c }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x3d }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x3e }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x3f }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x40 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x41 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x42 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x43 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x44 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x45 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x46 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x47 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x48 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x49 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x4a }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x4b }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x4c }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x4d }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x4e }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x4f }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x50 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x51 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x52 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x53 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x54 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x55 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x56 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x57 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x58 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x59 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x5a }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x5b }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x5c }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x5d }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x5e }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x5f }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x60 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x61 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x62 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x63 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x64 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x65 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x66 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x67 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x68 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x69 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x6a }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x6b }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x6c }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x6d }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x6e }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x6f }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x70 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x71 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x72 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x73 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x74 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x75 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x76 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x77 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x78 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x79 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x7a }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x7b }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x7c }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x7d }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x7e }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x7f }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x80 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x81 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x82 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x83 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x84 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x85 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x86 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x87 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x88 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x89 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x8a }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x8b }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x8c }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x8d }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x8e }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x8f }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x90 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x91 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x92 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x93 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x94 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x95 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x96 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x97 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x98 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x99 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x9a }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x9b }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x9c }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x9d }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x9e }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0x9f }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa0 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa1 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa2 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa3 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa4 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa5 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa6 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa7 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa8 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xa9 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xaa }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xab }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xac }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xad }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xae }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xaf }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb0 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb1 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb2 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb3 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb4 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb5 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb6 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb7 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb8 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xb9 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xba }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xbb }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xbc }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xbd }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xbe }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xbf }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc0 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc1 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc2 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc3 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc4 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc5 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc6 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc7 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc8 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xc9 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xca }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xcb }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xcc }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xcd }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xce }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xcf }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd0 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd1 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd2 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd3 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd4 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd5 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd6 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd7 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd8 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xd9 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xda }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xdb }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xdc }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xdd }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xde }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xdf }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe0 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe1 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe2 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe3 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe4 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe5 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe6 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe7 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe8 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xe9 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xea }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xeb }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xec }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xed }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xee }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xef }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf0 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf1 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf2 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf3 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf4 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf5 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf6 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf7 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf8 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xf9 }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xfa }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xfb }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xfc }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xfd }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xfe }, { 0xf, 0x00 }, +{ WAIT_IDLE }, { 0xe, 0xff }, { 0xf, 0x00 }, + +/* load page zero */ +{ 0x9, 0x05 }, { 0xb, 0x00 }, { 0xa, 0x00 }, + +{ 0xd, 0x01 }, { 0xc, 0x7c }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x1e }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0xf5 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x11 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x32 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x13 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x14 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0x76 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x60 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x80 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x18 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x19 }, { WAIT_IDLE }, +{ 0xd, 0x01 }, { 0xc, 0x1a }, { WAIT_IDLE }, +{ 0xd, 0x01 }, { 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xd, 0x01 }, { 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xd, 0x01 }, { 0xc, 0x17 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x01 }, { 0xc, 0x80 }, { WAIT_IDLE }, +{ 0xd, 0x01 }, { 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x10 }, { WAIT_IDLE }, +{ 0xd, 0x01 }, { 0xc, 0xa0 }, { WAIT_IDLE }, +{ 0xd, 0x03 }, { 0xc, 0xd1 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x01 }, { 0xc, 0xf2 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x13 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0xf4 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0xe0 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x15 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x16 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x17 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x50 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x71 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x60 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x92 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x80 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0xb3 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0xa0 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0xd4 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x80 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0xf5 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x70 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0xa0 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0x11 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x16 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x10 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x17 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x1b }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x1d }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0xdf }, { WAIT_IDLE }, + +/* Now load page one */ +{ 0x9, 0x05 }, { 0xb, 0x01 }, { 0xa, 0x00 }, + +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x19 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x1f }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x03 }, { 0xc, 0xd8 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x19 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x18 }, { WAIT_IDLE }, +{ 0xd, 0x01 }, { 0xc, 0xc0 }, { WAIT_IDLE }, +{ 0xd, 0x01 }, { 0xc, 0xfa }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x1a }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0x60 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0xc0 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0x80 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0xfb }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0xa0 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x1b }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0xd7 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0xf7 }, { WAIT_IDLE }, +{ 0xd, 0x03 }, { 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xd, 0x03 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x1c }, { WAIT_IDLE }, +{ 0xd, 0x03 }, { 0xc, 0x3c }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x03 }, { 0xc, 0x3f }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x03 }, { 0xc, 0xc0 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x03 }, { 0xc, 0xdf }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x03 }, { 0xc, 0x5d }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x03 }, { 0xc, 0xc0 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x03 }, { 0xc, 0x7d }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x03 }, { 0xc, 0xc0 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x03 }, { 0xc, 0x9e }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x03 }, { 0xc, 0xc0 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x03 }, { 0xc, 0xbe }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x03 }, { 0xc, 0xc0 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x1b }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0xdb }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0xdb }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0xe0 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0xfb }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0xc0 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0xfb }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0x60 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x1b }, { WAIT_IDLE }, + +{ 0x9, 0x05 }, { 0xb, 0x02 }, { 0xa, 0x00 }, + +{ 0xc, 0xc4 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x44 }, { WAIT_IDLE }, +{ 0xc, 0x07 }, { WAIT_IDLE }, +{ 0xc, 0x44 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xc, 0x25 }, { WAIT_IDLE }, +{ 0xc, 0x01 }, { WAIT_IDLE }, +{ 0xc, 0x06 }, { WAIT_IDLE }, +{ 0xc, 0xc4 }, { WAIT_IDLE }, +{ 0xc, 0x07 }, { WAIT_IDLE }, +{ 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xc, 0x25 }, { WAIT_IDLE }, +{ 0xc, 0x01 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x46 }, { WAIT_IDLE }, +{ 0xc, 0x46 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x46 }, { WAIT_IDLE }, +{ 0xc, 0x07 }, { WAIT_IDLE }, +{ 0xc, 0x05 }, { WAIT_IDLE }, +{ 0xc, 0x05 }, { WAIT_IDLE }, +{ 0xc, 0x05 }, { WAIT_IDLE }, +{ 0xc, 0x04 }, { WAIT_IDLE }, +{ 0xc, 0x07 }, { WAIT_IDLE }, +{ 0xc, 0x05 }, { WAIT_IDLE }, +{ 0xc, 0x04 }, { WAIT_IDLE }, +{ 0xc, 0x07 }, { WAIT_IDLE }, +{ 0xc, 0x05 }, { WAIT_IDLE }, +{ 0xc, 0x44 }, { WAIT_IDLE }, +{ 0xc, 0x46 }, { WAIT_IDLE }, +{ 0xc, 0x44 }, { WAIT_IDLE }, +{ 0xc, 0x46 }, { WAIT_IDLE }, +{ 0xc, 0x46 }, { WAIT_IDLE }, +{ 0xc, 0x07 }, { WAIT_IDLE }, +{ 0xc, 0x05 }, { WAIT_IDLE }, +{ 0xc, 0x44 }, { WAIT_IDLE }, +{ 0xc, 0x46 }, { WAIT_IDLE }, +{ 0xc, 0x05 }, { WAIT_IDLE }, +{ 0xc, 0x46 }, { WAIT_IDLE }, +{ 0xc, 0x05 }, { WAIT_IDLE }, +{ 0xc, 0x46 }, { WAIT_IDLE }, +{ 0xc, 0x05 }, { WAIT_IDLE }, +{ 0xc, 0x46 }, { WAIT_IDLE }, +{ 0xc, 0x05 }, { WAIT_IDLE }, +{ 0xc, 0x44 }, { WAIT_IDLE }, +{ 0xc, 0x46 }, { WAIT_IDLE }, +{ 0xc, 0x05 }, { WAIT_IDLE }, +{ 0xc, 0x07 }, { WAIT_IDLE }, +{ 0xc, 0x44 }, { WAIT_IDLE }, +{ 0xc, 0x46 }, { WAIT_IDLE }, +{ 0xc, 0x05 }, { WAIT_IDLE }, +{ 0xc, 0x07 }, { WAIT_IDLE }, +{ 0xc, 0x44 }, { WAIT_IDLE }, +{ 0xc, 0x46 }, { WAIT_IDLE }, +{ 0xc, 0x05 }, { WAIT_IDLE }, +{ 0xc, 0x07 }, { WAIT_IDLE }, +{ 0xc, 0x44 }, { WAIT_IDLE }, +{ 0xc, 0x46 }, { WAIT_IDLE }, +{ 0xc, 0x05 }, { WAIT_IDLE }, +{ 0xc, 0x07 }, { WAIT_IDLE }, +{ 0xc, 0x44 }, { WAIT_IDLE }, +{ 0xc, 0x05 }, { WAIT_IDLE }, +{ 0xc, 0x05 }, { WAIT_IDLE }, +{ 0xc, 0x05 }, { WAIT_IDLE }, +{ 0xc, 0x44 }, { WAIT_IDLE }, +{ 0xc, 0x05 }, { WAIT_IDLE }, +{ 0xc, 0x05 }, { WAIT_IDLE }, +{ 0xc, 0x05 }, { WAIT_IDLE }, +{ 0xc, 0x46 }, { WAIT_IDLE }, +{ 0xc, 0x05 }, { WAIT_IDLE }, +{ 0xc, 0x46 }, { WAIT_IDLE }, +{ 0xc, 0x05 }, { WAIT_IDLE }, +{ 0xc, 0x46 }, { WAIT_IDLE }, +{ 0xc, 0x05 }, { WAIT_IDLE }, +{ 0xc, 0x46 }, { WAIT_IDLE }, +{ 0xc, 0x05 }, { WAIT_IDLE }, +{ 0xc, 0x46 }, { WAIT_IDLE }, +{ 0xc, 0x07 }, { WAIT_IDLE }, +{ 0xc, 0x46 }, { WAIT_IDLE }, +{ 0xc, 0x07 }, { WAIT_IDLE }, +{ 0xc, 0x44 }, { WAIT_IDLE }, + +{ 0x9, 0x05 }, { 0xb, 0x03 }, { 0xa, 0x00 }, + +{ 0xc, 0x07 }, { WAIT_IDLE }, +{ 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x47 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xc, 0x06 }, { WAIT_IDLE }, +{ 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x80 }, { WAIT_IDLE }, +{ 0xc, 0x80 }, { WAIT_IDLE }, +{ 0xc, 0xc0 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x60 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x70 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x42 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x02 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x42 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x42 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x02 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x02 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x02 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x42 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0xc0 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x40 }, { WAIT_IDLE }, + +{ 0x9, 0x05 }, { 0xb, 0x04 }, { 0xa, 0x00 }, + +{ 0xc, 0x63 }, { WAIT_IDLE }, +{ 0xc, 0x03 }, { WAIT_IDLE }, +{ 0xc, 0x26 }, { WAIT_IDLE }, +{ 0xc, 0x02 }, { WAIT_IDLE }, +{ 0xc, 0x2c }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x24 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x2e }, { WAIT_IDLE }, +{ 0xc, 0x02 }, { WAIT_IDLE }, +{ 0xc, 0x02 }, { WAIT_IDLE }, +{ 0xc, 0x02 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x01 }, { WAIT_IDLE }, +{ 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x60 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x60 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x60 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x60 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x60 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x60 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x60 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x22 }, { WAIT_IDLE }, +{ 0xc, 0x02 }, { WAIT_IDLE }, +{ 0xc, 0x22 }, { WAIT_IDLE }, +{ 0xc, 0x02 }, { WAIT_IDLE }, +{ 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x60 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x22 }, { WAIT_IDLE }, +{ 0xc, 0x02 }, { WAIT_IDLE }, +{ 0xc, 0x62 }, { WAIT_IDLE }, +{ 0xc, 0x02 }, { WAIT_IDLE }, +{ 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xc, 0x01 }, { WAIT_IDLE }, +{ 0xc, 0x21 }, { WAIT_IDLE }, +{ 0xc, 0x01 }, { WAIT_IDLE }, + +/* Load memory area (page six) */ +{ 0x9, 0x01 }, { 0xb, 0x06 }, + +{ 0xa, 0x00 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x02 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x04 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x06 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x08 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x0a }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x0c }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x0e }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x10 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x12 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x14 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x16 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x18 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x1a }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x1c }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x1e }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x20 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x22 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x24 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x26 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x28 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x2a }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x2c }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x2e }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x30 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x32 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x34 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x36 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x38 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x3a }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x3c }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x3e }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x40 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x42 }, { 0xd, 0x03 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x44 }, { 0xd, 0x01 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x46 }, { 0xd, 0x0a }, { 0xc, 0x21 }, { WAIT_IDLE }, +{ 0xa, 0x48 }, { 0xd, 0x0d }, { 0xc, 0x23 }, { WAIT_IDLE }, +{ 0xa, 0x4a }, { 0xd, 0x23 }, { 0xc, 0x1b }, { WAIT_IDLE }, +{ 0xa, 0x4c }, { 0xd, 0x37 }, { 0xc, 0x8f }, { WAIT_IDLE }, +{ 0xa, 0x4e }, { 0xd, 0x45 }, { 0xc, 0x77 }, { WAIT_IDLE }, +{ 0xa, 0x50 }, { 0xd, 0x52 }, { 0xc, 0xe2 }, { WAIT_IDLE }, +{ 0xa, 0x52 }, { 0xd, 0x1c }, { 0xc, 0x92 }, { WAIT_IDLE }, +{ 0xa, 0x54 }, { 0xd, 0x1c }, { 0xc, 0x52 }, { WAIT_IDLE }, +{ 0xa, 0x56 }, { 0xd, 0x07 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x58 }, { 0xd, 0x2f }, { 0xc, 0xc6 }, { WAIT_IDLE }, +{ 0xa, 0x5a }, { 0xd, 0x0b }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x5c }, { 0xd, 0x30 }, { 0xc, 0x06 }, { WAIT_IDLE }, +{ 0xa, 0x5e }, { 0xd, 0x17 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x60 }, { 0xd, 0x3d }, { 0xc, 0xda }, { WAIT_IDLE }, +{ 0xa, 0x62 }, { 0xd, 0x29 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x64 }, { 0xd, 0x3e }, { 0xc, 0x41 }, { WAIT_IDLE }, +{ 0xa, 0x66 }, { 0xd, 0x39 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x68 }, { 0xd, 0x4c }, { 0xc, 0x48 }, { WAIT_IDLE }, +{ 0xa, 0x6a }, { 0xd, 0x49 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x6c }, { 0xd, 0x4c }, { 0xc, 0x6c }, { WAIT_IDLE }, +{ 0xa, 0x6e }, { 0xd, 0x11 }, { 0xc, 0xd2 }, { WAIT_IDLE }, +{ 0xa, 0x70 }, { 0xd, 0x16 }, { 0xc, 0x0c }, { WAIT_IDLE }, +{ 0xa, 0x72 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x74 }, { 0xd, 0x00 }, { 0xc, 0x80 }, { WAIT_IDLE }, +{ 0xa, 0x76 }, { 0xd, 0x0f }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x78 }, { 0xd, 0x00 }, { 0xc, 0x80 }, { WAIT_IDLE }, +{ 0xa, 0x7a }, { 0xd, 0x13 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x7c }, { 0xd, 0x80 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x7e }, { 0xd, 0x80 }, { 0xc, 0x80 }, { WAIT_IDLE }, + +{ 0x9, 0x05 }, { 0xb, 0x07 }, { 0xa, 0x00 }, + +{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x08 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x08 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x08 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x08 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, +{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, +{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, +{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, +{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0xe9 }, { WAIT_IDLE }, +{ 0xd, 0x06 }, { 0xc, 0x8c }, { WAIT_IDLE }, +{ 0xd, 0x06 }, { 0xc, 0x8c }, { WAIT_IDLE }, +{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, +{ 0xd, 0x1a }, { 0xc, 0x75 }, { WAIT_IDLE }, +{ 0xd, 0x0d }, { 0xc, 0x8b }, { WAIT_IDLE }, +{ 0xd, 0x04 }, { 0xc, 0xe9 }, { WAIT_IDLE }, +{ 0xd, 0x0b }, { 0xc, 0x16 }, { WAIT_IDLE }, +{ 0xd, 0x1a }, { 0xc, 0x38 }, { WAIT_IDLE }, +{ 0xd, 0x0d }, { 0xc, 0xc8 }, { WAIT_IDLE }, +{ 0xd, 0x04 }, { 0xc, 0x6f }, { WAIT_IDLE }, +{ 0xd, 0x0b }, { 0xc, 0x91 }, { WAIT_IDLE }, +{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, +{ 0xd, 0x06 }, { 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xd, 0x06 }, { 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0x8f }, { WAIT_IDLE }, +{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, +{ 0xd, 0x06 }, { 0xc, 0x62 }, { WAIT_IDLE }, +{ 0xd, 0x06 }, { 0xc, 0x62 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0x7b }, { WAIT_IDLE }, +{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, +{ 0xd, 0x06 }, { 0xc, 0x97 }, { WAIT_IDLE }, +{ 0xd, 0x06 }, { 0xc, 0x97 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0x52 }, { WAIT_IDLE }, +{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, +{ 0xd, 0x06 }, { 0xc, 0xf6 }, { WAIT_IDLE }, +{ 0xd, 0x06 }, { 0xc, 0xf6 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0x19 }, { WAIT_IDLE }, +{ 0xd, 0x05 }, { 0xc, 0x55 }, { WAIT_IDLE }, +{ 0xd, 0x05 }, { 0xc, 0x55 }, { WAIT_IDLE }, +{ 0xd, 0x05 }, { 0xc, 0x55 }, { WAIT_IDLE }, +{ 0xd, 0x05 }, { 0xc, 0x55 }, { WAIT_IDLE }, +{ 0xd, 0x05 }, { 0xc, 0x55 }, { WAIT_IDLE }, +{ 0xd, 0x05 }, { 0xc, 0x55 }, { WAIT_IDLE }, +{ 0xd, 0x05 }, { 0xc, 0x55 }, { WAIT_IDLE }, +{ 0xd, 0x05 }, { 0xc, 0x55 }, { WAIT_IDLE }, +{ 0xd, 0x14 }, { 0xc, 0xda }, { WAIT_IDLE }, +{ 0xd, 0x0d }, { 0xc, 0x93 }, { WAIT_IDLE }, +{ 0xd, 0x04 }, { 0xc, 0xda }, { WAIT_IDLE }, +{ 0xd, 0x05 }, { 0xc, 0x93 }, { WAIT_IDLE }, +{ 0xd, 0x14 }, { 0xc, 0xda }, { WAIT_IDLE }, +{ 0xd, 0x0d }, { 0xc, 0x93 }, { WAIT_IDLE }, +{ 0xd, 0x04 }, { 0xc, 0xda }, { WAIT_IDLE }, +{ 0xd, 0x05 }, { 0xc, 0x93 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0x00 }, { WAIT_IDLE }, + +/* Now setup the MOD area. */ +{ 0xe, 0x01 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x01 }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x02 }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x03 }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x04 }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x05 }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x06 }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x07 }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x08 }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x09 }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x0a }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x0b }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x0c }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x0d }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x0e }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x0f }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, + +{ 0xe, 0xb0 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xb1 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xb2 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xb3 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xb4 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xb5 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xb6 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xb7 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xb8 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xb9 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xba }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xbb }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xbc }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xbd }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xbe }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xbf }, { 0xf, 0x20 }, { WAIT_IDLE }, + +{ 0xe, 0xf0 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xf1 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xf2 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xf3 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xf4 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xf5 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xf6 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xf7 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xf8 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xf9 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xfa }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xfb }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xfc }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xfd }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xfe }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xff }, { 0xf, 0x20 }, { WAIT_IDLE }, + +{ 0xe, 0x10 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x11 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x12 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x13 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x14 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x15 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x16 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x17 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x18 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x19 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x1a }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x1b }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x1c }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x1d }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x1e }, { 0xf, 0x40 }, { WAIT_IDLE }, +{ 0xe, 0x1f }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x20 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x21 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x22 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x23 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x24 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x25 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x26 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x27 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x28 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x29 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x2a }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x2b }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x2c }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x2d }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x2e }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x2f }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x30 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x31 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x32 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x33 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x34 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x35 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x36 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x37 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x38 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x39 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x3a }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x3b }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x3c }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x3d }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x3e }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x3f }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0x40 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x41 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x42 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x43 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x44 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x45 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x46 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x47 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x48 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x49 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x4a }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x4b }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x4c }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x4d }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x4e }, { 0xf, 0x0e }, { WAIT_IDLE }, +{ 0xe, 0x4f }, { 0xf, 0x0e }, { WAIT_IDLE }, +{ 0xe, 0x50 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x51 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x52 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x53 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x54 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x55 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x56 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x57 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x58 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x59 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x5a }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x5b }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x5c }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x5d }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x5e }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x5f }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x60 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x61 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x62 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x63 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x64 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x65 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x66 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x67 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x68 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x69 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x6a }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x6b }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x6c }, { 0xf, 0x40 }, { WAIT_IDLE }, +{ 0xe, 0x6d }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x6e }, { 0xf, 0x40 }, { WAIT_IDLE }, +{ 0xe, 0x6f }, { 0xf, 0x40 }, { WAIT_IDLE }, +{ 0xe, 0x70 }, { 0xf, 0xc0 }, { WAIT_IDLE }, +{ 0xe, 0x71 }, { 0xf, 0xc0 }, { WAIT_IDLE }, +{ 0xe, 0x72 }, { 0xf, 0xc0 }, { WAIT_IDLE }, +{ 0xe, 0x73 }, { 0xf, 0xc0 }, { WAIT_IDLE }, +{ 0xe, 0x74 }, { 0xf, 0xc0 }, { WAIT_IDLE }, +{ 0xe, 0x75 }, { 0xf, 0xc0 }, { WAIT_IDLE }, +{ 0xe, 0x76 }, { 0xf, 0xc0 }, { WAIT_IDLE }, +{ 0xe, 0x77 }, { 0xf, 0xc0 }, { WAIT_IDLE }, +{ 0xe, 0x78 }, { 0xf, 0xc0 }, { WAIT_IDLE }, +{ 0xe, 0x79 }, { 0xf, 0xc0 }, { WAIT_IDLE }, +{ 0xe, 0x7a }, { 0xf, 0xc0 }, { WAIT_IDLE }, +{ 0xe, 0x7b }, { 0xf, 0xc0 }, { WAIT_IDLE }, +{ 0xe, 0x7c }, { 0xf, 0xc0 }, { WAIT_IDLE }, +{ 0xe, 0x7d }, { 0xf, 0xc0 }, { WAIT_IDLE }, +{ 0xe, 0x7e }, { 0xf, 0xc0 }, { WAIT_IDLE }, +{ 0xe, 0x7f }, { 0xf, 0xc0 }, { WAIT_IDLE }, +{ 0xe, 0x80 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x81 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x82 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x83 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x84 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x85 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x86 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x87 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x88 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x89 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x8a }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x8b }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x8c }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x8d }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x8e }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x8f }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x90 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x91 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x92 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x93 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x94 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x95 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x96 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x97 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x98 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x99 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x9a }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x9b }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x9c }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x9d }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x9e }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x9f }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xa0 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xa1 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xa2 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xa3 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xa4 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xa5 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xa6 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xa7 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xa8 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xa9 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xaa }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xab }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xac }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xad }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xae }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xaf }, { 0xf, 0x00 }, { WAIT_IDLE }, + +{ 0xe, 0xc0 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xc1 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xc2 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xc3 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xc4 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xc5 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xc6 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xc7 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xc8 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xc9 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xca }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xcb }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xcc }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xcd }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xce }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xcf }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xd0 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xd1 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xd2 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xd3 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xd4 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xd5 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xd6 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xd7 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xd8 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xd9 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xda }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xdb }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xdc }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xdd }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xde }, { 0xf, 0x10 }, { WAIT_IDLE }, +{ 0xe, 0xdf }, { 0xf, 0x10 }, { WAIT_IDLE }, +{ 0xe, 0xe0 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xe1 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xe2 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xe3 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xe4 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xe5 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xe6 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xe7 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xe8 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xe9 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xea }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xeb }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xec }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xed }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xee }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xef }, { 0xf, 0x00 }, { WAIT_IDLE }, + +{ 0xe, 0x01 }, { 0xf, 0x00 }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x01 }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x02 }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x03 }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x04 }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x05 }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x06 }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x07 }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x08 }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x09 }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x0a }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x0b }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x0c }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x0d }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x0e }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x0f }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, + +/* mute on */ +{ 0x8, 0x02 }, + +/* Now set the coefficients and so forth for the programs above */ +{ 0xb, 0x07 }, { 0xa, 0x46 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x49 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x00 }, { 0xa, 0x4b }, { 0xd, 0x03 }, { 0xc, 0x11 }, { WAIT_IDLE }, +{ 0xb, 0x00 }, { 0xa, 0x4d }, { 0xd, 0x01 }, { 0xc, 0x32 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x46 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x49 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x40 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x41 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x01 }, { 0xa, 0x40 }, { 0xd, 0x02 }, { 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xb, 0x01 }, { 0xa, 0x41 }, { 0xd, 0x02 }, { 0xc, 0x60 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x40 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x41 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x47 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x4a }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x00 }, { 0xa, 0x47 }, { 0xd, 0x01 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x00 }, { 0xa, 0x4a }, { 0xd, 0x01 }, { 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x47 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x4a }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x7c }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x7e }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x00 }, { 0xa, 0x00 }, { 0xd, 0x01 }, { 0xc, 0x1c }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x7c }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x7e }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x44 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x00 }, { 0xa, 0x44 }, { 0xd, 0x01 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x44 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x42 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x43 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x00 }, { 0xa, 0x42 }, { 0xd, 0x01 }, { 0xc, 0x1a }, { WAIT_IDLE }, +{ 0xb, 0x00 }, { 0xa, 0x43 }, { 0xd, 0x01 }, { 0xc, 0x20 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x42 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x43 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x40 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x41 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x01 }, { 0xa, 0x40 }, { 0xd, 0x02 }, { 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xb, 0x01 }, { 0xa, 0x41 }, { 0xd, 0x02 }, { 0xc, 0x60 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x40 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x41 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x44 }, { 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x42 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x43 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x40 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x41 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x51 }, { 0xd, 0x06 }, { 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x50 }, { 0xd, 0x06 }, { 0xc, 0x40 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x4f }, { 0xd, 0x03 }, { 0xc, 0x81 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x53 }, { 0xd, 0x1a }, { 0xc, 0x76 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x54 }, { 0xd, 0x0d }, { 0xc, 0x8b }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x55 }, { 0xd, 0x04 }, { 0xc, 0xe9 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x56 }, { 0xd, 0x0b }, { 0xc, 0x17 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x57 }, { 0xd, 0x1a }, { 0xc, 0x38 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x58 }, { 0xd, 0x0d }, { 0xc, 0xc9 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x59 }, { 0xd, 0x04 }, { 0xc, 0x6f }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x5a }, { 0xd, 0x0b }, { 0xc, 0x91 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x73 }, { 0xd, 0x14 }, { 0xc, 0xda }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x74 }, { 0xd, 0x0d }, { 0xc, 0x93 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x75 }, { 0xd, 0x04 }, { 0xc, 0xd9 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x76 }, { 0xd, 0x05 }, { 0xc, 0x93 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x77 }, { 0xd, 0x14 }, { 0xc, 0xda }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x78 }, { 0xd, 0x0d }, { 0xc, 0x93 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x79 }, { 0xd, 0x04 }, { 0xc, 0xd9 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x7a }, { 0xd, 0x05 }, { 0xc, 0x93 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x5e }, { 0xd, 0x03 }, { 0xc, 0x68 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x5c }, { 0xd, 0x04 }, { 0xc, 0x31 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x5d }, { 0xd, 0x04 }, { 0xc, 0x31 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x62 }, { 0xd, 0x03 }, { 0xc, 0x52 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x60 }, { 0xd, 0x04 }, { 0xc, 0x76 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x61 }, { 0xd, 0x04 }, { 0xc, 0x76 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x66 }, { 0xd, 0x03 }, { 0xc, 0x2e }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x64 }, { 0xd, 0x04 }, { 0xc, 0xda }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x65 }, { 0xd, 0x04 }, { 0xc, 0xda }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x6a }, { 0xd, 0x02 }, { 0xc, 0xf6 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x68 }, { 0xd, 0x05 }, { 0xc, 0x62 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x69 }, { 0xd, 0x05 }, { 0xc, 0x62 }, { WAIT_IDLE }, +{ 0xb, 0x06 }, { 0xa, 0x46 }, { 0xd, 0x0a }, { 0xc, 0x22 }, { WAIT_IDLE }, +{ 0xb, 0x06 }, { 0xa, 0x48 }, { 0xd, 0x0d }, { 0xc, 0x24 }, { WAIT_IDLE }, +{ 0xb, 0x06 }, { 0xa, 0x6e }, { 0xd, 0x11 }, { 0xc, 0xd3 }, { WAIT_IDLE }, +{ 0xb, 0x06 }, { 0xa, 0x70 }, { 0xd, 0x15 }, { 0xc, 0xcb }, { WAIT_IDLE }, +{ 0xb, 0x06 }, { 0xa, 0x52 }, { 0xd, 0x20 }, { 0xc, 0x93 }, { WAIT_IDLE }, +{ 0xb, 0x06 }, { 0xa, 0x54 }, { 0xd, 0x20 }, { 0xc, 0x54 }, { WAIT_IDLE }, +{ 0xb, 0x06 }, { 0xa, 0x4a }, { 0xd, 0x27 }, { 0xc, 0x1d }, { WAIT_IDLE }, +{ 0xb, 0x06 }, { 0xa, 0x58 }, { 0xd, 0x2f }, { 0xc, 0xc8 }, { WAIT_IDLE }, +{ 0xb, 0x06 }, { 0xa, 0x5c }, { 0xd, 0x30 }, { 0xc, 0x07 }, { WAIT_IDLE }, +{ 0xb, 0x06 }, { 0xa, 0x4c }, { 0xd, 0x37 }, { 0xc, 0x90 }, { WAIT_IDLE }, +{ 0xb, 0x06 }, { 0xa, 0x60 }, { 0xd, 0x3d }, { 0xc, 0xdb }, { WAIT_IDLE }, +{ 0xb, 0x06 }, { 0xa, 0x64 }, { 0xd, 0x3e }, { 0xc, 0x42 }, { WAIT_IDLE }, +{ 0xb, 0x06 }, { 0xa, 0x4e }, { 0xd, 0x45 }, { 0xc, 0x78 }, { WAIT_IDLE }, +{ 0xb, 0x06 }, { 0xa, 0x68 }, { 0xd, 0x4c }, { 0xc, 0x48 }, { WAIT_IDLE }, +{ 0xb, 0x06 }, { 0xa, 0x6c }, { 0xd, 0x4c }, { 0xc, 0x6c }, { WAIT_IDLE }, +{ 0xb, 0x06 }, { 0xa, 0x50 }, { 0xd, 0x52 }, { 0xc, 0xe2 }, { WAIT_IDLE }, +{ 0xb, 0x06 }, { 0xa, 0x42 }, { 0xd, 0x02 }, { 0xc, 0xba }, { WAIT_IDLE }, + +/* Some settings (?) */ +{ WAIT_IDLE }, { 0xe, 0x1e }, { 0xf, 0x14 }, +{ WAIT_IDLE }, { 0xe, 0xde }, { 0xf, 0x20 }, +{ WAIT_IDLE }, { 0xe, 0xdf }, { 0xf, 0x20 }, + +/* some more coefficients */ +{ WAIT_IDLE }, { 0xb, 0x06 }, { 0xa, 0x78 }, { 0xd, 0x00 }, { 0xc, 0x40 }, +{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x03 }, { 0xd, 0x0f }, { 0xc, 0xff }, +{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x0b }, { 0xd, 0x0f }, { 0xc, 0xff }, +{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x02 }, { 0xd, 0x00 }, { 0xc, 0x00 }, +{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x0a }, { 0xd, 0x00 }, { 0xc, 0x00 }, +{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x46 }, { 0xd, 0x00 }, { 0xc, 0x00 }, +{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x49 }, { 0xd, 0x00 }, { 0xc, 0x00 }, + +/* Now, for some strange reason, lets reload every page + and all the coefficients over again. I have *NO* idea + why this is done. I do know that no sound is produced + is this phase is omitted. */ +{ 0x9, 0x05 }, { 0xb, 0x00 }, { 0xa, 0x10 }, + +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x02 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, + +{ 0x9, 0x05 }, { 0xb, 0x01 }, { 0xa, 0x10 }, + +{ 0xd, 0x01 }, { 0xc, 0xc0 }, { WAIT_IDLE }, +{ 0xd, 0x01 }, { 0xc, 0xfa }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x1a }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, + +{ WAIT_IDLE }, { WAIT_IDLE }, + +{ 0x9, 0x05 }, { 0xb, 0x02 }, { 0xa, 0x10 }, + +{ 0xc, 0x46 }, { WAIT_IDLE }, +{ 0xc, 0x46 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, + +{ 0x9, 0x05 }, { 0xb, 0x03 }, { 0xa, 0x10 }, + +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, + +{ 0x9, 0x05 }, { 0xb, 0x04 }, { 0xa, 0x10 }, + +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xc, 0x00 }, { WAIT_IDLE }, + +/* Page six v.2 */ +{ 0x9, 0x01 }, { 0xb, 0x06 }, + +{ 0xa, 0x10 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x12 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x14 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x16 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x18 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x1a }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x1c }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x1e }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x20 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x22 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x24 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x26 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x28 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x2a }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x2c }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x2e }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x30 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x32 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x34 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x36 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x38 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x3a }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x3c }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xa, 0x3e }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, + +{ 0x9, 0x05 }, { 0xb, 0x07 }, { 0xa, 0x10 }, + +{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, +{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, + +{ 0xe, 0x01 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x01 }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x02 }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x03 }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x04 }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x05 }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x06 }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x07 }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xb0 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xb1 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xb2 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xb3 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xb4 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xb5 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xb6 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xb7 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xf0 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xf1 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xf2 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xf3 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xf4 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xf5 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xf6 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0xf7 }, { 0xf, 0x20 }, { WAIT_IDLE }, +{ 0xe, 0x10 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x11 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x12 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x13 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x14 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x15 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x16 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x17 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x20 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x21 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x22 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x23 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x24 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x25 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x26 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x27 }, { 0xf, 0xff }, { WAIT_IDLE }, +{ 0xe, 0x30 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x31 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x32 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x33 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x34 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x35 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x36 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x37 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x40 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x41 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x42 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x43 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x44 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x45 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x46 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x47 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x50 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x51 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x52 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x53 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x54 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x55 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x56 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x57 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x60 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x61 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x62 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x63 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x64 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x65 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x66 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x67 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x70 }, { 0xf, 0xc0 }, { WAIT_IDLE }, +{ 0xe, 0x71 }, { 0xf, 0xc0 }, { WAIT_IDLE }, +{ 0xe, 0x72 }, { 0xf, 0xc0 }, { WAIT_IDLE }, +{ 0xe, 0x73 }, { 0xf, 0xc0 }, { WAIT_IDLE }, +{ 0xe, 0x74 }, { 0xf, 0xc0 }, { WAIT_IDLE }, +{ 0xe, 0x75 }, { 0xf, 0xc0 }, { WAIT_IDLE }, +{ 0xe, 0x76 }, { 0xf, 0xc0 }, { WAIT_IDLE }, +{ 0xe, 0x77 }, { 0xf, 0xc0 }, { WAIT_IDLE }, +{ 0xe, 0x80 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x81 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x82 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x83 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x84 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x85 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x86 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x87 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x90 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x91 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x92 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x93 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x94 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x95 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x96 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x97 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xa0 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xa1 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xa2 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xa3 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xa4 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xa5 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xa6 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xa7 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xc0 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xc1 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xc2 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xc3 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xc4 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xc5 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xc6 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xc7 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xd0 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xd1 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xd2 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xd3 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xd4 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xd5 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xd6 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xd7 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xe0 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xe1 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xe2 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xe3 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xe4 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xe5 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xe6 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0xe7 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x00 }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x01 }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x02 }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x03 }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x04 }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x05 }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x06 }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, +{ 0xe, 0x01 }, { 0xf, 0x07 }, { WAIT_IDLE }, +{ 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE }, + +{ 0xb, 0x07 }, { 0xa, 0x46 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x49 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x45 }, { 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x48 }, { 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x7b }, { 0xd, 0x04 }, { 0xc, 0xcc }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x7d }, { 0xd, 0x04 }, { 0xc, 0xcc }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x7c }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x7e }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x46 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x49 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x47 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x4a }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE }, + +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x00 }, { 0xc, 0x00 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x00 }, { 0xc, 0x00 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x00 }, { 0xc, 0x28 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x00 }, { 0xc, 0x28 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x00 }, { 0xc, 0x51 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x00 }, { 0xc, 0x51 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x00 }, { 0xc, 0x7a }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x00 }, { 0xc, 0x7a }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x00 }, { 0xc, 0xa3 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x00 }, { 0xc, 0xa3 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x00 }, { 0xc, 0xcc }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x00 }, { 0xc, 0xcc }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x00 }, { 0xc, 0xf5 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x00 }, { 0xc, 0xf5 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x01 }, { 0xc, 0x1e }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x01 }, { 0xc, 0x1e }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x01 }, { 0xc, 0x47 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x01 }, { 0xc, 0x47 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x01 }, { 0xc, 0x70 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x01 }, { 0xc, 0x70 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x01 }, { 0xc, 0x99 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x01 }, { 0xc, 0x99 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x01 }, { 0xc, 0xc2 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x01 }, { 0xc, 0xc2 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x01 }, { 0xc, 0xeb }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x01 }, { 0xc, 0xeb }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x02 }, { 0xc, 0x14 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x02 }, { 0xc, 0x14 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x02 }, { 0xc, 0x3d }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x02 }, { 0xc, 0x3d }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x02 }, { 0xc, 0x66 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x02 }, { 0xc, 0x66 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x02 }, { 0xc, 0x8f }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x02 }, { 0xc, 0x8f }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x02 }, { 0xc, 0xb8 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x02 }, { 0xc, 0xb8 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x02 }, { 0xc, 0xe1 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x02 }, { 0xc, 0xe1 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x03 }, { 0xc, 0x0a }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x03 }, { 0xc, 0x0a }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x03 }, { 0xc, 0x33 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x03 }, { 0xc, 0x33 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x03 }, { 0xc, 0x5c }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x03 }, { 0xc, 0x5c }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x03 }, { 0xc, 0x85 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x03 }, { 0xc, 0x85 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x03 }, { 0xc, 0xae }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x03 }, { 0xc, 0xae }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x03 }, { 0xc, 0xd7 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x03 }, { 0xc, 0xd7 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x04 }, { 0xc, 0x00 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x04 }, { 0xc, 0x00 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x04 }, { 0xc, 0x28 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x04 }, { 0xc, 0x28 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x04 }, { 0xc, 0x51 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x04 }, { 0xc, 0x51 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x04 }, { 0xc, 0x7a }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x04 }, { 0xc, 0x7a }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x04 }, { 0xc, 0xa3 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x04 }, { 0xc, 0xa3 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x04 }, { 0xc, 0xcc }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x04 }, { 0xc, 0xcc }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x04 }, { 0xc, 0xf5 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x04 }, { 0xc, 0xf5 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x05 }, { 0xc, 0x1e }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x05 }, { 0xc, 0x1e }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x05 }, { 0xc, 0x47 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x05 }, { 0xc, 0x47 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x05 }, { 0xc, 0x70 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x05 }, { 0xc, 0x70 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x05 }, { 0xc, 0x99 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x05 }, { 0xc, 0x99 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x05 }, { 0xc, 0xc2 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x05 }, { 0xc, 0xc2 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x05 }, { 0xc, 0xeb }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x05 }, { 0xc, 0xeb }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x06 }, { 0xc, 0x14 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x06 }, { 0xc, 0x14 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x06 }, { 0xc, 0x3d }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x06 }, { 0xc, 0x3d }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x06 }, { 0xc, 0x66 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x06 }, { 0xc, 0x66 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x06 }, { 0xc, 0x8f }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x06 }, { 0xc, 0x8f }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x06 }, { 0xc, 0xb8 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x06 }, { 0xc, 0xb8 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x06 }, { 0xc, 0xe1 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x06 }, { 0xc, 0xe1 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x07 }, { 0xc, 0x0a }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x07 }, { 0xc, 0x0a }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x07 }, { 0xc, 0x33 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x07 }, { 0xc, 0x33 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x07 }, { 0xc, 0x5c }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x07 }, { 0xc, 0x5c }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x07 }, { 0xc, 0x85 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x07 }, { 0xc, 0x85 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x07 }, { 0xc, 0xae }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x07 }, { 0xc, 0xae }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x07 }, { 0xc, 0xd7 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x07 }, { 0xc, 0xd7 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x08 }, { 0xc, 0x00 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x08 }, { 0xc, 0x00 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x08 }, { 0xc, 0x28 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x08 }, { 0xc, 0x28 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x08 }, { 0xc, 0x51 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x08 }, { 0xc, 0x51 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x08 }, { 0xc, 0x7a }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x08 }, { 0xc, 0x7a }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x08 }, { 0xc, 0xa3 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x08 }, { 0xc, 0xa3 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x08 }, { 0xc, 0xcc }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x08 }, { 0xc, 0xcc }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x08 }, { 0xc, 0xf5 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x08 }, { 0xc, 0xf5 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x09 }, { 0xc, 0x1e }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x09 }, { 0xc, 0x1e }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x09 }, { 0xc, 0x47 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x09 }, { 0xc, 0x47 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x09 }, { 0xc, 0x70 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x09 }, { 0xc, 0x70 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x09 }, { 0xc, 0x99 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x09 }, { 0xc, 0x99 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x09 }, { 0xc, 0xc2 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x09 }, { 0xc, 0xc2 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x09 }, { 0xc, 0xeb }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x09 }, { 0xc, 0xeb }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0a }, { 0xc, 0x14 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0a }, { 0xc, 0x14 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0a }, { 0xc, 0x3d }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0a }, { 0xc, 0x3d }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0a }, { 0xc, 0x66 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0a }, { 0xc, 0x66 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0a }, { 0xc, 0x8f }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0a }, { 0xc, 0x8f }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0a }, { 0xc, 0xb8 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0a }, { 0xc, 0xb8 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0a }, { 0xc, 0xe1 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0a }, { 0xc, 0xe1 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0b }, { 0xc, 0x0a }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0b }, { 0xc, 0x0a }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0b }, { 0xc, 0x33 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0b }, { 0xc, 0x33 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0b }, { 0xc, 0x5c }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0b }, { 0xc, 0x5c }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0b }, { 0xc, 0x85 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0b }, { 0xc, 0x85 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0b }, { 0xc, 0xae }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0b }, { 0xc, 0xae }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0b }, { 0xc, 0xd7 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0b }, { 0xc, 0xd7 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0c }, { 0xc, 0x00 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0c }, { 0xc, 0x00 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0c }, { 0xc, 0x28 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0c }, { 0xc, 0x28 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0c }, { 0xc, 0x51 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0c }, { 0xc, 0x51 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0c }, { 0xc, 0x7a }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0c }, { 0xc, 0x7a }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0c }, { 0xc, 0xa3 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0c }, { 0xc, 0xa3 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0c }, { 0xc, 0xcc }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0c }, { 0xc, 0xcc }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0c }, { 0xc, 0xf5 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0c }, { 0xc, 0xf5 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0d }, { 0xc, 0x1e }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0d }, { 0xc, 0x1e }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0d }, { 0xc, 0x47 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0d }, { 0xc, 0x47 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0d }, { 0xc, 0x70 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0d }, { 0xc, 0x70 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0d }, { 0xc, 0x99 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0d }, { 0xc, 0x99 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0d }, { 0xc, 0xc2 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0d }, { 0xc, 0xc2 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0d }, { 0xc, 0xeb }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0d }, { 0xc, 0xeb }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0e }, { 0xc, 0x14 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0e }, { 0xc, 0x14 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0e }, { 0xc, 0x3d }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0e }, { 0xc, 0x3d }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0e }, { 0xc, 0x66 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0e }, { 0xc, 0x66 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0e }, { 0xc, 0x8f }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0e }, { 0xc, 0x8f }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0e }, { 0xc, 0xb8 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0e }, { 0xc, 0xb8 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0e }, { 0xc, 0xe1 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0e }, { 0xc, 0xe1 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0f }, { 0xc, 0x0a }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0f }, { 0xc, 0x0a }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0f }, { 0xc, 0x33 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0f }, { 0xc, 0x33 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0f }, { 0xc, 0x5c }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0f }, { 0xc, 0x5c }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0f }, { 0xc, 0x85 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0f }, { 0xc, 0x85 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0f }, { 0xc, 0xae }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0f }, { 0xc, 0xae }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0f }, { 0xc, 0xd7 }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0f }, { 0xc, 0xd7 }, +{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0f }, { 0xc, 0xff }, +{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0f }, { 0xc, 0xff }, + +/* mute off */ +{ 0x8, 0x00 }, { WAIT_IDLE } +}; -- cgit v1.2.3 From 226968c7afd464b794f34f9ea8cb4bcfe48447dc Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 6 Nov 2006 09:21:58 +0100 Subject: [ALSA] wavefront: add request_firmware() Load the YSS225 register initialization data using request_firmware(), if possible, instead of using the built-in data blob. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela --- sound/isa/Kconfig | 1 + sound/isa/wavefront/wavefront_fx.c | 51 ++++++++++++++++++++++++++++++-------- 2 files changed, 42 insertions(+), 10 deletions(-) (limited to 'sound') diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig index 565ed2add38..4e3a9729f56 100644 --- a/sound/isa/Kconfig +++ b/sound/isa/Kconfig @@ -391,6 +391,7 @@ config SND_SSCAPE config SND_WAVEFRONT tristate "Turtle Beach Maui,Tropez,Tropez+ (Wavefront)" depends on SND + select FW_LOADER select SND_OPL3_LIB select SND_MPU401_UART select SND_CS4231_LIB diff --git a/sound/isa/wavefront/wavefront_fx.c b/sound/isa/wavefront/wavefront_fx.c index 2e03dc504d4..15331ed8819 100644 --- a/sound/isa/wavefront/wavefront_fx.c +++ b/sound/isa/wavefront/wavefront_fx.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -34,7 +35,15 @@ #define WAIT_IDLE 0xff +#define FIRMWARE_IN_THE_KERNEL + +#ifdef FIRMWARE_IN_THE_KERNEL #include "yss225.c" +static const struct firmware yss225_registers_firmware = { + .data = (u8 *)yss225_registers, + .size = sizeof yss225_registers +}; +#endif static int wavefront_fx_idle (snd_wavefront_t *dev) @@ -248,25 +257,47 @@ int __devinit snd_wavefront_fx_start (snd_wavefront_t *dev) { unsigned int i; + int err; + const struct firmware *firmware; if (dev->fx_initialized) return 0; - for (i = 0; i < ARRAY_SIZE(yss225_registers); ++i) { - if (yss225_registers[i].addr >= 8 && - yss225_registers[i].addr < 16) { - outb(yss225_registers[i].data, - yss225_registers[i].addr + dev->base); - } else if (yss225_registers[i].addr == WAIT_IDLE) { - if (!wavefront_fx_idle(dev)) - return -1; + err = request_firmware(&firmware, "yamaha/yss225_registers.bin", + dev->card->dev); + if (err < 0) { +#ifdef FIRMWARE_IN_THE_KERNEL + firmware = &yss225_registers_firmware; +#else + err = -1; + goto out; +#endif + } + + for (i = 0; i + 1 < firmware->size; i += 2) { + if (firmware->data[i] >= 8 && firmware->data[i] < 16) { + outb(firmware->data[i + 1], + dev->base + firmware->data[i]); + } else if (firmware->data[i] == WAIT_IDLE) { + if (!wavefront_fx_idle(dev)) { + err = -1; + goto out; + } } else { snd_printk(KERN_ERR "invalid address" " in register data\n"); - return -1; + err = -1; + goto out; } } dev->fx_initialized = 1; - return (0); + err = 0; + +out: +#ifdef FIRMWARE_IN_THE_KERNEL + if (firmware != &yss225_registers_firmware) +#endif + release_firmware(firmware); + return err; } -- cgit v1.2.3 From 2493a6d18b1f5df59c7bcfeefcbde70bee146490 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 6 Nov 2006 09:24:29 +0100 Subject: [ALSA] korg1212: add request_firmware() Load the DSP code using request_firmware(), if possible, instead of using the built-in blob. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela --- sound/pci/Kconfig | 1 + sound/pci/korg1212/korg1212.c | 45 ++++++++++++++++++++++++++++++++++--------- 2 files changed, 37 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index fcbf9673db6..7573997af76 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -576,6 +576,7 @@ config SND_INTEL8X0M config SND_KORG1212 tristate "Korg 1212 IO" depends on SND + select FW_LOADER select SND_PCM help Say Y here to include support for Korg 1212IO soundcards. diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c index 345eefeedb3..b4e98f36229 100644 --- a/sound/pci/korg1212/korg1212.c +++ b/sound/pci/korg1212/korg1212.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -263,7 +264,15 @@ enum MonitorModeSelector { #define COMMAND_ACK_DELAY 13 // number of RTC ticks to wait for an acknowledgement // from the card after sending a command. +#define FIRMWARE_IN_THE_KERNEL + +#ifdef FIRMWARE_IN_THE_KERNEL #include "korg1212-firmware.h" +static const struct firmware static_dsp_code = { + .data = (u8 *)dspCode, + .size = sizeof dspCode +}; +#endif enum ClockSourceIndex { K1212_CLKIDX_AdatAt44_1K = 0, // selects source as ADAT at 44.1 kHz @@ -345,8 +354,6 @@ struct snd_korg1212 { struct snd_dma_buffer dma_rec; struct snd_dma_buffer dma_shared; - u32 dspCodeSize; - u32 DataBufsSize; struct KorgAudioBuffer * playDataBufsPtr; @@ -1223,8 +1230,6 @@ static int snd_korg1212_downloadDSPCode(struct snd_korg1212 *korg1212) snd_korg1212_setCardState(korg1212, K1212_STATE_DSP_IN_PROCESS); - memcpy(korg1212->dma_dsp.area, dspCode, korg1212->dspCodeSize); - rc = snd_korg1212_Send1212Command(korg1212, K1212_DB_StartDSPDownload, UpperWordSwap(korg1212->dma_dsp.addr), 0, 0, 0); @@ -2156,6 +2161,7 @@ static int __devinit snd_korg1212_create(struct snd_card *card, struct pci_dev * unsigned int i; unsigned ioport_size, iomem_size, iomem2_size; struct snd_korg1212 * korg1212; + const struct firmware *dsp_code; static struct snd_device_ops ops = { .dev_free = snd_korg1212_dev_free, @@ -2329,8 +2335,6 @@ static int __devinit snd_korg1212_create(struct snd_card *card, struct pci_dev * #endif // K1212_LARGEALLOC - korg1212->dspCodeSize = sizeof (dspCode); - korg1212->VolumeTablePhy = korg1212->sharedBufferPhy + offsetof(struct KorgSharedBuffer, volumeData); korg1212->RoutingTablePhy = korg1212->sharedBufferPhy + @@ -2338,17 +2342,40 @@ static int __devinit snd_korg1212_create(struct snd_card *card, struct pci_dev * korg1212->AdatTimeCodePhy = korg1212->sharedBufferPhy + offsetof(struct KorgSharedBuffer, AdatTimeCode); + err = request_firmware(&dsp_code, "korg/k1212.dsp", &pci->dev); + if (err < 0) { + release_firmware(dsp_code); +#ifdef FIRMWARE_IN_THE_KERNEL + dsp_code = &static_dsp_code; +#else + snd_printk(KERN_ERR "firmware not available\n"); + snd_korg1212_free(korg1212); + return err; +#endif + } + if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), - korg1212->dspCodeSize, &korg1212->dma_dsp) < 0) { - snd_printk(KERN_ERR "korg1212: can not allocate dsp code memory (%d bytes)\n", korg1212->dspCodeSize); + dsp_code->size, &korg1212->dma_dsp) < 0) { + snd_printk(KERN_ERR "korg1212: can not allocate dsp code memory (%d bytes)\n", dsp_code->size); snd_korg1212_free(korg1212); +#ifdef FIRMWARE_IN_THE_KERNEL + if (dsp_code != &static_dsp_code) +#endif + release_firmware(dsp_code); return -ENOMEM; } K1212_DEBUG_PRINTK("K1212_DEBUG: DSP Code area = 0x%p (0x%08x) %d bytes [%s]\n", - korg1212->dma_dsp.area, korg1212->dma_dsp.addr, korg1212->dspCodeSize, + korg1212->dma_dsp.area, korg1212->dma_dsp.addr, dsp_code->size, stateName[korg1212->cardState]); + memcpy(korg1212->dma_dsp.area, dsp_code->data, dsp_code->size); + +#ifdef FIRMWARE_IN_THE_KERNEL + if (dsp_code != &static_dsp_code) +#endif + release_firmware(dsp_code); + rc = snd_korg1212_Send1212Command(korg1212, K1212_DB_RebootCard, 0, 0, 0, 0); if (rc) -- cgit v1.2.3 From 81d7724a8ee84693befbd60d730199ffb3988f29 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 6 Nov 2006 09:26:41 +0100 Subject: [ALSA] maestro3: add request_firmware() Load the ASSP codes using request_firmware(), if possible, instead of using the built-in blobs. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela --- sound/pci/Kconfig | 1 + sound/pci/maestro3.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 74 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 7573997af76..1bcfb3aac18 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -587,6 +587,7 @@ config SND_KORG1212 config SND_MAESTRO3 tristate "ESS Allegro/Maestro3" depends on SND + select FW_LOADER select SND_AC97_CODEC help Say Y here to include support for soundcards based on ESS Maestro 3 diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index 6efe6d5ade1..053ea4fdbff 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -48,6 +49,7 @@ #include #include #include +#include MODULE_AUTHOR("Zach Brown , Takashi Iwai "); MODULE_DESCRIPTION("ESS Maestro3 PCI"); @@ -864,6 +866,9 @@ struct snd_m3 { #ifdef CONFIG_PM u16 *suspend_mem; #endif + + const struct firmware *assp_kernel_image; + const struct firmware *assp_minisrc_image; }; /* @@ -2132,6 +2137,10 @@ static int __devinit snd_m3_mixer(struct snd_m3 *chip) } +#define FIRMWARE_IN_THE_KERNEL + +#ifdef FIRMWARE_IN_THE_KERNEL + /* * DSP Code images */ @@ -2260,6 +2269,30 @@ static const u16 assp_minisrc_image[] = { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, }; +static const struct firmware assp_kernel = { + .data = (u8 *)assp_kernel_image, + .size = sizeof assp_kernel_image +}; +static const struct firmware assp_minisrc = { + .data = (u8 *)assp_minisrc_image, + .size = sizeof assp_minisrc_image +}; + +#endif /* FIRMWARE_IN_THE_KERNEL */ + +#ifdef __LITTLE_ENDIAN +static inline void snd_m3_convert_from_le(const struct firmware *fw) { } +#else +static void snd_m3_convert_from_le(const struct firmware *fw) +{ + int i; + u16 *data = (u16 *)fw->data; + + for (i = 0; i < fw->size / 2; ++i) + le16_to_cpus(&data[i]); +} +#endif + /* * initialize ASSP @@ -2274,6 +2307,7 @@ static const u16 minisrc_lpf[MINISRC_LPF_LEN] = { static void snd_m3_assp_init(struct snd_m3 *chip) { unsigned int i; + u16 *data; /* zero kernel data */ for (i = 0; i < (REV_B_DATA_MEMORY_UNIT_LENGTH * NUM_UNITS_KERNEL_DATA) / 2; i++) @@ -2291,10 +2325,10 @@ static void snd_m3_assp_init(struct snd_m3 *chip) KDATA_DMA_XFER0); /* write kernel into code memory.. */ - for (i = 0 ; i < ARRAY_SIZE(assp_kernel_image); i++) { + data = (u16 *)chip->assp_kernel_image->data; + for (i = 0 ; i * 2 < chip->assp_kernel_image->size; i++) { snd_m3_assp_write(chip, MEMTYPE_INTERNAL_CODE, - REV_B_CODE_MEMORY_BEGIN + i, - assp_kernel_image[i]); + REV_B_CODE_MEMORY_BEGIN + i, data[i]); } /* @@ -2303,10 +2337,10 @@ static void snd_m3_assp_init(struct snd_m3 *chip) * drop it there. It seems that the minisrc doesn't * need vectors, so we won't bother with them.. */ - for (i = 0; i < ARRAY_SIZE(assp_minisrc_image); i++) { + data = (u16 *)chip->assp_minisrc_image->data; + for (i = 0; i * 2 < chip->assp_minisrc_image->size; i++) { snd_m3_assp_write(chip, MEMTYPE_INTERNAL_CODE, - 0x400 + i, - assp_minisrc_image[i]); + 0x400 + i, data[i]); } /* @@ -2553,6 +2587,15 @@ static int snd_m3_free(struct snd_m3 *chip) if (chip->iobase) pci_release_regions(chip->pci); +#ifdef FIRMWARE_IN_THE_KERNEL + if (chip->assp_kernel_image != &assp_kernel) +#endif + release_firmware(chip->assp_kernel_image); +#ifdef FIRMWARE_IN_THE_KERNEL + if (chip->assp_minisrc_image != &assp_minisrc) +#endif + release_firmware(chip->assp_minisrc_image); + pci_disable_device(chip->pci); kfree(chip); return 0; @@ -2744,6 +2787,30 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci, return -ENOMEM; } + err = request_firmware(&chip->assp_kernel_image, + "ess/maestro3_assp_kernel.fw", &pci->dev); + if (err < 0) { +#ifdef FIRMWARE_IN_THE_KERNEL + chip->assp_kernel_image = &assp_kernel; +#else + snd_m3_free(chip); + return err; +#endif + } else + snd_m3_convert_from_le(chip->assp_kernel_image); + + err = request_firmware(&chip->assp_minisrc_image, + "ess/maestro3_assp_minisrc.fw", &pci->dev); + if (err < 0) { +#ifdef FIRMWARE_IN_THE_KERNEL + chip->assp_minisrc_image = &assp_minisrc; +#else + snd_m3_free(chip); + return err; +#endif + } else + snd_m3_convert_from_le(chip->assp_minisrc_image); + if ((err = pci_request_regions(pci, card->driver)) < 0) { snd_m3_free(chip); return err; -- cgit v1.2.3 From 9174140cf383c56bdcabb4caf9c99c5ac8f3fdd7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 6 Nov 2006 14:45:42 +0100 Subject: [ALSA] hda-codec - Fix model for ASUS M2N-MX Add a proper model (3stack) for ASUS M2N-MX with AD1986A codec. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_analog.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 5e63123f70b..9260560303e 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -800,6 +800,8 @@ static struct hda_board_config ad1986a_cfg_tbl[] = { .config = AD1986A_3STACK }, /* ASUS P5RD2-VM / P5GPL-X SE */ { .pci_subvendor = 0x1043, .pci_subdevice = 0x81cb, .config = AD1986A_3STACK }, /* ASUS M2NPV-VM */ + { .pci_subvendor = 0x1043, .pci_subdevice = 0x8234, + .config = AD1986A_3STACK }, /* ASUS M2N-MX */ { .pci_subvendor = 0x17aa, .pci_subdevice = 0x1017, .config = AD1986A_3STACK }, /* Lenovo A60 desktop */ { .modelname = "laptop", .config = AD1986A_LAPTOP }, -- cgit v1.2.3 From 54bf5dd9ccd8c37830d7dae0737466e8fda018aa Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 6 Nov 2006 15:38:55 +0100 Subject: [ALSA] hdspm - Fix printk warnings sound/pci/rme9652/hdspm.c: In function 'snd_hdspm_hw_params': sound/pci/rme9652/hdspm.c:3681: warning: format '%08X' expects type 'unsigned int', but argument 4 has type 'unsigned char *' sound/pci/rme9652/hdspm.c:3692: warning: format '%08X' expects type 'unsigned int', but argument 4 has type 'unsigned char *' Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/rme9652/hdspm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 3d3a4ce3a35..e0215aca119 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -3678,7 +3678,7 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream, hdspm->playback_buffer = (unsigned char *) substream->runtime->dma_area; - snd_printdd("Allocated sample buffer for playback at 0x%08X\n", + snd_printdd("Allocated sample buffer for playback at %p\n", hdspm->playback_buffer); } else { hdspm_set_sgbuf(hdspm, sgbuf, HDSPM_pageAddressBufferIn, @@ -3689,7 +3689,7 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream, hdspm->capture_buffer = (unsigned char *) substream->runtime->dma_area; - snd_printdd("Allocated sample buffer for capture at 0x%08X\n", + snd_printdd("Allocated sample buffer for capture at %p\n", hdspm->capture_buffer); } /* -- cgit v1.2.3 From b373bdebf57e2ac7994d9be3a68fd5507515caef Mon Sep 17 00:00:00 2001 From: "Andrew L. Neporada" Date: Tue, 7 Nov 2006 11:37:08 +0100 Subject: [ALSA] hda-codec - Clevo M540JE, M550JE laptops (Nvidia MCP51 chipset, ALC883 codec) We need to enable External Amplifier on this laptops. This patch basicly adds laptop-eapd model to ALC883 codec. Signed-off-by: Andrew L. Neporada Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 990714e2bcb..b1e8cd8961d 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -125,6 +125,7 @@ enum { ALC888_DEMO_BOARD, ALC883_ACER, ALC883_MEDION, + ALC883_LAPTOP_EAPD, ALC883_AUTO, ALC883_MODEL_LAST, }; @@ -4540,7 +4541,7 @@ static struct hda_verb alc882_init_verbs[] = { static struct hda_verb alc882_eapd_verbs[] = { /* change to EAPD mode */ {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, - {0x20, AC_VERB_SET_PROC_COEF, 0x3070}, + {0x20, AC_VERB_SET_PROC_COEF, 0x3060}, { } }; @@ -4998,6 +4999,13 @@ static struct hda_channel_mode alc883_sixstack_modes[2] = { { 8, alc883_sixstack_ch8_init }, }; +static struct hda_verb alc883_medion_eapd_verbs[] = { + /* eanable EAPD on medion laptop */ + {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, + {0x20, AC_VERB_SET_PROC_COEF, 0x3070}, + { } +}; + /* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b */ @@ -5471,6 +5479,9 @@ static struct hda_board_config alc883_cfg_tbl[] = { .config = ALC883_ACER }, { .pci_subvendor = 0x161f, .pci_subdevice = 0x2054, .modelname = "medion", .config = ALC883_MEDION }, + { .modelname = "laptop-eapd", .config = ALC883_LAPTOP_EAPD }, + { .pci_subvendor = 0x1558, .pci_subdevice = 0, + .config = ALC883_LAPTOP_EAPD }, /* Clevo */ { .modelname = "auto", .config = ALC883_AUTO }, {} }; @@ -5591,7 +5602,7 @@ static struct alc_config_preset alc883_presets[] = { .mixers = { alc883_fivestack_mixer, alc883_chmode_mixer }, .init_verbs = { alc883_init_verbs, - alc882_eapd_verbs }, + alc883_medion_eapd_verbs }, .num_dacs = ARRAY_SIZE(alc883_dac_nids), .dac_nids = alc883_dac_nids, .num_adc_nids = ARRAY_SIZE(alc883_adc_nids), @@ -5599,8 +5610,19 @@ static struct alc_config_preset alc883_presets[] = { .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes), .channel_mode = alc883_sixstack_modes, .input_mux = &alc883_capture_source, - } - + }, + [ALC883_LAPTOP_EAPD] = { + .mixers = { alc883_base_mixer, + alc883_chmode_mixer }, + .init_verbs = { alc883_init_verbs, alc882_eapd_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc883_adc_nids), + .adc_nids = alc883_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), + .channel_mode = alc883_3ST_2ch_modes, + .input_mux = &alc883_capture_source, + }, }; -- cgit v1.2.3 From bd903b6ed7fb107e122682db5ac8aaa323ab84c9 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Thu, 9 Nov 2006 16:35:01 +0100 Subject: [ALSA] ASoC - mixer name changes for older OSS app support This patch suggested by Richard Purdie changes the names of some WM8731 and WM8750 mixers so that they will be recognised by some older OSS mixer apps. Changes:- o WM8731 Playback changed to Master Playback o WM8750 Out1 changed to Headphone o WM8750 Out2 changed to Speaker Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/codecs/wm8731.c | 6 ++++-- sound/soc/codecs/wm8750.c | 12 +++++++----- 2 files changed, 11 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 412291241ec..8151b45a280 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -310,8 +310,10 @@ static const struct soc_enum wm8731_enum[] = { static const struct snd_kcontrol_new wm8731_snd_controls[] = { -SOC_DOUBLE_R("Playback Volume", WM8731_LOUT1V, WM8731_ROUT1V, 0, 127, 0), -SOC_DOUBLE_R("Playback ZC Switch", WM8731_LOUT1V, WM8731_ROUT1V, 7, 1, 0), +SOC_DOUBLE_R("Master Playback Volume", WM8731_LOUT1V, WM8731_ROUT1V, + 0, 127, 0), +SOC_DOUBLE_R("Master Playback ZC Switch", WM8731_LOUT1V, WM8731_ROUT1V, + 7, 1, 0), SOC_DOUBLE_R("Capture Volume", WM8731_LINVOL, WM8731_RINVOL, 0, 31, 0), SOC_DOUBLE_R("Line Capture Switch", WM8731_LINVOL, WM8731_RINVOL, 7, 1, 1), diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index c5d13a9454d..4cc85128dc5 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c @@ -444,9 +444,9 @@ SOC_DOUBLE_R("Capture Volume", WM8750_LINVOL, WM8750_RINVOL, 0, 63, 0), SOC_DOUBLE_R("Capture ZC Switch", WM8750_LINVOL, WM8750_RINVOL, 6, 1, 0), SOC_DOUBLE_R("Capture Switch", WM8750_LINVOL, WM8750_RINVOL, 7, 1, 1), -SOC_DOUBLE_R("Out1 Playback ZC Switch", WM8750_LOUT1V, +SOC_DOUBLE_R("Headphone Playback ZC Switch", WM8750_LOUT1V, WM8750_ROUT1V, 7, 1, 0), -SOC_DOUBLE_R("Out2 Playback ZC Switch", WM8750_LOUT2V, +SOC_DOUBLE_R("Speaker Playback ZC Switch", WM8750_LOUT2V, WM8750_ROUT2V, 7, 1, 0), SOC_ENUM("Playback De-emphasis", wm8750_enum[15]), @@ -487,7 +487,7 @@ SOC_SINGLE("Right ADC Capture Volume", WM8750_RADC, 0, 255, 0), SOC_SINGLE("ZC Timeout Switch", WM8750_ADCTL1, 0, 1, 0), SOC_SINGLE("Playback Invert Switch", WM8750_ADCTL1, 1, 1, 0), -SOC_SINGLE("Right Out2 Playback Invert Switch", WM8750_ADCTL2, 4, 1, 0), +SOC_SINGLE("Right Speaker Playback Invert Switch", WM8750_ADCTL2, 4, 1, 0), /* Unimplemented */ /* ADCDAC Bit 0 - ADCHPD */ @@ -514,8 +514,10 @@ SOC_DOUBLE_R("Bypass Mono Playback Volume", WM8750_MOUTM1, SOC_SINGLE("Mono Playback ZC Switch", WM8750_MOUTV, 7, 1, 0), -SOC_DOUBLE_R("Out1 Playback Volume", WM8750_LOUT1V, WM8750_ROUT1V, 0, 127, 0), -SOC_DOUBLE_R("Out2 Playback Volume", WM8750_LOUT2V, WM8750_ROUT2V, 0, 127, 0), +SOC_DOUBLE_R("Headphone Playback Volume", WM8750_LOUT1V, WM8750_ROUT1V, + 0, 127, 0), +SOC_DOUBLE_R("Speaker Playback Volume", WM8750_LOUT2V, WM8750_ROUT2V, + 0, 127, 0), SOC_SINGLE("Mono Playback Volume", WM8750_MOUTV, 0, 127, 0), -- cgit v1.2.3 From 56255060ea51984e728223d8056b3faaba0dadf6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 9 Nov 2006 16:47:26 +0100 Subject: [ALSA] ice1724 - Add support of M-Audio Audiophile 192 Added the (experimental) support of M-Audio Audiophile 192 board. Currently, the analog and the digital playbacks seem working fine. The inputs seem not working as far as I've tested yet. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/ice1712/revo.c | 204 +++++++++++++++++++++++++++++++++++++++++++++++ sound/pci/ice1712/revo.h | 5 +- 2 files changed, 208 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/ice1712/revo.c b/sound/pci/ice1712/revo.c index 233e9a5a2e7..0e578aa38af 100644 --- a/sound/pci/ice1712/revo.c +++ b/sound/pci/ice1712/revo.c @@ -303,6 +303,181 @@ static struct snd_ak4xxx_private akm_revo51_adc_priv __devinitdata = { static struct snd_pt2258 ptc_revo51_volume; +/* AK4358 for AP192 DAC, AK5385A for ADC */ +static void ap192_set_rate_val(struct snd_akm4xxx *ak, unsigned int rate) +{ + struct snd_ice1712 *ice = ak->private_data[0]; + + revo_set_rate_val(ak, rate); + +#if 1 /* FIXME: do we need this procedure? */ + /* reset DFS pin of AK5385A for ADC, too */ + /* DFS0 (pin 18) -- GPIO10 pin 77 */ + snd_ice1712_save_gpio_status(ice); + snd_ice1712_gpio_write_bits(ice, 1 << 10, + rate > 48000 ? (1 << 10) : 0); + snd_ice1712_restore_gpio_status(ice); +#endif +} + +static struct snd_akm4xxx_dac_channel ap192_dac[] = { + AK_DAC("PCM Playback Volume", 2) +}; + +static struct snd_akm4xxx akm_ap192 __devinitdata = { + .type = SND_AK4358, + .num_dacs = 2, + .ops = { + .set_rate_val = ap192_set_rate_val + }, + .dac_info = ap192_dac, +}; + +static struct snd_ak4xxx_private akm_ap192_priv __devinitdata = { + .caddr = 2, + .cif = 0, + .data_mask = VT1724_REVO_CDOUT, + .clk_mask = VT1724_REVO_CCLK, + .cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS3, + .cs_addr = VT1724_REVO_CS3, + .cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS3, + .add_flags = VT1724_REVO_CCLK, /* high at init */ + .mask_flags = 0, +}; + +#if 0 +/* FIXME: ak4114 makes the sound much lower due to some confliction, + * so let's disable it right now... + */ +#define BUILD_AK4114_AP192 +#endif + +#ifdef BUILD_AK4114_AP192 +/* AK4114 support on Audiophile 192 */ +/* CDTO (pin 32) -- GPIO2 pin 52 + * CDTI (pin 33) -- GPIO3 pin 53 (shared with AK4358) + * CCLK (pin 34) -- GPIO1 pin 51 (shared with AK4358) + * CSN (pin 35) -- GPIO7 pin 59 + */ +#define AK4114_ADDR 0x00 + +static void write_data(struct snd_ice1712 *ice, unsigned int gpio, + unsigned int data, int idx) +{ + for (; idx >= 0; idx--) { + /* drop clock */ + gpio &= ~VT1724_REVO_CCLK; + snd_ice1712_gpio_write(ice, gpio); + udelay(1); + /* set data */ + if (data & (1 << idx)) + gpio |= VT1724_REVO_CDOUT; + else + gpio &= ~VT1724_REVO_CDOUT; + snd_ice1712_gpio_write(ice, gpio); + udelay(1); + /* raise clock */ + gpio |= VT1724_REVO_CCLK; + snd_ice1712_gpio_write(ice, gpio); + udelay(1); + } +} + +static unsigned char read_data(struct snd_ice1712 *ice, unsigned int gpio, + int idx) +{ + unsigned char data = 0; + + for (; idx >= 0; idx--) { + /* drop clock */ + gpio &= ~VT1724_REVO_CCLK; + snd_ice1712_gpio_write(ice, gpio); + udelay(1); + /* read data */ + if (snd_ice1712_gpio_read(ice) & VT1724_REVO_CDIN) + data |= (1 << idx); + udelay(1); + /* raise clock */ + gpio |= VT1724_REVO_CCLK; + snd_ice1712_gpio_write(ice, gpio); + udelay(1); + } + return data; +} + +static unsigned char ap192_4wire_start(struct snd_ice1712 *ice) +{ + unsigned int tmp; + + snd_ice1712_save_gpio_status(ice); + tmp = snd_ice1712_gpio_read(ice); + tmp |= VT1724_REVO_CCLK; /* high at init */ + tmp |= VT1724_REVO_CS0; + tmp &= ~VT1724_REVO_CS3; + snd_ice1712_gpio_write(ice, tmp); + udelay(1); + return tmp; +} + +static void ap192_4wire_finish(struct snd_ice1712 *ice, unsigned int tmp) +{ + tmp |= VT1724_REVO_CS3; + tmp |= VT1724_REVO_CS0; + snd_ice1712_gpio_write(ice, tmp); + udelay(1); + snd_ice1712_restore_gpio_status(ice); +} + +static void ap192_ak4114_write(void *private_data, unsigned char addr, + unsigned char data) +{ + struct snd_ice1712 *ice = private_data; + unsigned int tmp, addrdata; + + tmp = ap192_4wire_start(ice); + addrdata = (AK4114_ADDR << 6) | 0x20 | (addr & 0x1f); + addrdata = (addrdata << 8) | data; + write_data(ice, tmp, addrdata, 15); + ap192_4wire_finish(ice, tmp); +} + +static unsigned char ap192_ak4114_read(void *private_data, unsigned char addr) +{ + struct snd_ice1712 *ice = private_data; + unsigned int tmp; + unsigned char data; + + tmp = ap192_4wire_start(ice); + write_data(ice, tmp, (AK4114_ADDR << 6) | (addr & 0x1f), 7); + data = read_data(ice, tmp, 7); + ap192_4wire_finish(ice, tmp); + return data; +} + +static int ap192_ak4114_init(struct snd_ice1712 *ice) +{ + static unsigned char ak4114_init_vals[] = { + AK4114_RST | AK4114_PWN | AK4114_OCKS0 | AK4114_OCKS1, + AK4114_DIF_I24I2S, + AK4114_TX1E, + AK4114_EFH_1024 | AK4114_DIT | AK4114_IPS(1), + 0, + 0 + }; + static unsigned char ak4114_init_txcsb[] = { + 0x41, 0x02, 0x2c, 0x00, 0x00 + }; + struct ak4114 *ak; + int err; + + return snd_ak4114_create(ice->card, + ap192_ak4114_read, + ap192_ak4114_write, + ak4114_init_vals, ak4114_init_txcsb, + ice, &ak); +} +#endif /* BUILD_AK4114_AP192 */ + static int __devinit revo_init(struct snd_ice1712 *ice) { struct snd_akm4xxx *ak; @@ -319,6 +494,10 @@ static int __devinit revo_init(struct snd_ice1712 *ice) ice->num_total_dacs = 6; ice->num_total_adcs = 2; break; + case VT1724_SUBDEVICE_AUDIOPHILE192: + ice->num_total_dacs = 2; + ice->num_total_adcs = 2; + break; default: snd_BUG(); return -EINVAL; @@ -356,6 +535,14 @@ static int __devinit revo_init(struct snd_ice1712 *ice) snd_ice1712_gpio_write_bits(ice, VT1724_REVO_MUTE, VT1724_REVO_MUTE); break; + case VT1724_SUBDEVICE_AUDIOPHILE192: + ice->akm_codecs = 1; + err = snd_ice1712_akm4xxx_init(ak, &akm_ap192, &akm_ap192_priv, + ice); + if (err < 0) + return err; + + break; } return 0; @@ -380,6 +567,16 @@ static int __devinit revo_add_controls(struct snd_ice1712 *ice) if (err < 0) return err; break; + case VT1724_SUBDEVICE_AUDIOPHILE192: + err = snd_ice1712_akm4xxx_build_controls(ice); + if (err < 0) + return err; +#ifdef BUILD_AK4114_AP192 + err = ap192_ak4114_init(ice); + if (err < 0) + return err; +#endif + break; } return 0; } @@ -400,5 +597,12 @@ struct snd_ice1712_card_info snd_vt1724_revo_cards[] __devinitdata = { .chip_init = revo_init, .build_controls = revo_add_controls, }, + { + .subvendor = VT1724_SUBDEVICE_AUDIOPHILE192, + .name = "M Audio Audiophile192", + .model = "ap192", + .chip_init = revo_init, + .build_controls = revo_add_controls, + }, { } /* terminator */ }; diff --git a/sound/pci/ice1712/revo.h b/sound/pci/ice1712/revo.h index c70adaf017c..a3ba425911c 100644 --- a/sound/pci/ice1712/revo.h +++ b/sound/pci/ice1712/revo.h @@ -26,10 +26,12 @@ #define REVO_DEVICE_DESC \ "{MidiMan M Audio,Revolution 7.1},"\ - "{MidiMan M Audio,Revolution 5.1}," + "{MidiMan M Audio,Revolution 5.1},"\ + "{MidiMan M Audio,Audiophile 192}," #define VT1724_SUBDEVICE_REVOLUTION71 0x12143036 #define VT1724_SUBDEVICE_REVOLUTION51 0x12143136 +#define VT1724_SUBDEVICE_AUDIOPHILE192 0x12143236 /* entry point */ extern struct snd_ice1712_card_info snd_vt1724_revo_cards[]; @@ -47,6 +49,7 @@ extern struct snd_ice1712_card_info snd_vt1724_revo_cards[]; #define VT1724_REVO_CS2 0x40 /* surround AKM4355 CS (revo71) */ #define VT1724_REVO_I2C_DATA 0x40 /* I2C: PT 2258 SDA (on revo51) */ #define VT1724_REVO_I2C_CLOCK 0x80 /* I2C: PT 2258 SCL (on revo51) */ +#define VT1724_REVO_CS3 0x80 /* AK4114 for AP192 */ #define VT1724_REVO_MUTE (1<<22) /* 0 = all mute, 1 = normal operation */ #endif /* __SOUND_REVO_H */ -- cgit v1.2.3 From 4c07c81832a9303eeb36afb8f76ad0594e66cf5e Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Sat, 11 Nov 2006 10:48:58 +0000 Subject: [ALSA] snd-emu10k1: Update Enum naming. Signed-off-by: James Courtier-Dutton Signed-off-by: Jaroslav Kysela --- sound/pci/emu10k1/emumixer.c | 92 ++++++++++++++++++++++---------------------- 1 file changed, 46 insertions(+), 46 deletions(-) (limited to 'sound') diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index 5ceb8dd5cb3..9b7fd564343 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c @@ -316,30 +316,30 @@ static int snd_emu1010_input_source_put(struct snd_kcontrol *kcontrol, } static struct snd_kcontrol_new snd_emu1010_output_enum_ctls[] __devinitdata = { - EMU1010_SOURCE_OUTPUT("Dock DAC1 Left Playback Switch", 0), - EMU1010_SOURCE_OUTPUT("Dock DAC1 Right Playback Switch", 1), - EMU1010_SOURCE_OUTPUT("Dock DAC2 Left Playback Switch", 2), - EMU1010_SOURCE_OUTPUT("Dock DAC2 Right Playback Switch", 3), - EMU1010_SOURCE_OUTPUT("Dock DAC3 Left Playback Switch", 4), - EMU1010_SOURCE_OUTPUT("Dock DAC3 Right Playback Switch", 5), - EMU1010_SOURCE_OUTPUT("Dock DAC4 Left Playback Switch", 6), - EMU1010_SOURCE_OUTPUT("Dock DAC4 Right Playback Switch", 7), - EMU1010_SOURCE_OUTPUT("Dock Phones Left Playback Switch", 8), - EMU1010_SOURCE_OUTPUT("Dock Phones Right Playback Switch", 9), - EMU1010_SOURCE_OUTPUT("Dock SPDIF Left Playback Switch", 0xa), - EMU1010_SOURCE_OUTPUT("Dock SPDIF Right Playback Switch", 0xb), - EMU1010_SOURCE_OUTPUT("1010 SPDIF Left Playback Switch", 0xc), - EMU1010_SOURCE_OUTPUT("1010 SPDIF Right Playback Switch", 0xd), - EMU1010_SOURCE_OUTPUT("0202 DAC Left Playback Switch", 0xe), - EMU1010_SOURCE_OUTPUT("0202 DAC Right Playback Switch", 0xf), - EMU1010_SOURCE_OUTPUT("1010 ADAT 0 Playback Switch", 0x10), - EMU1010_SOURCE_OUTPUT("1010 ADAT 1 Playback Switch", 0x11), - EMU1010_SOURCE_OUTPUT("1010 ADAT 2 Playback Switch", 0x12), - EMU1010_SOURCE_OUTPUT("1010 ADAT 3 Playback Switch", 0x13), - EMU1010_SOURCE_OUTPUT("1010 ADAT 4 Playback Switch", 0x14), - EMU1010_SOURCE_OUTPUT("1010 ADAT 5 Playback Switch", 0x15), - EMU1010_SOURCE_OUTPUT("1010 ADAT 6 Playback Switch", 0x16), - EMU1010_SOURCE_OUTPUT("1010 ADAT 7 Playback Switch", 0x17), + EMU1010_SOURCE_OUTPUT("Dock DAC1 Left Playback Enum", 0), + EMU1010_SOURCE_OUTPUT("Dock DAC1 Right Playback Enum", 1), + EMU1010_SOURCE_OUTPUT("Dock DAC2 Left Playback Enum", 2), + EMU1010_SOURCE_OUTPUT("Dock DAC2 Right Playback Enum", 3), + EMU1010_SOURCE_OUTPUT("Dock DAC3 Left Playback Enum", 4), + EMU1010_SOURCE_OUTPUT("Dock DAC3 Right Playback Enum", 5), + EMU1010_SOURCE_OUTPUT("Dock DAC4 Left Playback Enum", 6), + EMU1010_SOURCE_OUTPUT("Dock DAC4 Right Playback Enum", 7), + EMU1010_SOURCE_OUTPUT("Dock Phones Left Playback Enum", 8), + EMU1010_SOURCE_OUTPUT("Dock Phones Right Playback Enum", 9), + EMU1010_SOURCE_OUTPUT("Dock SPDIF Left Playback Enum", 0xa), + EMU1010_SOURCE_OUTPUT("Dock SPDIF Right Playback Enum", 0xb), + EMU1010_SOURCE_OUTPUT("1010 SPDIF Left Playback Enum", 0xc), + EMU1010_SOURCE_OUTPUT("1010 SPDIF Right Playback Enum", 0xd), + EMU1010_SOURCE_OUTPUT("0202 DAC Left Playback Enum", 0xe), + EMU1010_SOURCE_OUTPUT("0202 DAC Right Playback Enum", 0xf), + EMU1010_SOURCE_OUTPUT("1010 ADAT 0 Playback Enum", 0x10), + EMU1010_SOURCE_OUTPUT("1010 ADAT 1 Playback Enum", 0x11), + EMU1010_SOURCE_OUTPUT("1010 ADAT 2 Playback Enum", 0x12), + EMU1010_SOURCE_OUTPUT("1010 ADAT 3 Playback Enum", 0x13), + EMU1010_SOURCE_OUTPUT("1010 ADAT 4 Playback Enum", 0x14), + EMU1010_SOURCE_OUTPUT("1010 ADAT 5 Playback Enum", 0x15), + EMU1010_SOURCE_OUTPUT("1010 ADAT 6 Playback Enum", 0x16), + EMU1010_SOURCE_OUTPUT("1010 ADAT 7 Playback Enum", 0x17), }; #define EMU1010_SOURCE_INPUT(xname,chid) \ @@ -353,28 +353,28 @@ static struct snd_kcontrol_new snd_emu1010_output_enum_ctls[] __devinitdata = { } static struct snd_kcontrol_new snd_emu1010_input_enum_ctls[] __devinitdata = { - EMU1010_SOURCE_INPUT("DSP 0 Capture Switch", 0), - EMU1010_SOURCE_INPUT("DSP 1 Capture Switch", 1), - EMU1010_SOURCE_INPUT("DSP 2 Capture Switch", 2), - EMU1010_SOURCE_INPUT("DSP 3 Capture Switch", 3), - EMU1010_SOURCE_INPUT("DSP 4 Capture Switch", 4), - EMU1010_SOURCE_INPUT("DSP 5 Capture Switch", 5), - EMU1010_SOURCE_INPUT("DSP 6 Capture Switch", 6), - EMU1010_SOURCE_INPUT("DSP 7 Capture Switch", 7), - EMU1010_SOURCE_INPUT("DSP 8 Capture Switch", 8), - EMU1010_SOURCE_INPUT("DSP 9 Capture Switch", 9), - EMU1010_SOURCE_INPUT("DSP A Capture Switch", 0xa), - EMU1010_SOURCE_INPUT("DSP B Capture Switch", 0xb), - EMU1010_SOURCE_INPUT("DSP C Capture Switch", 0xc), - EMU1010_SOURCE_INPUT("DSP D Capture Switch", 0xd), - EMU1010_SOURCE_INPUT("DSP E Capture Switch", 0xe), - EMU1010_SOURCE_INPUT("DSP F Capture Switch", 0xf), - EMU1010_SOURCE_INPUT("DSP 10 Capture Switch", 0x10), - EMU1010_SOURCE_INPUT("DSP 11 Capture Switch", 0x11), - EMU1010_SOURCE_INPUT("DSP 12 Capture Switch", 0x12), - EMU1010_SOURCE_INPUT("DSP 13 Capture Switch", 0x13), - EMU1010_SOURCE_INPUT("DSP 14 Capture Switch", 0x14), - EMU1010_SOURCE_INPUT("DSP 15 Capture Switch", 0x15), + EMU1010_SOURCE_INPUT("DSP 0 Capture Enum", 0), + EMU1010_SOURCE_INPUT("DSP 1 Capture Enum", 1), + EMU1010_SOURCE_INPUT("DSP 2 Capture Enum", 2), + EMU1010_SOURCE_INPUT("DSP 3 Capture Enum", 3), + EMU1010_SOURCE_INPUT("DSP 4 Capture Enum", 4), + EMU1010_SOURCE_INPUT("DSP 5 Capture Enum", 5), + EMU1010_SOURCE_INPUT("DSP 6 Capture Enum", 6), + EMU1010_SOURCE_INPUT("DSP 7 Capture Enum", 7), + EMU1010_SOURCE_INPUT("DSP 8 Capture Enum", 8), + EMU1010_SOURCE_INPUT("DSP 9 Capture Enum", 9), + EMU1010_SOURCE_INPUT("DSP A Capture Enum", 0xa), + EMU1010_SOURCE_INPUT("DSP B Capture Enum", 0xb), + EMU1010_SOURCE_INPUT("DSP C Capture Enum", 0xc), + EMU1010_SOURCE_INPUT("DSP D Capture Enum", 0xd), + EMU1010_SOURCE_INPUT("DSP E Capture Enum", 0xe), + EMU1010_SOURCE_INPUT("DSP F Capture Enum", 0xf), + EMU1010_SOURCE_INPUT("DSP 10 Capture Enum", 0x10), + EMU1010_SOURCE_INPUT("DSP 11 Capture Enum", 0x11), + EMU1010_SOURCE_INPUT("DSP 12 Capture Enum", 0x12), + EMU1010_SOURCE_INPUT("DSP 13 Capture Enum", 0x13), + EMU1010_SOURCE_INPUT("DSP 14 Capture Enum", 0x14), + EMU1010_SOURCE_INPUT("DSP 15 Capture Enum", 0x15), }; -- cgit v1.2.3 From e6327cf90b1e5e849ac87fbdaee7822a64b6ff56 Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Sat, 11 Nov 2006 10:52:06 +0000 Subject: [ALSA] snd-ca0106: Updated Enum control names. Signed-off-by: James Courtier-Dutton Signed-off-by: Jaroslav Kysela --- sound/pci/ca0106/ca0106_mixer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c index 9855f528ea7..bd2a054c673 100644 --- a/sound/pci/ca0106/ca0106_mixer.c +++ b/sound/pci/ca0106/ca0106_mixer.c @@ -539,14 +539,14 @@ static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = { }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Digital Capture Source", + .name = "Digital Source Capture Enum", .info = snd_ca0106_capture_source_info, .get = snd_ca0106_capture_source_get, .put = snd_ca0106_capture_source_put }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", + .name = "Analog Source Capture Enum", .info = snd_ca0106_i2c_capture_source_info, .get = snd_ca0106_i2c_capture_source_get, .put = snd_ca0106_i2c_capture_source_put -- cgit v1.2.3 From c9b443d4fdf4e84ce1f40e1f507c313f3a8a8294 Mon Sep 17 00:00:00 2001 From: Tobin Davis Date: Tue, 14 Nov 2006 12:13:39 +0100 Subject: [ALSA] Add Conexant audio support to the HD Audio driver This driver adds limited support for the Conexant 5045 and 5047 HD Audio codecs. Some issues still need to be resolved. The code is based primarily on code from the Analog Devices AD1981 support and the Realtek ALC260 support. Some code came from the original code developed by Alex Pototskiy (see alsa bugtracker 2485). Signed-off-by: Tobin Davis Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/Makefile | 10 +- sound/pci/hda/hda_patch.h | 3 + sound/pci/hda/patch_conexant.c | 1298 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1310 insertions(+), 1 deletion(-) create mode 100644 sound/pci/hda/patch_conexant.c (limited to 'sound') diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index dbacba6177d..148140bb86b 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile @@ -1,5 +1,13 @@ snd-hda-intel-objs := hda_intel.o -snd-hda-codec-objs := hda_codec.o hda_generic.o patch_realtek.o patch_cmedia.o patch_analog.o patch_sigmatel.o patch_si3054.o patch_atihdmi.o +snd-hda-codec-objs := hda_codec.o \ + hda_generic.o \ + patch_realtek.o \ + patch_cmedia.o \ + patch_analog.o \ + patch_sigmatel.o \ + patch_si3054.o \ + patch_atihdmi.o \ + patch_conexant.o ifdef CONFIG_PROC_FS snd-hda-codec-objs += hda_proc.o endif diff --git a/sound/pci/hda/hda_patch.h b/sound/pci/hda/hda_patch.h index 0b668793fac..5904ecd88a5 100644 --- a/sound/pci/hda/hda_patch.h +++ b/sound/pci/hda/hda_patch.h @@ -14,6 +14,8 @@ extern struct hda_codec_preset snd_hda_preset_sigmatel[]; extern struct hda_codec_preset snd_hda_preset_si3054[]; /* ATI HDMI codecs */ extern struct hda_codec_preset snd_hda_preset_atihdmi[]; +/* Conexant audio codec */ +extern struct hda_codec_preset snd_hda_preset_conexant[]; static const struct hda_codec_preset *hda_preset_tables[] = { snd_hda_preset_realtek, @@ -22,5 +24,6 @@ static const struct hda_codec_preset *hda_preset_tables[] = { snd_hda_preset_sigmatel, snd_hda_preset_si3054, snd_hda_preset_atihdmi, + snd_hda_preset_conexant, NULL }; diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c new file mode 100644 index 00000000000..9b69b62a550 --- /dev/null +++ b/sound/pci/hda/patch_conexant.c @@ -0,0 +1,1298 @@ +/* + * HD audio interface patch for Conexant HDA audio codec + * + * Copyright (c) 2006 Pototskiy Akex + * Takashi Iwai + * Tobin Davis + * + * This driver is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This driver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include "hda_codec.h" +#include "hda_local.h" + +#define CXT_PIN_DIR_IN 0x00 +#define CXT_PIN_DIR_OUT 0x01 +#define CXT_PIN_DIR_INOUT 0x02 +#define CXT_PIN_DIR_IN_NOMICBIAS 0x03 +#define CXT_PIN_DIR_INOUT_NOMICBIAS 0x04 + +#define CONEXANT_HP_EVENT 0x37 +#define CONEXANT_MIC_EVENT 0x38 + + + +struct conexant_spec { + + struct snd_kcontrol_new *mixers[5]; + int num_mixers; + + const struct hda_verb *init_verbs[5]; /* initialization verbs + * don't forget NULL + * termination! + */ + unsigned int num_init_verbs; + + /* playback */ + struct hda_multi_out multiout; /* playback set-up + * max_channels, dacs must be set + * dig_out_nid and hp_nid are optional + */ + unsigned int cur_eapd; + unsigned int need_dac_fix; + + /* capture */ + unsigned int num_adc_nids; + hda_nid_t *adc_nids; + hda_nid_t dig_in_nid; /* digital-in NID; optional */ + + /* capture source */ + const struct hda_input_mux *input_mux; + hda_nid_t *capsrc_nids; + unsigned int cur_mux[3]; + + /* channel model */ + const struct hda_channel_mode *channel_mode; + int num_channel_mode; + + /* PCM information */ + struct hda_pcm pcm_rec[2]; /* used in build_pcms() */ + + struct mutex amp_mutex; /* PCM volume/mute control mutex */ + unsigned int spdif_route; + + /* dynamic controls, init_verbs and input_mux */ + struct auto_pin_cfg autocfg; + unsigned int num_kctl_alloc, num_kctl_used; + struct snd_kcontrol_new *kctl_alloc; + struct hda_input_mux private_imux; + hda_nid_t private_dac_nids[4]; + +}; + +static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct conexant_spec *spec = codec->spec; + return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream); +} + +static int conexant_playback_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + struct snd_pcm_substream *substream) +{ + struct conexant_spec *spec = codec->spec; + return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, + stream_tag, + format, substream); +} + +static int conexant_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct conexant_spec *spec = codec->spec; + return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); +} + +/* + * Digital out + */ +static int conexant_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct conexant_spec *spec = codec->spec; + return snd_hda_multi_out_dig_open(codec, &spec->multiout); +} + +static int conexant_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct conexant_spec *spec = codec->spec; + return snd_hda_multi_out_dig_close(codec, &spec->multiout); +} + +/* + * Analog capture + */ +static int conexant_capture_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + struct snd_pcm_substream *substream) +{ + struct conexant_spec *spec = codec->spec; + snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], + stream_tag, 0, format); + return 0; +} + +static int conexant_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct conexant_spec *spec = codec->spec; + snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], + 0, 0, 0); + return 0; +} + + + +static struct hda_pcm_stream conexant_pcm_analog_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + .nid = 0, /* fill later */ + .ops = { + .open = conexant_playback_pcm_open, + .prepare = conexant_playback_pcm_prepare, + .cleanup = conexant_playback_pcm_cleanup + }, +}; + +static struct hda_pcm_stream conexant_pcm_analog_capture = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + .nid = 0, /* fill later */ + .ops = { + .prepare = conexant_capture_pcm_prepare, + .cleanup = conexant_capture_pcm_cleanup + }, +}; + + +static struct hda_pcm_stream conexant_pcm_digital_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + .nid = 0, /* fill later */ + .ops = { + .open = conexant_dig_playback_pcm_open, + .close = conexant_dig_playback_pcm_close + }, +}; + +static struct hda_pcm_stream conexant_pcm_digital_capture = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + /* NID is set in alc_build_pcms */ +}; + +static int conexant_build_pcms(struct hda_codec *codec) +{ + struct conexant_spec *spec = codec->spec; + struct hda_pcm *info = spec->pcm_rec; + + codec->num_pcms = 1; + codec->pcm_info = info; + + info->name = "CONEXANT Analog"; + info->stream[SNDRV_PCM_STREAM_PLAYBACK] = conexant_pcm_analog_playback; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = + spec->multiout.max_channels; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = + spec->multiout.dac_nids[0]; + info->stream[SNDRV_PCM_STREAM_CAPTURE] = conexant_pcm_analog_capture; + info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adc_nids; + info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; + + if (spec->multiout.dig_out_nid) { + info++; + codec->num_pcms++; + info->name = "Conexant Digital"; + info->stream[SNDRV_PCM_STREAM_PLAYBACK] = + conexant_pcm_digital_playback; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = + spec->multiout.dig_out_nid; + if (spec->dig_in_nid) { + info->stream[SNDRV_PCM_STREAM_CAPTURE] = + conexant_pcm_digital_capture; + info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = + spec->dig_in_nid; + } + } + + return 0; +} + +static int conexant_mux_enum_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct conexant_spec *spec = codec->spec; + + return snd_hda_input_mux_info(spec->input_mux, uinfo); +} + +static int conexant_mux_enum_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct conexant_spec *spec = codec->spec; + unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + + ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx]; + return 0; +} + +static int conexant_mux_enum_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct conexant_spec *spec = codec->spec; + unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + + return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, + spec->capsrc_nids[adc_idx], + &spec->cur_mux[adc_idx]); +} + +static int conexant_init(struct hda_codec *codec) +{ + struct conexant_spec *spec = codec->spec; + int i; + + for (i = 0; i < spec->num_init_verbs; i++) + snd_hda_sequence_write(codec, spec->init_verbs[i]); + return 0; +} + +static void conexant_free(struct hda_codec *codec) +{ + struct conexant_spec *spec = codec->spec; + unsigned int i; + + if (spec->kctl_alloc) { + for (i = 0; i < spec->num_kctl_used; i++) + kfree(spec->kctl_alloc[i].name); + kfree(spec->kctl_alloc); + } + + kfree(codec->spec); +} + +#ifdef CONFIG_PM +static int conexant_resume(struct hda_codec *codec) +{ + struct conexant_spec *spec = codec->spec; + int i; + + codec->patch_ops.init(codec); + for (i = 0; i < spec->num_mixers; i++) + snd_hda_resume_ctls(codec, spec->mixers[i]); + if (spec->multiout.dig_out_nid) + snd_hda_resume_spdif_out(codec); + if (spec->dig_in_nid) + snd_hda_resume_spdif_in(codec); + return 0; +} +#endif + +static int conexant_build_controls(struct hda_codec *codec) +{ + struct conexant_spec *spec = codec->spec; + unsigned int i; + int err; + + for (i = 0; i < spec->num_mixers; i++) { + err = snd_hda_add_new_ctls(codec, spec->mixers[i]); + if (err < 0) + return err; + } + if (spec->multiout.dig_out_nid) { + err = snd_hda_create_spdif_out_ctls(codec, + spec->multiout.dig_out_nid); + if (err < 0) + return err; + } + if (spec->dig_in_nid) { + err = snd_hda_create_spdif_in_ctls(codec,spec->dig_in_nid); + if (err < 0) + return err; + } + return 0; +} + +static struct hda_codec_ops conexant_patch_ops = { + .build_controls = conexant_build_controls, + .build_pcms = conexant_build_pcms, + .init = conexant_init, + .free = conexant_free, +#ifdef CONFIG_PM + .resume = conexant_resume, +#endif +}; + +/* + * EAPD control + * the private value = nid | (invert << 8) + */ + +static int conexant_eapd_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int conexant_eapd_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct conexant_spec *spec = codec->spec; + int invert = (kcontrol->private_value >> 8) & 1; + if (invert) + ucontrol->value.integer.value[0] = !spec->cur_eapd; + else + ucontrol->value.integer.value[0] = spec->cur_eapd; + return 0; +} + +static int conexant_eapd_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct conexant_spec *spec = codec->spec; + int invert = (kcontrol->private_value >> 8) & 1; + hda_nid_t nid = kcontrol->private_value & 0xff; + unsigned int eapd; + eapd = ucontrol->value.integer.value[0]; + if (invert) + eapd = !eapd; + if (eapd == spec->cur_eapd && !codec->in_resume) + return 0; + spec->cur_eapd = eapd; + snd_hda_codec_write(codec, nid, + 0, AC_VERB_SET_EAPD_BTLENABLE, + eapd ? 0x02 : 0x00); + return 1; +} + +static int conexant_ch_mode_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct conexant_spec *spec = codec->spec; + return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode, + spec->num_channel_mode); +} + +static int conexant_ch_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct conexant_spec *spec = codec->spec; + return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode, + spec->num_channel_mode, + spec->multiout.max_channels); +} + +static int conexant_ch_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct conexant_spec *spec = codec->spec; + int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode, + spec->num_channel_mode, + &spec->multiout.max_channels); + if (err >= 0 && spec->need_dac_fix) + spec->multiout.num_dacs = spec->multiout.max_channels / 2; + return err; +} + +#define CXT_PIN_MODE(xname, nid, dir) \ + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ + .info = conexant_ch_mode_info, \ + .get = conexant_ch_mode_get, \ + .put = conexant_ch_mode_put, \ + .private_value = nid | (dir<<16) } + +static int cxt_gpio_data_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int cxt_gpio_data_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value & 0xffff; + unsigned char mask = (kcontrol->private_value >> 16) & 0xff; + long *valp = ucontrol->value.integer.value; + unsigned int val = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_GPIO_DATA, 0x00); + + *valp = (val & mask) != 0; + return 0; +} + +static int cxt_gpio_data_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value & 0xffff; + unsigned char mask = (kcontrol->private_value >> 16) & 0xff; + long val = *ucontrol->value.integer.value; + unsigned int gpio_data = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_GPIO_DATA, + 0x00); + unsigned int old_data = gpio_data; + + /* Set/unset the masked GPIO bit(s) as needed */ + if (val == 0) + gpio_data &= ~mask; + else + gpio_data |= mask; + if (gpio_data == old_data && !codec->in_resume) + return 0; + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_GPIO_DATA, gpio_data); + return 1; +} + +#define CXT_GPIO_DATA_SWITCH(xname, nid, mask) \ + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ + .info = cxt_gpio_data_info, \ + .get = cxt_gpio_data_get, \ + .put = cxt_gpio_data_put, \ + .private_value = nid | (mask<<16) } + +static int cxt_spdif_ctrl_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int cxt_spdif_ctrl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value & 0xffff; + unsigned char mask = (kcontrol->private_value >> 16) & 0xff; + long *valp = ucontrol->value.integer.value; + unsigned int val = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_DIGI_CONVERT, 0x00); + + *valp = (val & mask) != 0; + return 0; +} + +static int cxt_spdif_ctrl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value & 0xffff; + unsigned char mask = (kcontrol->private_value >> 16) & 0xff; + long val = *ucontrol->value.integer.value; + unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_DIGI_CONVERT, + 0x00); + unsigned int old_data = ctrl_data; + + /* Set/unset the masked control bit(s) as needed */ + if (val == 0) + ctrl_data &= ~mask; + else + ctrl_data |= mask; + if (ctrl_data == old_data && !codec->in_resume) + return 0; + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, + ctrl_data); + return 1; +} + +#define CXT_SPDIF_CTRL_SWITCH(xname, nid, mask) \ + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ + .info = cxt_spdif_ctrl_info, \ + .get = cxt_spdif_ctrl_get, \ + .put = cxt_spdif_ctrl_put, \ + .private_value = nid | (mask<<16) } + +/* Conexant 5045 specific */ + +static hda_nid_t cxt5045_dac_nids[1] = { 0x19 }; +static hda_nid_t cxt5045_adc_nids[1] = { 0x1a }; +static hda_nid_t cxt5045_capsrc_nids[1] = { 0x1a }; +#define CXT5045_SPDIF_OUT 0x13 + + +static struct hda_input_mux cxt5045_capture_source = { + .num_items = 2, + .items = { + { "ExtMic", 0x1 }, + { "LineIn", 0x2 }, + } +}; + +/* turn on/off EAPD (+ mute HP) as a master switch */ +static int cxt5045_hp_master_sw_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct conexant_spec *spec = codec->spec; + + if (!conexant_eapd_put(kcontrol, ucontrol)) + return 0; + + /* toggle HP mute appropriately */ + snd_hda_codec_amp_update(codec, 0x11, 0, HDA_OUTPUT, 0, + 0x80, spec->cur_eapd ? 0 : 0x80); + snd_hda_codec_amp_update(codec, 0x11, 1, HDA_OUTPUT, 0, + 0x80, spec->cur_eapd ? 0 : 0x80); + return 1; +} + +/* bind volumes of both NID 0x10 and 0x11 */ +static int cxt5045_hp_master_vol_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + long *valp = ucontrol->value.integer.value; + int change; + + change = snd_hda_codec_amp_update(codec, 0x10, 0, HDA_OUTPUT, 0, + 0x7f, valp[0] & 0x7f); + change |= snd_hda_codec_amp_update(codec, 0x10, 1, HDA_OUTPUT, 0, + 0x7f, valp[1] & 0x7f); + snd_hda_codec_amp_update(codec, 0x11, 0, HDA_OUTPUT, 0, + 0x7f, valp[0] & 0x7f); + snd_hda_codec_amp_update(codec, 0x11, 1, HDA_OUTPUT, 0, + 0x7f, valp[1] & 0x7f); + return change; +} + + +/* mute internal speaker if HP is plugged */ +static void cxt5045_hp_automute(struct hda_codec *codec) +{ + unsigned int present; + + present = snd_hda_codec_read(codec, 0x11, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + snd_hda_codec_amp_update(codec, 0x10, 0, HDA_OUTPUT, 0, + 0x80, present ? 0x80 : 0); + snd_hda_codec_amp_update(codec, 0x10, 1, HDA_OUTPUT, 0, + 0x80, present ? 0x80 : 0); +} + +/* unsolicited event for HP jack sensing */ +static void cxt5045_hp_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + res >>= 26; + switch (res) { + case CONEXANT_HP_EVENT: + cxt5045_hp_automute(codec); + break; + } +} + +static struct snd_kcontrol_new cxt5045_mixers[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Source", + .info = conexant_mux_enum_info, + .get = conexant_mux_enum_get, + .put = conexant_mux_enum_put + }, + HDA_CODEC_VOLUME("Mic Bypass Capture Volume", 0x17, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Mic Bypass Capture Switch", 0x17, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x1a, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x1a, 0x02, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Volume", + .info = snd_hda_mixer_amp_volume_info, + .get = snd_hda_mixer_amp_volume_get, + .put = cxt5045_hp_master_vol_put, + .private_value = HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT), + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .info = conexant_eapd_info, + .get = conexant_eapd_get, + .put = cxt5045_hp_master_sw_put, + .private_value = 0x11, + }, + + {} +}; + +static struct hda_verb cxt5045_init_verbs[] = { + /* Line in, Mic */ + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_50 }, + /* HP, Amp */ + {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + {0x1A, AC_VERB_SET_CONNECT_SEL,0x01}, + {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, + AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x00}, + {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, + AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x03}, + /* Record selector: Front mic */ + {0x14, AC_VERB_SET_CONNECT_SEL,0x03}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, + AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17}, + /* SPDIF route: PCM */ + { 0x13, AC_VERB_SET_CONNECT_SEL, 0x0 }, + /* pin sensing on HP and Mic jacks */ + {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, + /* EAPD */ + {0x10, AC_VERB_SET_EAPD_BTLENABLE, 0x0 }, /* default on */ + { } /* end */ +}; + +#ifdef CONFIG_SND_DEBUG +/* Test configuration for debugging, modelled after the ALC260 test + * configuration. + */ +static struct hda_input_mux cxt5045_test_capture_source = { + .num_items = 5, + .items = { + { "MIXER", 0x0 }, + { "MIC1 pin", 0x1 }, + { "LINE1 pin", 0x2 }, + { "HP-OUT pin", 0x3 }, + { "CD pin", 0x4 }, + }, +}; + +static struct snd_kcontrol_new cxt5045_test_mixer[] = { + + /* Output controls */ + HDA_CODEC_VOLUME("OutAmp-1 Volume", 0x19, 0x00, HDA_OUTPUT), + HDA_CODEC_MUTE("OutAmp-1 Switch", 0x19,0x00, HDA_OUTPUT), + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x10, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Speaker Playback Switch", 0x10, 0x0, HDA_OUTPUT), + + /* Modes for retasking pin widgets */ + CXT_PIN_MODE("HP-OUT pin mode", 0x11, CXT_PIN_DIR_INOUT), + CXT_PIN_MODE("LINE1 pin mode", 0x12, CXT_PIN_DIR_INOUT), + + /* Loopback mixer controls */ + HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x17, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("MIC1 Playback Switch", 0x17, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("LINE loopback Playback Volume", 0x17, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("LINE loopback Playback Switch", 0x17, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x17, 0x03, HDA_INPUT), + HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x17, 0x03, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x17, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x17, 0x04, HDA_INPUT), + + /* Controls for GPIO pins, assuming they exist and are configured as outputs */ + CXT_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01), +#if 0 /* limit this to one GPIO pin for now */ + CXT_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02), + CXT_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04), + CXT_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08), +#endif + CXT_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x13, 0x01), + + HDA_CODEC_VOLUME("Capture Volume", 0x17, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Capture Switch", 0x17, 0x0, HDA_OUTPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Input Source", + .info = conexant_mux_enum_info, + .get = conexant_mux_enum_get, + .put = conexant_mux_enum_put, + }, + + { } /* end */ +}; + +static struct hda_verb cxt5045_test_init_verbs[] = { + /* Enable all GPIOs as outputs with an initial value of 0 */ + {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f}, + {0x01, AC_VERB_SET_GPIO_DATA, 0x00}, + {0x01, AC_VERB_SET_GPIO_MASK, 0x0f}, + + /* Enable retasking pins as output, initially without power amp */ + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + + /* Disable digital (SPDIF) pins initially, but users can enable + * them via a mixer switch. In the case of SPDIF-out, this initverb + * payload also sets the generation to 0, output to be in "consumer" + * PCM format, copyright asserted, no pre-emphasis and no validity + * control. + */ + {0x13, AC_VERB_SET_DIGI_CONVERT_1, 0}, + + /* Start with output sum widgets muted and their output gains at min */ + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + + /* Unmute retasking pin widget output buffers since the default + * state appears to be output. As the pin mode is changed by the + * user the pin mode control will take care of enabling the pin's + * input/output buffers as needed. + */ + {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + /* Mute capture amp left and right */ + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + + /* Set ADC connection select to match default mixer setting (mic1 + * pin) + */ + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* Mute all inputs to mixer widget (even unconnected ones) */ + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* Mixer pin */ + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* Mic1 pin */ + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* Line pin */ + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* HP pin */ + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */ + + { } +}; +#endif + + +/* initialize jack-sensing, too */ +static int cxt5045_init(struct hda_codec *codec) +{ + conexant_init(codec); + cxt5045_hp_automute(codec); + return 0; +} + + +enum { + CXT5045_LAPTOP, +#ifdef CONFIG_SND_DEBUG + CXT5045_TEST, +#endif +}; + +static struct hda_board_config cxt5045_cfg_tbl[] = { + /* Laptops w/ EAPD support */ + { .modelname = "laptop", .config = CXT5045_LAPTOP }, + /* HP DV6000Z */ + { .pci_subvendor = 0x103c, .pci_subdevice = 0x30b7, + .config = CXT5045_LAPTOP }, +#ifdef CONFIG_SND_DEBUG + { .modelname = "test", .config = CXT5045_TEST }, +#endif + + {} +}; + +static int patch_cxt5045(struct hda_codec *codec) +{ + struct conexant_spec *spec; + int board_config; + + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (!spec) + return -ENOMEM; + mutex_init(&spec->amp_mutex); + codec->spec = spec; + + spec->multiout.max_channels = 2; + spec->multiout.num_dacs = ARRAY_SIZE(cxt5045_dac_nids); + spec->multiout.dac_nids = cxt5045_dac_nids; + spec->multiout.dig_out_nid = CXT5045_SPDIF_OUT; + spec->num_adc_nids = 1; + spec->adc_nids = cxt5045_adc_nids; + spec->capsrc_nids = cxt5045_capsrc_nids; + spec->input_mux = &cxt5045_capture_source; + spec->num_mixers = 1; + spec->mixers[0] = cxt5045_mixers; + spec->num_init_verbs = 1; + spec->init_verbs[0] = cxt5045_init_verbs; + spec->spdif_route = 0; + + codec->patch_ops = conexant_patch_ops; + codec->patch_ops.unsol_event = cxt5045_hp_unsol_event; + + board_config = snd_hda_check_board_config(codec, cxt5045_cfg_tbl); + switch (board_config) { + case CXT5045_LAPTOP: + spec->input_mux = &cxt5045_capture_source; + spec->num_init_verbs = 2; + spec->init_verbs[1] = cxt5045_init_verbs; + spec->mixers[0] = cxt5045_mixers; + codec->patch_ops.init = cxt5045_init; + break; +#ifdef CONFIG_SND_DEBUG + case CXT5045_TEST: + spec->input_mux = &cxt5045_test_capture_source; + spec->mixers[0] = cxt5045_test_mixer; + spec->init_verbs[0] = cxt5045_test_init_verbs; +#endif + } + return 0; +} + + +/* Conexant 5047 specific */ + +static hda_nid_t cxt5047_dac_nids[1] = { 0x10 }; +static hda_nid_t cxt5047_adc_nids[1] = { 0x12 }; +static hda_nid_t cxt5047_capsrc_nids[1] = { 0x1a }; +#define CXT5047_SPDIF_OUT 0x11 + + +static struct hda_input_mux cxt5047_capture_source = { + .num_items = 2, + .items = { + { "ExtMic", 0x1 }, + { "IntMic", 0x2 }, + } +}; + +static struct hda_input_mux cxt5047_hp_capture_source = { + .num_items = 1, + .items = { + { "ExtMic", 0x1 }, + } +}; + +/* turn on/off EAPD (+ mute HP) as a master switch */ +static int cxt5047_hp_master_sw_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct conexant_spec *spec = codec->spec; + + if (!conexant_eapd_put(kcontrol, ucontrol)) + return 0; + + /* toggle HP mute appropriately */ + snd_hda_codec_amp_update(codec, 0x13, 0, HDA_OUTPUT, 0, + 0x80, spec->cur_eapd ? 0 : 0x80); + snd_hda_codec_amp_update(codec, 0x13, 1, HDA_OUTPUT, 0, + 0x80, spec->cur_eapd ? 0 : 0x80); + return 1; +} + +#if 0 +/* bind volumes of both NID 0x13 and 0x1d */ +static int cxt5047_hp_master_vol_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + long *valp = ucontrol->value.integer.value; + int change; + + change = snd_hda_codec_amp_update(codec, 0x1c, 0, HDA_OUTPUT, 0, + 0x7f, valp[0] & 0x7f); + change |= snd_hda_codec_amp_update(codec, 0x1c, 1, HDA_OUTPUT, 0, + 0x7f, valp[1] & 0x7f); + snd_hda_codec_amp_update(codec, 0x13, 0, HDA_OUTPUT, 0, + 0x7f, valp[0] & 0x7f); + snd_hda_codec_amp_update(codec, 0x13, 1, HDA_OUTPUT, 0, + 0x7f, valp[1] & 0x7f); + return change; +} +#endif + +/* mute internal speaker if HP is plugged */ +static void cxt5047_hp_automute(struct hda_codec *codec) +{ + unsigned int present; + + present = snd_hda_codec_read(codec, 0x13, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + snd_hda_codec_amp_update(codec, 0x1c, 0, HDA_OUTPUT, 0, + 0x80, present ? 0x80 : 0); + snd_hda_codec_amp_update(codec, 0x1c, 1, HDA_OUTPUT, 0, + 0x80, present ? 0x80 : 0); +} + +/* toggle input of built-in and mic jack appropriately */ +static void cxt5047_hp_automic(struct hda_codec *codec) +{ + static struct hda_verb mic_jack_on[] = { + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, + {} + }; + static struct hda_verb mic_jack_off[] = { + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, + {} + }; + unsigned int present; + + present = snd_hda_codec_read(codec, 0x08, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + if (present) + snd_hda_sequence_write(codec, mic_jack_on); + else + snd_hda_sequence_write(codec, mic_jack_off); +} + +/* unsolicited event for HP jack sensing */ +static void cxt5047_hp_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + res >>= 26; + switch (res) { + case CONEXANT_HP_EVENT: + cxt5047_hp_automute(codec); + break; + case CONEXANT_MIC_EVENT: + cxt5047_hp_automic(codec); + break; + } +} + +static struct snd_kcontrol_new cxt5047_mixers[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Source", + .info = conexant_mux_enum_info, + .get = conexant_mux_enum_get, + .put = conexant_mux_enum_put + }, + HDA_CODEC_VOLUME("Mic Bypass Capture Volume", 0x19, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Mic Bypass Capture Switch", 0x19, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x03, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x12, 0x03, HDA_INPUT), + HDA_CODEC_VOLUME("PCM Volume", 0x10, 0x00, HDA_OUTPUT), + HDA_CODEC_MUTE("PCM Switch", 0x10, 0x00, HDA_OUTPUT), + HDA_CODEC_VOLUME("Master Playback Volume", 0x13, 0x00, HDA_OUTPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .info = conexant_eapd_info, + .get = conexant_eapd_get, + .put = cxt5047_hp_master_sw_put, + .private_value = 0x13, + }, + + {} +}; + +static struct snd_kcontrol_new cxt5047_hp_mixers[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Source", + .info = conexant_mux_enum_info, + .get = conexant_mux_enum_get, + .put = conexant_mux_enum_put + }, + HDA_CODEC_VOLUME("Mic Bypass Capture Volume", 0x19, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Mic Bypass Capture Switch", 0x19,0x02,HDA_INPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x03, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x12, 0x03, HDA_INPUT), + HDA_CODEC_VOLUME("PCM Volume", 0x10, 0x00, HDA_OUTPUT), + HDA_CODEC_MUTE("PCM Switch", 0x10, 0x00, HDA_OUTPUT), + HDA_CODEC_VOLUME("Master Playback Volume", 0x13, 0x00, HDA_OUTPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .info = conexant_eapd_info, + .get = conexant_eapd_get, + .put = cxt5047_hp_master_sw_put, + .private_value = 0x13, + }, + { } /* end */ +}; + +static struct hda_verb cxt5047_init_verbs[] = { + /* Line in, Mic, Built-in Mic */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_50 }, + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_50 }, + /* HP, Amp */ + {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + {0x1A, AC_VERB_SET_CONNECT_SEL,0x01}, + {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, + AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x00}, + {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, + AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x03}, + /* Record selector: Front mic */ + {0x12, AC_VERB_SET_CONNECT_SEL,0x03}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, + AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17}, + /* SPDIF route: PCM */ + { 0x18, AC_VERB_SET_CONNECT_SEL, 0x0 }, + { } /* end */ +}; + +/* configuration for Toshiba Laptops */ +static struct hda_verb cxt5047_toshiba_init_verbs[] = { + {0x13, AC_VERB_SET_EAPD_BTLENABLE, 0x0 }, /* default on */ + /* pin sensing on HP and Mic jacks */ + {0x13, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, + {} +}; + +/* configuration for HP Laptops */ +static struct hda_verb cxt5047_hp_init_verbs[] = { + /* pin sensing on HP and Mic jacks */ + {0x13, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, + {} +}; + +/* Test configuration for debugging, modelled after the ALC260 test + * configuration. + */ +#ifdef CONFIG_SND_DEBUG +static struct hda_input_mux cxt5047_test_capture_source = { + .num_items = 5, + .items = { + { "MIXER", 0x0 }, + { "LINE1 pin", 0x1 }, + { "MIC1 pin", 0x2 }, + { "MIC2 pin", 0x3 }, + { "CD pin", 0x4 }, + }, +}; + +static struct snd_kcontrol_new cxt5047_test_mixer[] = { + + /* Output only controls */ + HDA_CODEC_VOLUME("OutAmp-1 Volume", 0x10, 0x00, HDA_OUTPUT), + HDA_CODEC_MUTE("OutAmp-1 Switch", 0x10,0x00, HDA_OUTPUT), + HDA_CODEC_VOLUME("OutAmp-2 Volume", 0x1c, 0x00, HDA_OUTPUT), + HDA_CODEC_MUTE("OutAmp-2 Switch", 0x1c, 0x00, HDA_OUTPUT), + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x1d, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Speaker Playback Switch", 0x1d, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("HeadPhone Playback Volume", 0x13, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("HeadPhone Playback Switch", 0x13, 0x0, HDA_OUTPUT), + + /* Modes for retasking pin widgets */ + CXT_PIN_MODE("LINE1 pin mode", 0x14, CXT_PIN_DIR_INOUT), + CXT_PIN_MODE("MIC1 pin mode", 0x15, CXT_PIN_DIR_INOUT), + + /* Loopback mixer controls */ + HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x19, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("MIC1 Playback Switch", 0x19, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x19, 0x03, HDA_INPUT), + HDA_CODEC_MUTE("MIC2 Playback Switch", 0x19, 0x03, HDA_INPUT), + HDA_CODEC_VOLUME("LINE Playback Volume", 0x19, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("LINE Playback Switch", 0x19, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x19, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x19, 0x04, HDA_INPUT), + + /* Controls for GPIO pins, assuming they exist and are configured as outputs */ + CXT_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01), +#if 0 /* limit this to one GPIO pin for now */ + CXT_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02), + CXT_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04), + CXT_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08), +#endif + CXT_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x18, 0x01), + + HDA_CODEC_VOLUME("Capture Volume", 0x19, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Capture Switch", 0x19, 0x0, HDA_OUTPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Input Source", + .info = conexant_mux_enum_info, + .get = conexant_mux_enum_get, + .put = conexant_mux_enum_put, + }, + + { } /* end */ +}; + +static struct hda_verb cxt5047_test_init_verbs[] = { + /* Enable all GPIOs as outputs with an initial value of 0 */ + {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f}, + {0x01, AC_VERB_SET_GPIO_DATA, 0x00}, + {0x01, AC_VERB_SET_GPIO_MASK, 0x0f}, + + /* Enable retasking pins as output, initially without power amp */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + + /* Disable digital (SPDIF) pins initially, but users can enable + * them via a mixer switch. In the case of SPDIF-out, this initverb + * payload also sets the generation to 0, output to be in "consumer" + * PCM format, copyright asserted, no pre-emphasis and no validity + * control. + */ + {0x18, AC_VERB_SET_DIGI_CONVERT_1, 0}, + + /* Ensure mic1, mic2, line1 pin widgets take input from the + * OUT1 sum bus when acting as an output. + */ + {0x1a, AC_VERB_SET_CONNECT_SEL, 0}, + {0x1b, AC_VERB_SET_CONNECT_SEL, 0}, + + /* Start with output sum widgets muted and their output gains at min */ + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + + /* Unmute retasking pin widget output buffers since the default + * state appears to be output. As the pin mode is changed by the + * user the pin mode control will take care of enabling the pin's + * input/output buffers as needed. + */ + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + /* Mute capture amp left and right */ + {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + + /* Set ADC connection select to match default mixer setting (mic1 + * pin) + */ + {0x12, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* Mute all inputs to mixer widget (even unconnected ones) */ + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */ + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */ + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */ + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */ + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */ + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */ + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */ + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */ + + { } +}; +#endif + + +/* initialize jack-sensing, too */ +static int cxt5047_hp_init(struct hda_codec *codec) +{ + conexant_init(codec); + cxt5047_hp_automute(codec); + cxt5047_hp_automic(codec); + return 0; +} + + +enum { + CXT5047_LAPTOP, +#ifdef CONFIG_SND_DEBUG + CXT5047_TEST, +#endif + CXT5047_LAPTOP_HP, + CXT5047_LAPTOP_EAPD +}; + +static struct hda_board_config cxt5047_cfg_tbl[] = { + /* Laptops w/o EAPD support */ + { .modelname = "laptop", .config = CXT5047_LAPTOP }, + /*HP DV1000 */ + { .pci_subvendor = 0x103c, .pci_subdevice = 0x30a0, + .config = CXT5047_LAPTOP }, + /*HP DV2000T/DV3000T */ + { .pci_subvendor = 0x103c, .pci_subdevice = 0x30b2, + .config = CXT5047_LAPTOP }, + /* Not all HP's are created equal */ + { .modelname = "laptop-hp", .config = CXT5047_LAPTOP_HP }, + /*HP DV5200TX/DV8000T / Compaq V5209US/V5204NR */ + { .pci_subvendor = 0x103c, .pci_subdevice = 0x30a5, + .config = CXT5047_LAPTOP_HP }, + /* Laptops with EAPD support */ + { .modelname = "laptop-eapd", .config = CXT5047_LAPTOP_EAPD }, + { .pci_subvendor = 0x1179, .pci_subdevice = 0xff31, + .config = CXT5047_LAPTOP_EAPD }, /* Toshiba P100 */ +#ifdef CONFIG_SND_DEBUG + { .modelname = "test", .config = CXT5047_TEST }, +#endif + + {} +}; + +static int patch_cxt5047(struct hda_codec *codec) +{ + struct conexant_spec *spec; + int board_config; + + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (!spec) + return -ENOMEM; + mutex_init(&spec->amp_mutex); + codec->spec = spec; + + spec->multiout.max_channels = 2; + spec->multiout.num_dacs = ARRAY_SIZE(cxt5047_dac_nids); + spec->multiout.dac_nids = cxt5047_dac_nids; + spec->multiout.dig_out_nid = CXT5047_SPDIF_OUT; + spec->num_adc_nids = 1; + spec->adc_nids = cxt5047_adc_nids; + spec->capsrc_nids = cxt5047_capsrc_nids; + spec->input_mux = &cxt5047_capture_source; + spec->num_mixers = 1; + spec->mixers[0] = cxt5047_mixers; + spec->num_init_verbs = 1; + spec->init_verbs[0] = cxt5047_init_verbs; + spec->spdif_route = 0; + + codec->patch_ops = conexant_patch_ops; + codec->patch_ops.unsol_event = cxt5047_hp_unsol_event; + + board_config = snd_hda_check_board_config(codec, cxt5047_cfg_tbl); + switch (board_config) { + case CXT5047_LAPTOP: + break; + case CXT5047_LAPTOP_HP: + spec->input_mux = &cxt5047_hp_capture_source; + spec->num_init_verbs = 2; + spec->init_verbs[1] = cxt5047_hp_init_verbs; + spec->mixers[0] = cxt5047_hp_mixers; + codec->patch_ops.init = cxt5047_hp_init; + break; + case CXT5047_LAPTOP_EAPD: + spec->num_init_verbs = 2; + spec->init_verbs[1] = cxt5047_toshiba_init_verbs; + break; +#ifdef CONFIG_SND_DEBUG + case CXT5047_TEST: + spec->input_mux = &cxt5047_test_capture_source; + spec->mixers[0] = cxt5047_test_mixer; + spec->init_verbs[0] = cxt5047_test_init_verbs; +#endif + } + return 0; +} + +struct hda_codec_preset snd_hda_preset_conexant[] = { + { .id = 0x14f15045, .name = "CXT5045", .patch = patch_cxt5045 }, + { .id = 0x14f15047, .name = "CXT5047", .patch = patch_cxt5047 }, + {} /* terminator */ +}; -- cgit v1.2.3 From d1f6754748a6523fcd35be7f4aaaf6fde5e5ca87 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 14 Nov 2006 12:30:52 +0100 Subject: [ALSA] hda-codec - Add support for Sony UX-90s Added the model entry (model=hippo) for Sony UX-90s with ALC262 codec. Although the device has no SPDIF output, the hippo model adds a PCM output, but it must be harmless. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index b1e8cd8961d..8fc0fbb4f52 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6440,6 +6440,9 @@ static struct hda_board_config alc262_cfg_tbl[] = { { .modelname = "hippo", .pci_subvendor =0x1002, .pci_subdevice = 0x437b, .config = ALC262_HIPPO}, + { .modelname = "hippo", + .pci_subvendor = 0x104d, .pci_subdevice = 0x8203, + .config = ALC262_HIPPO }, /* Sony UX-90s */ { .modelname = "hippo_1", .pci_subvendor =0x17ff, .pci_subdevice = 0x058f, .config = ALC262_HIPPO_1}, -- cgit v1.2.3 From a2ee47026025a3d1a5c2eccf3b0aa6c9fb02b101 Mon Sep 17 00:00:00 2001 From: Tobin Davis Date: Thu, 16 Nov 2006 16:24:35 +0100 Subject: [ALSA] hda-codec - Change Gigabyte K8N51 from 6stack to 6stack-digout This patch moves the entry for the Gigabyte K8N51 from the 6stack grouping to the 6stack-digout grouping, allowing for S/PDIF output functionality. Signed-off-by: Tobin Davis Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 8fc0fbb4f52..7b4bac3567d 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -2427,7 +2427,6 @@ static struct hda_board_config alc880_cfg_tbl[] = { { .pci_subvendor = 0x1043, .pci_subdevice = 0x8196, .config = ALC880_6ST }, /* ASUS P5GD1-HVM */ { .pci_subvendor = 0x1043, .pci_subdevice = 0x81b4, .config = ALC880_6ST }, { .pci_subvendor = 0x1019, .pci_subdevice = 0xa884, .config = ALC880_6ST }, /* Acer APFV */ - { .pci_subvendor = 0x1458, .pci_subdevice = 0xa102, .config = ALC880_6ST }, /* Gigabyte K8N51 */ { .modelname = "6stack-digout", .config = ALC880_6ST_DIG }, { .pci_subvendor = 0x2668, .pci_subdevice = 0x8086, .config = ALC880_6ST_DIG }, @@ -2441,6 +2440,7 @@ static struct hda_board_config alc880_cfg_tbl[] = { { .pci_subvendor = 0x1297, .pci_subdevice = 0xc790, .config = ALC880_6ST_DIG }, /* Shuttle ST20G5 */ { .pci_subvendor = 0x1509, .pci_subdevice = 0x925d, .config = ALC880_6ST_DIG }, /* FIC P4M-915GD1 */ { .pci_subvendor = 0x1695, .pci_subdevice = 0x4012, .config = ALC880_5ST_DIG }, /* Epox EP-5LDA+ GLi */ + { .pci_subvendor = 0x1458, .pci_subdevice = 0xa102, .config = ALC880_6ST_DIG }, /* Gigabyte K8N51 */ { .modelname = "asus", .config = ALC880_ASUS }, { .pci_subvendor = 0x1043, .pci_subdevice = 0x1964, .config = ALC880_ASUS_DIG }, -- cgit v1.2.3 From 9dece1d74bd41f593cb1d9e387dc894dd826abf7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 16 Nov 2006 17:12:49 +0100 Subject: [ALSA] hda-codec - Fix ALC861 connection of front-output Fix the wrongly set SET_CONNECTION verb for NID 0x0f of ALC861. The widget has only a single connection although the init verb sets to 0x01. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 7b4bac3567d..02ee6565b6e 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6922,7 +6922,7 @@ static struct hda_verb alc861_base_init_verbs[] = { /* port-E for HP out (front panel) */ { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* route front PCM to HP */ - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, /* port-F for mic-in (front panel) with vref */ { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, /* port-G for CLFE (rear panel) */ @@ -6986,7 +6986,7 @@ static struct hda_verb alc861_threestack_init_verbs[] = { /* port-E for HP out (front panel) */ { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* route front PCM to HP */ - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, /* port-F for mic-in (front panel) with vref */ { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, /* port-G for CLFE (rear panel) */ @@ -7046,7 +7046,7 @@ static struct hda_verb alc861_uniwill_m31_init_verbs[] = { /* port-E for HP out (front panel) */ { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, // this has to be set to VREF80 /* route front PCM to HP */ - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, /* port-F for mic-in (front panel) with vref */ { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, /* port-G for CLFE (rear panel) */ @@ -7108,7 +7108,7 @@ static struct hda_verb alc861_asus_init_verbs[] = { /* port-E for HP out (front panel) */ { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, /* this has to be set to VREF80 */ /* route front PCM to HP */ - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, /* port-F for mic-in (front panel) with vref */ { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, /* port-G for CLFE (rear panel) */ -- cgit v1.2.3 From e3a4050cdd7df05fba6512ac71c9360246e19ac4 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 16 Nov 2006 17:24:20 +0100 Subject: [ALSA] hda-codec - Add model for ASUS W3j laptop Added a proper model entry (model=laptop-eapd) for ASUS W3j laptop with AD1986A codec. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_analog.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 9260560303e..9ce4c9f869b 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -830,6 +830,8 @@ static struct hda_board_config ad1986a_cfg_tbl[] = { .config = AD1986A_LAPTOP_EAPD }, /* ASUS Z62F */ { .pci_subvendor = 0x1043, .pci_subdevice = 0x12b3, .config = AD1986A_LAPTOP_EAPD }, /* ASUS V1j */ + { .pci_subvendor = 0x1043, .pci_subdevice = 0x1302, + .config = AD1986A_LAPTOP_EAPD }, /* ASUS W3j */ { .pci_subvendor = 0x103c, .pci_subdevice = 0x30af, .config = AD1986A_LAPTOP_EAPD }, /* HP Compaq Presario B2800 */ { .pci_subvendor = 0x17aa, .pci_subdevice = 0x2066, -- cgit v1.2.3 From 761ccb24b4cad211295a5abe231f418ad97aac04 Mon Sep 17 00:00:00 2001 From: Tobin Davis Date: Mon, 20 Nov 2006 12:02:56 +0100 Subject: [ALSA] hda-codec - Add support for Evesham Voyager C530RD laptops This patch adds support for the Evesham Voyager C530RD series laptops. So far, only playback has been tested, but microphone should also work. Signed-off-by: Tobin Davis Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 02ee6565b6e..aeb408cbe1e 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -5480,6 +5480,8 @@ static struct hda_board_config alc883_cfg_tbl[] = { { .pci_subvendor = 0x161f, .pci_subdevice = 0x2054, .modelname = "medion", .config = ALC883_MEDION }, { .modelname = "laptop-eapd", .config = ALC883_LAPTOP_EAPD }, + { .pci_subvendor = 0x1071, .pci_subdevice = 0x8258, + .config = ALC883_LAPTOP_EAPD }, /* Evesham Voyager C530RD */ { .pci_subvendor = 0x1558, .pci_subdevice = 0, .config = ALC883_LAPTOP_EAPD }, /* Clevo */ { .modelname = "auto", .config = ALC883_AUTO }, -- cgit v1.2.3 From ddc2cec4dbec157ac7426111205d59ac28f887ee Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Mon, 20 Nov 2006 12:03:44 +0100 Subject: [ALSA] make sound/pci/hda/patch_sigmatel.c:stac92xx_dmic_labels[] static This patch makes the needlessly global stac92xx_dmic_labels[] static. Signed-off-by: Adrian Bunk Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_sigmatel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 8f52372d66a..1b428a1eafd 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -1201,7 +1201,7 @@ static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec, } /* labels for dmic mux inputs */ -const char *stac92xx_dmic_labels[5] = { +static const char *stac92xx_dmic_labels[5] = { "Analog Inputs", "Digital Mic 1", "Digital Mic 2", "Digital Mic 3", "Digital Mic 4" }; -- cgit v1.2.3 From 14e1d357e4fed9577d349952b71ec7d81aad710c Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 20 Nov 2006 16:35:18 +0100 Subject: [ALSA] atiixp - Add a parameter ac97_quirk Add an option to specify the AC'97 codec instead of probing. This is a fix for bugzilla #7467. Signed-off-by: Dan Carpenter Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/atiixp.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) (limited to 'sound') diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c index 86710df71a8..92df811d695 100644 --- a/sound/pci/atiixp.c +++ b/sound/pci/atiixp.c @@ -45,6 +45,7 @@ static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */ static int ac97_clock = 48000; static char *ac97_quirk; static int spdif_aclink = 1; +static int ac97_codec = -1; module_param(index, int, 0444); MODULE_PARM_DESC(index, "Index value for ATI IXP controller."); @@ -54,6 +55,8 @@ module_param(ac97_clock, int, 0444); MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (default 48000Hz)."); module_param(ac97_quirk, charp, 0444); MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware."); +module_param(ac97_codec, int, 0444); +MODULE_PARM_DESC(ac97_codec, "Specify codec instead of probing."); module_param(spdif_aclink, bool, 0444); MODULE_PARM_DESC(spdif_aclink, "S/PDIF over AC-link."); @@ -293,6 +296,22 @@ static struct pci_device_id snd_atiixp_ids[] = { MODULE_DEVICE_TABLE(pci, snd_atiixp_ids); +struct atiixp_quirk { + unsigned short subvendor; + unsigned short subdevice; + const char *name; + int ac97_codec; +}; + +static struct atiixp_quirk atiixp_quirks[] __devinitdata = { + { + .subvendor = 0x15bd, + .subdevice = 0x3100, + .name = "DFI RS482", + .ac97_codec = 0, + }, + { .subvendor = 0 } /* terminator */ +}; /* * lowlevel functions @@ -553,11 +572,37 @@ static int snd_atiixp_aclink_down(struct atiixp *chip) ATI_REG_ISR_CODEC2_NOT_READY) #define CODEC_CHECK_BITS (ALL_CODEC_NOT_READY|ATI_REG_ISR_NEW_FRAME) +static int ac97_probing_bugs(struct pci_dev *pci) +{ + int i = 0; + + while (atiixp_quirks[i].subvendor) { + if (pci->subsystem_vendor == atiixp_quirks[i].subvendor && + pci->subsystem_device == atiixp_quirks[i].subdevice) { + printk(KERN_INFO "Atiixp quirk for %s. " + "Forcing codec %d\n", atiixp_quirks[i].name, + atiixp_quirks[i].ac97_codec); + return atiixp_quirks[i].ac97_codec; + } + i++; + } + /* this hardware doesn't need workarounds. Probe for codec */ + return -1; +} + static int snd_atiixp_codec_detect(struct atiixp *chip) { int timeout; chip->codec_not_ready_bits = 0; + if (ac97_codec == -1) + ac97_codec = ac97_probing_bugs(chip->pci); + if (ac97_codec >= 0) { + chip->codec_not_ready_bits |= + CODEC_CHECK_BITS ^ (1 << (ac97_codec + 10)); + return 0; + } + atiixp_write(chip, IER, CODEC_CHECK_BITS); /* wait for the interrupts */ timeout = 50; -- cgit v1.2.3 From 5cd575290b4481b3a6ea307afed760df60d01cbc Mon Sep 17 00:00:00 2001 From: Tobin Davis Date: Mon, 20 Nov 2006 17:42:09 +0100 Subject: [ALSA] hda-codec - Add missing array to conexant driver This patch adds a missing array to the conexant driver. Signed-off-by: Tobin Davis Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_conexant.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 9b69b62a550..7e7d0c110c4 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -552,6 +552,9 @@ static hda_nid_t cxt5045_adc_nids[1] = { 0x1a }; static hda_nid_t cxt5045_capsrc_nids[1] = { 0x1a }; #define CXT5045_SPDIF_OUT 0x13 +static struct hda_channel_mode cxt5045_modes[1] = { + { 2, NULL }, +}; static struct hda_input_mux cxt5045_capture_source = { .num_items = 2, @@ -842,6 +845,9 @@ static int patch_cxt5045(struct hda_codec *codec) spec->num_init_verbs = 1; spec->init_verbs[0] = cxt5045_init_verbs; spec->spdif_route = 0; + spec->num_channel_mode = ARRAY_SIZE(cxt5045_modes), + spec->channel_mode = cxt5045_modes, + codec->patch_ops = conexant_patch_ops; codec->patch_ops.unsol_event = cxt5045_hp_unsol_event; @@ -873,6 +879,9 @@ static hda_nid_t cxt5047_adc_nids[1] = { 0x12 }; static hda_nid_t cxt5047_capsrc_nids[1] = { 0x1a }; #define CXT5047_SPDIF_OUT 0x11 +static struct hda_channel_mode cxt5047_modes[1] = { + { 2, NULL }, +}; static struct hda_input_mux cxt5047_capture_source = { .num_items = 2, @@ -1039,7 +1048,7 @@ static struct hda_verb cxt5047_init_verbs[] = { {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_50 }, /* HP, Amp */ {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - {0x1A, AC_VERB_SET_CONNECT_SEL,0x01}, + {0x1A, AC_VERB_SET_CONNECT_SEL,0x03}, {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x00}, {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, @@ -1111,9 +1120,9 @@ static struct snd_kcontrol_new cxt5047_test_mixer[] = { HDA_CODEC_VOLUME("CD Playback Volume", 0x19, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x19, 0x04, HDA_INPUT), +#if 0 /* Controls for GPIO pins, assuming they exist and are configured as outputs */ CXT_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01), -#if 0 /* limit this to one GPIO pin for now */ CXT_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02), CXT_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04), CXT_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08), @@ -1262,6 +1271,8 @@ static int patch_cxt5047(struct hda_codec *codec) spec->num_init_verbs = 1; spec->init_verbs[0] = cxt5047_init_verbs; spec->spdif_route = 0; + spec->num_channel_mode = ARRAY_SIZE(cxt5047_modes), + spec->channel_mode = cxt5047_modes, codec->patch_ops = conexant_patch_ops; codec->patch_ops.unsol_event = cxt5047_hp_unsol_event; -- cgit v1.2.3 From 0b51ba07e2e2866bfea40c5551a926dbefae64da Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Mon, 20 Nov 2006 17:50:17 +0100 Subject: [ALSA] make sound/core/control.c:snd_ctl_new() static Now that everyone uses snd_ctl_new1() and noone is using snd_ctl_new() anymore, we can make it static. Signed-off-by: Adrian Bunk Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/core/control.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/core/control.c b/sound/core/control.c index 67f09b8f85e..42bcf2794b2 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -183,7 +183,8 @@ EXPORT_SYMBOL(snd_ctl_notify); * * Returns the pointer of the new instance, or NULL on failure. */ -struct snd_kcontrol *snd_ctl_new(struct snd_kcontrol *control, unsigned int access) +static struct snd_kcontrol *snd_ctl_new(struct snd_kcontrol *control, + unsigned int access) { struct snd_kcontrol *kctl; unsigned int idx; @@ -201,8 +202,6 @@ struct snd_kcontrol *snd_ctl_new(struct snd_kcontrol *control, unsigned int acce return kctl; } -EXPORT_SYMBOL(snd_ctl_new); - /** * snd_ctl_new1 - create a control instance from the template * @ncontrol: the initialization record -- cgit v1.2.3 From 69e134189763341560a5201c2eee9930eeb0b4f1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 21 Nov 2006 12:10:55 +0100 Subject: [ALSA] hda-intel - Disable INTX when MSI is used Call pci_intx() to disable/enable INTX when MSI is used/unused. Nvidia and AMD boards seem to have problems with MSI when INTX isn't disabled. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/hda_intel.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index d15c9b845f2..e6a1e37b373 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1391,6 +1391,7 @@ static int azx_acquire_irq(struct azx *chip, int do_disconnect) return -1; } chip->irq = chip->pci->irq; + pci_intx(chip->pci, !chip->msi); return 0; } -- cgit v1.2.3 From 9fb62c9f23d437241051e27a11de568361a4745d Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 21 Nov 2006 19:01:51 +0100 Subject: [ALSA] korg1212: fix printk format warning sound/pci/korg1212/korg1212.c:2359: warning: format '%d' expects type 'int', but argument 4 has type 'size_t' Signed-off-by: Randy Dunlap Signed-off-by: Andrew Morton Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/korg1212/korg1212.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c index b4e98f36229..21d0899ac38 100644 --- a/sound/pci/korg1212/korg1212.c +++ b/sound/pci/korg1212/korg1212.c @@ -2356,7 +2356,7 @@ static int __devinit snd_korg1212_create(struct snd_card *card, struct pci_dev * if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), dsp_code->size, &korg1212->dma_dsp) < 0) { - snd_printk(KERN_ERR "korg1212: can not allocate dsp code memory (%d bytes)\n", dsp_code->size); + snd_printk(KERN_ERR "korg1212: cannot allocate dsp code memory (%zd bytes)\n", dsp_code->size); snd_korg1212_free(korg1212); #ifdef FIRMWARE_IN_THE_KERNEL if (dsp_code != &static_dsp_code) -- cgit v1.2.3 From 56bb0cab1c1698544e61409e3727f2b6bc205501 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 22 Nov 2006 11:52:52 +0100 Subject: [ALSA] hda-codec - Add asus-laptop model for ALC861 (ALC660) Added a new model 'asus-laptop' for ASUS F2*/F3* laptops with ALC861 (equivalent with ALC660) codec chip. Also fixed the model for PCI SSID 1043:1338. Corresponding to ALSA bug#2480. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 40 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index aeb408cbe1e..60f199459ad 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -101,6 +101,7 @@ enum { ALC861_UNIWILL_M31, ALC861_TOSHIBA, ALC861_ASUS, + ALC861_ASUS_LAPTOP, ALC861_AUTO, ALC861_MODEL_LAST, }; @@ -6901,9 +6902,17 @@ static struct snd_kcontrol_new alc861_asus_mixer[] = { .private_value = ARRAY_SIZE(alc861_asus_modes), }, { } -}; +}; + +/* additional mixer */ +static snd_kcontrol_new_t alc861_asus_laptop_mixer[] = { + HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x23, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("PC Beep Playback Switch", 0x23, 0x0, HDA_OUTPUT), + { } +}; - /* * generic initialization of ADC, input mixers and output mixers */ @@ -7153,6 +7162,12 @@ static struct hda_verb alc861_asus_init_verbs[] = { { } }; +/* additional init verbs for ASUS laptops */ +static struct hda_verb alc861_asus_laptop_init_verbs[] = { + { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */ + { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */ + { } +}; /* * generic initialization of ADC, input mixers and output mixers @@ -7530,8 +7545,11 @@ static struct hda_board_config alc861_cfg_tbl[] = { { .modelname = "asus", .config = ALC861_ASUS}, { .pci_subvendor = 0x1043, .pci_subdevice = 0x1393, .config = ALC861_ASUS }, + { .modelname = "asus-laptop", .config = ALC861_ASUS_LAPTOP }, + { .pci_subvendor = 0x1043, .pci_subdevice = 0x1335, + .config = ALC861_ASUS_LAPTOP }, /* ASUS F2/F3 */ { .pci_subvendor = 0x1043, .pci_subdevice = 0x1338, - .config = ALC861_ASUS }, + .config = ALC861_ASUS_LAPTOP }, /* ASUS F2/F3 */ { .modelname = "auto", .config = ALC861_AUTO }, {} }; @@ -7626,7 +7644,21 @@ static struct alc_config_preset alc861_presets[] = { .adc_nids = alc861_adc_nids, .input_mux = &alc861_capture_source, }, -}; + [ALC861_ASUS_LAPTOP] = { + .mixers = { alc861_toshiba_mixer, alc861_asus_laptop_mixer }, + .init_verbs = { alc861_asus_init_verbs, + alc861_asus_laptop_init_verbs }, + .num_dacs = ARRAY_SIZE(alc861_dac_nids), + .dac_nids = alc861_dac_nids, + .dig_out_nid = ALC861_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), + .channel_mode = alc883_3ST_2ch_modes, + .need_dac_fix = 1, + .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), + .adc_nids = alc861_adc_nids, + .input_mux = &alc861_capture_source, + }, +}; static int patch_alc861(struct hda_codec *codec) -- cgit v1.2.3 From d1d985f019c3b290e09881b7b23abdc87aee2895 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 23 Nov 2006 19:27:12 +0100 Subject: [ALSA] Fix obsolete *_t typedefs Fixed obsolete *_t typedefs. Now completely removed. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/als300.c | 6 +++--- sound/pci/hda/patch_realtek.c | 6 +++--- sound/pci/hda/patch_sigmatel.c | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/pci/als300.c b/sound/pci/als300.c index 9f406fbe0d9..8afcb98ca7b 100644 --- a/sound/pci/als300.c +++ b/sound/pci/als300.c @@ -444,7 +444,7 @@ static int snd_als300_capture_close(struct snd_pcm_substream *substream) } static int snd_als300_pcm_hw_params(struct snd_pcm_substream *substream, - snd_pcm_hw_params_t * hw_params) + struct snd_pcm_hw_params *hw_params) { return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); @@ -673,7 +673,7 @@ static void snd_als300_init(struct snd_als300 *chip) snd_als300_dbgcallleave(); } -static int __devinit snd_als300_create(snd_card_t *card, +static int __devinit snd_als300_create(struct snd_card *card, struct pci_dev *pci, int chip_type, struct snd_als300 **rchip) { @@ -681,7 +681,7 @@ static int __devinit snd_als300_create(snd_card_t *card, void *irq_handler; int err; - static snd_device_ops_t ops = { + static struct snd_device_ops ops = { .dev_free = snd_als300_dev_free, }; *rchip = NULL; diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 60f199459ad..02c465147d9 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -5115,7 +5115,7 @@ static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = { { } /* end */ }; -static snd_kcontrol_new_t alc883_fivestack_mixer[] = { +static struct snd_kcontrol_new alc883_fivestack_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), @@ -6799,7 +6799,7 @@ static struct snd_kcontrol_new alc861_3ST_mixer[] = { { } /* end */ }; -static snd_kcontrol_new_t alc861_toshiba_mixer[] = { +static struct snd_kcontrol_new alc861_toshiba_mixer[] = { /* output mixer control */ HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT), @@ -6905,7 +6905,7 @@ static struct snd_kcontrol_new alc861_asus_mixer[] = { }; /* additional mixer */ -static snd_kcontrol_new_t alc861_asus_laptop_mixer[] = { +static struct snd_kcontrol_new alc861_asus_laptop_mixer[] = { HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x23, 0x0, HDA_OUTPUT), diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 1b428a1eafd..c8696ddc03a 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -301,7 +301,7 @@ static struct snd_kcontrol_new stac9227_mixer[] = { { } /* end */ }; -static snd_kcontrol_new_t stac927x_mixer[] = { +static struct snd_kcontrol_new stac927x_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Input Source", @@ -316,7 +316,7 @@ static snd_kcontrol_new_t stac927x_mixer[] = { { } /* end */ }; -static snd_kcontrol_new_t stac9205_mixer[] = { +static struct snd_kcontrol_new stac9205_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Digital Input Source", -- cgit v1.2.3 From 048b945077bdc7e8dff5d5810ff2a0ced3590ca9 Mon Sep 17 00:00:00 2001 From: Giuliano Pochini Date: Fri, 24 Nov 2006 13:03:58 +0100 Subject: [ALSA] echoaudio, add TLV support This patch adds TLV support to the echoaudio driver. All gains are in the range -127dB to +6dB with steps of 1dB, and -128 is mute. VU-meters levels go from -128 to 0dB. The input gain of the Layla20 ranges from -25dB to +25dB in steps of 0.5dB. Signed-off-by: Giuliano Pochini Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/echoaudio/darla20.c | 1 + sound/pci/echoaudio/darla24.c | 1 + sound/pci/echoaudio/echo3g.c | 1 + sound/pci/echoaudio/echoaudio.c | 18 +++++++++++++++++- sound/pci/echoaudio/gina20.c | 1 + sound/pci/echoaudio/gina24.c | 1 + sound/pci/echoaudio/indigo.c | 1 + sound/pci/echoaudio/indigodj.c | 1 + sound/pci/echoaudio/indigoio.c | 1 + sound/pci/echoaudio/layla20.c | 1 + sound/pci/echoaudio/layla24.c | 1 + sound/pci/echoaudio/mia.c | 1 + sound/pci/echoaudio/mona.c | 1 + 13 files changed, 29 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/echoaudio/darla20.c b/sound/pci/echoaudio/darla20.c index b7108e29a66..8e7fe033270 100644 --- a/sound/pci/echoaudio/darla20.c +++ b/sound/pci/echoaudio/darla20.c @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include diff --git a/sound/pci/echoaudio/darla24.c b/sound/pci/echoaudio/darla24.c index e59a982ee36..a13c623eb99 100644 --- a/sound/pci/echoaudio/darla24.c +++ b/sound/pci/echoaudio/darla24.c @@ -51,6 +51,7 @@ #include #include #include +#include #include #include #include diff --git a/sound/pci/echoaudio/echo3g.c b/sound/pci/echoaudio/echo3g.c index 12099fe1547..8fb15823aca 100644 --- a/sound/pci/echoaudio/echo3g.c +++ b/sound/pci/echoaudio/echo3g.c @@ -58,6 +58,7 @@ #include #include #include +#include #include #include #include diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c index 047e0b5bf15..3410bd4450a 100644 --- a/sound/pci/echoaudio/echoaudio.c +++ b/sound/pci/echoaudio/echoaudio.c @@ -34,6 +34,7 @@ module_param_array(enable, bool, NULL, 0444); MODULE_PARM_DESC(enable, "Enable " ECHOCARD_NAME " soundcard."); static unsigned int channels_list[10] = {1, 2, 4, 6, 8, 10, 12, 14, 16, 999999}; +static DECLARE_TLV_DB_SCALE(db_scale_output_gain, -12800, 100, 1); static int get_firmware(const struct firmware **fw_entry, const struct firmware *frm, struct echoaudio *chip) @@ -1011,17 +1012,21 @@ static int snd_echo_output_gain_put(struct snd_kcontrol *kcontrol, static struct snd_kcontrol_new snd_echo_line_output_gain __devinitdata = { .name = "Line Playback Volume", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, .info = snd_echo_output_gain_info, .get = snd_echo_output_gain_get, .put = snd_echo_output_gain_put, + .tlv = {.p = db_scale_output_gain}, }; #else static struct snd_kcontrol_new snd_echo_pcm_output_gain __devinitdata = { .name = "PCM Playback Volume", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, .info = snd_echo_output_gain_info, .get = snd_echo_output_gain_get, .put = snd_echo_output_gain_put, + .tlv = {.p = db_scale_output_gain}, }; #endif @@ -1080,12 +1085,16 @@ static int snd_echo_input_gain_put(struct snd_kcontrol *kcontrol, return changed; } +static DECLARE_TLV_DB_SCALE(db_scale_input_gain, -2500, 50, 0); + static struct snd_kcontrol_new snd_echo_line_input_gain __devinitdata = { .name = "Line Capture Volume", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, .info = snd_echo_input_gain_info, .get = snd_echo_input_gain_get, .put = snd_echo_input_gain_put, + .tlv = {.p = db_scale_input_gain}, }; #endif /* ECHOCARD_HAS_INPUT_GAIN */ @@ -1277,9 +1286,11 @@ static int snd_echo_mixer_put(struct snd_kcontrol *kcontrol, static struct snd_kcontrol_new snd_echo_monitor_mixer __devinitdata = { .name = "Monitor Mixer Volume", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, .info = snd_echo_mixer_info, .get = snd_echo_mixer_get, .put = snd_echo_mixer_put, + .tlv = {.p = db_scale_output_gain}, }; #endif /* ECHOCARD_HAS_MONITOR */ @@ -1343,9 +1354,11 @@ static int snd_echo_vmixer_put(struct snd_kcontrol *kcontrol, static struct snd_kcontrol_new snd_echo_vmixer __devinitdata = { .name = "VMixer Volume", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, .info = snd_echo_vmixer_info, .get = snd_echo_vmixer_get, .put = snd_echo_vmixer_put, + .tlv = {.p = db_scale_output_gain}, }; #endif /* ECHOCARD_HAS_VMIXER */ @@ -1753,9 +1766,12 @@ static int snd_echo_vumeters_get(struct snd_kcontrol *kcontrol, static struct snd_kcontrol_new snd_echo_vumeters __devinitdata = { .name = "VU-meters", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .access = SNDRV_CTL_ELEM_ACCESS_READ | + SNDRV_CTL_ELEM_ACCESS_VOLATILE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ, .info = snd_echo_vumeters_info, .get = snd_echo_vumeters_get, + .tlv = {.p = db_scale_output_gain}, }; diff --git a/sound/pci/echoaudio/gina20.c b/sound/pci/echoaudio/gina20.c index 29d6d12f80c..af4d32026e4 100644 --- a/sound/pci/echoaudio/gina20.c +++ b/sound/pci/echoaudio/gina20.c @@ -51,6 +51,7 @@ #include #include #include +#include #include #include #include diff --git a/sound/pci/echoaudio/gina24.c b/sound/pci/echoaudio/gina24.c index e464d720d0b..9ff454a947e 100644 --- a/sound/pci/echoaudio/gina24.c +++ b/sound/pci/echoaudio/gina24.c @@ -57,6 +57,7 @@ #include #include #include +#include #include #include #include diff --git a/sound/pci/echoaudio/indigo.c b/sound/pci/echoaudio/indigo.c index bfd2467099a..37eb726fd03 100644 --- a/sound/pci/echoaudio/indigo.c +++ b/sound/pci/echoaudio/indigo.c @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include diff --git a/sound/pci/echoaudio/indigodj.c b/sound/pci/echoaudio/indigodj.c index 8ed7ff1fd87..dc8b9182418 100644 --- a/sound/pci/echoaudio/indigodj.c +++ b/sound/pci/echoaudio/indigodj.c @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include diff --git a/sound/pci/echoaudio/indigoio.c b/sound/pci/echoaudio/indigoio.c index a8788e95917..eadf3263453 100644 --- a/sound/pci/echoaudio/indigoio.c +++ b/sound/pci/echoaudio/indigoio.c @@ -50,6 +50,7 @@ #include #include #include +#include #include #include #include diff --git a/sound/pci/echoaudio/layla20.c b/sound/pci/echoaudio/layla20.c index e503d74b3ba..6cede497579 100644 --- a/sound/pci/echoaudio/layla20.c +++ b/sound/pci/echoaudio/layla20.c @@ -56,6 +56,7 @@ #include #include #include +#include #include #include #include diff --git a/sound/pci/echoaudio/layla24.c b/sound/pci/echoaudio/layla24.c index d4581fdc841..44f735426aa 100644 --- a/sound/pci/echoaudio/layla24.c +++ b/sound/pci/echoaudio/layla24.c @@ -58,6 +58,7 @@ #include #include #include +#include #include #include #include diff --git a/sound/pci/echoaudio/mia.c b/sound/pci/echoaudio/mia.c index be40c64263d..dc172d03ac3 100644 --- a/sound/pci/echoaudio/mia.c +++ b/sound/pci/echoaudio/mia.c @@ -56,6 +56,7 @@ #include #include #include +#include #include #include #include diff --git a/sound/pci/echoaudio/mona.c b/sound/pci/echoaudio/mona.c index 5dc512add37..c856ed50dd9 100644 --- a/sound/pci/echoaudio/mona.c +++ b/sound/pci/echoaudio/mona.c @@ -55,6 +55,7 @@ #include #include #include +#include #include #include #include -- cgit v1.2.3 From d9ea472c743ccd7344055cb118bc210befbd8007 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 24 Nov 2006 15:34:06 +0100 Subject: [ALSA] Add PCI quirk list helper function Added a helper function snd_pci_quirk_lookup() to look up PCI SSID quirk list. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/core/misc.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'sound') diff --git a/sound/core/misc.c b/sound/core/misc.c index 03fc711f412..6db86a7c970 100644 --- a/sound/core/misc.c +++ b/sound/core/misc.c @@ -78,3 +78,31 @@ void snd_verbose_printd(const char *file, int line, const char *format, ...) EXPORT_SYMBOL(snd_verbose_printd); #endif + +#ifdef CONFIG_PCI +#include +/** + * snd_pci_quirk_lookup - look up a PCI SSID quirk list + * @pci: pci_dev handle + * @list: quirk list, terminated by a null entry + * + * Look through the given quirk list and finds a matching entry + * with the same PCI SSID. When subdevice is 0, all subdevice + * values may match. + * + * Returns the matched entry pointer, or NULL if nothing matched. + */ +const struct snd_pci_quirk * +snd_pci_quirk_lookup(struct pci_dev *pci, const struct snd_pci_quirk *list) +{ + const struct snd_pci_quirk *q; + + for (q = list; q->subvendor; q++) + if (q->subvendor == pci->subsystem_vendor && + (!q->subdevice || q->subdevice == pci->subsystem_device)) + return q; + return NULL; +} + +EXPORT_SYMBOL(snd_pci_quirk_lookup); +#endif -- cgit v1.2.3 From f41bea84c030793b502aa2526bb22476788e731e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 24 Nov 2006 15:35:18 +0100 Subject: [ALSA] atiixp - Use quirk list helper function Clean up ac97_codec quirk using snd_pci_quirk_lookup(). Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/atiixp.c | 36 ++++++++++-------------------------- 1 file changed, 10 insertions(+), 26 deletions(-) (limited to 'sound') diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c index 92df811d695..7d8053b5e8d 100644 --- a/sound/pci/atiixp.c +++ b/sound/pci/atiixp.c @@ -296,21 +296,9 @@ static struct pci_device_id snd_atiixp_ids[] = { MODULE_DEVICE_TABLE(pci, snd_atiixp_ids); -struct atiixp_quirk { - unsigned short subvendor; - unsigned short subdevice; - const char *name; - int ac97_codec; -}; - -static struct atiixp_quirk atiixp_quirks[] __devinitdata = { - { - .subvendor = 0x15bd, - .subdevice = 0x3100, - .name = "DFI RS482", - .ac97_codec = 0, - }, - { .subvendor = 0 } /* terminator */ +static struct snd_pci_quirk atiixp_quirks[] __devinitdata = { + SND_PCI_QUIRK(0x15bd, 0x3100, "DFI RS482", 0), + { } /* terminator */ }; /* @@ -574,17 +562,13 @@ static int snd_atiixp_aclink_down(struct atiixp *chip) static int ac97_probing_bugs(struct pci_dev *pci) { - int i = 0; - - while (atiixp_quirks[i].subvendor) { - if (pci->subsystem_vendor == atiixp_quirks[i].subvendor && - pci->subsystem_device == atiixp_quirks[i].subdevice) { - printk(KERN_INFO "Atiixp quirk for %s. " - "Forcing codec %d\n", atiixp_quirks[i].name, - atiixp_quirks[i].ac97_codec); - return atiixp_quirks[i].ac97_codec; - } - i++; + const struct snd_pci_quirk *q; + + q = snd_pci_quirk_lookup(pci, atiixp_quirks); + if (q) { + snd_printdd(KERN_INFO "Atiixp quirk for %s. " + "Forcing codec %d\n", q->name, q->value); + return q->value; } /* this hardware doesn't need workarounds. Probe for codec */ return -1; -- cgit v1.2.3 From e2b6d13be4ac3b564ac642a76756f6cf1a7b7b99 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 24 Nov 2006 15:36:13 +0100 Subject: [ALSA] nm256 - Use quirk list helper function Clean up nm256-quirk lookup using snd_pci_quirk_lookup(). Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/nm256/nm256.c | 56 +++++++++++++++++++------------------------------ 1 file changed, 22 insertions(+), 34 deletions(-) (limited to 'sound') diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c index 879e31a9f9c..03b3a4792f7 100644 --- a/sound/pci/nm256/nm256.c +++ b/sound/pci/nm256/nm256.c @@ -1628,23 +1628,15 @@ __error: } -struct nm256_quirk { - unsigned short vendor; - unsigned short device; - int type; -}; - enum { NM_BLACKLISTED, NM_RESET_WORKAROUND, NM_RESET_WORKAROUND_2 }; -static struct nm256_quirk nm256_quirks[] __devinitdata = { +static struct snd_pci_quirk nm256_quirks[] __devinitdata = { /* HP omnibook 4150 has cs4232 codec internally */ - { .vendor = 0x103c, .device = 0x0007, .type = NM_BLACKLISTED }, - /* Sony PCG-F305 */ - { .vendor = 0x104d, .device = 0x8041, .type = NM_RESET_WORKAROUND }, - /* Dell Latitude LS */ - { .vendor = 0x1028, .device = 0x0080, .type = NM_RESET_WORKAROUND }, - /* Dell Latitude CSx */ - { .vendor = 0x1028, .device = 0x0091, .type = NM_RESET_WORKAROUND_2 }, + SND_PCI_QUIRK(0x103c, 0x0007, "HP omnibook 4150", NM_BLACKLISTED), + /* Reset workarounds to avoid lock-ups */ + SND_PCI_QUIRK(0x104d, 0x8041, "Sony PCG-F305", NM_RESET_WORKAROUND), + SND_PCI_QUIRK(0x1028, 0x0080, "Dell Latitude LS", NM_RESET_WORKAROUND), + SND_PCI_QUIRK(0x1028, 0x0091, "Dell Latitude CSx", NM_RESET_WORKAROUND_2), { } /* terminator */ }; @@ -1655,26 +1647,22 @@ static int __devinit snd_nm256_probe(struct pci_dev *pci, struct snd_card *card; struct nm256 *chip; int err; - struct nm256_quirk *q; - u16 subsystem_vendor, subsystem_device; - - pci_read_config_word(pci, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vendor); - pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &subsystem_device); - - for (q = nm256_quirks; q->vendor; q++) { - if (q->vendor == subsystem_vendor && q->device == subsystem_device) { - switch (q->type) { - case NM_BLACKLISTED: - printk(KERN_INFO "nm256: The device is blacklisted. " - "Loading stopped\n"); - return -ENODEV; - case NM_RESET_WORKAROUND_2: - reset_workaround_2 = 1; - /* Fall-through */ - case NM_RESET_WORKAROUND: - reset_workaround = 1; - break; - } + const struct snd_pci_quirk *q; + + q = snd_pci_quirk_lookup(pci, nm256_quirks); + if (q) { + snd_printdd(KERN_INFO "nm256: Enabled quirk for %s.\n", q->name); + switch (q->value) { + case NM_BLACKLISTED: + printk(KERN_INFO "nm256: The device is blacklisted. " + "Loading stopped\n"); + return -ENODEV; + case NM_RESET_WORKAROUND_2: + reset_workaround_2 = 1; + /* Fall-through */ + case NM_RESET_WORKAROUND: + reset_workaround = 1; + break; } } -- cgit v1.2.3 From 1061eeb44493176eb1d12b47d619e61c428c4395 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 24 Nov 2006 15:36:46 +0100 Subject: [ALSA] maestro3 - Use quirk list helper function Clean up maestro3 amp and GPIO quirks using snd_pci_quirk_lookup(). Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/maestro3.c | 294 ++++++++++++++++++++++----------------------------- 1 file changed, 127 insertions(+), 167 deletions(-) (limited to 'sound') diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index 053ea4fdbff..4526904e3f8 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c @@ -770,21 +770,6 @@ MODULE_PARM_DESC(amp_gpio, "GPIO pin number for external amp. (default = -1)"); /* */ -/* quirk lists */ -struct m3_quirk { - const char *name; /* device name */ - u16 vendor, device; /* subsystem ids */ - int amp_gpio; /* gpio pin # for external amp, -1 = default */ - int irda_workaround; /* non-zero if avoid to touch 0x10 on GPIO_DIRECTION - (e.g. for IrDA on Dell Inspirons) */ -}; - -struct m3_hv_quirk { - u16 vendor, device, subsystem_vendor, subsystem_device; - u32 config; /* ALLEGRO_CONFIG hardware volume bits */ - int is_omnibook; /* Do HP OmniBook GPIO magic? */ -}; - struct m3_list { int curlen; int mem_addr; @@ -832,8 +817,6 @@ struct snd_m3 { struct snd_pcm *pcm; struct pci_dev *pci; - const struct m3_quirk *quirk; - const struct m3_hv_quirk *hv_quirk; int dacs_active; int timer_users; @@ -847,7 +830,11 @@ struct snd_m3 { u8 reset_state; int external_amp; - int amp_gpio; + int amp_gpio; /* gpio pin # for external amp, -1 = default */ + unsigned int hv_config; /* hardware-volume config bits */ + unsigned irda_workaround :1; /* avoid to touch 0x10 on GPIO_DIRECTION + (e.g. for IrDA on Dell Inspirons) */ + unsigned is_omnibook :1; /* Do HP OmniBook GPIO magic? */ /* midi */ struct snd_rawmidi *rmidi; @@ -896,127 +883,104 @@ static struct pci_device_id snd_m3_ids[] = { MODULE_DEVICE_TABLE(pci, snd_m3_ids); -static const struct m3_quirk m3_quirk_list[] = { - /* panasonic CF-28 "toughbook" */ - { - .name = "Panasonic CF-28", - .vendor = 0x10f7, - .device = 0x833e, - .amp_gpio = 0x0d, - }, - /* panasonic CF-72 "toughbook" */ - { - .name = "Panasonic CF-72", - .vendor = 0x10f7, - .device = 0x833d, - .amp_gpio = 0x0d, - }, - /* Dell Inspiron 4000 */ - { - .name = "Dell Inspiron 4000", - .vendor = 0x1028, - .device = 0x00b0, - .amp_gpio = -1, - .irda_workaround = 1, - }, - /* Dell Inspiron 8000 */ - { - .name = "Dell Inspiron 8000", - .vendor = 0x1028, - .device = 0x00a4, - .amp_gpio = -1, - .irda_workaround = 1, - }, - /* Dell Inspiron 8100 */ - { - .name = "Dell Inspiron 8100", - .vendor = 0x1028, - .device = 0x00e6, - .amp_gpio = -1, - .irda_workaround = 1, - }, - /* NEC LM800J/7 */ - { - .name = "NEC LM800J/7", - .vendor = 0x1033, - .device = 0x80f1, - .amp_gpio = 0x03, - }, - /* LEGEND ZhaoYang 3100CF */ - { - .name = "LEGEND ZhaoYang 3100CF", - .vendor = 0x1509, - .device = 0x1740, - .amp_gpio = 0x03, - }, - /* END */ - { NULL } +static struct snd_pci_quirk m3_amp_quirk_list[] __devinitdata = { + SND_PCI_QUIRK(0x10f7, 0x833e, "Panasonic CF-28", 0x0d), + SND_PCI_QUIRK(0x10f7, 0x833d, "Panasonic CF-72", 0x0d), + SND_PCI_QUIRK(0x1033, 0x80f1, "NEC LM800J/7", 0x03), + SND_PCI_QUIRK(0x1509, 0x1740, "LEGEND ZhaoYang 3100CF", 0x03), + { } /* END */ +}; + +static struct snd_pci_quirk m3_irda_quirk_list[] __devinitdata = { + SND_PCI_QUIRK(0x1028, 0x00b0, "Dell Inspiron 4000", 1), + SND_PCI_QUIRK(0x1028, 0x00a4, "Dell Inspiron 8000", 1), + SND_PCI_QUIRK(0x1028, 0x00e6, "Dell Inspiron 8100", 1), + { } /* END */ }; -/* These values came from the Windows driver. */ -static const struct m3_hv_quirk m3_hv_quirk_list[] = { +/* hardware volume quirks */ +static struct snd_pci_quirk m3_hv_quirk_list[] __devinitdata = { /* Allegro chips */ - { 0x125D, 0x1988, 0x0E11, 0x002E, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, - { 0x125D, 0x1988, 0x0E11, 0x0094, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, - { 0x125D, 0x1988, 0x0E11, 0xB112, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, - { 0x125D, 0x1988, 0x0E11, 0xB114, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, - { 0x125D, 0x1988, 0x103C, 0x0012, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, - { 0x125D, 0x1988, 0x103C, 0x0018, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, - { 0x125D, 0x1988, 0x103C, 0x001C, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, - { 0x125D, 0x1988, 0x103C, 0x001D, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, - { 0x125D, 0x1988, 0x103C, 0x001E, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, - { 0x125D, 0x1988, 0x107B, 0x3350, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, - { 0x125D, 0x1988, 0x10F7, 0x8338, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, - { 0x125D, 0x1988, 0x10F7, 0x833C, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, - { 0x125D, 0x1988, 0x10F7, 0x833D, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, - { 0x125D, 0x1988, 0x10F7, 0x833E, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, - { 0x125D, 0x1988, 0x10F7, 0x833F, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, - { 0x125D, 0x1988, 0x13BD, 0x1018, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, - { 0x125D, 0x1988, 0x13BD, 0x1019, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, - { 0x125D, 0x1988, 0x13BD, 0x101A, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, - { 0x125D, 0x1988, 0x14FF, 0x0F03, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, - { 0x125D, 0x1988, 0x14FF, 0x0F04, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, - { 0x125D, 0x1988, 0x14FF, 0x0F05, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, - { 0x125D, 0x1988, 0x156D, 0xB400, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, - { 0x125D, 0x1988, 0x156D, 0xB795, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, - { 0x125D, 0x1988, 0x156D, 0xB797, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, - { 0x125D, 0x1988, 0x156D, 0xC700, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, - { 0x125D, 0x1988, 0x1033, 0x80F1, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, - { 0x125D, 0x1988, 0x103C, 0x001A, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, /* HP OmniBook 6100 */ - { 0x125D, 0x1988, 0x107B, 0x340A, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, - { 0x125D, 0x1988, 0x107B, 0x3450, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, - { 0x125D, 0x1988, 0x109F, 0x3134, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, - { 0x125D, 0x1988, 0x109F, 0x3161, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, - { 0x125D, 0x1988, 0x144D, 0x3280, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, - { 0x125D, 0x1988, 0x144D, 0x3281, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, - { 0x125D, 0x1988, 0x144D, 0xC002, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, - { 0x125D, 0x1988, 0x144D, 0xC003, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, - { 0x125D, 0x1988, 0x1509, 0x1740, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, - { 0x125D, 0x1988, 0x1610, 0x0010, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, - { 0x125D, 0x1988, 0x1042, 0x1042, HV_CTRL_ENABLE, 0 }, - { 0x125D, 0x1988, 0x107B, 0x9500, HV_CTRL_ENABLE, 0 }, - { 0x125D, 0x1988, 0x14FF, 0x0F06, HV_CTRL_ENABLE, 0 }, - { 0x125D, 0x1988, 0x1558, 0x8586, HV_CTRL_ENABLE, 0 }, - { 0x125D, 0x1988, 0x161F, 0x2011, HV_CTRL_ENABLE, 0 }, + SND_PCI_QUIRK(0x0E11, 0x002E, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), + SND_PCI_QUIRK(0x0E11, 0x0094, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), + SND_PCI_QUIRK(0x0E11, 0xB112, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), + SND_PCI_QUIRK(0x0E11, 0xB114, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), + SND_PCI_QUIRK(0x103C, 0x0012, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), + SND_PCI_QUIRK(0x103C, 0x0018, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), + SND_PCI_QUIRK(0x103C, 0x001C, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), + SND_PCI_QUIRK(0x103C, 0x001D, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), + SND_PCI_QUIRK(0x103C, 0x001E, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), + SND_PCI_QUIRK(0x107B, 0x3350, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), + SND_PCI_QUIRK(0x10F7, 0x8338, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), + SND_PCI_QUIRK(0x10F7, 0x833C, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), + SND_PCI_QUIRK(0x10F7, 0x833D, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), + SND_PCI_QUIRK(0x10F7, 0x833E, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), + SND_PCI_QUIRK(0x10F7, 0x833F, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), + SND_PCI_QUIRK(0x13BD, 0x1018, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), + SND_PCI_QUIRK(0x13BD, 0x1019, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), + SND_PCI_QUIRK(0x13BD, 0x101A, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), + SND_PCI_QUIRK(0x14FF, 0x0F03, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), + SND_PCI_QUIRK(0x14FF, 0x0F04, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), + SND_PCI_QUIRK(0x14FF, 0x0F05, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), + SND_PCI_QUIRK(0x156D, 0xB400, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), + SND_PCI_QUIRK(0x156D, 0xB795, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), + SND_PCI_QUIRK(0x156D, 0xB797, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), + SND_PCI_QUIRK(0x156D, 0xC700, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), + SND_PCI_QUIRK(0x1033, 0x80F1, NULL, + HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE), + SND_PCI_QUIRK(0x103C, 0x001A, NULL, /* HP OmniBook 6100 */ + HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE), + SND_PCI_QUIRK(0x107B, 0x340A, NULL, + HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE), + SND_PCI_QUIRK(0x107B, 0x3450, NULL, + HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE), + SND_PCI_QUIRK(0x109F, 0x3134, NULL, + HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE), + SND_PCI_QUIRK(0x109F, 0x3161, NULL, + HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE), + SND_PCI_QUIRK(0x144D, 0x3280, NULL, + HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE), + SND_PCI_QUIRK(0x144D, 0x3281, NULL, + HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE), + SND_PCI_QUIRK(0x144D, 0xC002, NULL, + HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE), + SND_PCI_QUIRK(0x144D, 0xC003, NULL, + HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE), + SND_PCI_QUIRK(0x1509, 0x1740, NULL, + HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE), + SND_PCI_QUIRK(0x1610, 0x0010, NULL, + HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE), + SND_PCI_QUIRK(0x1042, 0x1042, NULL, HV_CTRL_ENABLE), + SND_PCI_QUIRK(0x107B, 0x9500, NULL, HV_CTRL_ENABLE), + SND_PCI_QUIRK(0x14FF, 0x0F06, NULL, HV_CTRL_ENABLE), + SND_PCI_QUIRK(0x1558, 0x8586, NULL, HV_CTRL_ENABLE), + SND_PCI_QUIRK(0x161F, 0x2011, NULL, HV_CTRL_ENABLE), /* Maestro3 chips */ - { 0x125D, 0x1998, 0x103C, 0x000E, HV_CTRL_ENABLE, 0 }, - { 0x125D, 0x1998, 0x103C, 0x0010, HV_CTRL_ENABLE, 1 }, /* HP OmniBook 6000 */ - { 0x125D, 0x1998, 0x103C, 0x0011, HV_CTRL_ENABLE, 1 }, /* HP OmniBook 500 */ - { 0x125D, 0x1998, 0x103C, 0x001B, HV_CTRL_ENABLE, 0 }, - { 0x125D, 0x1998, 0x104D, 0x80A6, HV_CTRL_ENABLE, 0 }, - { 0x125D, 0x1998, 0x104D, 0x80AA, HV_CTRL_ENABLE, 0 }, - { 0x125D, 0x1998, 0x107B, 0x5300, HV_CTRL_ENABLE, 0 }, - { 0x125D, 0x1998, 0x110A, 0x1998, HV_CTRL_ENABLE, 0 }, - { 0x125D, 0x1998, 0x13BD, 0x1015, HV_CTRL_ENABLE, 0 }, - { 0x125D, 0x1998, 0x13BD, 0x101C, HV_CTRL_ENABLE, 0 }, - { 0x125D, 0x1998, 0x13BD, 0x1802, HV_CTRL_ENABLE, 0 }, - { 0x125D, 0x1998, 0x1599, 0x0715, HV_CTRL_ENABLE, 0 }, - { 0x125D, 0x1998, 0x5643, 0x5643, HV_CTRL_ENABLE, 0 }, - { 0x125D, 0x199A, 0x144D, 0x3260, HV_CTRL_ENABLE | REDUCED_DEBOUNCE, 0 }, - { 0x125D, 0x199A, 0x144D, 0x3261, HV_CTRL_ENABLE | REDUCED_DEBOUNCE, 0 }, - { 0x125D, 0x199A, 0x144D, 0xC000, HV_CTRL_ENABLE | REDUCED_DEBOUNCE, 0 }, - { 0x125D, 0x199A, 0x144D, 0xC001, HV_CTRL_ENABLE | REDUCED_DEBOUNCE, 0 }, - { 0 } + SND_PCI_QUIRK(0x103C, 0x000E, NULL, HV_CTRL_ENABLE), + SND_PCI_QUIRK(0x103C, 0x0010, NULL, HV_CTRL_ENABLE), + SND_PCI_QUIRK(0x103C, 0x0011, NULL, HV_CTRL_ENABLE), + SND_PCI_QUIRK(0x103C, 0x001B, NULL, HV_CTRL_ENABLE), + SND_PCI_QUIRK(0x104D, 0x80A6, NULL, HV_CTRL_ENABLE), + SND_PCI_QUIRK(0x104D, 0x80AA, NULL, HV_CTRL_ENABLE), + SND_PCI_QUIRK(0x107B, 0x5300, NULL, HV_CTRL_ENABLE), + SND_PCI_QUIRK(0x110A, 0x1998, NULL, HV_CTRL_ENABLE), + SND_PCI_QUIRK(0x13BD, 0x1015, NULL, HV_CTRL_ENABLE), + SND_PCI_QUIRK(0x13BD, 0x101C, NULL, HV_CTRL_ENABLE), + SND_PCI_QUIRK(0x13BD, 0x1802, NULL, HV_CTRL_ENABLE), + SND_PCI_QUIRK(0x1599, 0x0715, NULL, HV_CTRL_ENABLE), + SND_PCI_QUIRK(0x5643, 0x5643, NULL, HV_CTRL_ENABLE), + SND_PCI_QUIRK(0x144D, 0x3260, NULL, HV_CTRL_ENABLE | REDUCED_DEBOUNCE), + SND_PCI_QUIRK(0x144D, 0x3261, NULL, HV_CTRL_ENABLE | REDUCED_DEBOUNCE), + SND_PCI_QUIRK(0x144D, 0xC000, NULL, HV_CTRL_ENABLE | REDUCED_DEBOUNCE), + SND_PCI_QUIRK(0x144D, 0xC001, NULL, HV_CTRL_ENABLE | REDUCED_DEBOUNCE), + { } /* END */ +}; + +/* HP Omnibook quirks */ +static struct snd_pci_quirk m3_omnibook_quirk_list[] __devinitdata = { + SND_PCI_QUIRK_ID(0x103c, 0x0010), /* HP OmniBook 6000 */ + SND_PCI_QUIRK_ID(0x103c, 0x0011), /* HP OmniBook 500 */ + { } /* END */ }; /* @@ -2055,7 +2019,7 @@ static void snd_m3_ac97_reset(struct snd_m3 *chip) for (i = 0; i < 5; i++) { dir = inw(io + GPIO_DIRECTION); - if (! chip->quirk || ! chip->quirk->irda_workaround) + if (!chip->irda_workaround) dir |= 0x10; /* assuming pci bus master? */ snd_m3_remote_codec_config(io, 0); @@ -2478,7 +2442,7 @@ snd_m3_chip_init(struct snd_m3 *chip) DISABLE_LEGACY); pci_write_config_word(pcidev, PCI_LEGACY_AUDIO_CTRL, w); - if (chip->hv_quirk && chip->hv_quirk->is_omnibook) { + if (chip->is_omnibook) { /* * Volume buttons on some HP OmniBook laptops don't work * correctly. This makes them work for the most part. @@ -2495,8 +2459,7 @@ snd_m3_chip_init(struct snd_m3 *chip) } pci_read_config_dword(pcidev, PCI_ALLEGRO_CONFIG, &n); n &= ~(HV_CTRL_ENABLE | REDUCED_DEBOUNCE | HV_BUTTON_FROM_GD); - if (chip->hv_quirk) - n |= chip->hv_quirk->config; + n |= chip->hv_config; /* For some reason we must always use reduced debounce. */ n |= REDUCED_DEBOUNCE; n |= PM_CTRL_ENABLE | CLK_DIV_BY_49 | USE_PCI_TIMING; @@ -2544,7 +2507,7 @@ snd_m3_enable_ints(struct snd_m3 *chip) /* TODO: MPU401 not supported yet */ val = ASSP_INT_ENABLE /*| MPU401_INT_ENABLE*/; - if (chip->hv_quirk && (chip->hv_quirk->config & HV_CTRL_ENABLE)) + if (chip->hv_config & HV_CTRL_ENABLE) val |= HV_INT_ENABLE; outw(val, io + HOST_INT_CTRL); outb(inb(io + ASSP_CONTROL_C) | ASSP_HOST_INT_ENABLE, @@ -2708,8 +2671,7 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci, { struct snd_m3 *chip; int i, err; - const struct m3_quirk *quirk; - const struct m3_hv_quirk *hv_quirk; + const struct snd_pci_quirk *quirk; static struct snd_device_ops ops = { .dev_free = snd_m3_dev_free, }; @@ -2749,34 +2711,32 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci, chip->pci = pci; chip->irq = -1; - for (quirk = m3_quirk_list; quirk->vendor; quirk++) { - if (pci->subsystem_vendor == quirk->vendor && - pci->subsystem_device == quirk->device) { - printk(KERN_INFO "maestro3: enabled hack for '%s'\n", quirk->name); - chip->quirk = quirk; - break; - } - } - - for (hv_quirk = m3_hv_quirk_list; hv_quirk->vendor; hv_quirk++) { - if (pci->vendor == hv_quirk->vendor && - pci->device == hv_quirk->device && - pci->subsystem_vendor == hv_quirk->subsystem_vendor && - pci->subsystem_device == hv_quirk->subsystem_device) { - chip->hv_quirk = hv_quirk; - break; - } - } - chip->external_amp = enable_amp; if (amp_gpio >= 0 && amp_gpio <= 0x0f) chip->amp_gpio = amp_gpio; - else if (chip->quirk && chip->quirk->amp_gpio >= 0) - chip->amp_gpio = chip->quirk->amp_gpio; - else if (chip->allegro_flag) - chip->amp_gpio = GPO_EXT_AMP_ALLEGRO; - else /* presumably this is for all 'maestro3's.. */ - chip->amp_gpio = GPO_EXT_AMP_M3; + else { + quirk = snd_pci_quirk_lookup(pci, m3_amp_quirk_list); + if (quirk) { + snd_printdd(KERN_INFO "maestro3: set amp-gpio " + "for '%s'\n", quirk->name); + chip->amp_gpio = quirk->value; + } else if (chip->allegro_flag) + chip->amp_gpio = GPO_EXT_AMP_ALLEGRO; + else /* presumably this is for all 'maestro3's.. */ + chip->amp_gpio = GPO_EXT_AMP_M3; + } + + quirk = snd_pci_quirk_lookup(pci, m3_irda_quirk_list); + if (quirk) { + snd_printdd(KERN_INFO "maestro3: enabled irda workaround " + "for '%s'\n", quirk->name); + chip->irda_workaround = 1; + } + quirk = snd_pci_quirk_lookup(pci, m3_hv_quirk_list); + if (quirk) + chip->hv_config = quirk->value; + if (snd_pci_quirk_lookup(pci, m3_omnibook_quirk_list)) + chip->is_omnibook = 1; chip->num_substreams = NR_DSPS; chip->substreams = kcalloc(chip->num_substreams, sizeof(struct m3_dma), -- cgit v1.2.3 From 9d74958a845b54c8ccfd4c6d14659f601e6ef43b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 24 Nov 2006 15:37:18 +0100 Subject: [ALSA] via82xx - Use quirk list helper function Clean up dxs_support quirk list using snd_pci_quirk_lookup(). Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/via82xx.c | 130 +++++++++++++++++++--------------------------------- 1 file changed, 48 insertions(+), 82 deletions(-) (limited to 'sound') diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 0440df7de37..22caf5d7ff1 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -2357,93 +2357,59 @@ static struct via823x_info via823x_cards[] __devinitdata = { /* * auto detection of DXS channel supports. */ -struct dxs_whitelist { - unsigned short subvendor; - unsigned short subdevice; - unsigned short mask; - short action; /* new dxs_support value */ + +static struct snd_pci_quirk dxs_whitelist[] __devinitdata = { + SND_PCI_QUIRK(0x1005, 0x4710, "Avance Logic Mobo", VIA_DXS_ENABLE), + SND_PCI_QUIRK(0x1019, 0x0996, "ESC Mobo", VIA_DXS_48K), + SND_PCI_QUIRK(0x1019, 0x0a81, "ECS K7VTA3 v8.0", VIA_DXS_NO_VRA), + SND_PCI_QUIRK(0x1019, 0x0a85, "ECS L7VMM2", VIA_DXS_NO_VRA), + SND_PCI_QUIRK(0x1019, 0, "ESC K8", VIA_DXS_SRC), + SND_PCI_QUIRK(0x1019, 0xaa01, "ESC K8T890-A", VIA_DXS_SRC), + SND_PCI_QUIRK(0x1025, 0x0033, "Acer Inspire 1353LM", VIA_DXS_NO_VRA), + SND_PCI_QUIRK(0x1025, 0x0046, "Acer Aspire 1524 WLMi", VIA_DXS_SRC), + SND_PCI_QUIRK(0x1043, 0, "ASUS A7/A8", VIA_DXS_NO_VRA), + SND_PCI_QUIRK(0x1071, 0, "Diverse Notebook", VIA_DXS_NO_VRA), + SND_PCI_QUIRK(0x10cf, 0x118e, "FSC Laptop", VIA_DXS_ENABLE), + SND_PCI_QUIRK(0x1106, 0, "ASRock", VIA_DXS_SRC), + SND_PCI_QUIRK(0x1297, 0xa232, "Shuttle", VIA_DXS_ENABLE), + SND_PCI_QUIRK(0x1297, 0xc160, "Shuttle Sk41G", VIA_DXS_ENABLE), + SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte GA-7VAXP", VIA_DXS_ENABLE), + SND_PCI_QUIRK(0x1462, 0x3800, "MSI KT266", VIA_DXS_ENABLE), + SND_PCI_QUIRK(0x1462, 0x7120, "MSI KT4V", VIA_DXS_ENABLE), + SND_PCI_QUIRK(0x1462, 0x7142, "MSI K8MM-V", VIA_DXS_ENABLE), + SND_PCI_QUIRK(0x1462, 0, "MSI Mobo", VIA_DXS_SRC), + SND_PCI_QUIRK(0x147b, 0x1401, "ABIT KD7(-RAID)", VIA_DXS_ENABLE), + SND_PCI_QUIRK(0x147b, 0x1411, "ABIT VA-20", VIA_DXS_ENABLE), + SND_PCI_QUIRK(0x147b, 0x1413, "ABIT KV8 Pro", VIA_DXS_ENABLE), + SND_PCI_QUIRK(0x147b, 0x1415, "ABIT AV8", VIA_DXS_NO_VRA), + SND_PCI_QUIRK(0x14ff, 0x0403, "Twinhead mobo", VIA_DXS_ENABLE), + SND_PCI_QUIRK(0x14ff, 0x0408, "Twinhead laptop", VIA_DXS_SRC), + SND_PCI_QUIRK(0x1558, 0x4701, "Clevo D470", VIA_DXS_SRC), + SND_PCI_QUIRK(0x1584, 0x8120, "Diverse Laptop", VIA_DXS_ENABLE), + SND_PCI_QUIRK(0x1584, 0x8123, "Targa/Uniwill", VIA_DXS_NO_VRA), + SND_PCI_QUIRK(0x161f, 0x202b, "Amira Notebook", VIA_DXS_NO_VRA), + SND_PCI_QUIRK(0x161f, 0x2032, "m680x machines", VIA_DXS_48K), + SND_PCI_QUIRK(0x1631, 0xe004, "PB EasyNote 3174", VIA_DXS_ENABLE), + SND_PCI_QUIRK(0x1695, 0x3005, "EPoX EP-8K9A", VIA_DXS_ENABLE), + SND_PCI_QUIRK(0x1695, 0, "EPoX mobo", VIA_DXS_SRC), + SND_PCI_QUIRK(0x16f3, 0, "Jetway K8", VIA_DXS_SRC), + SND_PCI_QUIRK(0x1734, 0, "FSC Laptop", VIA_DXS_SRC), + SND_PCI_QUIRK(0x1849, 0x3059, "ASRock K7VM2", VIA_DXS_NO_VRA), + SND_PCI_QUIRK(0x1849, 0, "ASRock mobo", VIA_DXS_SRC), + SND_PCI_QUIRK(0x1919, 0x200a, "Soltek SL-K8", VIA_DXS_NO_VRA), + SND_PCI_QUIRK(0x4005, 0x4710, "MSI K7T266", VIA_DXS_SRC), + { } /* terminator */ }; static int __devinit check_dxs_list(struct pci_dev *pci, int revision) { - static struct dxs_whitelist whitelist[] __devinitdata = { - { .subvendor = 0x1005, .subdevice = 0x4710, .action = VIA_DXS_ENABLE }, /* Avance Logic Mobo */ - { .subvendor = 0x1019, .subdevice = 0x0996, .action = VIA_DXS_48K }, - { .subvendor = 0x1019, .subdevice = 0x0a81, .action = VIA_DXS_NO_VRA }, /* ECS K7VTA3 v8.0 */ - { .subvendor = 0x1019, .subdevice = 0x0a85, .action = VIA_DXS_NO_VRA }, /* ECS L7VMM2 */ - { .subvendor = 0x1019, .subdevice = 0xa101, .action = VIA_DXS_SRC }, - { .subvendor = 0x1019, .subdevice = 0xaa01, .action = VIA_DXS_SRC }, /* ECS K8T890-A */ - { .subvendor = 0x1025, .subdevice = 0x0033, .action = VIA_DXS_NO_VRA }, /* Acer Inspire 1353LM */ - { .subvendor = 0x1025, .subdevice = 0x0046, .action = VIA_DXS_SRC }, /* Acer Aspire 1524 WLMi */ - { .subvendor = 0x1043, .subdevice = 0x8095, .action = VIA_DXS_NO_VRA }, /* ASUS A7V8X (FIXME: possibly VIA_DXS_ENABLE?)*/ - { .subvendor = 0x1043, .subdevice = 0x80a1, .action = VIA_DXS_NO_VRA }, /* ASUS A7V8-X */ - { .subvendor = 0x1043, .subdevice = 0x80b0, .action = VIA_DXS_NO_VRA }, /* ASUS A7V600 & K8V*/ - { .subvendor = 0x1043, .subdevice = 0x810d, .action = VIA_DXS_SRC }, /* ASUS */ - { .subvendor = 0x1043, .subdevice = 0x812a, .action = VIA_DXS_SRC }, /* ASUS A8V Deluxe */ - { .subvendor = 0x1043, .subdevice = 0x8174, .action = VIA_DXS_SRC }, /* ASUS */ - { .subvendor = 0x1043, .subdevice = 0x81b9, .action = VIA_DXS_SRC }, /* ASUS A8V-MX */ - { .subvendor = 0x1071, .subdevice = 0x8375, .action = VIA_DXS_NO_VRA }, /* Vobis/Yakumo/Mitac notebook */ - { .subvendor = 0x1071, .subdevice = 0x8399, .action = VIA_DXS_NO_VRA }, /* Umax AB 595T (VIA K8N800A - VT8237) */ - { .subvendor = 0x10cf, .subdevice = 0x118e, .action = VIA_DXS_ENABLE }, /* FSC laptop */ - { .subvendor = 0x1106, .subdevice = 0x4161, .action = VIA_DXS_NO_VRA }, /* ASRock K7VT2 */ - { .subvendor = 0x1106, .subdevice = 0x4552, .action = VIA_DXS_NO_VRA }, /* QDI Kudoz 7X/600-6AL */ - { .subvendor = 0x1106, .subdevice = 0xaa01, .action = VIA_DXS_NO_VRA }, /* EPIA MII */ - { .subvendor = 0x1106, .subdevice = 0xc001, .action = VIA_DXS_SRC }, /* Insight P4-ITX */ - { .subvendor = 0x1297, .subdevice = 0xa232, .action = VIA_DXS_ENABLE }, /* Shuttle ?? */ - { .subvendor = 0x1297, .subdevice = 0xc160, .action = VIA_DXS_ENABLE }, /* Shuttle SK41G */ - { .subvendor = 0x1458, .subdevice = 0xa002, .action = VIA_DXS_ENABLE }, /* Gigabyte GA-7VAXP */ - { .subvendor = 0x1462, .subdevice = 0x0080, .action = VIA_DXS_SRC }, /* MSI K8T Neo-FIS2R */ - { .subvendor = 0x1462, .subdevice = 0x0430, .action = VIA_DXS_SRC }, /* MSI 7142 (K8MM-V) */ - { .subvendor = 0x1462, .subdevice = 0x0470, .action = VIA_DXS_SRC }, /* MSI KT880 Delta-FSR */ - { .subvendor = 0x1462, .subdevice = 0x3800, .action = VIA_DXS_ENABLE }, /* MSI KT266 */ - { .subvendor = 0x1462, .subdevice = 0x5901, .action = VIA_DXS_NO_VRA }, /* MSI KT6 Delta-SR */ - { .subvendor = 0x1462, .subdevice = 0x7023, .action = VIA_DXS_SRC }, /* MSI K8T Neo2-FI */ - { .subvendor = 0x1462, .subdevice = 0x7120, .action = VIA_DXS_ENABLE }, /* MSI KT4V */ - { .subvendor = 0x1462, .subdevice = 0x7142, .action = VIA_DXS_ENABLE }, /* MSI K8MM-V */ - { .subvendor = 0x1462, .subdevice = 0xb012, .action = VIA_DXS_SRC }, /* P4M800/VIA8237R */ - { .subvendor = 0x147b, .subdevice = 0x1401, .action = VIA_DXS_ENABLE }, /* ABIT KD7(-RAID) */ - { .subvendor = 0x147b, .subdevice = 0x1411, .action = VIA_DXS_ENABLE }, /* ABIT VA-20 */ - { .subvendor = 0x147b, .subdevice = 0x1413, .action = VIA_DXS_ENABLE }, /* ABIT KV8 Pro */ - { .subvendor = 0x147b, .subdevice = 0x1415, .action = VIA_DXS_NO_VRA }, /* Abit AV8 */ - { .subvendor = 0x14ff, .subdevice = 0x0403, .action = VIA_DXS_ENABLE }, /* Twinhead mobo */ - { .subvendor = 0x14ff, .subdevice = 0x0408, .action = VIA_DXS_SRC }, /* Twinhead laptop */ - { .subvendor = 0x1558, .subdevice = 0x4701, .action = VIA_DXS_SRC }, /* Clevo D470 */ - { .subvendor = 0x1584, .subdevice = 0x8120, .action = VIA_DXS_ENABLE }, /* Gericom/Targa/Vobis/Uniwill laptop */ - { .subvendor = 0x1584, .subdevice = 0x8123, .action = VIA_DXS_NO_VRA }, /* Uniwill (Targa Visionary XP-210) */ - { .subvendor = 0x161f, .subdevice = 0x202b, .action = VIA_DXS_NO_VRA }, /* Amira Note book */ - { .subvendor = 0x161f, .subdevice = 0x2032, .action = VIA_DXS_48K }, /* m680x machines */ - { .subvendor = 0x1631, .subdevice = 0xe004, .action = VIA_DXS_ENABLE }, /* Easy Note 3174, Packard Bell */ - { .subvendor = 0x1695, .subdevice = 0x3005, .action = VIA_DXS_ENABLE }, /* EPoX EP-8K9A */ - { .subvendor = 0x1695, .subdevice = 0x300c, .action = VIA_DXS_SRC }, /* EPoX EP-8KRAI */ - { .subvendor = 0x1695, .subdevice = 0x300e, .action = VIA_DXS_SRC }, /* EPoX 9HEAI */ - { .subvendor = 0x16f3, .subdevice = 0x6405, .action = VIA_DXS_SRC }, /* Jetway K8M8MS */ - { .subvendor = 0x1734, .subdevice = 0x1078, .action = VIA_DXS_SRC }, /* FSC Amilo L7300 */ - { .subvendor = 0x1734, .subdevice = 0x1093, .action = VIA_DXS_SRC }, /* FSC */ - { .subvendor = 0x1734, .subdevice = 0x10ab, .action = VIA_DXS_SRC }, /* FSC */ - { .subvendor = 0x1849, .subdevice = 0x3059, .action = VIA_DXS_NO_VRA }, /* ASRock K7VM2 */ - { .subvendor = 0x1849, .subdevice = 0x9739, .action = VIA_DXS_SRC }, /* ASRock mobo(?) */ - { .subvendor = 0x1849, .subdevice = 0x9761, .action = VIA_DXS_SRC }, /* ASRock mobo(?) */ - { .subvendor = 0x1919, .subdevice = 0x200a, .action = VIA_DXS_NO_VRA }, /* Soltek SL-K8Tpro-939 */ - { .subvendor = 0x4005, .subdevice = 0x4710, .action = VIA_DXS_SRC }, /* MSI K7T266 Pro2 (MS-6380 V2.0) BIOS 3.7 */ - { } /* terminator */ - }; - const struct dxs_whitelist *w; - unsigned short subsystem_vendor; - unsigned short subsystem_device; - - pci_read_config_word(pci, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vendor); - pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &subsystem_device); + const struct snd_pci_quirk *w; - for (w = whitelist; w->subvendor; w++) { - if (w->subvendor != subsystem_vendor) - continue; - if (w->mask) { - if ((w->mask & subsystem_device) == w->subdevice) - return w->action; - } else { - if (subsystem_device == w->subdevice) - return w->action; - } + w = snd_pci_quirk_lookup(pci, dxs_whitelist); + if (w) { + snd_printdd(KERN_INFO "via82xx: DXS white list for %s found\n", + w->name); + return w->value; } /* for newer revision, default to DXS_SRC */ -- cgit v1.2.3 From 5da8fa2516388a20a43cd928fda19f6ac2521afc Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 24 Nov 2006 15:38:18 +0100 Subject: [ALSA] ens1371 - Clean up quirks Clean up quirks in snd-ens1371 driver using snd_pci_quirk_lookup(). Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/ens1370.c | 154 ++++++++++++++++++++++++---------------------------- 1 file changed, 70 insertions(+), 84 deletions(-) (limited to 'sound') diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c index a84f6b21024..425b167522d 100644 --- a/sound/pci/ens1370.c +++ b/sound/pci/ens1370.c @@ -413,8 +413,6 @@ struct ensoniq { } u; struct pci_dev *pci; - unsigned short subsystem_vendor_id; - unsigned short subsystem_device_id; struct snd_card *card; struct snd_pcm *pcm1; /* DAC1/ADC PCM */ struct snd_pcm *pcm2; /* DAC2 PCM */ @@ -1607,11 +1605,26 @@ static void snd_ensoniq_mixer_free_ac97(struct snd_ac97 *ac97) ensoniq->u.es1371.ac97 = NULL; } -static struct { +struct es1371_quirk { unsigned short vid; /* vendor ID */ unsigned short did; /* device ID */ unsigned char rev; /* revision */ -} es1371_spdif_present[] __devinitdata = { +}; + +static int __devinit es1371_quirk_lookup(struct ensoniq *ensoniq, + struct es1371_quirk *list) +{ + while (list->vid != (unsigned short)PCI_ANY_ID) { + if (ensoniq->pci->vendor == list->vid && + ensoniq->pci->device == list->did && + ensoniq->rev == list->rev) + return 1; + list++; + } + return 0; +} + +static struct es1371_quirk es1371_spdif_present[] __devinitdata = { { .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_C }, { .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_D }, { .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_E }, @@ -1620,12 +1633,19 @@ static struct { { .vid = PCI_ANY_ID, .did = PCI_ANY_ID } }; -static int snd_ensoniq_1371_mixer(struct ensoniq * ensoniq, int has_spdif, int has_line) +static struct snd_pci_quirk ens1373_line_quirk[] __devinitdata = { + SND_PCI_QUIRK_ID(0x1274, 0x2000), /* GA-7DXR */ + SND_PCI_QUIRK_ID(0x1458, 0xa000), /* GA-8IEXP */ + { } /* end */ +}; + +static int __devinit snd_ensoniq_1371_mixer(struct ensoniq *ensoniq, + int has_spdif, int has_line) { struct snd_card *card = ensoniq->card; struct snd_ac97_bus *pbus; struct snd_ac97_template ac97; - int err, idx; + int err; static struct snd_ac97_bus_ops ops = { .write = snd_es1371_codec_write, .read = snd_es1371_codec_read, @@ -1641,33 +1661,28 @@ static int snd_ensoniq_1371_mixer(struct ensoniq * ensoniq, int has_spdif, int h ac97.scaps = AC97_SCAP_AUDIO; if ((err = snd_ac97_mixer(pbus, &ac97, &ensoniq->u.es1371.ac97)) < 0) return err; - for (idx = 0; es1371_spdif_present[idx].vid != (unsigned short)PCI_ANY_ID; idx++) - if ((ensoniq->pci->vendor == es1371_spdif_present[idx].vid && - ensoniq->pci->device == es1371_spdif_present[idx].did && - ensoniq->rev == es1371_spdif_present[idx].rev) || has_spdif > 0) { - struct snd_kcontrol *kctl; - int i, index = 0; - - if (has_spdif < 0) - break; - - ensoniq->spdif_default = ensoniq->spdif_stream = - SNDRV_PCM_DEFAULT_CON_SPDIF; - outl(ensoniq->spdif_default, ES_REG(ensoniq, CHANNEL_STATUS)); - - if (ensoniq->u.es1371.ac97->ext_id & AC97_EI_SPDIF) - index++; - - for (i = 0; i < (int)ARRAY_SIZE(snd_es1371_mixer_spdif); i++) { - kctl = snd_ctl_new1(&snd_es1371_mixer_spdif[i], ensoniq); - if (! kctl) - return -ENOMEM; - kctl->id.index = index; - if ((err = snd_ctl_add(card, kctl)) < 0) - return err; - } - break; + if (has_spdif > 0 || + (!has_spdif && es1371_quirk_lookup(ensoniq, es1371_spdif_present))) { + struct snd_kcontrol *kctl; + int i, index = 0; + + ensoniq->spdif_default = ensoniq->spdif_stream = + SNDRV_PCM_DEFAULT_CON_SPDIF; + outl(ensoniq->spdif_default, ES_REG(ensoniq, CHANNEL_STATUS)); + + if (ensoniq->u.es1371.ac97->ext_id & AC97_EI_SPDIF) + index++; + + for (i = 0; i < ARRAY_SIZE(snd_es1371_mixer_spdif); i++) { + kctl = snd_ctl_new1(&snd_es1371_mixer_spdif[i], ensoniq); + if (!kctl) + return -ENOMEM; + kctl->id.index = index; + err = snd_ctl_add(card, kctl); + if (err < 0) + return err; } + } if (ensoniq->u.es1371.ac97->ext_id & AC97_EI_SDAC) { /* mirror rear to front speakers */ ensoniq->cssr &= ~(ES_1373_REAR_BIT27|ES_1373_REAR_BIT24); @@ -1676,12 +1691,10 @@ static int snd_ensoniq_1371_mixer(struct ensoniq * ensoniq, int has_spdif, int h if (err < 0) return err; } - if (((ensoniq->subsystem_vendor_id == 0x1274) && - (ensoniq->subsystem_device_id == 0x2000)) || /* GA-7DXR */ - ((ensoniq->subsystem_vendor_id == 0x1458) && - (ensoniq->subsystem_device_id == 0xa000)) || /* GA-8IEXP */ - has_line > 0) { - err = snd_ctl_add(card, snd_ctl_new1(&snd_ens1373_line, ensoniq)); + if (has_line > 0 || + snd_pci_quirk_lookup(ensoniq->pci, ens1373_line_quirk)) { + err = snd_ctl_add(card, snd_ctl_new1(&snd_ens1373_line, + ensoniq)); if (err < 0) return err; } @@ -1956,21 +1969,15 @@ static int snd_ensoniq_dev_free(struct snd_device *device) } #ifdef CHIP1371 -static struct { - unsigned short svid; /* subsystem vendor ID */ - unsigned short sdid; /* subsystem device ID */ -} es1371_amplifier_hack[] = { - { .svid = 0x107b, .sdid = 0x2150 }, /* Gateway Solo 2150 */ - { .svid = 0x13bd, .sdid = 0x100c }, /* EV1938 on Mebius PC-MJ100V */ - { .svid = 0x1102, .sdid = 0x5938 }, /* Targa Xtender300 */ - { .svid = 0x1102, .sdid = 0x8938 }, /* IPC Topnote G notebook */ - { .svid = PCI_ANY_ID, .sdid = PCI_ANY_ID } +static struct snd_pci_quirk es1371_amplifier_hack[] __devinitdata = { + SND_PCI_QUIRK_ID(0x107b, 0x2150), /* Gateway Solo 2150 */ + SND_PCI_QUIRK_ID(0x13bd, 0x100c), /* EV1938 on Mebius PC-MJ100V */ + SND_PCI_QUIRK_ID(0x1102, 0x5938), /* Targa Xtender300 */ + SND_PCI_QUIRK_ID(0x1102, 0x8938), /* IPC Topnote G notebook */ + { } /* end */ }; -static struct { - unsigned short vid; /* vendor ID */ - unsigned short did; /* device ID */ - unsigned char rev; /* revision */ -} es1371_ac97_reset_hack[] = { + +static struct es1371_quirk es1371_ac97_reset_hack[] = { { .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_C }, { .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_D }, { .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_E }, @@ -1984,7 +1991,6 @@ static void snd_ensoniq_chip_init(struct ensoniq *ensoniq) { #ifdef CHIP1371 int idx; - struct pci_dev *pci = ensoniq->pci; #endif /* this code was part of snd_ensoniq_create before intruduction * of suspend/resume @@ -1999,16 +2005,12 @@ static void snd_ensoniq_chip_init(struct ensoniq *ensoniq) outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL)); outl(ensoniq->sctrl, ES_REG(ensoniq, SERIAL)); outl(0, ES_REG(ensoniq, 1371_LEGACY)); - for (idx = 0; es1371_ac97_reset_hack[idx].vid != (unsigned short)PCI_ANY_ID; idx++) - if (pci->vendor == es1371_ac97_reset_hack[idx].vid && - pci->device == es1371_ac97_reset_hack[idx].did && - ensoniq->rev == es1371_ac97_reset_hack[idx].rev) { - outl(ensoniq->cssr, ES_REG(ensoniq, STATUS)); - /* need to delay around 20ms(bleech) to give - some CODECs enough time to wakeup */ - msleep(20); - break; - } + if (es1371_quirk_lookup(ensoniq, es1371_ac97_reset_hack)) { + outl(ensoniq->cssr, ES_REG(ensoniq, STATUS)); + /* need to delay around 20ms(bleech) to give + some CODECs enough time to wakeup */ + msleep(20); + } /* AC'97 warm reset to start the bitclk */ outl(ensoniq->ctrl | ES_1371_SYNC_RES, ES_REG(ensoniq, CONTROL)); inl(ES_REG(ensoniq, CONTROL)); @@ -2112,11 +2114,7 @@ static int __devinit snd_ensoniq_create(struct snd_card *card, struct ensoniq ** rensoniq) { struct ensoniq *ensoniq; - unsigned short cmdw; unsigned char cmdb; -#ifdef CHIP1371 - int idx; -#endif int err; static struct snd_device_ops ops = { .dev_free = snd_ensoniq_dev_free, @@ -2159,10 +2157,6 @@ static int __devinit snd_ensoniq_create(struct snd_card *card, pci_set_master(pci); pci_read_config_byte(pci, PCI_REVISION_ID, &cmdb); ensoniq->rev = cmdb; - pci_read_config_word(pci, PCI_SUBSYSTEM_VENDOR_ID, &cmdw); - ensoniq->subsystem_vendor_id = cmdw; - pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &cmdw); - ensoniq->subsystem_device_id = cmdw; #ifdef CHIP1370 #if 0 ensoniq->ctrl = ES_1370_CDC_EN | ES_1370_SERR_DISABLE | @@ -2175,19 +2169,11 @@ static int __devinit snd_ensoniq_create(struct snd_card *card, ensoniq->ctrl = 0; ensoniq->sctrl = 0; ensoniq->cssr = 0; - for (idx = 0; es1371_amplifier_hack[idx].svid != (unsigned short)PCI_ANY_ID; idx++) - if (ensoniq->subsystem_vendor_id == es1371_amplifier_hack[idx].svid && - ensoniq->subsystem_device_id == es1371_amplifier_hack[idx].sdid) { - ensoniq->ctrl |= ES_1371_GPIO_OUT(1); /* turn amplifier on */ - break; - } - for (idx = 0; es1371_ac97_reset_hack[idx].vid != (unsigned short)PCI_ANY_ID; idx++) - if (pci->vendor == es1371_ac97_reset_hack[idx].vid && - pci->device == es1371_ac97_reset_hack[idx].did && - ensoniq->rev == es1371_ac97_reset_hack[idx].rev) { - ensoniq->cssr |= ES_1371_ST_AC97_RST; - break; - } + if (snd_pci_quirk_lookup(pci, es1371_amplifier_hack)) + ensoniq->ctrl |= ES_1371_GPIO_OUT(1); /* turn amplifier on */ + + if (es1371_quirk_lookup(ensoniq, es1371_ac97_reset_hack)) + ensoniq->cssr |= ES_1371_ST_AC97_RST; #endif snd_ensoniq_chip_init(ensoniq); -- cgit v1.2.3 From a9e996604f77be6f1f4deb0eb1cc2652000054f1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 24 Nov 2006 15:42:07 +0100 Subject: [ALSA] intel8x0 - Add spdif_aclink option Added spdif_aclink module option to specify whether the board has SPDIF over AC-link or a direct connection from the controller chip. NForce and ICH4 (or newer) boards may be equipped with SPDIF through AC97 codec. In such a case, SPDIF should be handled as if the old ICH style (the same slot for analog and digital). A quirk list is added to detect this automatically for known hardwares. Corresponds to ALSA bug#2637. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/intel8x0.c | 86 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 60 insertions(+), 26 deletions(-) (limited to 'sound') diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index f8aef131be7..a289abfc717 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -71,6 +71,7 @@ static char *ac97_quirk; static int buggy_semaphore; static int buggy_irq = -1; /* auto-check */ static int xbox; +static int spdif_aclink = -1; module_param(index, int, 0444); MODULE_PARM_DESC(index, "Index value for Intel i8x0 soundcard."); @@ -86,6 +87,8 @@ module_param(buggy_irq, bool, 0444); MODULE_PARM_DESC(buggy_irq, "Enable workaround for buggy interrupts on some motherboards."); module_param(xbox, bool, 0444); MODULE_PARM_DESC(xbox, "Set to 1 for Xbox, if you have problems with the AC'97 codec detection."); +module_param(spdif_aclink, int, 0444); +MODULE_PARM_DESC(spdif_aclink, "S/PDIF over AC-link."); /* just for backward compatibility */ static int enable; @@ -1578,10 +1581,14 @@ static int __devinit snd_intel8x0_pcm(struct intel8x0 *chip) case DEVICE_INTEL_ICH4: tbl = intel_pcms; tblsize = ARRAY_SIZE(intel_pcms); + if (spdif_aclink) + tblsize--; break; case DEVICE_NFORCE: tbl = nforce_pcms; tblsize = ARRAY_SIZE(nforce_pcms); + if (spdif_aclink) + tblsize--; break; case DEVICE_ALI: tbl = ali_pcms; @@ -2040,17 +2047,19 @@ static int __devinit snd_intel8x0_mixer(struct intel8x0 *chip, int ac97_clock, }; chip->spdif_idx = -1; /* use PCMOUT (or disabled) */ - switch (chip->device_type) { - case DEVICE_NFORCE: - chip->spdif_idx = NVD_SPBAR; - break; - case DEVICE_ALI: - chip->spdif_idx = ALID_AC97SPDIFOUT; - break; - case DEVICE_INTEL_ICH4: - chip->spdif_idx = ICHD_SPBAR; - break; - }; + if (!spdif_aclink) { + switch (chip->device_type) { + case DEVICE_NFORCE: + chip->spdif_idx = NVD_SPBAR; + break; + case DEVICE_ALI: + chip->spdif_idx = ALID_AC97SPDIFOUT; + break; + case DEVICE_INTEL_ICH4: + chip->spdif_idx = ICHD_SPBAR; + break; + }; + } chip->in_ac97_init = 1; @@ -2173,11 +2182,11 @@ static int __devinit snd_intel8x0_mixer(struct intel8x0 *chip, int ac97_clock, if ((igetdword(chip, ICHREG(GLOB_STA)) & ICH_SAMPLE_CAP) == ICH_SAMPLE_16_20) chip->smp20bit = 1; } - if (chip->device_type == DEVICE_NFORCE) { + if (chip->device_type == DEVICE_NFORCE && !spdif_aclink) { /* 48kHz only */ chip->ichd[chip->spdif_idx].pcm->rates = SNDRV_PCM_RATE_48000; } - if (chip->device_type == DEVICE_INTEL_ICH4) { + if (chip->device_type == DEVICE_INTEL_ICH4 && !spdif_aclink) { /* use slot 10/11 for SPDIF */ u32 val; val = igetdword(chip, ICHREG(GLOB_CNT)) & ~ICH_PCM_SPDIF_MASK; @@ -2305,7 +2314,7 @@ static int snd_intel8x0_ich_chip_init(struct intel8x0 *chip, int probing) /* unmute the output on SIS7012 */ iputword(chip, 0x4c, igetword(chip, 0x4c) | 1); } - if (chip->device_type == DEVICE_NFORCE) { + if (chip->device_type == DEVICE_NFORCE && !spdif_aclink) { /* enable SPDIF interrupt */ unsigned int val; pci_read_config_dword(chip->pci, 0x4c, &val); @@ -2398,7 +2407,7 @@ static int snd_intel8x0_free(struct intel8x0 *chip) /* reset channels */ for (i = 0; i < chip->bdbars_count; i++) iputbyte(chip, ICH_REG_OFF_CR + chip->ichd[i].reg_offset, ICH_RESETREGS); - if (chip->device_type == DEVICE_NFORCE) { + if (chip->device_type == DEVICE_NFORCE && !spdif_aclink) { /* stop the spdif interrupt */ unsigned int val; pci_read_config_dword(chip->pci, 0x4c, &val); @@ -2492,7 +2501,7 @@ static int intel8x0_resume(struct pci_dev *pci) snd_intel8x0_chip_init(chip, 0); /* re-initialize mixer stuff */ - if (chip->device_type == DEVICE_INTEL_ICH4) { + if (chip->device_type == DEVICE_INTEL_ICH4 && !spdif_aclink) { /* enable separate SDINs for ICH4 */ iputbyte(chip, ICHREG(SDM), chip->sdm_saved); /* use slot 10/11 for SPDIF */ @@ -2928,6 +2937,29 @@ static struct shortname_table { { 0, NULL }, }; +static struct snd_pci_quirk spdif_aclink_defaults[] __devinitdata = { + SND_PCI_QUIRK(0x147b, 0x1c1a, "ASUS KN8", 1), + { } /* end */ +}; + +/* look up white/black list for SPDIF over ac-link */ +static int __devinit check_default_spdif_aclink(struct pci_dev *pci) +{ + const struct snd_pci_quirk *w; + + w = snd_pci_quirk_lookup(pci, spdif_aclink_defaults); + if (w) { + if (w->value) + snd_printdd(KERN_INFO "intel8x0: Using SPDIF over " + "AC-Link for %s\n", w->name); + else + snd_printdd(KERN_INFO "intel8x0: Using integrated " + "SPDIF DMA for %s\n", w->name); + return w->value; + } + return 0; +} + static int __devinit snd_intel8x0_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { @@ -2940,16 +2972,18 @@ static int __devinit snd_intel8x0_probe(struct pci_dev *pci, if (card == NULL) return -ENOMEM; - switch (pci_id->driver_data) { - case DEVICE_NFORCE: - strcpy(card->driver, "NFORCE"); - break; - case DEVICE_INTEL_ICH4: - strcpy(card->driver, "ICH4"); - break; - default: - strcpy(card->driver, "ICH"); - break; + if (spdif_aclink < 0) + spdif_aclink = check_default_spdif_aclink(pci); + + strcpy(card->driver, "ICH"); + if (!spdif_aclink) { + switch (pci_id->driver_data) { + case DEVICE_NFORCE: + strcpy(card->driver, "NFORCE"); + break; + case DEVICE_INTEL_ICH4: + strcpy(card->driver, "ICH4"); + } } strcpy(card->shortname, "Intel ICH"); -- cgit v1.2.3 From 9f0ac6e1a8677ac509821f4ff0c77d39b1d63125 Mon Sep 17 00:00:00 2001 From: Frank Mandarino Date: Fri, 24 Nov 2006 15:49:39 +0100 Subject: [ALSA] Update AT91 ASoC driver for 2.6.19 kernel. Changes were required to support latest AT91 header files. Also updated to remove AT91RM9200-specific code in the ASoC platform drivers to support the AT91SAM9260 and AT91SAM9261 chips, but no testing was performed on these chips. Signed-off-by: Frank Mandarino Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/at91/Makefile | 4 +- sound/soc/at91/at91-i2s.c | 673 +++++++++++++++++++++++++++++++++++++ sound/soc/at91/at91-pcm.c | 427 ++++++++++++++++++++++++ sound/soc/at91/at91-pcm.h | 71 ++++ sound/soc/at91/at91rm9200-i2s.c | 715 ---------------------------------------- sound/soc/at91/at91rm9200-pcm.c | 428 ------------------------ sound/soc/at91/at91rm9200-pcm.h | 75 ----- sound/soc/at91/eti_b1_wm8731.c | 64 +++- 8 files changed, 1224 insertions(+), 1233 deletions(-) create mode 100644 sound/soc/at91/at91-i2s.c create mode 100644 sound/soc/at91/at91-pcm.c create mode 100644 sound/soc/at91/at91-pcm.h delete mode 100644 sound/soc/at91/at91rm9200-i2s.c delete mode 100644 sound/soc/at91/at91rm9200-pcm.c delete mode 100644 sound/soc/at91/at91rm9200-pcm.h (limited to 'sound') diff --git a/sound/soc/at91/Makefile b/sound/soc/at91/Makefile index eb12ea2d194..b77b01ab202 100644 --- a/sound/soc/at91/Makefile +++ b/sound/soc/at91/Makefile @@ -1,6 +1,6 @@ # AT91 Platform Support -snd-soc-at91-objs := at91rm9200-pcm.o -snd-soc-at91-i2s-objs := at91rm9200-i2s.o +snd-soc-at91-objs := at91-pcm.o +snd-soc-at91-i2s-objs := at91-i2s.o obj-$(CONFIG_SND_AT91_SOC) += snd-soc-at91.o obj-$(CONFIG_SND_AT91_SOC_I2S) += snd-soc-at91-i2s.o diff --git a/sound/soc/at91/at91-i2s.c b/sound/soc/at91/at91-i2s.c new file mode 100644 index 00000000000..b452e8e6a72 --- /dev/null +++ b/sound/soc/at91/at91-i2s.c @@ -0,0 +1,673 @@ +/* + * at91-i2s.c -- ALSA SoC I2S Audio Layer Platform driver + * + * Author: Frank Mandarino + * Endrelia Technologies Inc. + * + * Based on pxa2xx Platform drivers by + * Liam Girdwood + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision history + * 3rd Mar 2006 Initial version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "at91-pcm.h" + +#if 0 +#define DBG(x...) printk(KERN_DEBUG "at91-i2s:" x) +#else +#define DBG(x...) +#endif + +#if defined(CONFIG_ARCH_AT91SAM9260) +#define NUM_SSC_DEVICES 1 +#else +#define NUM_SSC_DEVICES 3 +#endif + + +#define AT91_I2S_DAIFMT \ + (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_NB_NF) + +#define AT91_I2S_DIR \ + (SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE) + +/* priv is (SSC_CMR.DIV << 16 | SSC_TCMR.PERIOD ) */ +static struct snd_soc_dai_mode at91_i2s[] = { + + /* 8k: BCLK = (MCLK/10) = (60MHz/50) = 1.2MHz */ + { + .fmt = AT91_I2S_DAIFMT, + .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, + .pcmrate = SNDRV_PCM_RATE_8000, + .pcmdir = AT91_I2S_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 1500, + .bfs = SND_SOC_FSBD(10), + .priv = (25 << 16 | 74), + }, + + /* 16k: BCLK = (MCLK/3) ~= (60MHz/14) = 4.285714MHz */ + { + .fmt = AT91_I2S_DAIFMT, + .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, + .pcmrate = SNDRV_PCM_RATE_16000, + .pcmdir = AT91_I2S_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 750, + .bfs = SND_SOC_FSBD(3), + .priv = (7 << 16 | 133), + }, + + /* 32k: BCLK = (MCLK/3) ~= (60MHz/14) = 4.285714MHz */ + { + .fmt = AT91_I2S_DAIFMT, + .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, + .pcmrate = SNDRV_PCM_RATE_32000, + .pcmdir = AT91_I2S_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 375, + .bfs = SND_SOC_FSBD(3), + .priv = (7 << 16 | 66), + }, + + /* 48k: BCLK = (MCLK/5) ~= (60MHz/26) = 2.3076923MHz */ + { + .fmt = AT91_I2S_DAIFMT, + .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, + .pcmrate = SNDRV_PCM_RATE_48000, + .pcmdir = AT91_I2S_DIR, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 250, + .bfs SND_SOC_FSBD(5), + .priv = (13 << 16 | 23), + }, +}; + + +/* + * SSC PDC registers required by the PCM DMA engine. + */ +static struct at91_pdc_regs pdc_tx_reg = { + .xpr = AT91_PDC_TPR, + .xcr = AT91_PDC_TCR, + .xnpr = AT91_PDC_TNPR, + .xncr = AT91_PDC_TNCR, +}; + +static struct at91_pdc_regs pdc_rx_reg = { + .xpr = AT91_PDC_RPR, + .xcr = AT91_PDC_RCR, + .xnpr = AT91_PDC_RNPR, + .xncr = AT91_PDC_RNCR, +}; + +/* + * SSC & PDC status bits for transmit and receive. + */ +static struct at91_ssc_mask ssc_tx_mask = { + .ssc_enable = AT91_SSC_TXEN, + .ssc_disable = AT91_SSC_TXDIS, + .ssc_endx = AT91_SSC_ENDTX, + .ssc_endbuf = AT91_SSC_TXBUFE, + .pdc_enable = AT91_PDC_TXTEN, + .pdc_disable = AT91_PDC_TXTDIS, +}; + +static struct at91_ssc_mask ssc_rx_mask = { + .ssc_enable = AT91_SSC_RXEN, + .ssc_disable = AT91_SSC_RXDIS, + .ssc_endx = AT91_SSC_ENDRX, + .ssc_endbuf = AT91_SSC_RXBUFF, + .pdc_enable = AT91_PDC_RXTEN, + .pdc_disable = AT91_PDC_RXTDIS, +}; + + +/* + * DMA parameters. + */ +static struct at91_pcm_dma_params ssc_dma_params[NUM_SSC_DEVICES][2] = { + {{ + .name = "SSC0/I2S PCM Stereo out", + .pdc = &pdc_tx_reg, + .mask = &ssc_tx_mask, + }, + { + .name = "SSC0/I2S PCM Stereo in", + .pdc = &pdc_rx_reg, + .mask = &ssc_rx_mask, + }}, +#if NUM_SSC_DEVICES == 3 + {{ + .name = "SSC1/I2S PCM Stereo out", + .pdc = &pdc_tx_reg, + .mask = &ssc_tx_mask, + }, + { + .name = "SSC1/I2S PCM Stereo in", + .pdc = &pdc_rx_reg, + .mask = &ssc_rx_mask, + }}, + {{ + .name = "SSC2/I2S PCM Stereo out", + .pdc = &pdc_tx_reg, + .mask = &ssc_tx_mask, + }, + { + .name = "SSC1/I2S PCM Stereo in", + .pdc = &pdc_rx_reg, + .mask = &ssc_rx_mask, + }}, +#endif +}; + + +/* + * A MUTEX is used to protect an SSC initialzed flag which allows + * the substream hw_params() call to initialize the SSC only if + * there are no other substreams open. If there are other + * substreams open, the hw_param() call can only check that + * it is using the same format and rate. + */ +static DECLARE_MUTEX(ssc0_mutex); +#if NUM_SSC_DEVICES == 3 +static DECLARE_MUTEX(ssc1_mutex); +static DECLARE_MUTEX(ssc2_mutex); +#endif + + +struct at91_ssc_state { + u32 ssc_cmr; + u32 ssc_rcmr; + u32 ssc_rfmr; + u32 ssc_tcmr; + u32 ssc_tfmr; + u32 ssc_sr; + u32 ssc_imr; +}; + + +static struct at91_ssc_info { + char *name; + struct at91_ssc_periph ssc; + spinlock_t lock; /* lock for dir_mask */ + int dir_mask; /* 0=unused, 1=playback, 2=capture */ + struct semaphore *mutex; + int initialized; + int pcmfmt; + int rate; + struct at91_pcm_dma_params *dma_params[2]; + struct at91_ssc_state ssc_state; + +} ssc_info[NUM_SSC_DEVICES] = { + { + .name = "ssc0", + .lock = SPIN_LOCK_UNLOCKED, + .dir_mask = 0, + .mutex = &ssc0_mutex, + .initialized = 0, + }, +#if NUM_SSC_DEVICES == 3 + { + .name = "ssc1", + .lock = SPIN_LOCK_UNLOCKED, + .dir_mask = 0, + .mutex = &ssc1_mutex, + .initialized = 0, + }, + { + .name = "ssc2", + .lock = SPIN_LOCK_UNLOCKED, + .dir_mask = 0, + .mutex = &ssc2_mutex, + .initialized = 0, + }, +#endif +}; + + +static irqreturn_t at91_i2s_interrupt(int irq, void *dev_id) +{ + struct at91_ssc_info *ssc_p = dev_id; + struct at91_pcm_dma_params *dma_params; + u32 ssc_sr; + int i; + + ssc_sr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR) + & at91_ssc_read(ssc_p->ssc.base + AT91_SSC_IMR); + + /* + * Loop through the substreams attached to this SSC. If + * a DMA-related interrupt occurred on that substream, call + * the DMA interrupt handler function, if one has been + * registered in the dma_params structure by the PCM driver. + */ + for (i = 0; i < ARRAY_SIZE(ssc_p->dma_params); i++) { + dma_params = ssc_p->dma_params[i]; + + if (dma_params != NULL && dma_params->dma_intr_handler != NULL && + (ssc_sr & + (dma_params->mask->ssc_endx | dma_params->mask->ssc_endbuf))) + + dma_params->dma_intr_handler(ssc_sr, dma_params->substream); + } + + return IRQ_HANDLED; +} + +static int at91_i2s_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct at91_ssc_info *ssc_p = &ssc_info[rtd->cpu_dai->id]; + int dir_mask; + + DBG("i2s_startup: SSC_SR=0x%08lx\n", + at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR)); + dir_mask = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0x1 : 0x2; + + spin_lock_irq(&ssc_p->lock); + if (ssc_p->dir_mask & dir_mask) { + spin_unlock_irq(&ssc_p->lock); + return -EBUSY; + } + ssc_p->dir_mask |= dir_mask; + spin_unlock_irq(&ssc_p->lock); + + return 0; +} + +static void at91_i2s_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct at91_ssc_info *ssc_p = &ssc_info[rtd->cpu_dai->id]; + struct at91_pcm_dma_params *dma_params = rtd->cpu_dai->dma_data; + int dir, dir_mask; + + dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1; + + if (dma_params != NULL) { + at91_ssc_write(dma_params->ssc_base + AT91_SSC_CR, + dma_params->mask->ssc_disable); + DBG("%s disabled SSC_SR=0x%08lx\n", (dir ? "receive" : "transmit"), + at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR)); + + dma_params->ssc_base = NULL; + dma_params->substream = NULL; + ssc_p->dma_params[dir] = NULL; + } + + dir_mask = 1 << dir; + + spin_lock_irq(&ssc_p->lock); + ssc_p->dir_mask &= ~dir_mask; + if (!ssc_p->dir_mask) { + /* Shutdown the SSC clock. */ + DBG("Stopping pid %d clock\n", ssc_p->ssc.pid); + at91_sys_write(AT91_PMC_PCDR, 1<ssc.pid); + + if (ssc_p->initialized) + free_irq(ssc_p->ssc.pid, ssc_p); + + /* Reset the SSC */ + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR, AT91_SSC_SWRST); + + /* Force a re-init on the next hw_params() call. */ + ssc_p->initialized = 0; + } + spin_unlock_irq(&ssc_p->lock); +} + +#ifdef CONFIG_PM +static int at91_i2s_suspend(struct platform_device *pdev, + struct snd_soc_cpu_dai *dai) +{ + struct at91_ssc_info *ssc_p; + + if(!dai->active) + return 0; + + ssc_p = &ssc_info[dai->id]; + + /* Save the status register before disabling transmit and receive. */ + ssc_p->state->ssc_sr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR); + at91_ssc_write(ssc_p->ssc.base + + AT91_SSC_CR, AT91_SSC_TXDIS | AT91_SSC_RXDIS); + + /* Save the current interrupt mask, then disable unmasked interrupts. */ + ssc_p->state->ssc_imr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_IMR); + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_IDR, ssc_p->state->ssc_imr); + + ssc_p->state->ssc_cmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_CMR); + ssc_p->state->ssc_rcmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_RCMR); + ssc_p->state->ssc_rfmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_RCMR); + ssc_p->state->ssc_tcmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_RCMR); + ssc_p->state->ssc_tfmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_RCMR); + + return 0; +} + +static int at91_i2s_resume(struct platform_device *pdev, + struct snd_soc_cpu_dai *dai) +{ + struct at91_ssc_info *ssc_p; + u32 cr_mask; + + if(!dai->active) + return 0; + + ssc_p = &ssc_info[dai->id]; + + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RCMR, ssc_p->state->ssc_tfmr); + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RCMR, ssc_p->state->ssc_tcmr); + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RCMR, ssc_p->state->ssc_rfmr); + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RCMR, ssc_p->state->ssc_rcmr); + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CMR, ssc_p->state->ssc_cmr); + + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_IER, ssc_p->state->ssc_imr); + + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR, + ((ssc_p->state->ssc_sr & AT91_SSC_RXENA) ? AT91_SSC_RXEN : 0) | + ((ssc_p->state->ssc_sr & AT91_SSC_TXENA) ? AT91_SSC_TXEN : 0)); + + return 0; +} + +#else +#define at91_i2s_suspend NULL +#define at91_i2s_resume NULL +#endif + +static unsigned int at91_i2s_config_sysclk( + struct snd_soc_cpu_dai *iface, struct snd_soc_clock_info *info, + unsigned int clk) +{ + /* Currently, there is only support for USB (12Mhz) mode */ + if (clk != 12000000) + return 0; + return 12000000; +} + +static int at91_i2s_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + int id = rtd->cpu_dai->id; + struct at91_ssc_info *ssc_p = &ssc_info[id]; + struct at91_pcm_dma_params *dma_params; + unsigned int pcmfmt, rate; + int dir, channels, bits; + struct clk *mck_clk; + u32 div, period, tfmr, rfmr, tcmr, rcmr; + int ret; + + /* + * Currently, there is only one set of dma params for + * each direction. If more are added, this code will + * have to be changed to select the proper set. + */ + dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1; + + dma_params = &ssc_dma_params[id][dir]; + dma_params->ssc_base = ssc_p->ssc.base; + dma_params->substream = substream; + + ssc_p->dma_params[dir] = dma_params; + rtd->cpu_dai->dma_data = dma_params; + + rate = params_rate(params); + channels = params_channels(params); + + pcmfmt = rtd->cpu_dai->dai_runtime.pcmfmt; + switch (pcmfmt) { + case SNDRV_PCM_FMTBIT_S16_LE: + /* likely this is all we'll ever support, but ... */ + bits = 16; + dma_params->pdc_xfer_size = 2; + break; + default: + printk(KERN_WARNING "at91-i2s: unsupported format %x\n", + pcmfmt); + return -EINVAL; + } + + /* Don't allow both SSC substreams to initialize at the same time. */ + down(ssc_p->mutex); + + /* + * If this SSC is alreadly initialized, then this substream must use + * the same format and rate. + */ + if (ssc_p->initialized) { + if (pcmfmt != ssc_p->pcmfmt || rate != ssc_p->rate) { + printk(KERN_WARNING "at91-i2s: " + "incompatible substream in other direction\n"); + up(ssc_p->mutex); + return -EINVAL; + } + } else { + /* Enable PMC peripheral clock for this SSC */ + DBG("Starting pid %d clock\n", ssc_p->ssc.pid); + at91_sys_write(AT91_PMC_PCER, 1<ssc.pid); + + /* Reset the SSC */ + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR, AT91_SSC_SWRST); + + at91_ssc_write(ssc_p->ssc.base + AT91_PDC_RPR, 0); + at91_ssc_write(ssc_p->ssc.base + AT91_PDC_RCR, 0); + at91_ssc_write(ssc_p->ssc.base + AT91_PDC_RNPR, 0); + at91_ssc_write(ssc_p->ssc.base + AT91_PDC_RNCR, 0); + at91_ssc_write(ssc_p->ssc.base + AT91_PDC_TPR, 0); + at91_ssc_write(ssc_p->ssc.base + AT91_PDC_TCR, 0); + at91_ssc_write(ssc_p->ssc.base + AT91_PDC_TNPR, 0); + at91_ssc_write(ssc_p->ssc.base + AT91_PDC_TNCR, 0); + + div = rtd->cpu_dai->dai_runtime.priv >> 16; + period = rtd->cpu_dai->dai_runtime.priv & 0xffff; + + mck_clk = clk_get(NULL, "mck"); + + DBG("mck %lu fsbd %u bfs %llu bfs_real %u bclk %lu div %u period %u\n", + clk_get_rate(mck_clk), + SND_SOC_FSBD(6), + rtd->cpu_dai->dai_runtime.bfs, + SND_SOC_FSBD_REAL(rtd->cpu_dai->dai_runtime.bfs), + clk_get_rate(mck_clk) / (2 * div), + div, + period); + + clk_put(mck_clk); + + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CMR, div); + + /* + * Setup the TFMR and RFMR for the proper data format. + */ + tfmr = + (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE) + | (( 0 << 23) & AT91_SSC_FSDEN) + | (( AT91_SSC_FSOS_NEGATIVE ) & AT91_SSC_FSOS) + | (((bits - 1) << 16) & AT91_SSC_FSLEN) + | (((channels - 1) << 8) & AT91_SSC_DATNB) + | (( 1 << 7) & AT91_SSC_MSBF) + | (( 0 << 5) & AT91_SSC_DATDEF) + | (((bits - 1) << 0) & AT91_SSC_DATALEN); + DBG("SSC_TFMR=0x%08x\n", tfmr); + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TFMR, tfmr); + + rfmr = + (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE) + | (( AT91_SSC_FSOS_NONE ) & AT91_SSC_FSOS) + | (( 0 << 16) & AT91_SSC_FSLEN) + | (((channels - 1) << 8) & AT91_SSC_DATNB) + | (( 1 << 7) & AT91_SSC_MSBF) + | (( 0 << 5) & AT91_SSC_LOOP) + | (((bits - 1) << 0) & AT91_SSC_DATALEN); + + DBG("SSC_RFMR=0x%08x\n", rfmr); + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RFMR, rfmr); + + /* + * Setup the TCMR and RCMR to generate the proper BCLK + * and LRC signals. + */ + tcmr = + (( period << 24) & AT91_SSC_PERIOD) + | (( 1 << 16) & AT91_SSC_STTDLY) + | (( AT91_SSC_START_FALLING_RF ) & AT91_SSC_START) + | (( AT91_SSC_CKI_FALLING ) & AT91_SSC_CKI) + | (( AT91_SSC_CKO_CONTINUOUS ) & AT91_SSC_CKO) + | (( AT91_SSC_CKS_DIV ) & AT91_SSC_CKS); + + DBG("SSC_TCMR=0x%08x\n", tcmr); + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TCMR, tcmr); + + rcmr = + (( 0 << 24) & AT91_SSC_PERIOD) + | (( 1 << 16) & AT91_SSC_STTDLY) + | (( AT91_SSC_START_TX_RX ) & AT91_SSC_START) + | (( AT91_SSC_CK_RISING ) & AT91_SSC_CKI) + | (( AT91_SSC_CKO_NONE ) & AT91_SSC_CKO) + | (( AT91_SSC_CKS_CLOCK ) & AT91_SSC_CKS); + + DBG("SSC_RCMR=0x%08x\n", rcmr); + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RCMR, rcmr); + + if ((ret = request_irq(ssc_p->ssc.pid, at91_i2s_interrupt, + 0, ssc_p->name, ssc_p)) < 0) { + printk(KERN_WARNING "at91-i2s: request_irq failure\n"); + return ret; + } + + /* + * Save the current substream parameters in order to check + * that the substream in the opposite direction uses the + * same parameters. + */ + ssc_p->pcmfmt = pcmfmt; + ssc_p->rate = rate; + ssc_p->initialized = 1; + + DBG("hw_params: SSC initialized\n"); + } + + up(ssc_p->mutex); + + return 0; +} + + +static int at91_i2s_prepare(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct at91_pcm_dma_params *dma_params = rtd->cpu_dai->dma_data; + + at91_ssc_write(dma_params->ssc_base + AT91_SSC_CR, + dma_params->mask->ssc_enable); + + DBG("%s enabled SSC_SR=0x%08lx\n", + substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? "transmit" : "receive", + at91_ssc_read(ssc_info[rtd->cpu_dai->id].ssc.base + AT91_SSC_SR)); + return 0; +} + + +struct snd_soc_cpu_dai at91_i2s_dai[NUM_SSC_DEVICES] = { + { .name = "at91_ssc0/i2s", + .id = 0, + .type = SND_SOC_DAI_I2S, + .suspend = at91_i2s_suspend, + .resume = at91_i2s_resume, + .config_sysclk = at91_i2s_config_sysclk, + .playback = { + .channels_min = 1, + .channels_max = 2,}, + .capture = { + .channels_min = 1, + .channels_max = 2,}, + .ops = { + .startup = at91_i2s_startup, + .shutdown = at91_i2s_shutdown, + .prepare = at91_i2s_prepare, + .hw_params = at91_i2s_hw_params,}, + .caps = { + .mode = &at91_i2s[0], + .num_modes = ARRAY_SIZE(at91_i2s),}, + .private_data = &ssc_info[0].ssc, + }, +#if NUM_SSC_DEVICES == 3 + { .name = "at91_ssc1/i2s", + .id = 1, + .type = SND_SOC_DAI_I2S, + .suspend = at91_i2s_suspend, + .resume = at91_i2s_resume, + .config_sysclk = at91_i2s_config_sysclk, + .playback = { + .channels_min = 1, + .channels_max = 2,}, + .capture = { + .channels_min = 1, + .channels_max = 2,}, + .ops = { + .startup = at91_i2s_startup, + .shutdown = at91_i2s_shutdown, + .prepare = at91_i2s_prepare, + .hw_params = at91_i2s_hw_params,}, + .caps = { + .mode = &at91_i2s[0], + .num_modes = ARRAY_SIZE(at91_i2s),}, + .private_data = &ssc_info[1].ssc, + }, + { .name = "at91_ssc2/i2s", + .id = 2, + .type = SND_SOC_DAI_I2S, + .suspend = at91_i2s_suspend, + .resume = at91_i2s_resume, + .config_sysclk = at91_i2s_config_sysclk, + .playback = { + .channels_min = 1, + .channels_max = 2,}, + .capture = { + .channels_min = 1, + .channels_max = 2,}, + .ops = { + .startup = at91_i2s_startup, + .shutdown = at91_i2s_shutdown, + .prepare = at91_i2s_prepare, + .hw_params = at91_i2s_hw_params,}, + .caps = { + .mode = &at91_i2s[0], + .num_modes = ARRAY_SIZE(at91_i2s),}, + .private_data = &ssc_info[2].ssc, + }, +#endif +}; + +EXPORT_SYMBOL_GPL(at91_i2s_dai); + +/* Module information */ +MODULE_AUTHOR("Frank Mandarino, fmandarino@endrelia.com, www.endrelia.com"); +MODULE_DESCRIPTION("AT91 I2S ASoC Interface"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/at91/at91-pcm.c b/sound/soc/at91/at91-pcm.c new file mode 100644 index 00000000000..fd9d7327b23 --- /dev/null +++ b/sound/soc/at91/at91-pcm.c @@ -0,0 +1,427 @@ +/* + * at91-pcm.c -- ALSA PCM interface for the Atmel AT91 SoC + * + * Author: Frank Mandarino + * Endrelia Technologies Inc. + * Created: Mar 3, 2006 + * + * Based on pxa2xx-pcm.c by: + * + * Author: Nicolas Pitre + * Created: Nov 30, 2004 + * Copyright: (C) 2004 MontaVista Software, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "at91-pcm.h" + +#if 0 +#define DBG(x...) printk(KERN_INFO "at91-pcm: " x) +#else +#define DBG(x...) +#endif + +static const struct snd_pcm_hardware at91_pcm_hardware = { + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .period_bytes_min = 32, + .period_bytes_max = 8192, + .periods_min = 2, + .periods_max = 1024, + .buffer_bytes_max = 32 * 1024, +}; + +struct at91_runtime_data { + struct at91_pcm_dma_params *params; + dma_addr_t dma_buffer; /* physical address of dma buffer */ + dma_addr_t dma_buffer_end; /* first address beyond DMA buffer */ + size_t period_size; + dma_addr_t period_ptr; /* physical address of next period */ + u32 pdc_xpr_save; /* PDC register save */ + u32 pdc_xcr_save; + u32 pdc_xnpr_save; + u32 pdc_xncr_save; +}; + +static void at91_pcm_dma_irq(u32 ssc_sr, + struct snd_pcm_substream *substream) +{ + struct at91_runtime_data *prtd = substream->runtime->private_data; + struct at91_pcm_dma_params *params = prtd->params; + static int count = 0; + + count++; + + if (ssc_sr & params->mask->ssc_endbuf) { + + printk(KERN_WARNING + "at91-pcm: buffer %s on %s (SSC_SR=%#x, count=%d)\n", + substream->stream == SNDRV_PCM_STREAM_PLAYBACK + ? "underrun" : "overrun", + params->name, ssc_sr, count); + + /* re-start the PDC */ + at91_ssc_write(params->ssc_base + AT91_PDC_PTCR, params->mask->pdc_disable); + + prtd->period_ptr += prtd->period_size; + if (prtd->period_ptr >= prtd->dma_buffer_end) { + prtd->period_ptr = prtd->dma_buffer; + } + + at91_ssc_write(params->ssc_base + params->pdc->xpr, prtd->period_ptr); + at91_ssc_write(params->ssc_base + params->pdc->xcr, + prtd->period_size / params->pdc_xfer_size); + + at91_ssc_write(params->ssc_base + AT91_PDC_PTCR, params->mask->pdc_enable); + } + + if (ssc_sr & params->mask->ssc_endx) { + + /* Load the PDC next pointer and counter registers */ + prtd->period_ptr += prtd->period_size; + if (prtd->period_ptr >= prtd->dma_buffer_end) { + prtd->period_ptr = prtd->dma_buffer; + } + at91_ssc_write(params->ssc_base + params->pdc->xnpr, prtd->period_ptr); + at91_ssc_write(params->ssc_base + params->pdc->xncr, + prtd->period_size / params->pdc_xfer_size); + } + + snd_pcm_period_elapsed(substream); +} + +static int at91_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct at91_runtime_data *prtd = runtime->private_data; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + + /* this may get called several times by oss emulation + * with different params */ + + snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); + runtime->dma_bytes = params_buffer_bytes(params); + + prtd->params = rtd->cpu_dai->dma_data; + prtd->params->dma_intr_handler = at91_pcm_dma_irq; + + prtd->dma_buffer = runtime->dma_addr; + prtd->dma_buffer_end = runtime->dma_addr + runtime->dma_bytes; + prtd->period_size = params_period_bytes(params); + + DBG("hw_params: DMA for %s initialized (dma_bytes=%d, period_size=%d)\n", + prtd->params->name, runtime->dma_bytes, prtd->period_size); + return 0; +} + +static int at91_pcm_hw_free(struct snd_pcm_substream *substream) +{ + struct at91_runtime_data *prtd = substream->runtime->private_data; + struct at91_pcm_dma_params *params = prtd->params; + + if (params != NULL) { + at91_ssc_write(params->ssc_base + AT91_PDC_PTCR, params->mask->pdc_disable); + prtd->params->dma_intr_handler = NULL; + } + + return 0; +} + +static int at91_pcm_prepare(struct snd_pcm_substream *substream) +{ + struct at91_runtime_data *prtd = substream->runtime->private_data; + struct at91_pcm_dma_params *params = prtd->params; + + at91_ssc_write(params->ssc_base + AT91_SSC_IDR, + params->mask->ssc_endx | params->mask->ssc_endbuf); + + at91_ssc_write(params->ssc_base + AT91_PDC_PTCR, params->mask->pdc_disable); + return 0; +} + +static int at91_pcm_trigger(struct snd_pcm_substream *substream, + int cmd) +{ + struct at91_runtime_data *prtd = substream->runtime->private_data; + struct at91_pcm_dma_params *params = prtd->params; + int ret = 0; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + prtd->period_ptr = prtd->dma_buffer; + + at91_ssc_write(params->ssc_base + params->pdc->xpr, prtd->period_ptr); + at91_ssc_write(params->ssc_base + params->pdc->xcr, + prtd->period_size / params->pdc_xfer_size); + + prtd->period_ptr += prtd->period_size; + at91_ssc_write(params->ssc_base + params->pdc->xnpr, prtd->period_ptr); + at91_ssc_write(params->ssc_base + params->pdc->xncr, + prtd->period_size / params->pdc_xfer_size); + + DBG("trigger: period_ptr=%lx, xpr=%lx, xcr=%ld, xnpr=%lx, xncr=%ld\n", + (unsigned long) prtd->period_ptr, + at91_ssc_read(params->ssc_base + params->pdc->xpr), + at91_ssc_read(params->ssc_base + params->pdc->xcr), + at91_ssc_read(params->ssc_base + params->pdc->xnpr), + at91_ssc_read(params->ssc_base + params->pdc->xncr)); + + at91_ssc_write(params->ssc_base + AT91_SSC_IER, + params->mask->ssc_endx | params->mask->ssc_endbuf); + + at91_ssc_write(params->ssc_base + AT91_PDC_PTCR, params->mask->pdc_enable); + + DBG("sr=%lx imr=%lx\n", at91_ssc_read(params->ssc_base + AT91_SSC_SR), + at91_ssc_read(params->ssc_base + AT91_SSC_IER)); + break; + + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + at91_ssc_write(params->ssc_base + AT91_PDC_PTCR, params->mask->pdc_disable); + break; + + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + at91_ssc_write(params->ssc_base + AT91_PDC_PTCR, params->mask->pdc_enable); + break; + + default: + ret = -EINVAL; + } + + return ret; +} + +static snd_pcm_uframes_t at91_pcm_pointer( + struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct at91_runtime_data *prtd = runtime->private_data; + struct at91_pcm_dma_params *params = prtd->params; + dma_addr_t ptr; + snd_pcm_uframes_t x; + + ptr = (dma_addr_t) at91_ssc_read(params->ssc_base + params->pdc->xpr); + x = bytes_to_frames(runtime, ptr - prtd->dma_buffer); + + if (x == runtime->buffer_size) + x = 0; + return x; +} + +static int at91_pcm_open(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct at91_runtime_data *prtd; + int ret = 0; + + snd_soc_set_runtime_hwparams(substream, &at91_pcm_hardware); + + /* ensure that buffer size is a multiple of period size */ + ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + if (ret < 0) + goto out; + + prtd = kzalloc(sizeof(struct at91_runtime_data), GFP_KERNEL); + if (prtd == NULL) { + ret = -ENOMEM; + goto out; + } + runtime->private_data = prtd; + + out: + return ret; +} + +static int at91_pcm_close(struct snd_pcm_substream *substream) +{ + struct at91_runtime_data *prtd = substream->runtime->private_data; + + kfree(prtd); + return 0; +} + +static int at91_pcm_mmap(struct snd_pcm_substream *substream, + struct vm_area_struct *vma) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + return dma_mmap_writecombine(substream->pcm->card->dev, vma, + runtime->dma_area, + runtime->dma_addr, + runtime->dma_bytes); +} + +struct snd_pcm_ops at91_pcm_ops = { + .open = at91_pcm_open, + .close = at91_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = at91_pcm_hw_params, + .hw_free = at91_pcm_hw_free, + .prepare = at91_pcm_prepare, + .trigger = at91_pcm_trigger, + .pointer = at91_pcm_pointer, + .mmap = at91_pcm_mmap, +}; + +static int at91_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, + int stream) +{ + struct snd_pcm_substream *substream = pcm->streams[stream].substream; + struct snd_dma_buffer *buf = &substream->dma_buffer; + size_t size = at91_pcm_hardware.buffer_bytes_max; + + buf->dev.type = SNDRV_DMA_TYPE_DEV; + buf->dev.dev = pcm->card->dev; + buf->private_data = NULL; + buf->area = dma_alloc_writecombine(pcm->card->dev, size, + &buf->addr, GFP_KERNEL); + + DBG("preallocate_dma_buffer: area=%p, addr=%p, size=%d\n", + (void *) buf->area, + (void *) buf->addr, + size); + + if (!buf->area) + return -ENOMEM; + + buf->bytes = size; + return 0; +} + +static u64 at91_pcm_dmamask = 0xffffffff; + +static int at91_pcm_new(struct snd_card *card, + struct snd_soc_codec_dai *dai, struct snd_pcm *pcm) +{ + int ret = 0; + + if (!card->dev->dma_mask) + card->dev->dma_mask = &at91_pcm_dmamask; + if (!card->dev->coherent_dma_mask) + card->dev->coherent_dma_mask = 0xffffffff; + + if (dai->playback.channels_min) { + ret = at91_pcm_preallocate_dma_buffer(pcm, + SNDRV_PCM_STREAM_PLAYBACK); + if (ret) + goto out; + } + + if (dai->capture.channels_min) { + ret = at91_pcm_preallocate_dma_buffer(pcm, + SNDRV_PCM_STREAM_CAPTURE); + if (ret) + goto out; + } + out: + return ret; +} + +static void at91_pcm_free_dma_buffers(struct snd_pcm *pcm) +{ + struct snd_pcm_substream *substream; + struct snd_dma_buffer *buf; + int stream; + + for (stream = 0; stream < 2; stream++) { + substream = pcm->streams[stream].substream; + if (!substream) + continue; + + buf = &substream->dma_buffer; + if (!buf->area) + continue; + + dma_free_writecombine(pcm->card->dev, buf->bytes, + buf->area, buf->addr); + buf->area = NULL; + } +} + +static int at91_pcm_suspend(struct platform_device *pdev, + struct snd_soc_cpu_dai *dai) +{ + struct snd_pcm_runtime *runtime = dai->runtime; + struct at91_runtime_data *prtd; + struct at91_pcm_dma_params *params; + + if (!runtime) + return 0; + + prtd = runtime->private_data; + params = prtd->params; + + /* disable the PDC and save the PDC registers */ + + at91_ssc_write(params->ssc_base + AT91_PDC_PTCR, params->mask->pdc_disable); + + prtd->pdc_xpr_save = at91_ssc_read(params->ssc_base + params->pdc->xpr); + prtd->pdc_xcr_save = at91_ssc_read(params->ssc_base + params->pdc->xcr); + prtd->pdc_xnpr_save = at91_ssc_read(params->ssc_base + params->pdc->xnpr); + prtd->pdc_xncr_save = at91_ssc_read(params->ssc_base + params->pdc->xncr); + + return 0; +} + +static int at91_pcm_resume(struct platform_device *pdev, + struct snd_soc_cpu_dai *dai) +{ + struct snd_pcm_runtime *runtime = dai->runtime; + struct at91_runtime_data *prtd; + struct at91_pcm_dma_params *params; + + if (!runtime) + return 0; + + prtd = runtime->private_data; + params = prtd->params; + + /* restore the PDC registers and enable the PDC */ + at91_ssc_write(params->ssc_base + params->pdc->xpr, prtd->pdc_xpr_save); + at91_ssc_write(params->ssc_base + params->pdc->xcr, prtd->pdc_xcr_save); + at91_ssc_write(params->ssc_base + params->pdc->xnpr, prtd->pdc_xnpr_save); + at91_ssc_write(params->ssc_base + params->pdc->xncr, prtd->pdc_xncr_save); + + at91_ssc_write(params->ssc_base + AT91_PDC_PTCR, params->mask->pdc_enable); + return 0; +} + +struct snd_soc_platform at91_soc_platform = { + .name = "at91-audio", + .pcm_ops = &at91_pcm_ops, + .pcm_new = at91_pcm_new, + .pcm_free = at91_pcm_free_dma_buffers, + .suspend = at91_pcm_suspend, + .resume = at91_pcm_resume, +}; + +EXPORT_SYMBOL_GPL(at91_soc_platform); + +MODULE_AUTHOR("Frank Mandarino "); +MODULE_DESCRIPTION("Atmel AT91 PCM module"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/at91/at91-pcm.h b/sound/soc/at91/at91-pcm.h new file mode 100644 index 00000000000..6c3b095725c --- /dev/null +++ b/sound/soc/at91/at91-pcm.h @@ -0,0 +1,71 @@ +/* + * at91-pcm.h - ALSA PCM interface for the Atmel AT91 SoC + * + * Author: Frank Mandarino + * Endrelia Technologies Inc. + * Created: Mar 3, 2006 + * + * Based on pxa2xx-pcm.h by: + * + * Author: Nicolas Pitre + * Created: Nov 30, 2004 + * Copyright: MontaVista Software, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include + +struct at91_ssc_periph { + void __iomem *base; + u32 pid; +}; + + +/* + * Registers and status bits that are required by the PCM driver. + */ +struct at91_pdc_regs { + unsigned int xpr; /* PDC recv/trans pointer */ + unsigned int xcr; /* PDC recv/trans counter */ + unsigned int xnpr; /* PDC next recv/trans pointer */ + unsigned int xncr; /* PDC next recv/trans counter */ + unsigned int ptcr; /* PDC transfer control */ +}; + +struct at91_ssc_mask { + u32 ssc_enable; /* SSC recv/trans enable */ + u32 ssc_disable; /* SSC recv/trans disable */ + u32 ssc_endx; /* SSC ENDTX or ENDRX */ + u32 ssc_endbuf; /* SSC TXBUFE or RXBUFF */ + u32 pdc_enable; /* PDC recv/trans enable */ + u32 pdc_disable; /* PDC recv/trans disable */ +}; + + +/* + * This structure, shared between the PCM driver and the interface, + * contains all information required by the PCM driver to perform the + * PDC DMA operation. All fields except dma_intr_handler() are initialized + * by the interface. The dms_intr_handler() pointer is set by the PCM + * driver and called by the interface SSC interrupt handler if it is + * non-NULL. + */ +struct at91_pcm_dma_params { + char *name; /* stream identifier */ + int pdc_xfer_size; /* PDC counter increment in bytes */ + void __iomem *ssc_base; /* SSC base address */ + struct at91_pdc_regs *pdc; /* PDC receive or transmit registers */ + struct at91_ssc_mask *mask;/* SSC & PDC status bits */ + struct snd_pcm_substream *substream; + void (*dma_intr_handler)(u32, struct snd_pcm_substream *); +}; + +extern struct snd_soc_cpu_dai at91_i2s_dai[3]; +extern struct snd_soc_platform at91_soc_platform; + + +#define at91_ssc_read(a) ((unsigned long) __raw_readl(a)) +#define at91_ssc_write(a,v) __raw_writel((v),(a)) diff --git a/sound/soc/at91/at91rm9200-i2s.c b/sound/soc/at91/at91rm9200-i2s.c deleted file mode 100644 index e3e6345fc8b..00000000000 --- a/sound/soc/at91/at91rm9200-i2s.c +++ /dev/null @@ -1,715 +0,0 @@ -/* - * at91rm9200-i2s.c -- ALSA Soc Audio Layer Platform driver and DMA engine - * - * Author: Frank Mandarino - * Endrelia Technologies Inc. - * - * Based on pxa2xx Platform drivers by - * Liam Girdwood - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * Revision history - * 3rd Mar 2006 Initial version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "at91rm9200-pcm.h" - -#if 0 -#define DBG(x...) printk(KERN_DEBUG "at91rm9200-i2s:" x) -#else -#define DBG(x...) -#endif - -#define AT91RM9200_I2S_DAIFMT \ - (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_NB_NF) - -#define AT91RM9200_I2S_DIR \ - (SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE) - -/* priv is (SSC_CMR.DIV << 16 | SSC_TCMR.PERIOD ) */ -static struct snd_soc_dai_mode at91rm9200_i2s[] = { - - /* 8k: BCLK = (MCLK/10) = (60MHz/50) = 1.2MHz */ - { - .fmt = AT91RM9200_I2S_DAIFMT, - .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, - .pcmrate = SNDRV_PCM_RATE_8000, - .pcmdir = AT91RM9200_I2S_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 1500, - .bfs = SND_SOC_FSBD(10), - .priv = (25 << 16 | 74), - }, - - /* 16k: BCLK = (MCLK/3) ~= (60MHz/14) = 4.285714MHz */ - { - .fmt = AT91RM9200_I2S_DAIFMT, - .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, - .pcmrate = SNDRV_PCM_RATE_16000, - .pcmdir = AT91RM9200_I2S_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 750, - .bfs = SND_SOC_FSBD(3), - .priv = (7 << 16 | 133), - }, - - /* 32k: BCLK = (MCLK/3) ~= (60MHz/14) = 4.285714MHz */ - { - .fmt = AT91RM9200_I2S_DAIFMT, - .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, - .pcmrate = SNDRV_PCM_RATE_32000, - .pcmdir = AT91RM9200_I2S_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 375, - .bfs = SND_SOC_FSBD(3), - .priv = (7 << 16 | 66), - }, - - /* 48k: BCLK = (MCLK/5) ~= (60MHz/26) = 2.3076923MHz */ - { - .fmt = AT91RM9200_I2S_DAIFMT, - .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, - .pcmrate = SNDRV_PCM_RATE_48000, - .pcmdir = AT91RM9200_I2S_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 250, - .bfs SND_SOC_FSBD(5), - .priv = (13 << 16 | 23), - }, -}; - - -/* - * SSC registers required by the PCM DMA engine. - */ -static struct at91rm9200_ssc_regs ssc_reg[3] = { - { - .cr = (void __iomem *) (AT91_VA_BASE_SSC0 + AT91_SSC_CR), - .ier = (void __iomem *) (AT91_VA_BASE_SSC0 + AT91_SSC_IER), - .idr = (void __iomem *) (AT91_VA_BASE_SSC0 + AT91_SSC_IDR), - }, - { - .cr = (void __iomem *) (AT91_VA_BASE_SSC1 + AT91_SSC_CR), - .ier = (void __iomem *) (AT91_VA_BASE_SSC1 + AT91_SSC_IER), - .idr = (void __iomem *) (AT91_VA_BASE_SSC1 + AT91_SSC_IDR), - }, - { - .cr = (void __iomem *) (AT91_VA_BASE_SSC2 + AT91_SSC_CR), - .ier = (void __iomem *) (AT91_VA_BASE_SSC2 + AT91_SSC_IER), - .idr = (void __iomem *) (AT91_VA_BASE_SSC2 + AT91_SSC_IDR), - }, -}; - -static struct at91rm9200_pdc_regs pdc_tx_reg[3] = { - { - .xpr = (void __iomem *) (AT91_VA_BASE_SSC0 + AT91_PDC_TPR), - .xcr = (void __iomem *) (AT91_VA_BASE_SSC0 + AT91_PDC_TCR), - .xnpr = (void __iomem *) (AT91_VA_BASE_SSC0 + AT91_PDC_TNPR), - .xncr = (void __iomem *) (AT91_VA_BASE_SSC0 + AT91_PDC_TNCR), - .ptcr = (void __iomem *) (AT91_VA_BASE_SSC0 + AT91_PDC_PTCR), - }, - { - .xpr = (void __iomem *) (AT91_VA_BASE_SSC1 + AT91_PDC_TPR), - .xcr = (void __iomem *) (AT91_VA_BASE_SSC1 + AT91_PDC_TCR), - .xnpr = (void __iomem *) (AT91_VA_BASE_SSC1 + AT91_PDC_TNPR), - .xncr = (void __iomem *) (AT91_VA_BASE_SSC1 + AT91_PDC_TNCR), - .ptcr = (void __iomem *) (AT91_VA_BASE_SSC1 + AT91_PDC_PTCR), - }, - { - .xpr = (void __iomem *) (AT91_VA_BASE_SSC2 + AT91_PDC_TPR), - .xcr = (void __iomem *) (AT91_VA_BASE_SSC2 + AT91_PDC_TCR), - .xnpr = (void __iomem *) (AT91_VA_BASE_SSC2 + AT91_PDC_TNPR), - .xncr = (void __iomem *) (AT91_VA_BASE_SSC2 + AT91_PDC_TNCR), - .ptcr = (void __iomem *) (AT91_VA_BASE_SSC2 + AT91_PDC_PTCR), - }, -}; - -static struct at91rm9200_pdc_regs pdc_rx_reg[3] = { - { - .xpr = (void __iomem *) (AT91_VA_BASE_SSC0 + AT91_PDC_RPR), - .xcr = (void __iomem *) (AT91_VA_BASE_SSC0 + AT91_PDC_RCR), - .xnpr = (void __iomem *) (AT91_VA_BASE_SSC0 + AT91_PDC_RNPR), - .xncr = (void __iomem *) (AT91_VA_BASE_SSC0 + AT91_PDC_RNCR), - .ptcr = (void __iomem *) (AT91_VA_BASE_SSC0 + AT91_PDC_PTCR), - }, - { - .xpr = (void __iomem *) (AT91_VA_BASE_SSC1 + AT91_PDC_RPR), - .xcr = (void __iomem *) (AT91_VA_BASE_SSC1 + AT91_PDC_RCR), - .xnpr = (void __iomem *) (AT91_VA_BASE_SSC1 + AT91_PDC_RNPR), - .xncr = (void __iomem *) (AT91_VA_BASE_SSC1 + AT91_PDC_RNCR), - .ptcr = (void __iomem *) (AT91_VA_BASE_SSC1 + AT91_PDC_PTCR), - }, - { - .xpr = (void __iomem *) (AT91_VA_BASE_SSC2 + AT91_PDC_RPR), - .xcr = (void __iomem *) (AT91_VA_BASE_SSC2 + AT91_PDC_RCR), - .xnpr = (void __iomem *) (AT91_VA_BASE_SSC2 + AT91_PDC_RNPR), - .xncr = (void __iomem *) (AT91_VA_BASE_SSC2 + AT91_PDC_RNCR), - .ptcr = (void __iomem *) (AT91_VA_BASE_SSC2 + AT91_PDC_PTCR), - }, -}; - -/* - * SSC & PDC status bits for transmit and receive. - */ -static struct at91rm9200_ssc_mask ssc_tx_mask = { - .ssc_enable = AT91_SSC_TXEN, - .ssc_disable = AT91_SSC_TXDIS, - .ssc_endx = AT91_SSC_ENDTX, - .ssc_endbuf = AT91_SSC_TXBUFE, - .pdc_enable = AT91_PDC_TXTEN, - .pdc_disable = AT91_PDC_TXTDIS, -}; - -static struct at91rm9200_ssc_mask ssc_rx_mask = { - .ssc_enable = AT91_SSC_RXEN, - .ssc_disable = AT91_SSC_RXDIS, - .ssc_endx = AT91_SSC_ENDRX, - .ssc_endbuf = AT91_SSC_RXBUFF, - .pdc_enable = AT91_PDC_RXTEN, - .pdc_disable = AT91_PDC_RXTDIS, -}; - -/* - * A MUTEX is used to protect an SSC initialzed flag which allows - * the substream hw_params() call to initialize the SSC only if - * there are no other substreams open. If there are other - * substreams open, the hw_param() call can only check that - * it is using the same format and rate. - */ -static DECLARE_MUTEX(ssc0_mutex); -static DECLARE_MUTEX(ssc1_mutex); -static DECLARE_MUTEX(ssc2_mutex); - -/* - * DMA parameters. - */ -static at91rm9200_pcm_dma_params_t ssc_dma_params[3][2] = { - {{ - .name = "SSC0/I2S PCM Stereo out", - .ssc = &ssc_reg[0], - .pdc = &pdc_tx_reg[0], - .mask = &ssc_tx_mask, - }, - { - .name = "SSC0/I2S PCM Stereo in", - .ssc = &ssc_reg[0], - .pdc = &pdc_rx_reg[0], - .mask = &ssc_rx_mask, - }}, - {{ - .name = "SSC1/I2S PCM Stereo out", - .ssc = &ssc_reg[1], - .pdc = &pdc_tx_reg[1], - .mask = &ssc_tx_mask, - }, - { - .name = "SSC1/I2S PCM Stereo in", - .ssc = &ssc_reg[1], - .pdc = &pdc_rx_reg[1], - .mask = &ssc_rx_mask, - }}, - {{ - .name = "SSC2/I2S PCM Stereo out", - .ssc = &ssc_reg[2], - .pdc = &pdc_tx_reg[2], - .mask = &ssc_tx_mask, - }, - { - .name = "SSC1/I2S PCM Stereo in", - .ssc = &ssc_reg[2], - .pdc = &pdc_rx_reg[2], - .mask = &ssc_rx_mask, - }}, -}; - - -struct at91rm9200_ssc_state { - u32 ssc_cmr; - u32 ssc_rcmr; - u32 ssc_rfmr; - u32 ssc_tcmr; - u32 ssc_tfmr; - u32 ssc_sr; - u32 ssc_imr; -}; - -static struct at91rm9200_ssc_info { - char *name; - void __iomem *ssc_base; - u32 pid; - spinlock_t lock; /* lock for dir_mask */ - int dir_mask; /* 0=unused, 1=playback, 2=capture */ - struct semaphore *mutex; - int initialized; - int pcmfmt; - int rate; - at91rm9200_pcm_dma_params_t *dma_params[2]; - struct at91rm9200_ssc_state ssc_state; - -} ssc_info[3] = { - { - .name = "ssc0", - .ssc_base = (void __iomem *) AT91_VA_BASE_SSC0, - .pid = AT91_ID_SSC0, - .lock = SPIN_LOCK_UNLOCKED, - .dir_mask = 0, - .mutex = &ssc0_mutex, - .initialized = 0, - }, - { - .name = "ssc1", - .ssc_base = (void __iomem *) AT91_VA_BASE_SSC1, - .pid = AT91_ID_SSC1, - .lock = SPIN_LOCK_UNLOCKED, - .dir_mask = 0, - .mutex = &ssc1_mutex, - .initialized = 0, - }, - { - .name = "ssc2", - .ssc_base = (void __iomem *) AT91_VA_BASE_SSC2, - .pid = AT91_ID_SSC2, - .lock = SPIN_LOCK_UNLOCKED, - .dir_mask = 0, - .mutex = &ssc2_mutex, - .initialized = 0, - }, -}; - - -static irqreturn_t at91rm9200_i2s_interrupt(int irq, void *dev_id) -{ - struct at91rm9200_ssc_info *ssc_p = dev_id; - at91rm9200_pcm_dma_params_t *dma_params; - u32 ssc_sr; - int i; - - ssc_sr = at91_ssc_read(ssc_p->ssc_base + AT91_SSC_SR) - & at91_ssc_read(ssc_p->ssc_base + AT91_SSC_IMR); - - /* - * Loop through the substreams attached to this SSC. If - * a DMA-related interrupt occurred on that substream, call - * the DMA interrupt handler function, if one has been - * registered in the dma_params structure by the PCM driver. - */ - for (i = 0; i < ARRAY_SIZE(ssc_p->dma_params); i++) { - dma_params = ssc_p->dma_params[i]; - - if (dma_params != NULL && dma_params->dma_intr_handler != NULL && - (ssc_sr & - (dma_params->mask->ssc_endx | dma_params->mask->ssc_endbuf))) - - dma_params->dma_intr_handler(ssc_sr, dma_params->substream); - } - - return IRQ_HANDLED; -} - -static int at91rm9200_i2s_startup(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct at91rm9200_ssc_info *ssc_p = &ssc_info[rtd->cpu_dai->id]; - int dir_mask; - - DBG("i2s_startup: SSC_SR=0x%08lx\n", - at91_ssc_read(ssc_p->ssc_base + AT91_SSC_SR)); - dir_mask = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0x1 : 0x2; - - spin_lock_irq(&ssc_p->lock); - if (ssc_p->dir_mask & dir_mask) { - spin_unlock_irq(&ssc_p->lock); - return -EBUSY; - } - ssc_p->dir_mask |= dir_mask; - spin_unlock_irq(&ssc_p->lock); - - return 0; -} - -static void at91rm9200_i2s_shutdown(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct at91rm9200_ssc_info *ssc_p = &ssc_info[rtd->cpu_dai->id]; - at91rm9200_pcm_dma_params_t *dma_params = rtd->cpu_dai->dma_data; - int dir, dir_mask; - - dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1; - - if (dma_params != NULL) { - at91_ssc_write(dma_params->ssc->cr, dma_params->mask->ssc_disable); - DBG("%s disabled SSC_SR=0x%08lx\n", (dir ? "receive" : "transmit"), - at91_ssc_read(ssc_p->ssc_base + AT91_SSC_SR)); - - dma_params->substream = NULL; - ssc_p->dma_params[dir] = NULL; - } - - dir_mask = 1 << dir; - - spin_lock_irq(&ssc_p->lock); - ssc_p->dir_mask &= ~dir_mask; - if (!ssc_p->dir_mask) { - /* Shutdown the SSC clock. */ - DBG("Stopping pid %d clock\n", ssc_p->pid); - at91_sys_write(AT91_PMC_PCDR, 1<pid); - - if (ssc_p->initialized) - free_irq(ssc_p->pid, ssc_p); - - /* Reset the SSC */ - at91_ssc_write(ssc_p->ssc_base + AT91_SSC_CR, AT91_SSC_SWRST); - - /* Force a re-init on the next hw_params() call. */ - ssc_p->initialized = 0; - } - spin_unlock_irq(&ssc_p->lock); -} - -#ifdef CONFIG_PM -static int at91rm9200_i2s_suspend(struct platform_device *pdev, - struct snd_soc_cpu_dai *dai) -{ - struct at91rm9200_ssc_info *ssc_p; - - if(!dai->active) - return 0; - - ssc_p = &ssc_info[dai->id]; - - /* Save the status register before disabling transmit and receive. */ - ssc_p->state->ssc_sr = at91_ssc_read(ssc_p->ssc_base + AT91_SSC_SR); - at91_ssc_write(ssc_p->ssc_base + - AT91_SSC_CR, AT91_SSC_TXDIS | AT91_SSC_RXDIS); - - /* Save the current interrupt mask, then disable unmasked interrupts. */ - ssc_p->state->ssc_imr = at91_ssc_read(ssc_p->ssc_base + AT91_SSC_IMR); - at91_ssc_write(ssc_p->ssc_base + AT91_SSC_IDR, ssc_p->state->ssc_imr); - - ssc_p->state->ssc_cmr = at91_ssc_read(ssc_p->ssc_base + AT91_SSC_CMR); - ssc_p->state->ssc_rcmr = at91_ssc_read(ssc_p->ssc_base + AT91_SSC_RCMR); - ssc_p->state->ssc_rfmr = at91_ssc_read(ssc_p->ssc_base + AT91_SSC_RCMR); - ssc_p->state->ssc_tcmr = at91_ssc_read(ssc_p->ssc_base + AT91_SSC_RCMR); - ssc_p->state->ssc_tfmr = at91_ssc_read(ssc_p->ssc_base + AT91_SSC_RCMR); - - return 0; -} - -static int at91rm9200_i2s_resume(struct platform_device *pdev, - struct snd_soc_cpu_dai *dai) -{ - struct at91rm9200_ssc_info *ssc_p; - u32 cr_mask; - - if(!dai->active) - return 0; - - ssc_p = &ssc_info[dai->id]; - - at91_ssc_write(ssc_p->ssc_base + AT91_SSC_RCMR, ssc_p->state->ssc_tfmr); - at91_ssc_write(ssc_p->ssc_base + AT91_SSC_RCMR, ssc_p->state->ssc_tcmr); - at91_ssc_write(ssc_p->ssc_base + AT91_SSC_RCMR, ssc_p->state->ssc_rfmr); - at91_ssc_write(ssc_p->ssc_base + AT91_SSC_RCMR, ssc_p->state->ssc_rcmr); - at91_ssc_write(ssc_p->ssc_base + AT91_SSC_CMR, ssc_p->state->ssc_cmr); - - at91_ssc_write(ssc_p->ssc_base + AT91_SSC_IER, ssc_p->state->ssc_imr); - - at91_ssc_write(ssc_p->ssc_base + AT91_SSC_CR, - ((ssc_p->state->ssc_sr & AT91_SSC_RXENA) ? AT91_SSC_RXEN : 0) | - ((ssc_p->state->ssc_sr & AT91_SSC_TXENA) ? AT91_SSC_TXEN : 0)); - - return 0; -} - -#else -#define at91rm9200_i2s_suspend NULL -#define at91rm9200_i2s_resume NULL -#endif - -static unsigned int at91rm9200_i2s_config_sysclk( - struct snd_soc_cpu_dai *iface, struct snd_soc_clock_info *info, - unsigned int clk) -{ - /* Currently, there is only support for USB (12Mhz) mode */ - if (clk != 12000000) - return 0; - return 12000000; -} - -static int at91rm9200_i2s_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - int id = rtd->cpu_dai->id; - struct at91rm9200_ssc_info *ssc_p = &ssc_info[id]; - at91rm9200_pcm_dma_params_t *dma_params; - unsigned int pcmfmt, rate; - int dir, channels, bits; - struct clk *mck_clk; - unsigned long bclk; - u32 div, period, tfmr, rfmr, tcmr, rcmr; - int ret; - - /* - * Currently, there is only one set of dma params for - * each direction. If more are added, this code will - * have to be changed to select the proper set. - */ - dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1; - - dma_params = &ssc_dma_params[id][dir]; - dma_params->substream = substream; - - ssc_p->dma_params[dir] = dma_params; - rtd->cpu_dai->dma_data = dma_params; - - rate = params_rate(params); - channels = params_channels(params); - - pcmfmt = rtd->cpu_dai->dai_runtime.pcmfmt; - switch (pcmfmt) { - case SNDRV_PCM_FMTBIT_S16_LE: - /* likely this is all we'll ever support, but ... */ - bits = 16; - dma_params->pdc_xfer_size = 2; - break; - default: - printk(KERN_WARNING "at91rm9200-i2s: unsupported format %x\n", - pcmfmt); - return -EINVAL; - } - - /* Don't allow both SSC substreams to initialize at the same time. */ - down(ssc_p->mutex); - - /* - * If this SSC is alreadly initialized, then this substream must use - * the same format and rate. - */ - if (ssc_p->initialized) { - if (pcmfmt != ssc_p->pcmfmt || rate != ssc_p->rate) { - printk(KERN_WARNING "at91rm9200-i2s: " - "incompatible substream in other direction\n"); - up(ssc_p->mutex); - return -EINVAL; - } - } else { - /* Enable PMC peripheral clock for this SSC */ - DBG("Starting pid %d clock\n", ssc_p->pid); - at91_sys_write(AT91_PMC_PCER, 1<pid); - - /* Reset the SSC */ - at91_ssc_write(ssc_p->ssc_base + AT91_SSC_CR, AT91_SSC_SWRST); - - at91_ssc_write(ssc_p->ssc_base + AT91_PDC_RPR, 0); - at91_ssc_write(ssc_p->ssc_base + AT91_PDC_RCR, 0); - at91_ssc_write(ssc_p->ssc_base + AT91_PDC_RNPR, 0); - at91_ssc_write(ssc_p->ssc_base + AT91_PDC_RNCR, 0); - at91_ssc_write(ssc_p->ssc_base + AT91_PDC_TPR, 0); - at91_ssc_write(ssc_p->ssc_base + AT91_PDC_TCR, 0); - at91_ssc_write(ssc_p->ssc_base + AT91_PDC_TNPR, 0); - at91_ssc_write(ssc_p->ssc_base + AT91_PDC_TNCR, 0); - - mck_clk = clk_get(NULL, "mck"); - - div = rtd->cpu_dai->dai_runtime.priv >> 16; - period = rtd->cpu_dai->dai_runtime.priv & 0xffff; - bclk = 60000000 / (2 * div); - - DBG("mck %ld fsbd %d bfs %d bfs_real %d bclk %ld div %d period %d\n", - clk_get_rate(mck_clk), - SND_SOC_FSBD(6), - rtd->cpu_dai->dai_runtime.bfs, - SND_SOC_FSBD_REAL(rtd->cpu_dai->dai_runtime.bfs), - bclk, - div, - period); - - clk_put(mck_clk); - - at91_ssc_write(ssc_p->ssc_base + AT91_SSC_CMR, div); - - /* - * Setup the TFMR and RFMR for the proper data format. - */ - tfmr = - (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE) - | (( 0 << 23) & AT91_SSC_FSDEN) - | (( AT91_SSC_FSOS_NEGATIVE ) & AT91_SSC_FSOS) - | (((bits - 1) << 16) & AT91_SSC_FSLEN) - | (((channels - 1) << 8) & AT91_SSC_DATNB) - | (( 1 << 7) & AT91_SSC_MSBF) - | (( 0 << 5) & AT91_SSC_DATDEF) - | (((bits - 1) << 0) & AT91_SSC_DATALEN); - DBG("SSC_TFMR=0x%08x\n", tfmr); - at91_ssc_write(ssc_p->ssc_base + AT91_SSC_TFMR, tfmr); - - rfmr = - (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE) - | (( AT91_SSC_FSOS_NONE ) & AT91_SSC_FSOS) - | (( 0 << 16) & AT91_SSC_FSLEN) - | (((channels - 1) << 8) & AT91_SSC_DATNB) - | (( 1 << 7) & AT91_SSC_MSBF) - | (( 0 << 5) & AT91_SSC_LOOP) - | (((bits - 1) << 0) & AT91_SSC_DATALEN); - - DBG("SSC_RFMR=0x%08x\n", rfmr); - at91_ssc_write(ssc_p->ssc_base + AT91_SSC_RFMR, rfmr); - - /* - * Setup the TCMR and RCMR to generate the proper BCLK - * and LRC signals. - */ - tcmr = - (( period << 24) & AT91_SSC_PERIOD) - | (( 1 << 16) & AT91_SSC_STTDLY) - | (( AT91_SSC_START_FALLING_RF ) & AT91_SSC_START) - | (( AT91_SSC_CKI_FALLING ) & AT91_SSC_CKI) - | (( AT91_SSC_CKO_CONTINUOUS ) & AT91_SSC_CKO) - | (( AT91_SSC_CKS_DIV ) & AT91_SSC_CKS); - - DBG("SSC_TCMR=0x%08x\n", tcmr); - at91_ssc_write(ssc_p->ssc_base + AT91_SSC_TCMR, tcmr); - - rcmr = - (( 0 << 24) & AT91_SSC_PERIOD) - | (( 1 << 16) & AT91_SSC_STTDLY) - | (( AT91_SSC_START_TX_RX ) & AT91_SSC_START) - | (( AT91_SSC_CK_RISING ) & AT91_SSC_CKI) - | (( AT91_SSC_CKO_NONE ) & AT91_SSC_CKO) - | (( AT91_SSC_CKS_CLOCK ) & AT91_SSC_CKS); - - DBG("SSC_RCMR=0x%08x\n", rcmr); - at91_ssc_write(ssc_p->ssc_base + AT91_SSC_RCMR, rcmr); - - if ((ret = request_irq(ssc_p->pid, at91rm9200_i2s_interrupt, - 0, ssc_p->name, ssc_p)) < 0) { - printk(KERN_WARNING "at91rm9200-i2s: request_irq failure\n"); - return ret; - } - - /* - * Save the current substream parameters in order to check - * that the substream in the opposite direction uses the - * same parameters. - */ - ssc_p->pcmfmt = pcmfmt; - ssc_p->rate = rate; - ssc_p->initialized = 1; - - DBG("hw_params: SSC initialized\n"); - } - - up(ssc_p->mutex); - - return 0; -} - - -static int at91rm9200_i2s_prepare(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - at91rm9200_pcm_dma_params_t *dma_params = rtd->cpu_dai->dma_data; - - at91_ssc_write(dma_params->ssc->cr, dma_params->mask->ssc_enable); - - DBG("%s enabled SSC_SR=0x%08lx\n", - substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? "transmit" : "receive", - at91_ssc_read(ssc_info[rtd->cpu_dai->id].ssc_base + AT91_SSC_SR)); - return 0; -} - - -struct snd_soc_cpu_dai at91rm9200_i2s_dai[] = { - { .name = "at91rm9200-ssc0/i2s", - .id = 0, - .type = SND_SOC_DAI_I2S, - .suspend = at91rm9200_i2s_suspend, - .resume = at91rm9200_i2s_resume, - .config_sysclk = at91rm9200_i2s_config_sysclk, - .playback = { - .channels_min = 1, - .channels_max = 2,}, - .capture = { - .channels_min = 1, - .channels_max = 2,}, - .ops = { - .startup = at91rm9200_i2s_startup, - .shutdown = at91rm9200_i2s_shutdown, - .prepare = at91rm9200_i2s_prepare, - .hw_params = at91rm9200_i2s_hw_params,}, - .caps = { - .mode = &at91rm9200_i2s[0], - .num_modes = ARRAY_SIZE(at91rm9200_i2s),}, - }, - { .name = "at91rm9200-ssc1/i2s", - .id = 1, - .type = SND_SOC_DAI_I2S, - .suspend = at91rm9200_i2s_suspend, - .resume = at91rm9200_i2s_resume, - .config_sysclk = at91rm9200_i2s_config_sysclk, - .playback = { - .channels_min = 1, - .channels_max = 2,}, - .capture = { - .channels_min = 1, - .channels_max = 2,}, - .ops = { - .startup = at91rm9200_i2s_startup, - .shutdown = at91rm9200_i2s_shutdown, - .prepare = at91rm9200_i2s_prepare, - .hw_params = at91rm9200_i2s_hw_params,}, - .caps = { - .mode = &at91rm9200_i2s[0], - .num_modes = ARRAY_SIZE(at91rm9200_i2s),}, - }, - { .name = "at91rm9200-ssc2/i2s", - .id = 2, - .type = SND_SOC_DAI_I2S, - .suspend = at91rm9200_i2s_suspend, - .resume = at91rm9200_i2s_resume, - .config_sysclk = at91rm9200_i2s_config_sysclk, - .playback = { - .channels_min = 1, - .channels_max = 2,}, - .capture = { - .channels_min = 1, - .channels_max = 2,}, - .ops = { - .startup = at91rm9200_i2s_startup, - .shutdown = at91rm9200_i2s_shutdown, - .prepare = at91rm9200_i2s_prepare, - .hw_params = at91rm9200_i2s_hw_params,}, - .caps = { - .mode = &at91rm9200_i2s[0], - .num_modes = ARRAY_SIZE(at91rm9200_i2s),}, - }, -}; - -EXPORT_SYMBOL_GPL(at91rm9200_i2s_dai); - -/* Module information */ -MODULE_AUTHOR("Frank Mandarino, fmandarino@endrelia.com, www.endrelia.com"); -MODULE_DESCRIPTION("AT91RM9200 I2S ASoC Interface"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/at91/at91rm9200-pcm.c b/sound/soc/at91/at91rm9200-pcm.c deleted file mode 100644 index 237bc5f0757..00000000000 --- a/sound/soc/at91/at91rm9200-pcm.c +++ /dev/null @@ -1,428 +0,0 @@ -/* - * at91rm9200-pcm.c -- ALSA PCM interface for the Atmel AT91RM9200 chip. - * - * Author: Frank Mandarino - * Endrelia Technologies Inc. - * Created: Mar 3, 2006 - * - * Based on pxa2xx-pcm.c by: - * - * Author: Nicolas Pitre - * Created: Nov 30, 2004 - * Copyright: (C) 2004 MontaVista Software, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "at91rm9200-pcm.h" - -#if 0 -#define DBG(x...) printk(KERN_INFO "at91rm9200-pcm: " x) -#else -#define DBG(x...) -#endif - -static const snd_pcm_hardware_t at91rm9200_pcm_hardware = { - .info = SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_PAUSE, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - .period_bytes_min = 32, - .period_bytes_max = 8192, - .periods_min = 2, - .periods_max = 1024, - .buffer_bytes_max = 32 * 1024, -}; - -struct at91rm9200_runtime_data { - at91rm9200_pcm_dma_params_t *params; - dma_addr_t dma_buffer; /* physical address of dma buffer */ - dma_addr_t dma_buffer_end; /* first address beyond DMA buffer */ - size_t period_size; - dma_addr_t period_ptr; /* physical address of next period */ - u32 pdc_xpr_save; /* PDC register save */ - u32 pdc_xcr_save; - u32 pdc_xnpr_save; - u32 pdc_xncr_save; -}; - -static void at91rm9200_pcm_dma_irq(u32 ssc_sr, - struct snd_pcm_substream *substream) -{ - struct at91rm9200_runtime_data *prtd = substream->runtime->private_data; - at91rm9200_pcm_dma_params_t *params = prtd->params; - static int count = 0; - - count++; - - if (ssc_sr & params->mask->ssc_endbuf) { - - printk(KERN_WARNING - "at91rm9200-pcm: buffer %s on %s (SSC_SR=%#x, count=%d)\n", - substream->stream == SNDRV_PCM_STREAM_PLAYBACK - ? "underrun" : "overrun", - params->name, ssc_sr, count); - - /* re-start the PDC */ - at91_ssc_write(params->pdc->ptcr, params->mask->pdc_disable); - - prtd->period_ptr += prtd->period_size; - if (prtd->period_ptr >= prtd->dma_buffer_end) { - prtd->period_ptr = prtd->dma_buffer; - } - - at91_ssc_write(params->pdc->xpr, prtd->period_ptr); - at91_ssc_write(params->pdc->xcr, - prtd->period_size / params->pdc_xfer_size); - - at91_ssc_write(params->pdc->ptcr, params->mask->pdc_enable); - } - - if (ssc_sr & params->mask->ssc_endx) { - - /* Load the PDC next pointer and counter registers */ - prtd->period_ptr += prtd->period_size; - if (prtd->period_ptr >= prtd->dma_buffer_end) { - prtd->period_ptr = prtd->dma_buffer; - } - at91_ssc_write(params->pdc->xnpr, prtd->period_ptr); - at91_ssc_write(params->pdc->xncr, - prtd->period_size / params->pdc_xfer_size); - } - - snd_pcm_period_elapsed(substream); -} - -static int at91rm9200_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - snd_pcm_runtime_t *runtime = substream->runtime; - struct at91rm9200_runtime_data *prtd = runtime->private_data; - struct snd_soc_pcm_runtime *rtd = substream->private_data; - - /* this may get called several times by oss emulation - * with different params */ - - snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); - runtime->dma_bytes = params_buffer_bytes(params); - - prtd->params = rtd->cpu_dai->dma_data; - prtd->params->dma_intr_handler = at91rm9200_pcm_dma_irq; - - prtd->dma_buffer = runtime->dma_addr; - prtd->dma_buffer_end = runtime->dma_addr + runtime->dma_bytes; - prtd->period_size = params_period_bytes(params); - - DBG("hw_params: DMA for %s initialized (dma_bytes=%d, period_size=%d)\n", - prtd->params->name, runtime->dma_bytes, prtd->period_size); - return 0; -} - -static int at91rm9200_pcm_hw_free(struct snd_pcm_substream *substream) -{ - struct at91rm9200_runtime_data *prtd = substream->runtime->private_data; - at91rm9200_pcm_dma_params_t *params = prtd->params; - - if (params != NULL) { - at91_ssc_write(params->pdc->ptcr, params->mask->pdc_disable); - prtd->params->dma_intr_handler = NULL; - } - - return 0; -} - -static int at91rm9200_pcm_prepare(struct snd_pcm_substream *substream) -{ - struct at91rm9200_runtime_data *prtd = substream->runtime->private_data; - at91rm9200_pcm_dma_params_t *params = prtd->params; - - at91_ssc_write(params->ssc->idr, - params->mask->ssc_endx | params->mask->ssc_endbuf); - - at91_ssc_write(params->pdc->ptcr, params->mask->pdc_disable); - return 0; -} - -static int at91rm9200_pcm_trigger(struct snd_pcm_substream *substream, - int cmd) -{ - struct at91rm9200_runtime_data *prtd = substream->runtime->private_data; - at91rm9200_pcm_dma_params_t *params = prtd->params; - int ret = 0; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - prtd->period_ptr = prtd->dma_buffer; - - at91_ssc_write(params->pdc->xpr, prtd->period_ptr); - at91_ssc_write(params->pdc->xcr, - prtd->period_size / params->pdc_xfer_size); - - prtd->period_ptr += prtd->period_size; - at91_ssc_write(params->pdc->xnpr, prtd->period_ptr); - at91_ssc_write(params->pdc->xncr, - prtd->period_size / params->pdc_xfer_size); - - DBG("trigger: period_ptr=%lx, xpr=%lx, xcr=%ld, xnpr=%lx, xncr=%ld\n", - (unsigned long) prtd->period_ptr, - at91_ssc_read(params->pdc->xpr), - at91_ssc_read(params->pdc->xcr), - at91_ssc_read(params->pdc->xnpr), - at91_ssc_read(params->pdc->xncr)); - - at91_ssc_write(params->ssc->ier, - params->mask->ssc_endx | params->mask->ssc_endbuf); - - at91_ssc_write(params->pdc->ptcr, params->mask->pdc_enable); - - DBG("sr=%lx imr=%lx\n", at91_ssc_read(params->ssc->ier - 4), - at91_ssc_read(params->ssc->ier + 8)); - break; - - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - at91_ssc_write(params->pdc->ptcr, params->mask->pdc_disable); - break; - - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - at91_ssc_write(params->pdc->ptcr, params->mask->pdc_enable); - break; - - default: - ret = -EINVAL; - } - - return ret; -} - -static snd_pcm_uframes_t at91rm9200_pcm_pointer( - struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct at91rm9200_runtime_data *prtd = runtime->private_data; - at91rm9200_pcm_dma_params_t *params = prtd->params; - dma_addr_t ptr; - snd_pcm_uframes_t x; - - ptr = (dma_addr_t) at91_ssc_read(params->pdc->xpr); - x = bytes_to_frames(runtime, ptr - prtd->dma_buffer); - - if (x == runtime->buffer_size) - x = 0; - return x; -} - -static int at91rm9200_pcm_open(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct at91rm9200_runtime_data *prtd; - int ret = 0; - - snd_soc_set_runtime_hwparams(substream, &at91rm9200_pcm_hardware); - - /* ensure that buffer size is a multiple of period size */ - ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); - if (ret < 0) - goto out; - - prtd = kzalloc(sizeof(struct at91rm9200_runtime_data), GFP_KERNEL); - if (prtd == NULL) { - ret = -ENOMEM; - goto out; - } - runtime->private_data = prtd; - - out: - return ret; -} - -static int at91rm9200_pcm_close(struct snd_pcm_substream *substream) -{ - struct at91rm9200_runtime_data *prtd = substream->runtime->private_data; - - kfree(prtd); - return 0; -} - -static int at91rm9200_pcm_mmap(struct snd_pcm_substream *substream, - struct vm_area_struct *vma) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - return dma_mmap_writecombine(substream->pcm->card->dev, vma, - runtime->dma_area, - runtime->dma_addr, - runtime->dma_bytes); -} - -struct snd_pcm_ops at91rm9200_pcm_ops = { - .open = at91rm9200_pcm_open, - .close = at91rm9200_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = at91rm9200_pcm_hw_params, - .hw_free = at91rm9200_pcm_hw_free, - .prepare = at91rm9200_pcm_prepare, - .trigger = at91rm9200_pcm_trigger, - .pointer = at91rm9200_pcm_pointer, - .mmap = at91rm9200_pcm_mmap, -}; - -static int at91rm9200_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, - int stream) -{ - struct snd_pcm_substream *substream = pcm->streams[stream].substream; - struct snd_dma_buffer *buf = &substream->dma_buffer; - size_t size = at91rm9200_pcm_hardware.buffer_bytes_max; - - buf->dev.type = SNDRV_DMA_TYPE_DEV; - buf->dev.dev = pcm->card->dev; - buf->private_data = NULL; - buf->area = dma_alloc_writecombine(pcm->card->dev, size, - &buf->addr, GFP_KERNEL); - - DBG("preallocate_dma_buffer: area=%p, addr=%p, size=%d\n", - (void *) buf->area, - (void *) buf->addr, - size); - - if (!buf->area) - return -ENOMEM; - - buf->bytes = size; - return 0; -} - -static u64 at91rm9200_pcm_dmamask = 0xffffffff; - -static int at91rm9200_pcm_new(struct snd_card *card, - struct snd_soc_codec_dai *dai, struct snd_pcm *pcm) -{ - int ret = 0; - - if (!card->dev->dma_mask) - card->dev->dma_mask = &at91rm9200_pcm_dmamask; - if (!card->dev->coherent_dma_mask) - card->dev->coherent_dma_mask = 0xffffffff; - - if (dai->playback.channels_min) { - ret = at91rm9200_pcm_preallocate_dma_buffer(pcm, - SNDRV_PCM_STREAM_PLAYBACK); - if (ret) - goto out; - } - - if (dai->capture.channels_min) { - ret = at91rm9200_pcm_preallocate_dma_buffer(pcm, - SNDRV_PCM_STREAM_CAPTURE); - if (ret) - goto out; - } - out: - return ret; -} - -static void at91rm9200_pcm_free_dma_buffers(struct snd_pcm *pcm) -{ - struct snd_pcm_substream *substream; - struct snd_dma_buffer *buf; - int stream; - - for (stream = 0; stream < 2; stream++) { - substream = pcm->streams[stream].substream; - if (!substream) - continue; - - buf = &substream->dma_buffer; - if (!buf->area) - continue; - - dma_free_writecombine(pcm->card->dev, buf->bytes, - buf->area, buf->addr); - buf->area = NULL; - } -} - -static int at91rm9200_pcm_suspend(struct platform_device *pdev, - struct snd_soc_cpu_dai *dai) -{ - struct snd_pcm_runtime *runtime = dai->runtime; - struct at91rm9200_runtime_data *prtd; - at91rm9200_pcm_dma_params_t *params; - - if (!runtime) - return 0; - - prtd = runtime->private_data; - params = prtd->params; - - /* disable the PDC and save the PDC registers */ - - at91_ssc_write(params->pdc->ptcr, params->mask->pdc_disable); - - prtd->pdc_xpr_save = at91_ssc_read(params->pdc->xpr); - prtd->pdc_xcr_save = at91_ssc_read(params->pdc->xcr); - prtd->pdc_xnpr_save = at91_ssc_read(params->pdc->xnpr); - prtd->pdc_xncr_save = at91_ssc_read(params->pdc->xncr); - - return 0; -} - -static int at91rm9200_pcm_resume(struct platform_device *pdev, - struct snd_soc_cpu_dai *dai) -{ - struct snd_pcm_runtime *runtime = dai->runtime; - struct at91rm9200_runtime_data *prtd; - at91rm9200_pcm_dma_params_t *params; - - if (!runtime) - return 0; - - prtd = runtime->private_data; - params = prtd->params; - - /* restore the PDC registers and enable the PDC */ - at91_ssc_write(params->pdc->xpr, prtd->pdc_xpr_save); - at91_ssc_write(params->pdc->xcr, prtd->pdc_xcr_save); - at91_ssc_write(params->pdc->xnpr, prtd->pdc_xnpr_save); - at91_ssc_write(params->pdc->xncr, prtd->pdc_xncr_save); - - at91_ssc_write(params->pdc->ptcr, params->mask->pdc_enable); - return 0; -} - -struct snd_soc_platform at91rm9200_soc_platform = { - .name = "at91rm9200-audio", - .pcm_ops = &at91rm9200_pcm_ops, - .pcm_new = at91rm9200_pcm_new, - .pcm_free = at91rm9200_pcm_free_dma_buffers, - .suspend = at91rm9200_pcm_suspend, - .resume = at91rm9200_pcm_resume, -}; - -EXPORT_SYMBOL_GPL(at91rm9200_soc_platform); - -MODULE_AUTHOR("Frank Mandarino "); -MODULE_DESCRIPTION("Atmel AT91RM9200 PCM module"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/at91/at91rm9200-pcm.h b/sound/soc/at91/at91rm9200-pcm.h deleted file mode 100644 index 65468f17377..00000000000 --- a/sound/soc/at91/at91rm9200-pcm.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * at91rm9200-pcm.h - ALSA PCM interface for the Atmel AT91RM9200 chip - * - * Author: Frank Mandarino - * Endrelia Technologies Inc. - * Created: Mar 3, 2006 - * - * Based on pxa2xx-pcm.h by: - * - * Author: Nicolas Pitre - * Created: Nov 30, 2004 - * Copyright: MontaVista Software, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -/* - * Registers and status bits that are required by the PCM driver. - */ -struct at91rm9200_ssc_regs { - void __iomem *cr; /* SSC control */ - void __iomem *ier; /* SSC interrupt enable */ - void __iomem *idr; /* SSC interrupt disable */ -}; - -struct at91rm9200_pdc_regs { - void __iomem *xpr; /* PDC recv/trans pointer */ - void __iomem *xcr; /* PDC recv/trans counter */ - void __iomem *xnpr; /* PDC next recv/trans pointer */ - void __iomem *xncr; /* PDC next recv/trans counter */ - void __iomem *ptcr; /* PDC transfer control */ -}; - -struct at91rm9200_ssc_mask { - u32 ssc_enable; /* SSC recv/trans enable */ - u32 ssc_disable; /* SSC recv/trans disable */ - u32 ssc_endx; /* SSC ENDTX or ENDRX */ - u32 ssc_endbuf; /* SSC TXBUFE or RXBUFF */ - u32 pdc_enable; /* PDC recv/trans enable */ - u32 pdc_disable; /* PDC recv/trans disable */ -}; - - -/* - * This structure, shared between the PCM driver and the interface, - * contains all information required by the PCM driver to perform the - * PDC DMA operation. All fields except dma_intr_handler() are initialized - * by the interface. The dms_intr_handler() pointer is set by the PCM - * driver and called by the interface SSC interrupt handler if it is - * non-NULL. - */ -typedef struct { - char *name; /* stream identifier */ - int pdc_xfer_size; /* PDC counter increment in bytes */ - struct at91rm9200_ssc_regs *ssc; /* SSC register addresses */ - struct at91rm9200_pdc_regs *pdc; /* PDC receive/transmit registers */ - struct at91rm9200_ssc_mask *mask;/* SSC & PDC status bits */ - snd_pcm_substream_t *substream; - void (*dma_intr_handler)(u32, snd_pcm_substream_t *); -} at91rm9200_pcm_dma_params_t; - -extern struct snd_soc_cpu_dai at91rm9200_i2s_dai[3]; -extern struct snd_soc_platform at91rm9200_soc_platform; - - -/* - * SSC I/O helpers. - * E.g., at91_ssc_write(AT91_SSC(1) + AT91_SSC_CR, AT91_SSC_RXEN); - */ -#define AT91_SSC(x) (((x)==0) ? AT91_VA_BASE_SSC0 :\ - ((x)==1) ? AT91_VA_BASE_SSC1 : ((x)==2) ? AT91_VA_BASE_SSC2 : NULL) -#define at91_ssc_read(a) ((unsigned long) __raw_readl(a)) -#define at91_ssc_write(a,v) __raw_writel((v),(a)) diff --git a/sound/soc/at91/eti_b1_wm8731.c b/sound/soc/at91/eti_b1_wm8731.c index d955cacf2d0..089cdc9e726 100644 --- a/sound/soc/at91/eti_b1_wm8731.c +++ b/sound/soc/at91/eti_b1_wm8731.c @@ -1,5 +1,5 @@ /* - * eti_b1_wm8731 -- SoC audio for Endrelia ETI_B1. + * eti_b1_wm8731 -- SoC audio for AT91RM9200-based Endrelia ETI_B1 board. * * Author: Frank Mandarino * Endrelia Technologies Inc. @@ -37,12 +37,12 @@ #include #include -#include -#include #include +#include +#include #include "../codecs/wm8731.h" -#include "at91rm9200-pcm.h" +#include "at91-pcm.h" #if 0 #define DBG(x...) printk(KERN_INFO "eti_b1_wm8731:" x) @@ -50,10 +50,18 @@ #define DBG(x...) #endif +#define AT91_PIO_TF1 (1 << (AT91_PIN_PB6 - PIN_BASE) % 32) +#define AT91_PIO_TK1 (1 << (AT91_PIN_PB7 - PIN_BASE) % 32) +#define AT91_PIO_TD1 (1 << (AT91_PIN_PB8 - PIN_BASE) % 32) +#define AT91_PIO_RD1 (1 << (AT91_PIN_PB9 - PIN_BASE) % 32) +#define AT91_PIO_RK1 (1 << (AT91_PIN_PB10 - PIN_BASE) % 32) +#define AT91_PIO_RF1 (1 << (AT91_PIN_PB11 - PIN_BASE) % 32) + + static struct clk *pck1_clk; static struct clk *pllb_clk; -static int eti_b1_startup(snd_pcm_substream_t *substream) +static int eti_b1_startup(struct snd_pcm_substream *substream) { /* Start PCK1 clock. */ clk_enable(pck1_clk); @@ -62,7 +70,7 @@ static int eti_b1_startup(snd_pcm_substream_t *substream) return 0; } -static void eti_b1_shutdown(snd_pcm_substream_t *substream) +static void eti_b1_shutdown(struct snd_pcm_substream *substream) { /* Stop PCK1 clock. */ clk_disable(pck1_clk); @@ -138,7 +146,7 @@ unsigned int eti_b1_config_sysclk(struct snd_soc_pcm_runtime *rtd, static struct snd_soc_dai_link eti_b1_dai = { .name = "WM8731", .stream_name = "WM8731", - .cpu_dai = &at91rm9200_i2s_dai[1], + .cpu_dai = &at91_i2s_dai[1], .codec_dai = &wm8731_dai, .init = eti_b1_wm8731_init, .config_sysclk = eti_b1_config_sysclk, @@ -157,7 +165,7 @@ static struct wm8731_setup_data eti_b1_wm8731_setup = { static struct snd_soc_device eti_b1_snd_devdata = { .machine = &snd_soc_machine_eti_b1, - .platform = &at91rm9200_soc_platform, + .platform = &at91_soc_platform, .codec_dev = &soc_codec_dev_wm8731, .codec_data = &eti_b1_wm8731_setup, }; @@ -168,22 +176,41 @@ static int __init eti_b1_init(void) { int ret; u32 ssc_pio_lines; + struct at91_ssc_periph *ssc = eti_b1_dai.cpu_dai->private_data; + + if (!request_mem_region(AT91RM9200_BASE_SSC1, SZ_16K, "soc-audio")) { + DBG("SSC1 memory region is busy\n"); + return -EBUSY; + } + + ssc->base = ioremap(AT91RM9200_BASE_SSC1, SZ_16K); + if (!ssc->base) { + DBG("SSC1 memory ioremap failed\n"); + ret = -ENOMEM; + goto fail_release_mem; + } + + ssc->pid = AT91RM9200_ID_SSC1; eti_b1_snd_device = platform_device_alloc("soc-audio", -1); - if (!eti_b1_snd_device) - return -ENOMEM; + if (!eti_b1_snd_device) { + DBG("platform device allocation failed\n"); + ret = -ENOMEM; + goto fail_io_unmap; + } platform_set_drvdata(eti_b1_snd_device, &eti_b1_snd_devdata); eti_b1_snd_devdata.dev = &eti_b1_snd_device->dev; ret = platform_device_add(eti_b1_snd_device); if (ret) { + DBG("platform device add failed\n"); platform_device_put(eti_b1_snd_device); - return ret; + goto fail_io_unmap; } - ssc_pio_lines = AT91_PB6_TF1 | AT91_PB7_TK1 | AT91_PB8_TD1 - | AT91_PB9_RD1 /* | AT91_PB10_RK1 | AT91_PB11_RF1 */; + ssc_pio_lines = AT91_PIO_TF1 | AT91_PIO_TK1 | AT91_PIO_TD1 + | AT91_PIO_RD1 /* | AT91_PIO_RK1 | AT91_PIO_RF1 */; /* Reset all PIO registers and assign lines to peripheral A */ at91_sys_write(AT91_PIOB + PIO_PDR, ssc_pio_lines); @@ -211,14 +238,25 @@ static int __init eti_b1_init(void) at91_set_B_periph(AT91_PIN_PA24, 0); return ret; + +fail_io_unmap: + iounmap(ssc->base); +fail_release_mem: + release_mem_region(AT91RM9200_BASE_SSC1, SZ_16K); + return ret; } static void __exit eti_b1_exit(void) { + struct at91_ssc_periph *ssc = eti_b1_dai.cpu_dai->private_data; + clk_put(pck1_clk); clk_put(pllb_clk); platform_device_unregister(eti_b1_snd_device); + + iounmap(ssc->base); + release_mem_region(AT91RM9200_BASE_SSC1, SZ_16K); } module_init(eti_b1_init); -- cgit v1.2.3 From 0b830bac35dd6e3996bee675c3893857da8a4d0a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 24 Nov 2006 16:13:57 +0100 Subject: [ALSA] Clean up serial-u16500.c Remove uesless typedefs and clean up the code a bit to follow the standard coding style. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/drivers/serial-u16550.c | 221 +++++++++++++++++++++++------------------- 1 file changed, 123 insertions(+), 98 deletions(-) (limited to 'sound') diff --git a/sound/drivers/serial-u16550.c b/sound/drivers/serial-u16550.c index 74028b2219c..3a86a582072 100644 --- a/sound/drivers/serial-u16550.c +++ b/sound/drivers/serial-u16550.c @@ -117,13 +117,13 @@ MODULE_PARM_DESC(adaptor, "Type of adaptor."); #define SERIAL_MODE_INPUT_TRIGGERED (1 << 2) #define SERIAL_MODE_OUTPUT_TRIGGERED (1 << 3) -typedef struct _snd_uart16550 { +struct snd_uart16550 { struct snd_card *card; struct snd_rawmidi *rmidi; struct snd_rawmidi_substream *midi_output[SNDRV_SERIAL_MAX_OUTS]; struct snd_rawmidi_substream *midi_input[SNDRV_SERIAL_MAX_INS]; - int filemode; //open status of file + int filemode; /* open status of file */ spinlock_t open_lock; @@ -140,39 +140,39 @@ typedef struct _snd_uart16550 { unsigned char old_divisor_msb; unsigned char old_line_ctrl_reg; - // parameter for using of write loop - short int fifo_limit; //used in uart16550 - short int fifo_count; //used in uart16550 + /* parameter for using of write loop */ + short int fifo_limit; /* used in uart16550 */ + short int fifo_count; /* used in uart16550 */ - // type of adaptor + /* type of adaptor */ int adaptor; - // inputs + /* inputs */ int prev_in; unsigned char rstatus; - // outputs + /* outputs */ int prev_out; unsigned char prev_status[SNDRV_SERIAL_MAX_OUTS]; - // write buffer and its writing/reading position + /* write buffer and its writing/reading position */ unsigned char tx_buff[TX_BUFF_SIZE]; int buff_in_count; int buff_in; int buff_out; int drop_on_full; - // wait timer + /* wait timer */ unsigned int timer_running:1; struct timer_list buffer_timer; -} snd_uart16550_t; +}; static struct platform_device *devices[SNDRV_CARDS]; -static inline void snd_uart16550_add_timer(snd_uart16550_t *uart) +static inline void snd_uart16550_add_timer(struct snd_uart16550 *uart) { - if (! uart->timer_running) { + if (!uart->timer_running) { /* timer 38600bps * 10bit * 16byte */ uart->buffer_timer.expires = jiffies + (HZ+255)/256; uart->timer_running = 1; @@ -180,7 +180,7 @@ static inline void snd_uart16550_add_timer(snd_uart16550_t *uart) } } -static inline void snd_uart16550_del_timer(snd_uart16550_t *uart) +static inline void snd_uart16550_del_timer(struct snd_uart16550 *uart) { if (uart->timer_running) { del_timer(&uart->buffer_timer); @@ -189,10 +189,10 @@ static inline void snd_uart16550_del_timer(snd_uart16550_t *uart) } /* This macro is only used in snd_uart16550_io_loop */ -static inline void snd_uart16550_buffer_output(snd_uart16550_t *uart) +static inline void snd_uart16550_buffer_output(struct snd_uart16550 *uart) { unsigned short buff_out = uart->buff_out; - if( uart->buff_in_count > 0 ) { + if (uart->buff_in_count > 0) { outb(uart->tx_buff[buff_out], uart->base + UART_TX); uart->fifo_count++; buff_out++; @@ -206,7 +206,7 @@ static inline void snd_uart16550_buffer_output(snd_uart16550_t *uart) * We don't want to interrupt this, * as we're already handling an interrupt */ -static void snd_uart16550_io_loop(snd_uart16550_t * uart) +static void snd_uart16550_io_loop(struct snd_uart16550 * uart) { unsigned char c, status; int substream; @@ -220,9 +220,8 @@ static void snd_uart16550_io_loop(snd_uart16550_t * uart) c = inb(uart->base + UART_RX); /* keep track of last status byte */ - if (c & 0x80) { + if (c & 0x80) uart->rstatus = c; - } /* handle stream switch */ if (uart->adaptor == SNDRV_SERIAL_GENERIC) { @@ -230,14 +229,16 @@ static void snd_uart16550_io_loop(snd_uart16550_t * uart) if (c <= SNDRV_SERIAL_MAX_INS && c > 0) substream = c - 1; if (c != 0xf5) - uart->rstatus = 0; /* prevent future bytes from being interpreted as streams */ - } - else if ((uart->filemode & SERIAL_MODE_INPUT_OPEN) && (uart->midi_input[substream] != NULL)) { - snd_rawmidi_receive(uart->midi_input[substream], &c, 1); - } - } else if ((uart->filemode & SERIAL_MODE_INPUT_OPEN) && (uart->midi_input[substream] != NULL)) { + /* prevent future bytes from being + interpreted as streams */ + uart->rstatus = 0; + } else if ((uart->filemode & SERIAL_MODE_INPUT_OPEN) + && uart->midi_input[substream]) + snd_rawmidi_receive(uart->midi_input[substream], + &c, 1); + } else if ((uart->filemode & SERIAL_MODE_INPUT_OPEN) && + uart->midi_input[substream]) snd_rawmidi_receive(uart->midi_input[substream], &c, 1); - } if (status & UART_LSR_OE) snd_printk("%s: Overrun on device at 0x%lx\n", @@ -250,21 +251,20 @@ static void snd_uart16550_io_loop(snd_uart16550_t * uart) /* no need of check SERIAL_MODE_OUTPUT_OPEN because if not, buffer is never filled. */ /* Check write status */ - if (status & UART_LSR_THRE) { + if (status & UART_LSR_THRE) uart->fifo_count = 0; - } if (uart->adaptor == SNDRV_SERIAL_MS124W_SA || uart->adaptor == SNDRV_SERIAL_GENERIC) { /* Can't use FIFO, must send only when CTS is true */ status = inb(uart->base + UART_MSR); - while( (uart->fifo_count == 0) && (status & UART_MSR_CTS) && - (uart->buff_in_count > 0) ) { + while (uart->fifo_count == 0 && (status & UART_MSR_CTS) && + uart->buff_in_count > 0) { snd_uart16550_buffer_output(uart); - status = inb( uart->base + UART_MSR ); + status = inb(uart->base + UART_MSR); } } else { /* Write loop */ - while (uart->fifo_count < uart->fifo_limit /* Can we write ? */ + while (uart->fifo_count < uart->fifo_limit /* Can we write ? */ && uart->buff_in_count > 0) /* Do we want to? */ snd_uart16550_buffer_output(uart); } @@ -294,15 +294,16 @@ static void snd_uart16550_io_loop(snd_uart16550_t * uart) */ static irqreturn_t snd_uart16550_interrupt(int irq, void *dev_id) { - snd_uart16550_t *uart; + struct snd_uart16550 *uart; - uart = (snd_uart16550_t *) dev_id; + uart = dev_id; spin_lock(&uart->open_lock); if (uart->filemode == SERIAL_MODE_NOT_OPENED) { spin_unlock(&uart->open_lock); return IRQ_NONE; } - inb(uart->base + UART_IIR); /* indicate to the UART that the interrupt has been serviced */ + /* indicate to the UART that the interrupt has been serviced */ + inb(uart->base + UART_IIR); snd_uart16550_io_loop(uart); spin_unlock(&uart->open_lock); return IRQ_HANDLED; @@ -312,9 +313,9 @@ static irqreturn_t snd_uart16550_interrupt(int irq, void *dev_id) static void snd_uart16550_buffer_timer(unsigned long data) { unsigned long flags; - snd_uart16550_t *uart; + struct snd_uart16550 *uart; - uart = (snd_uart16550_t *)data; + uart = (struct snd_uart16550 *)data; spin_lock_irqsave(&uart->open_lock, flags); snd_uart16550_del_timer(uart); snd_uart16550_io_loop(uart); @@ -326,7 +327,7 @@ static void snd_uart16550_buffer_timer(unsigned long data) * return 0 if found * return negative error if not found */ -static int __init snd_uart16550_detect(snd_uart16550_t *uart) +static int __init snd_uart16550_detect(struct snd_uart16550 *uart) { unsigned long io_base = uart->base; int ok; @@ -343,7 +344,8 @@ static int __init snd_uart16550_detect(snd_uart16550_t *uart) return -EBUSY; } - ok = 1; /* uart detected unless one of the following tests should fail */ + /* uart detected unless one of the following tests should fail */ + ok = 1; /* 8 data-bits, 1 stop-bit, parity off, DLAB = 0 */ outb(UART_LCR_WLEN8, io_base + UART_LCR); /* Line Control Register */ c = inb(io_base + UART_IER); @@ -368,7 +370,7 @@ static int __init snd_uart16550_detect(snd_uart16550_t *uart) return ok; } -static void snd_uart16550_do_open(snd_uart16550_t * uart) +static void snd_uart16550_do_open(struct snd_uart16550 * uart) { char byte; @@ -460,7 +462,7 @@ static void snd_uart16550_do_open(snd_uart16550_t * uart) inb(uart->base + UART_RX); /* Clear any pre-existing receive interrupt */ } -static void snd_uart16550_do_close(snd_uart16550_t * uart) +static void snd_uart16550_do_close(struct snd_uart16550 * uart) { if (uart->irq < 0) snd_uart16550_del_timer(uart); @@ -514,7 +516,7 @@ static void snd_uart16550_do_close(snd_uart16550_t * uart) static int snd_uart16550_input_open(struct snd_rawmidi_substream *substream) { unsigned long flags; - snd_uart16550_t *uart = substream->rmidi->private_data; + struct snd_uart16550 *uart = substream->rmidi->private_data; spin_lock_irqsave(&uart->open_lock, flags); if (uart->filemode == SERIAL_MODE_NOT_OPENED) @@ -528,7 +530,7 @@ static int snd_uart16550_input_open(struct snd_rawmidi_substream *substream) static int snd_uart16550_input_close(struct snd_rawmidi_substream *substream) { unsigned long flags; - snd_uart16550_t *uart = substream->rmidi->private_data; + struct snd_uart16550 *uart = substream->rmidi->private_data; spin_lock_irqsave(&uart->open_lock, flags); uart->filemode &= ~SERIAL_MODE_INPUT_OPEN; @@ -539,24 +541,24 @@ static int snd_uart16550_input_close(struct snd_rawmidi_substream *substream) return 0; } -static void snd_uart16550_input_trigger(struct snd_rawmidi_substream *substream, int up) +static void snd_uart16550_input_trigger(struct snd_rawmidi_substream *substream, + int up) { unsigned long flags; - snd_uart16550_t *uart = substream->rmidi->private_data; + struct snd_uart16550 *uart = substream->rmidi->private_data; spin_lock_irqsave(&uart->open_lock, flags); - if (up) { + if (up) uart->filemode |= SERIAL_MODE_INPUT_TRIGGERED; - } else { + else uart->filemode &= ~SERIAL_MODE_INPUT_TRIGGERED; - } spin_unlock_irqrestore(&uart->open_lock, flags); } static int snd_uart16550_output_open(struct snd_rawmidi_substream *substream) { unsigned long flags; - snd_uart16550_t *uart = substream->rmidi->private_data; + struct snd_uart16550 *uart = substream->rmidi->private_data; spin_lock_irqsave(&uart->open_lock, flags); if (uart->filemode == SERIAL_MODE_NOT_OPENED) @@ -570,7 +572,7 @@ static int snd_uart16550_output_open(struct snd_rawmidi_substream *substream) static int snd_uart16550_output_close(struct snd_rawmidi_substream *substream) { unsigned long flags; - snd_uart16550_t *uart = substream->rmidi->private_data; + struct snd_uart16550 *uart = substream->rmidi->private_data; spin_lock_irqsave(&uart->open_lock, flags); uart->filemode &= ~SERIAL_MODE_OUTPUT_OPEN; @@ -581,18 +583,20 @@ static int snd_uart16550_output_close(struct snd_rawmidi_substream *substream) return 0; }; -static inline int snd_uart16550_buffer_can_write( snd_uart16550_t *uart, int Num ) +static inline int snd_uart16550_buffer_can_write(struct snd_uart16550 *uart, + int Num) { - if( uart->buff_in_count + Num < TX_BUFF_SIZE ) + if (uart->buff_in_count + Num < TX_BUFF_SIZE) return 1; else return 0; } -static inline int snd_uart16550_write_buffer(snd_uart16550_t *uart, unsigned char byte) +static inline int snd_uart16550_write_buffer(struct snd_uart16550 *uart, + unsigned char byte) { unsigned short buff_in = uart->buff_in; - if( uart->buff_in_count < TX_BUFF_SIZE ) { + if (uart->buff_in_count < TX_BUFF_SIZE) { uart->tx_buff[buff_in] = byte; buff_in++; buff_in &= TX_BUFF_MASK; @@ -605,12 +609,14 @@ static inline int snd_uart16550_write_buffer(snd_uart16550_t *uart, unsigned cha return 0; } -static int snd_uart16550_output_byte(snd_uart16550_t *uart, struct snd_rawmidi_substream *substream, unsigned char midi_byte) +static int snd_uart16550_output_byte(struct snd_uart16550 *uart, + struct snd_rawmidi_substream *substream, + unsigned char midi_byte) { - if (uart->buff_in_count == 0 /* Buffer empty? */ + if (uart->buff_in_count == 0 /* Buffer empty? */ && ((uart->adaptor != SNDRV_SERIAL_MS124W_SA && uart->adaptor != SNDRV_SERIAL_GENERIC) || - (uart->fifo_count == 0 /* FIFO empty? */ + (uart->fifo_count == 0 /* FIFO empty? */ && (inb(uart->base + UART_MSR) & UART_MSR_CTS)))) { /* CTS? */ /* Tx Buffer Empty - try to write immediately */ @@ -623,12 +629,13 @@ static int snd_uart16550_output_byte(snd_uart16550_t *uart, struct snd_rawmidi_s uart->fifo_count++; outb(midi_byte, uart->base + UART_TX); } else { - /* Cannot write (buffer empty) - put char in buffer */ + /* Cannot write (buffer empty) - + * put char in buffer */ snd_uart16550_write_buffer(uart, midi_byte); } } } else { - if( !snd_uart16550_write_buffer(uart, midi_byte) ) { + if (!snd_uart16550_write_buffer(uart, midi_byte)) { snd_printk("%s: Buffer overrun on device at 0x%lx\n", uart->rmidi->name, uart->base); return 0; @@ -642,9 +649,9 @@ static void snd_uart16550_output_write(struct snd_rawmidi_substream *substream) { unsigned long flags; unsigned char midi_byte, addr_byte; - snd_uart16550_t *uart = substream->rmidi->private_data; + struct snd_uart16550 *uart = substream->rmidi->private_data; char first; - static unsigned long lasttime=0; + static unsigned long lasttime = 0; /* Interupts are disabled during the updating of the tx_buff, * since it is 'bad' to have two processes updating the same @@ -653,7 +660,7 @@ static void snd_uart16550_output_write(struct snd_rawmidi_substream *substream) spin_lock_irqsave(&uart->open_lock, flags); - if (uart->irq < 0) //polling + if (uart->irq < 0) /* polling */ snd_uart16550_io_loop(uart); if (uart->adaptor == SNDRV_SERIAL_MS124W_MB) { @@ -671,7 +678,8 @@ static void snd_uart16550_output_write(struct snd_rawmidi_substream *substream) /* select any combination of the four ports */ addr_byte = (substream->number << 4) | 0x08; /* ...except none */ - if (addr_byte == 0x08) addr_byte = 0xf8; + if (addr_byte == 0x08) + addr_byte = 0xf8; #endif snd_uart16550_output_byte(uart, substream, addr_byte); /* send midi byte */ @@ -679,31 +687,42 @@ static void snd_uart16550_output_write(struct snd_rawmidi_substream *substream) } } else { first = 0; - while( 1 == snd_rawmidi_transmit_peek(substream, &midi_byte, 1) ) { - /* Also send F5 after 3 seconds with no data to handle device disconnect */ - if (first == 0 && (uart->adaptor == SNDRV_SERIAL_SOUNDCANVAS || - uart->adaptor == SNDRV_SERIAL_GENERIC) && - (uart->prev_out != substream->number || jiffies-lasttime > 3*HZ)) { - - if( snd_uart16550_buffer_can_write( uart, 3 ) ) { + while (snd_rawmidi_transmit_peek(substream, &midi_byte, 1) == 1) { + /* Also send F5 after 3 seconds with no data + * to handle device disconnect */ + if (first == 0 && + (uart->adaptor == SNDRV_SERIAL_SOUNDCANVAS || + uart->adaptor == SNDRV_SERIAL_GENERIC) && + (uart->prev_out != substream->number || + jiffies-lasttime > 3*HZ)) { + + if (snd_uart16550_buffer_can_write(uart, 3)) { /* Roland Soundcanvas part selection */ - /* If this substream of the data is different previous - substream in this uart, send the change part event */ + /* If this substream of the data is + * different previous substream + * in this uart, send the change part + * event + */ uart->prev_out = substream->number; /* change part */ - snd_uart16550_output_byte(uart, substream, 0xf5); + snd_uart16550_output_byte(uart, substream, + 0xf5); /* data */ - snd_uart16550_output_byte(uart, substream, uart->prev_out + 1); - /* If midi_byte is a data byte, send the previous status byte */ - if ((midi_byte < 0x80) && (uart->adaptor == SNDRV_SERIAL_SOUNDCANVAS)) + snd_uart16550_output_byte(uart, substream, + uart->prev_out + 1); + /* If midi_byte is a data byte, + * send the previous status byte */ + if (midi_byte < 0x80 && + uart->adaptor == SNDRV_SERIAL_SOUNDCANVAS) snd_uart16550_output_byte(uart, substream, uart->prev_status[uart->prev_out]); - } else if( !uart->drop_on_full ) + } else if (!uart->drop_on_full) break; } /* send midi byte */ - if( !snd_uart16550_output_byte(uart, substream, midi_byte) && !uart->drop_on_full ) + if (!snd_uart16550_output_byte(uart, substream, midi_byte) && + !uart->drop_on_full ) break; if (midi_byte >= 0x80 && midi_byte < 0xf0) @@ -717,17 +736,17 @@ static void snd_uart16550_output_write(struct snd_rawmidi_substream *substream) spin_unlock_irqrestore(&uart->open_lock, flags); } -static void snd_uart16550_output_trigger(struct snd_rawmidi_substream *substream, int up) +static void snd_uart16550_output_trigger(struct snd_rawmidi_substream *substream, + int up) { unsigned long flags; - snd_uart16550_t *uart = substream->rmidi->private_data; + struct snd_uart16550 *uart = substream->rmidi->private_data; spin_lock_irqsave(&uart->open_lock, flags); - if (up) { + if (up) uart->filemode |= SERIAL_MODE_OUTPUT_TRIGGERED; - } else { + else uart->filemode &= ~SERIAL_MODE_OUTPUT_TRIGGERED; - } spin_unlock_irqrestore(&uart->open_lock, flags); if (up) snd_uart16550_output_write(substream); @@ -747,10 +766,10 @@ static struct snd_rawmidi_ops snd_uart16550_input = .trigger = snd_uart16550_input_trigger, }; -static int snd_uart16550_free(snd_uart16550_t *uart) +static int snd_uart16550_free(struct snd_uart16550 *uart) { if (uart->irq >= 0) - free_irq(uart->irq, (void *)uart); + free_irq(uart->irq, uart); release_and_free_resource(uart->res_base); kfree(uart); return 0; @@ -758,7 +777,7 @@ static int snd_uart16550_free(snd_uart16550_t *uart) static int snd_uart16550_dev_free(struct snd_device *device) { - snd_uart16550_t *uart = device->device_data; + struct snd_uart16550 *uart = device->device_data; return snd_uart16550_free(uart); } @@ -769,12 +788,12 @@ static int __init snd_uart16550_create(struct snd_card *card, unsigned int base, int adaptor, int droponfull, - snd_uart16550_t **ruart) + struct snd_uart16550 **ruart) { static struct snd_device_ops ops = { .dev_free = snd_uart16550_dev_free, }; - snd_uart16550_t *uart; + struct snd_uart16550 *uart; int err; @@ -795,7 +814,7 @@ static int __init snd_uart16550_create(struct snd_card *card, if (irq >= 0 && irq != SNDRV_AUTO_IRQ) { if (request_irq(irq, snd_uart16550_interrupt, - IRQF_DISABLED, "Serial MIDI", (void *) uart)) { + IRQF_DISABLED, "Serial MIDI", uart)) { snd_printk("irq %d busy. Using Polling.\n", irq); } else { uart->irq = irq; @@ -843,23 +862,28 @@ static int __init snd_uart16550_create(struct snd_card *card, static void __init snd_uart16550_substreams(struct snd_rawmidi_str *stream) { - struct list_head *list; + struct snd_rawmidi_substream *substream; - list_for_each(list, &stream->substreams) { - struct snd_rawmidi_substream *substream = list_entry(list, struct snd_rawmidi_substream, list); + list_for_each_entry(substream, &stream->substreams, list) { sprintf(substream->name, "Serial MIDI %d", substream->number + 1); } } -static int __init snd_uart16550_rmidi(snd_uart16550_t *uart, int device, int outs, int ins, struct snd_rawmidi **rmidi) +static int __init snd_uart16550_rmidi(struct snd_uart16550 *uart, int device, + int outs, int ins, + struct snd_rawmidi **rmidi) { struct snd_rawmidi *rrawmidi; int err; - if ((err = snd_rawmidi_new(uart->card, "UART Serial MIDI", device, outs, ins, &rrawmidi)) < 0) + err = snd_rawmidi_new(uart->card, "UART Serial MIDI", device, + outs, ins, &rrawmidi); + if (err < 0) return err; - snd_rawmidi_set_ops(rrawmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_uart16550_input); - snd_rawmidi_set_ops(rrawmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_uart16550_output); + snd_rawmidi_set_ops(rrawmidi, SNDRV_RAWMIDI_STREAM_INPUT, + &snd_uart16550_input); + snd_rawmidi_set_ops(rrawmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, + &snd_uart16550_output); strcpy(rrawmidi->name, "Serial MIDI"); snd_uart16550_substreams(&rrawmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]); snd_uart16550_substreams(&rrawmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT]); @@ -875,7 +899,7 @@ static int __init snd_uart16550_rmidi(snd_uart16550_t *uart, int device, int out static int __init snd_serial_probe(struct platform_device *devptr) { struct snd_card *card; - snd_uart16550_t *uart; + struct snd_uart16550 *uart; int err; int dev = devptr->id; @@ -929,7 +953,8 @@ static int __init snd_serial_probe(struct platform_device *devptr) &uart)) < 0) goto _err; - if ((err = snd_uart16550_rmidi(uart, 0, outs[dev], ins[dev], &uart->rmidi)) < 0) + err = snd_uart16550_rmidi(uart, 0, outs[dev], ins[dev], &uart->rmidi); + if (err < 0) goto _err; sprintf(card->longname, "%s at 0x%lx, irq %d speed %d div %d outs %d ins %d adaptor %s droponfull %d", -- cgit v1.2.3 From f5fcc13c2fc62da6f75d80189a51c2492afb39c0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 24 Nov 2006 17:07:44 +0100 Subject: [ALSA] hda-codec - Use snd_pci_quirk_lookup() for board config lookup Use snd_pci_quirk_lookup() for looking up a board config table. The config table is sorted in numerical order of PCI SSIDs. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/hda_codec.c | 57 +++-- sound/pci/hda/hda_local.h | 11 +- sound/pci/hda/patch_analog.c | 145 ++++++----- sound/pci/hda/patch_cmedia.c | 24 +- sound/pci/hda/patch_conexant.c | 65 +++-- sound/pci/hda/patch_realtek.c | 550 ++++++++++++++++++----------------------- sound/pci/hda/patch_sigmatel.c | 406 ++++++++++++++---------------- 7 files changed, 575 insertions(+), 683 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 18bbc87e376..c07d5db6b05 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1714,6 +1714,8 @@ EXPORT_SYMBOL(snd_hda_build_pcms); /** * snd_hda_check_board_config - compare the current codec with the config table * @codec: the HDA codec + * @num_configs: number of config enums + * @models: array of model name strings * @tbl: configuration table, terminated by null entries * * Compares the modelname or PCI subsystem id of the current codec with the @@ -1722,33 +1724,44 @@ EXPORT_SYMBOL(snd_hda_build_pcms); * * If no entries are matching, the function returns a negative value. */ -int snd_hda_check_board_config(struct hda_codec *codec, const struct hda_board_config *tbl) -{ - const struct hda_board_config *c; - - if (codec->bus->modelname) { - for (c = tbl; c->modelname || c->pci_subvendor; c++) { - if (c->modelname && - ! strcmp(codec->bus->modelname, c->modelname)) { - snd_printd(KERN_INFO "hda_codec: model '%s' is selected\n", c->modelname); - return c->config; +int snd_hda_check_board_config(struct hda_codec *codec, + int num_configs, const char **models, + const struct snd_pci_quirk *tbl) +{ + if (codec->bus->modelname && models) { + int i; + for (i = 0; i < num_configs; i++) { + if (models[i] && + !strcmp(codec->bus->modelname, models[i])) { + snd_printd(KERN_INFO "hda_codec: model '%s' is " + "selected\n", models[i]); + return i; } } } - if (codec->bus->pci) { - u16 subsystem_vendor, subsystem_device; - pci_read_config_word(codec->bus->pci, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vendor); - pci_read_config_word(codec->bus->pci, PCI_SUBSYSTEM_ID, &subsystem_device); - for (c = tbl; c->modelname || c->pci_subvendor; c++) { - if (c->pci_subvendor == subsystem_vendor && - (! c->pci_subdevice /* all match */|| - (c->pci_subdevice == subsystem_device))) { - snd_printdd(KERN_INFO "hda_codec: PCI %x:%x, codec config %d is selected\n", - subsystem_vendor, subsystem_device, c->config); - return c->config; - } + if (!codec->bus->pci || !tbl) + return -1; + + tbl = snd_pci_quirk_lookup(codec->bus->pci, tbl); + if (!tbl) + return -1; + if (tbl->value >= 0 && tbl->value < num_configs) { +#ifdef CONFIG_SND_DEBUG_DETECT + char tmp[10]; + const char *model = NULL; + if (models) + model = models[tbl->value]; + if (!model) { + sprintf(tmp, "#%d", tbl->value); + model = tmp; } + snd_printdd(KERN_INFO "hda_codec: model '%s' is selected " + "for config %x:%x (%s)\n", + model, tbl->subvendor, tbl->subdevice, + (tbl->name ? tbl->name : "Unknown device")); +#endif + return tbl->value; } return -1; } diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 9ca1baf860b..b2f56d68885 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -173,14 +173,9 @@ static inline int snd_hda_codec_proc_new(struct hda_codec *codec) { return 0; } /* * Misc */ -struct hda_board_config { - const char *modelname; - int config; - unsigned short pci_subvendor; - unsigned short pci_subdevice; -}; - -int snd_hda_check_board_config(struct hda_codec *codec, const struct hda_board_config *tbl); +int snd_hda_check_board_config(struct hda_codec *codec, int num_configs, + const char **modelnames, + const struct snd_pci_quirk *pci_list); int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew); /* diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 9ce4c9f869b..2e18a716a09 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -787,55 +787,43 @@ static struct hda_verb ad1986a_eapd_init_verbs[] = { }; /* models */ -enum { AD1986A_6STACK, AD1986A_3STACK, AD1986A_LAPTOP, AD1986A_LAPTOP_EAPD }; - -static struct hda_board_config ad1986a_cfg_tbl[] = { - { .modelname = "6stack", .config = AD1986A_6STACK }, - { .modelname = "3stack", .config = AD1986A_3STACK }, - { .pci_subvendor = 0x10de, .pci_subdevice = 0xcb84, - .config = AD1986A_3STACK }, /* ASUS A8N-VM CSM */ - { .pci_subvendor = 0x1043, .pci_subdevice = 0x817f, - .config = AD1986A_3STACK }, /* ASUS P5P-L2 */ - { .pci_subvendor = 0x1043, .pci_subdevice = 0x81b3, - .config = AD1986A_3STACK }, /* ASUS P5RD2-VM / P5GPL-X SE */ - { .pci_subvendor = 0x1043, .pci_subdevice = 0x81cb, - .config = AD1986A_3STACK }, /* ASUS M2NPV-VM */ - { .pci_subvendor = 0x1043, .pci_subdevice = 0x8234, - .config = AD1986A_3STACK }, /* ASUS M2N-MX */ - { .pci_subvendor = 0x17aa, .pci_subdevice = 0x1017, - .config = AD1986A_3STACK }, /* Lenovo A60 desktop */ - { .modelname = "laptop", .config = AD1986A_LAPTOP }, - { .pci_subvendor = 0x144d, .pci_subdevice = 0xc01e, - .config = AD1986A_LAPTOP }, /* FSC V2060 */ - { .pci_subvendor = 0x17c0, .pci_subdevice = 0x2017, - .config = AD1986A_LAPTOP }, /* Samsung M50 */ - { .pci_subvendor = 0x1043, .pci_subdevice = 0x818f, - .config = AD1986A_LAPTOP }, /* ASUS P5GV-MX */ - { .modelname = "laptop-eapd", .config = AD1986A_LAPTOP_EAPD }, - { .pci_subvendor = 0x144d, .pci_subdevice = 0xc023, - .config = AD1986A_LAPTOP_EAPD }, /* Samsung X60 Chane */ - { .pci_subvendor = 0x144d, .pci_subdevice = 0xc024, - .config = AD1986A_LAPTOP_EAPD }, /* Samsung R65-T2300 Charis */ - { .pci_subvendor = 0x144d, .pci_subdevice = 0xc026, - .config = AD1986A_LAPTOP_EAPD }, /* Samsung X11-T2300 Culesa */ - { .pci_subvendor = 0x1043, .pci_subdevice = 0x1153, - .config = AD1986A_LAPTOP_EAPD }, /* ASUS M9 */ - { .pci_subvendor = 0x1043, .pci_subdevice = 0x1213, - .config = AD1986A_LAPTOP_EAPD }, /* ASUS A6J */ - { .pci_subvendor = 0x1043, .pci_subdevice = 0x11f7, - .config = AD1986A_LAPTOP_EAPD }, /* ASUS U5A */ - { .pci_subvendor = 0x1043, .pci_subdevice = 0x1263, - .config = AD1986A_LAPTOP_EAPD }, /* ASUS U5F */ - { .pci_subvendor = 0x1043, .pci_subdevice = 0x1297, - .config = AD1986A_LAPTOP_EAPD }, /* ASUS Z62F */ - { .pci_subvendor = 0x1043, .pci_subdevice = 0x12b3, - .config = AD1986A_LAPTOP_EAPD }, /* ASUS V1j */ - { .pci_subvendor = 0x1043, .pci_subdevice = 0x1302, - .config = AD1986A_LAPTOP_EAPD }, /* ASUS W3j */ - { .pci_subvendor = 0x103c, .pci_subdevice = 0x30af, - .config = AD1986A_LAPTOP_EAPD }, /* HP Compaq Presario B2800 */ - { .pci_subvendor = 0x17aa, .pci_subdevice = 0x2066, - .config = AD1986A_LAPTOP_EAPD }, /* Lenovo 3000 N100-07684JU */ +enum { + AD1986A_6STACK, + AD1986A_3STACK, + AD1986A_LAPTOP, + AD1986A_LAPTOP_EAPD, + AD1986A_MODELS +}; + +static const char *ad1986a_models[AD1986A_MODELS] = { + [AD1986A_6STACK] = "6stack", + [AD1986A_3STACK] = "3stack", + [AD1986A_LAPTOP] = "laptop", + [AD1986A_LAPTOP_EAPD] = "laptop-eapd", +}; + +static struct snd_pci_quirk ad1986a_cfg_tbl[] = { + SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_LAPTOP_EAPD), + SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_3STACK), + SND_PCI_QUIRK(0x1043, 0x1153, "ASUS M9", AD1986A_LAPTOP_EAPD), + SND_PCI_QUIRK(0x1043, 0x1213, "ASUS A6J", AD1986A_LAPTOP_EAPD), + SND_PCI_QUIRK(0x1043, 0x11f7, "ASUS U5A", AD1986A_LAPTOP_EAPD), + SND_PCI_QUIRK(0x1043, 0x1263, "ASUS U5F", AD1986A_LAPTOP_EAPD), + SND_PCI_QUIRK(0x1043, 0x1297, "ASUS Z62F", AD1986A_LAPTOP_EAPD), + SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS V1j", AD1986A_LAPTOP_EAPD), + SND_PCI_QUIRK(0x1043, 0x1302, "ASUS W3j", AD1986A_LAPTOP_EAPD), + SND_PCI_QUIRK(0x1043, 0x817f, "ASUS P5", AD1986A_3STACK), + SND_PCI_QUIRK(0x1043, 0x818f, "ASUS P5", AD1986A_LAPTOP), + SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS P5", AD1986A_3STACK), + SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS M2N", AD1986A_3STACK), + SND_PCI_QUIRK(0x1043, 0x8234, "ASUS M2N", AD1986A_3STACK), + SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP), + SND_PCI_QUIRK(0x144d, 0xc023, "Samsung X60", AD1986A_LAPTOP_EAPD), + SND_PCI_QUIRK(0x144d, 0xc024, "Samsung R65", AD1986A_LAPTOP_EAPD), + SND_PCI_QUIRK(0x144d, 0xc026, "Samsung X11", AD1986A_LAPTOP_EAPD), + SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_3STACK), + SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_LAPTOP_EAPD), + SND_PCI_QUIRK(0x17c0, 0x2017, "Samsung M50", AD1986A_LAPTOP), {} }; @@ -867,7 +855,9 @@ static int patch_ad1986a(struct hda_codec *codec) codec->patch_ops = ad198x_patch_ops; /* override some parameters */ - board_config = snd_hda_check_board_config(codec, ad1986a_cfg_tbl); + board_config = snd_hda_check_board_config(codec, AD1986A_MODELS, + ad1986a_models, + ad1986a_cfg_tbl); switch (board_config) { case AD1986A_3STACK: spec->num_mixers = 2; @@ -1397,20 +1387,27 @@ static struct hda_input_mux ad1981_thinkpad_capture_source = { }; /* models */ -enum { AD1981_BASIC, AD1981_HP, AD1981_THINKPAD }; +enum { + AD1981_BASIC, + AD1981_HP, + AD1981_THINKPAD, + AD1981_MODELS +}; -static struct hda_board_config ad1981_cfg_tbl[] = { - { .modelname = "hp", .config = AD1981_HP }, +static const char *ad1981_models[AD1981_MODELS] = { + [AD1981_HP] = "hp", + [AD1981_THINKPAD] = "thinkpad", + [AD1981_BASIC] = "basic", +}; + +static struct snd_pci_quirk ad1981_cfg_tbl[] = { /* All HP models */ - { .pci_subvendor = 0x103c, .config = AD1981_HP }, - { .pci_subvendor = 0x30b0, .pci_subdevice = 0x103c, - .config = AD1981_HP }, /* HP nx6320 (reversed SSID, H/W bug) */ - { .modelname = "thinkpad", .config = AD1981_THINKPAD }, + SND_PCI_QUIRK(0x103c, 0, "HP nx", AD1981_HP), + /* HP nx6320 (reversed SSID, H/W bug) */ + SND_PCI_QUIRK(0x30b0, 0x103c, "HP nx6320", AD1981_HP), /* Lenovo Thinkpad T60/X60/Z6xx */ - { .pci_subvendor = 0x17aa, .config = AD1981_THINKPAD }, - { .pci_subvendor = 0x1014, .pci_subdevice = 0x0597, - .config = AD1981_THINKPAD }, /* Z60m/t */ - { .modelname = "basic", .config = AD1981_BASIC }, + SND_PCI_QUIRK(0x17aa, 0, "Lenovo Thinkpad", AD1981_THINKPAD), + SND_PCI_QUIRK(0x1014, 0x0597, "Lenovo Z60", AD1981_THINKPAD), {} }; @@ -1443,7 +1440,9 @@ static int patch_ad1981(struct hda_codec *codec) codec->patch_ops = ad198x_patch_ops; /* override some parameters */ - board_config = snd_hda_check_board_config(codec, ad1981_cfg_tbl); + board_config = snd_hda_check_board_config(codec, AD1981_MODELS, + ad1981_models, + ad1981_cfg_tbl); switch (board_config) { case AD1981_HP: spec->mixers[0] = ad1981_hp_mixers; @@ -2571,15 +2570,14 @@ static int ad1988_auto_init(struct hda_codec *codec) /* */ -static struct hda_board_config ad1988_cfg_tbl[] = { - { .modelname = "6stack", .config = AD1988_6STACK }, - { .modelname = "6stack-dig", .config = AD1988_6STACK_DIG }, - { .modelname = "3stack", .config = AD1988_3STACK }, - { .modelname = "3stack-dig", .config = AD1988_3STACK_DIG }, - { .modelname = "laptop", .config = AD1988_LAPTOP }, - { .modelname = "laptop-dig", .config = AD1988_LAPTOP_DIG }, - { .modelname = "auto", .config = AD1988_AUTO }, - {} +static const char *ad1988_models[AD1988_MODEL_LAST] = { + [AD1988_6STACK] = "6stack", + [AD1988_6STACK_DIG] = "6stack-dig", + [AD1988_3STACK] = "3stack", + [AD1988_3STACK_DIG] = "3stack-dig", + [AD1988_LAPTOP] = "laptop", + [AD1988_LAPTOP_DIG] = "laptop-dig", + [AD1988_AUTO] = "auto", }; static int patch_ad1988(struct hda_codec *codec) @@ -2597,8 +2595,9 @@ static int patch_ad1988(struct hda_codec *codec) if (is_rev2(codec)) snd_printk(KERN_INFO "patch_analog: AD1988A rev.2 is detected, enable workarounds\n"); - board_config = snd_hda_check_board_config(codec, ad1988_cfg_tbl); - if (board_config < 0 || board_config >= AD1988_MODEL_LAST) { + board_config = snd_hda_check_board_config(codec, AD1988_MODEL_LAST, + ad1988_models, NULL); + if (board_config < 0) { printk(KERN_INFO "hda_codec: Unknown model for AD1988, trying auto-probe from BIOS...\n"); board_config = AD1988_AUTO; } diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index d38ce22507a..5b9d3a31a1a 100644 --- a/sound/pci/hda/patch_cmedia.c +++ b/sound/pci/hda/patch_cmedia.c @@ -40,6 +40,7 @@ enum { CMI_FULL_DIG, /* back 6-jack + front-panel 2-jack + digital I/O */ CMI_ALLOUT, /* back 5-jack + front-panel 2-jack + digital out */ CMI_AUTO, /* let driver guess it */ + CMI_MODELS }; struct cmi_spec { @@ -603,14 +604,17 @@ static void cmi9880_free(struct hda_codec *codec) /* */ -static struct hda_board_config cmi9880_cfg_tbl[] = { - { .modelname = "minimal", .config = CMI_MINIMAL }, - { .modelname = "min_fp", .config = CMI_MIN_FP }, - { .modelname = "full", .config = CMI_FULL }, - { .modelname = "full_dig", .config = CMI_FULL_DIG }, - { .pci_subvendor = 0x1043, .pci_subdevice = 0x813d, .config = CMI_FULL_DIG }, /* ASUS P5AD2 */ - { .modelname = "allout", .config = CMI_ALLOUT }, - { .modelname = "auto", .config = CMI_AUTO }, +static const char *cmi9880_models[CMI_MODELS] = { + [CMI_MINIMAL] = "minimal", + [CMI_MIN_FP] = "min_fp", + [CMI_FULL] = "full", + [CMI_FULL_DIG] = "full_dig", + [CMI_ALLOUT] = "allout", + [CMI_AUTO] = "auto", +}; + +static struct snd_pci_quirk cmi9880_cfg_tbl[] = { + SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", CMI_FULL_DIG), {} /* terminator */ }; @@ -633,7 +637,9 @@ static int patch_cmi9880(struct hda_codec *codec) return -ENOMEM; codec->spec = spec; - spec->board_config = snd_hda_check_board_config(codec, cmi9880_cfg_tbl); + spec->board_config = snd_hda_check_board_config(codec, CMI_MODELS, + cmi9880_models, + cmi9880_cfg_tbl); if (spec->board_config < 0) { snd_printdd(KERN_INFO "hda_codec: Unknown model for CMI9880\n"); spec->board_config = CMI_AUTO; /* try everything */ diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 7e7d0c110c4..dec8f9747fc 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -802,22 +802,22 @@ static int cxt5045_init(struct hda_codec *codec) enum { - CXT5045_LAPTOP, + CXT5045_LAPTOP, /* Laptops w/ EAPD support */ #ifdef CONFIG_SND_DEBUG CXT5045_TEST, #endif + CXT5045_MODELS }; -static struct hda_board_config cxt5045_cfg_tbl[] = { - /* Laptops w/ EAPD support */ - { .modelname = "laptop", .config = CXT5045_LAPTOP }, - /* HP DV6000Z */ - { .pci_subvendor = 0x103c, .pci_subdevice = 0x30b7, - .config = CXT5045_LAPTOP }, +static const char *cxt5045_models[CXT5045_MODELS] = { + [CXT5045_LAPTOP] = "laptop", #ifdef CONFIG_SND_DEBUG - { .modelname = "test", .config = CXT5045_TEST }, + [CXT5045_TEST] = "test", #endif - +}; + +static struct snd_pci_quirk cxt5045_cfg_tbl[] = { + SND_PCI_QUIRK(0x103c, 0x30b7, "HP DV6000Z", CXT5045_LAPTOP), {} }; @@ -852,7 +852,9 @@ static int patch_cxt5045(struct hda_codec *codec) codec->patch_ops = conexant_patch_ops; codec->patch_ops.unsol_event = cxt5045_hp_unsol_event; - board_config = snd_hda_check_board_config(codec, cxt5045_cfg_tbl); + board_config = snd_hda_check_board_config(codec, CXT5045_MODELS, + cxt5045_models, + cxt5045_cfg_tbl); switch (board_config) { case CXT5045_LAPTOP: spec->input_mux = &cxt5045_capture_source; @@ -1214,36 +1216,29 @@ static int cxt5047_hp_init(struct hda_codec *codec) enum { - CXT5047_LAPTOP, + CXT5047_LAPTOP, /* Laptops w/o EAPD support */ + CXT5047_LAPTOP_HP, /* Some HP laptops */ + CXT5047_LAPTOP_EAPD, /* Laptops with EAPD support */ #ifdef CONFIG_SND_DEBUG CXT5047_TEST, #endif - CXT5047_LAPTOP_HP, - CXT5047_LAPTOP_EAPD + CXT5047_MODELS }; -static struct hda_board_config cxt5047_cfg_tbl[] = { - /* Laptops w/o EAPD support */ - { .modelname = "laptop", .config = CXT5047_LAPTOP }, - /*HP DV1000 */ - { .pci_subvendor = 0x103c, .pci_subdevice = 0x30a0, - .config = CXT5047_LAPTOP }, - /*HP DV2000T/DV3000T */ - { .pci_subvendor = 0x103c, .pci_subdevice = 0x30b2, - .config = CXT5047_LAPTOP }, - /* Not all HP's are created equal */ - { .modelname = "laptop-hp", .config = CXT5047_LAPTOP_HP }, - /*HP DV5200TX/DV8000T / Compaq V5209US/V5204NR */ - { .pci_subvendor = 0x103c, .pci_subdevice = 0x30a5, - .config = CXT5047_LAPTOP_HP }, - /* Laptops with EAPD support */ - { .modelname = "laptop-eapd", .config = CXT5047_LAPTOP_EAPD }, - { .pci_subvendor = 0x1179, .pci_subdevice = 0xff31, - .config = CXT5047_LAPTOP_EAPD }, /* Toshiba P100 */ +static const char *cxt5047_models[CXT5047_MODELS] = { + [CXT5047_LAPTOP] = "laptop", + [CXT5047_LAPTOP_HP] = "laptop-hp", + [CXT5047_LAPTOP_EAPD] = "laptop-eapd", #ifdef CONFIG_SND_DEBUG - { .modelname = "test", .config = CXT5047_TEST }, + [CXT5047_TEST] = "test", #endif - +}; + +static struct snd_pci_quirk cxt5047_cfg_tbl[] = { + SND_PCI_QUIRK(0x103c, 0x30a0, "HP DV1000", CXT5047_LAPTOP), + SND_PCI_QUIRK(0x103c, 0x30b2, "HP DV2000T/DV3000T", CXT5047_LAPTOP), + SND_PCI_QUIRK(0x103c, 0x30a5, "HP DV5200T/DV8000T", CXT5047_LAPTOP_HP), + SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P100", CXT5047_LAPTOP_EAPD), {} }; @@ -1277,7 +1272,9 @@ static int patch_cxt5047(struct hda_codec *codec) codec->patch_ops = conexant_patch_ops; codec->patch_ops.unsol_event = cxt5047_hp_unsol_event; - board_config = snd_hda_check_board_config(codec, cxt5047_cfg_tbl); + board_config = snd_hda_check_board_config(codec, CXT5047_MODELS, + cxt5047_models, + cxt5047_cfg_tbl); switch (board_config) { case CXT5047_LAPTOP: break; diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 02c465147d9..415a6db4c90 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -2328,162 +2328,108 @@ static struct hda_verb alc880_test_init_verbs[] = { /* */ -static struct hda_board_config alc880_cfg_tbl[] = { - /* Back 3 jack, front 2 jack */ - { .modelname = "3stack", .config = ALC880_3ST }, - { .pci_subvendor = 0x8086, .pci_subdevice = 0xe200, .config = ALC880_3ST }, - { .pci_subvendor = 0x8086, .pci_subdevice = 0xe201, .config = ALC880_3ST }, - { .pci_subvendor = 0x8086, .pci_subdevice = 0xe202, .config = ALC880_3ST }, - { .pci_subvendor = 0x8086, .pci_subdevice = 0xe203, .config = ALC880_3ST }, - { .pci_subvendor = 0x8086, .pci_subdevice = 0xe204, .config = ALC880_3ST }, - { .pci_subvendor = 0x8086, .pci_subdevice = 0xe205, .config = ALC880_3ST }, - { .pci_subvendor = 0x8086, .pci_subdevice = 0xe206, .config = ALC880_3ST }, - { .pci_subvendor = 0x8086, .pci_subdevice = 0xe207, .config = ALC880_3ST }, - { .pci_subvendor = 0x8086, .pci_subdevice = 0xe208, .config = ALC880_3ST }, - { .pci_subvendor = 0x8086, .pci_subdevice = 0xe209, .config = ALC880_3ST }, - { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20a, .config = ALC880_3ST }, - { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20b, .config = ALC880_3ST }, - { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20c, .config = ALC880_3ST }, - { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20d, .config = ALC880_3ST }, - { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20e, .config = ALC880_3ST }, - { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20f, .config = ALC880_3ST }, - { .pci_subvendor = 0x8086, .pci_subdevice = 0xe210, .config = ALC880_3ST }, - { .pci_subvendor = 0x8086, .pci_subdevice = 0xe211, .config = ALC880_3ST }, - { .pci_subvendor = 0x8086, .pci_subdevice = 0xe212, .config = ALC880_3ST }, - { .pci_subvendor = 0x8086, .pci_subdevice = 0xe213, .config = ALC880_3ST }, - { .pci_subvendor = 0x8086, .pci_subdevice = 0xe214, .config = ALC880_3ST }, - { .pci_subvendor = 0x8086, .pci_subdevice = 0xe234, .config = ALC880_3ST }, - { .pci_subvendor = 0x8086, .pci_subdevice = 0xe302, .config = ALC880_3ST }, - { .pci_subvendor = 0x8086, .pci_subdevice = 0xe303, .config = ALC880_3ST }, - { .pci_subvendor = 0x8086, .pci_subdevice = 0xe304, .config = ALC880_3ST }, - { .pci_subvendor = 0x8086, .pci_subdevice = 0xe306, .config = ALC880_3ST }, - { .pci_subvendor = 0x8086, .pci_subdevice = 0xe307, .config = ALC880_3ST }, - { .pci_subvendor = 0x8086, .pci_subdevice = 0xe404, .config = ALC880_3ST }, - { .pci_subvendor = 0x8086, .pci_subdevice = 0xa101, .config = ALC880_3ST }, - { .pci_subvendor = 0x107b, .pci_subdevice = 0x3031, .config = ALC880_3ST }, - { .pci_subvendor = 0x107b, .pci_subdevice = 0x4036, .config = ALC880_3ST }, - { .pci_subvendor = 0x107b, .pci_subdevice = 0x4037, .config = ALC880_3ST }, - { .pci_subvendor = 0x107b, .pci_subdevice = 0x4038, .config = ALC880_3ST }, - { .pci_subvendor = 0x107b, .pci_subdevice = 0x4040, .config = ALC880_3ST }, - { .pci_subvendor = 0x107b, .pci_subdevice = 0x4041, .config = ALC880_3ST }, - /* TCL S700 */ - { .modelname = "tcl", .config = ALC880_TCL_S700 }, - { .pci_subvendor = 0x19db, .pci_subdevice = 0x4188, .config = ALC880_TCL_S700 }, - - /* Back 3 jack, front 2 jack (Internal add Aux-In) */ - { .pci_subvendor = 0x1025, .pci_subdevice = 0xe310, .config = ALC880_3ST }, - { .pci_subvendor = 0x104d, .pci_subdevice = 0x81d6, .config = ALC880_3ST }, - { .pci_subvendor = 0x104d, .pci_subdevice = 0x81a0, .config = ALC880_3ST }, - - /* Back 3 jack plus 1 SPDIF out jack, front 2 jack */ - { .modelname = "3stack-digout", .config = ALC880_3ST_DIG }, - { .pci_subvendor = 0x8086, .pci_subdevice = 0xe308, .config = ALC880_3ST_DIG }, - { .pci_subvendor = 0x1025, .pci_subdevice = 0x0070, .config = ALC880_3ST_DIG }, - - /* Clevo laptops */ - { .modelname = "clevo", .config = ALC880_CLEVO }, - { .pci_subvendor = 0x1558, .pci_subdevice = 0x0520, - .config = ALC880_CLEVO }, /* Clevo m520G NB */ - { .pci_subvendor = 0x1558, .pci_subdevice = 0x0660, - .config = ALC880_CLEVO }, /* Clevo m665n */ - - /* Back 3 jack plus 1 SPDIF out jack, front 2 jack (Internal add Aux-In)*/ - { .pci_subvendor = 0x8086, .pci_subdevice = 0xe305, .config = ALC880_3ST_DIG }, - { .pci_subvendor = 0x8086, .pci_subdevice = 0xd402, .config = ALC880_3ST_DIG }, - { .pci_subvendor = 0x1025, .pci_subdevice = 0xe309, .config = ALC880_3ST_DIG }, - - /* Back 5 jack, front 2 jack */ - { .modelname = "5stack", .config = ALC880_5ST }, - { .pci_subvendor = 0x107b, .pci_subdevice = 0x3033, .config = ALC880_5ST }, - { .pci_subvendor = 0x107b, .pci_subdevice = 0x4039, .config = ALC880_5ST }, - { .pci_subvendor = 0x107b, .pci_subdevice = 0x3032, .config = ALC880_5ST }, - { .pci_subvendor = 0x103c, .pci_subdevice = 0x2a09, .config = ALC880_5ST }, - { .pci_subvendor = 0x1043, .pci_subdevice = 0x814e, .config = ALC880_5ST }, - - /* Back 5 jack plus 1 SPDIF out jack, front 2 jack */ - { .modelname = "5stack-digout", .config = ALC880_5ST_DIG }, - { .pci_subvendor = 0x8086, .pci_subdevice = 0xe224, .config = ALC880_5ST_DIG }, - { .pci_subvendor = 0x8086, .pci_subdevice = 0xe400, .config = ALC880_5ST_DIG }, - { .pci_subvendor = 0x8086, .pci_subdevice = 0xe401, .config = ALC880_5ST_DIG }, - { .pci_subvendor = 0x8086, .pci_subdevice = 0xe402, .config = ALC880_5ST_DIG }, - { .pci_subvendor = 0x8086, .pci_subdevice = 0xd400, .config = ALC880_5ST_DIG }, - { .pci_subvendor = 0x8086, .pci_subdevice = 0xd401, .config = ALC880_5ST_DIG }, - { .pci_subvendor = 0x8086, .pci_subdevice = 0xa100, .config = ALC880_5ST_DIG }, - { .pci_subvendor = 0x1565, .pci_subdevice = 0x8202, .config = ALC880_5ST_DIG }, - { .pci_subvendor = 0x1019, .pci_subdevice = 0xa880, .config = ALC880_5ST_DIG }, - { .pci_subvendor = 0xa0a0, .pci_subdevice = 0x0560, - .config = ALC880_5ST_DIG }, /* Aopen i915GMm-HFS */ - /* { .pci_subvendor = 0x1019, .pci_subdevice = 0xa884, .config = ALC880_5ST_DIG }, */ /* conflict with 6stack */ - { .pci_subvendor = 0x1695, .pci_subdevice = 0x400d, .config = ALC880_5ST_DIG }, - /* note subvendor = 0 below */ - /* { .pci_subvendor = 0x0000, .pci_subdevice = 0x8086, .config = ALC880_5ST_DIG }, */ - - { .modelname = "w810", .config = ALC880_W810 }, - { .pci_subvendor = 0x161f, .pci_subdevice = 0x203d, .config = ALC880_W810 }, - - { .modelname = "z71v", .config = ALC880_Z71V }, - { .pci_subvendor = 0x1043, .pci_subdevice = 0x1964, .config = ALC880_Z71V }, - - { .modelname = "6stack", .config = ALC880_6ST }, - { .pci_subvendor = 0x1043, .pci_subdevice = 0x8196, .config = ALC880_6ST }, /* ASUS P5GD1-HVM */ - { .pci_subvendor = 0x1043, .pci_subdevice = 0x81b4, .config = ALC880_6ST }, - { .pci_subvendor = 0x1019, .pci_subdevice = 0xa884, .config = ALC880_6ST }, /* Acer APFV */ - - { .modelname = "6stack-digout", .config = ALC880_6ST_DIG }, - { .pci_subvendor = 0x2668, .pci_subdevice = 0x8086, .config = ALC880_6ST_DIG }, - { .pci_subvendor = 0x8086, .pci_subdevice = 0x2668, .config = ALC880_6ST_DIG }, - { .pci_subvendor = 0x1462, .pci_subdevice = 0x1150, .config = ALC880_6ST_DIG }, - { .pci_subvendor = 0xe803, .pci_subdevice = 0x1019, .config = ALC880_6ST_DIG }, - { .pci_subvendor = 0x1039, .pci_subdevice = 0x1234, .config = ALC880_6ST_DIG }, - { .pci_subvendor = 0x1025, .pci_subdevice = 0x0077, .config = ALC880_6ST_DIG }, - { .pci_subvendor = 0x1025, .pci_subdevice = 0x0078, .config = ALC880_6ST_DIG }, - { .pci_subvendor = 0x1025, .pci_subdevice = 0x0087, .config = ALC880_6ST_DIG }, - { .pci_subvendor = 0x1297, .pci_subdevice = 0xc790, .config = ALC880_6ST_DIG }, /* Shuttle ST20G5 */ - { .pci_subvendor = 0x1509, .pci_subdevice = 0x925d, .config = ALC880_6ST_DIG }, /* FIC P4M-915GD1 */ - { .pci_subvendor = 0x1695, .pci_subdevice = 0x4012, .config = ALC880_5ST_DIG }, /* Epox EP-5LDA+ GLi */ - { .pci_subvendor = 0x1458, .pci_subdevice = 0xa102, .config = ALC880_6ST_DIG }, /* Gigabyte K8N51 */ - - { .modelname = "asus", .config = ALC880_ASUS }, - { .pci_subvendor = 0x1043, .pci_subdevice = 0x1964, .config = ALC880_ASUS_DIG }, - { .pci_subvendor = 0x1043, .pci_subdevice = 0x1973, .config = ALC880_ASUS_DIG }, - { .pci_subvendor = 0x1043, .pci_subdevice = 0x19b3, .config = ALC880_ASUS_DIG }, - { .pci_subvendor = 0x1043, .pci_subdevice = 0x1113, .config = ALC880_ASUS_DIG }, - { .pci_subvendor = 0x1043, .pci_subdevice = 0x1173, .config = ALC880_ASUS_DIG }, - { .pci_subvendor = 0x1043, .pci_subdevice = 0x1993, .config = ALC880_ASUS }, - { .pci_subvendor = 0x1043, .pci_subdevice = 0x10c2, .config = ALC880_ASUS_DIG }, /* Asus W6A */ - { .pci_subvendor = 0x1043, .pci_subdevice = 0x10c3, .config = ALC880_ASUS_DIG }, - { .pci_subvendor = 0x1043, .pci_subdevice = 0x1133, .config = ALC880_ASUS }, - { .pci_subvendor = 0x1043, .pci_subdevice = 0x1123, .config = ALC880_ASUS_DIG }, - { .pci_subvendor = 0x1043, .pci_subdevice = 0x1143, .config = ALC880_ASUS }, - { .modelname = "asus-w1v", .config = ALC880_ASUS_W1V }, - { .pci_subvendor = 0x1043, .pci_subdevice = 0x10b3, .config = ALC880_ASUS_W1V }, - { .modelname = "asus-dig", .config = ALC880_ASUS_DIG }, - { .pci_subvendor = 0x1043, .pci_subdevice = 0x8181, .config = ALC880_ASUS_DIG }, /* ASUS P4GPL-X */ - { .modelname = "asus-dig2", .config = ALC880_ASUS_DIG2 }, - { .pci_subvendor = 0x1558, .pci_subdevice = 0x5401, .config = ALC880_ASUS_DIG2 }, - - { .modelname = "uniwill", .config = ALC880_UNIWILL_DIG }, - { .pci_subvendor = 0x1584, .pci_subdevice = 0x9050, .config = ALC880_UNIWILL_DIG }, - { .pci_subvendor = 0x1584, .pci_subdevice = 0x9070, .config = ALC880_UNIWILL }, - { .pci_subvendor = 0x1734, .pci_subdevice = 0x10ac, .config = ALC880_UNIWILL }, - { .pci_subvendor = 0x1584, .pci_subdevice = 0x9077, .config = ALC880_UNIWILL_P53 }, - - { .modelname = "F1734", .config = ALC880_F1734 }, - { .pci_subvendor = 0x1734, .pci_subdevice = 0x107c, .config = ALC880_F1734 }, - { .pci_subvendor = 0x1584, .pci_subdevice = 0x9054, .config = ALC880_F1734 }, - - { .modelname = "lg", .config = ALC880_LG }, - { .pci_subvendor = 0x1854, .pci_subdevice = 0x003b, .config = ALC880_LG }, - { .pci_subvendor = 0x1854, .pci_subdevice = 0x0068, .config = ALC880_LG }, - - { .modelname = "lg-lw", .config = ALC880_LG_LW }, - { .pci_subvendor = 0x1854, .pci_subdevice = 0x0018, .config = ALC880_LG_LW }, - { .pci_subvendor = 0x1854, .pci_subdevice = 0x0077, .config = ALC880_LG_LW }, - +static const char *alc880_models[ALC880_MODEL_LAST] = { + [ALC880_3ST] = "3stack", + [ALC880_TCL_S700] = "tcl", + [ALC880_3ST_DIG] = "3stack-digout", + [ALC880_CLEVO] = "clevo", + [ALC880_5ST] = "5stack", + [ALC880_5ST_DIG] = "5stack-digout", + [ALC880_W810] = "w810", + [ALC880_Z71V] = "z71v", + [ALC880_6ST] = "6stack", + [ALC880_6ST_DIG] = "6stack-digout", + [ALC880_ASUS] = "asus", + [ALC880_ASUS_W1V] = "asus-w1v", + [ALC880_ASUS_DIG] = "asus-dig", + [ALC880_ASUS_DIG2] = "asus-dig2", + [ALC880_UNIWILL_DIG] = "uniwill", + [ALC880_F1734] = "F1734", + [ALC880_LG] = "lg", + [ALC880_LG_LW] = "lg-lw", #ifdef CONFIG_SND_DEBUG - { .modelname = "test", .config = ALC880_TEST }, + [ALC880_TEST] = "test", #endif - { .modelname = "auto", .config = ALC880_AUTO }, + [ALC880_AUTO] = "auto", +}; + +static struct snd_pci_quirk alc880_cfg_tbl[] = { + /* Broken BIOS configuration */ + SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG), + SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG), + + SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG), + SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST), + SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG), + SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG), + SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG), + SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_6ST_DIG), + SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG), + SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST), + + SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG), + SND_PCI_QUIRK(0x103c, 0x2a09, "HP", ALC880_5ST), + + SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V), + SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG), + SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG), + SND_PCI_QUIRK(0x1043, 0x1113, "ASUS", ALC880_ASUS_DIG), + SND_PCI_QUIRK(0x1043, 0x1123, "ASUS", ALC880_ASUS_DIG), + SND_PCI_QUIRK(0x1043, 0x1173, "ASUS", ALC880_ASUS_DIG), + SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_Z71V), + /* SND_PCI_QUIRK(0x1043, 0x1964, "ASUS", ALC880_ASUS_DIG), */ + SND_PCI_QUIRK(0x1043, 0x1973, "ASUS", ALC880_ASUS_DIG), + SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS", ALC880_ASUS_DIG), + SND_PCI_QUIRK(0x1043, 0x814e, "ASUS", ALC880_5ST), + SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG), + SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST), + SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST), + SND_PCI_QUIRK(0x1043, 0, "ASUS", ALC880_ASUS), + + SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST), + SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST), + SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_5ST), + SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_5ST), + SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST), + SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO), + SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO), + SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG), + SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810), + SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG), + SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700), + SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG), + SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG), + SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_6ST_DIG), + SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_6ST_DIG), + SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_6ST_DIG), + SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_6ST_DIG), + SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2), + + SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG), + SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL), + SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53), + SND_PCI_QUIRK(0x1584, 0x9054, "Uniwlll", ALC880_F1734), + + SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG), + SND_PCI_QUIRK(0x1734, 0x10ac, "FSC", ALC880_UNIWILL), + SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734), + + SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG), + SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG), + SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW), + SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW), + + SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG), + SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG), + SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG), + SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_5ST_DIG), + SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_5ST_DIG), + SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_5ST_DIG), + SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG), + SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG), + SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG), + SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG), + SND_PCI_QUIRK(0x8086, 0, "Intel mobo", ALC880_3ST), {} }; @@ -3074,8 +3020,10 @@ static int patch_alc880(struct hda_codec *codec) codec->spec = spec; - board_config = snd_hda_check_board_config(codec, alc880_cfg_tbl); - if (board_config < 0 || board_config >= ALC880_MODEL_LAST) { + board_config = snd_hda_check_board_config(codec, ALC880_MODEL_LAST, + alc880_models, + alc880_cfg_tbl); + if (board_config < 0) { printk(KERN_INFO "hda_codec: Unknown model for ALC880, " "trying auto-probe from BIOS...\n"); board_config = ALC880_AUTO; @@ -4161,33 +4109,32 @@ static void alc260_auto_init(struct hda_codec *codec) /* * ALC260 configurations */ -static struct hda_board_config alc260_cfg_tbl[] = { - { .modelname = "basic", .config = ALC260_BASIC }, - { .pci_subvendor = 0x104d, .pci_subdevice = 0x81bb, - .config = ALC260_BASIC }, /* Sony VAIO */ - { .pci_subvendor = 0x104d, .pci_subdevice = 0x81cc, - .config = ALC260_BASIC }, /* Sony VAIO VGN-S3HP */ - { .pci_subvendor = 0x104d, .pci_subdevice = 0x81cd, - .config = ALC260_BASIC }, /* Sony VAIO */ - { .pci_subvendor = 0x152d, .pci_subdevice = 0x0729, - .config = ALC260_BASIC }, /* CTL Travel Master U553W */ - { .modelname = "hp", .config = ALC260_HP }, - { .modelname = "hp-3013", .config = ALC260_HP_3013 }, - { .pci_subvendor = 0x103c, .pci_subdevice = 0x3010, .config = ALC260_HP_3013 }, - { .pci_subvendor = 0x103c, .pci_subdevice = 0x3011, .config = ALC260_HP }, - { .pci_subvendor = 0x103c, .pci_subdevice = 0x3012, .config = ALC260_HP_3013 }, - { .pci_subvendor = 0x103c, .pci_subdevice = 0x3013, .config = ALC260_HP_3013 }, - { .pci_subvendor = 0x103c, .pci_subdevice = 0x3014, .config = ALC260_HP }, - { .pci_subvendor = 0x103c, .pci_subdevice = 0x3015, .config = ALC260_HP }, - { .pci_subvendor = 0x103c, .pci_subdevice = 0x3016, .config = ALC260_HP }, - { .modelname = "fujitsu", .config = ALC260_FUJITSU_S702X }, - { .pci_subvendor = 0x10cf, .pci_subdevice = 0x1326, .config = ALC260_FUJITSU_S702X }, - { .modelname = "acer", .config = ALC260_ACER }, - { .pci_subvendor = 0x1025, .pci_subdevice = 0x008f, .config = ALC260_ACER }, +static const char *alc260_models[ALC260_MODEL_LAST] = { + [ALC260_BASIC] = "basic", + [ALC260_HP] = "hp", + [ALC260_HP_3013] = "hp-3013", + [ALC260_FUJITSU_S702X] = "fujitsu", + [ALC260_ACER] = "acer", #ifdef CONFIG_SND_DEBUG - { .modelname = "test", .config = ALC260_TEST }, + [ALC260_TEST] = "test", #endif - { .modelname = "auto", .config = ALC260_AUTO }, + [ALC260_AUTO] = "auto", +}; + +static struct snd_pci_quirk alc260_cfg_tbl[] = { + SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER), + SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013), + SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP), + SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_3013), + SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013), + SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP), + SND_PCI_QUIRK(0x103c, 0x3015, "HP", ALC260_HP), + SND_PCI_QUIRK(0x103c, 0x3016, "HP", ALC260_HP), + SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_BASIC), + SND_PCI_QUIRK(0x104d, 0x81cc, "Sony VAIO", ALC260_BASIC), + SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC), + SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X), + SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC), {} }; @@ -4286,8 +4233,10 @@ static int patch_alc260(struct hda_codec *codec) codec->spec = spec; - board_config = snd_hda_check_board_config(codec, alc260_cfg_tbl); - if (board_config < 0 || board_config >= ALC260_MODEL_LAST) { + board_config = snd_hda_check_board_config(codec, ALC260_MODEL_LAST, + alc260_models, + alc260_cfg_tbl); + if (board_config < 0) { snd_printd(KERN_INFO "hda_codec: Unknown model for ALC260, " "trying auto-probe from BIOS...\n"); board_config = ALC260_AUTO; @@ -4668,19 +4617,18 @@ static struct snd_kcontrol_new alc882_capture_mixer[] = { /* * configuration and preset */ -static struct hda_board_config alc882_cfg_tbl[] = { - { .modelname = "3stack-dig", .config = ALC882_3ST_DIG }, - { .modelname = "6stack-dig", .config = ALC882_6ST_DIG }, - { .pci_subvendor = 0x1462, .pci_subdevice = 0x6668, - .config = ALC882_6ST_DIG }, /* MSI */ - { .pci_subvendor = 0x105b, .pci_subdevice = 0x6668, - .config = ALC882_6ST_DIG }, /* Foxconn */ - { .pci_subvendor = 0x1019, .pci_subdevice = 0x6668, - .config = ALC882_6ST_DIG }, /* ECS to Intel*/ - { .modelname = "arima", .config = ALC882_ARIMA }, - { .pci_subvendor = 0x161f, .pci_subdevice = 0x2054, - .config = ALC882_ARIMA }, /* Arima W820Di1 */ - { .modelname = "auto", .config = ALC882_AUTO }, +static const char *alc882_models[ALC882_MODEL_LAST] = { + [ALC882_3ST_DIG] = "3stack-dig", + [ALC882_6ST_DIG] = "6stack-dig", + [ALC882_ARIMA] = "arima", + [ALC882_AUTO] = "auto", +}; + +static struct snd_pci_quirk alc882_cfg_tbl[] = { + SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG), + SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG), + SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG), + SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA), {} }; @@ -4817,7 +4765,9 @@ static int patch_alc882(struct hda_codec *codec) codec->spec = spec; - board_config = snd_hda_check_board_config(codec, alc882_cfg_tbl); + board_config = snd_hda_check_board_config(codec, ALC882_MODEL_LAST, + alc882_models, + alc882_cfg_tbl); if (board_config < 0 || board_config >= ALC882_MODEL_LAST) { printk(KERN_INFO "hda_codec: Unknown model for ALC882, " @@ -5427,65 +5377,41 @@ static struct snd_kcontrol_new alc883_capture_mixer[] = { /* * configuration and preset */ -static struct hda_board_config alc883_cfg_tbl[] = { - { .modelname = "3stack-dig", .config = ALC883_3ST_2ch_DIG }, - { .modelname = "3stack-6ch-dig", .config = ALC883_3ST_6ch_DIG }, - { .pci_subvendor = 0x1019, .pci_subdevice = 0x6668, - .config = ALC883_3ST_6ch_DIG }, /* ECS to Intel*/ - { .modelname = "3stack-6ch", .config = ALC883_3ST_6ch }, - { .pci_subvendor = 0x108e, .pci_subdevice = 0x534d, - .config = ALC883_3ST_6ch }, - { .pci_subvendor = 0x8086, .pci_subdevice = 0xd601, - .config = ALC883_3ST_6ch }, /* D102GGC */ - { .modelname = "6stack-dig", .config = ALC883_6ST_DIG }, - { .pci_subvendor = 0x1462, .pci_subdevice = 0x6668, - .config = ALC883_6ST_DIG }, /* MSI */ - { .pci_subvendor = 0x1462, .pci_subdevice = 0x7280, - .config = ALC883_6ST_DIG }, /* MSI K9A Platinum (MS-7280) */ - { .pci_subvendor = 0x105b, .pci_subdevice = 0x6668, - .config = ALC883_6ST_DIG }, /* Foxconn */ - { .pci_subvendor = 0x1462, .pci_subdevice = 0x7187, - .config = ALC883_6ST_DIG }, /* MSI */ - { .modelname = "targa-dig", .config = ALC883_TARGA_DIG }, - { .pci_subvendor = 0x1462, .pci_subdevice = 0x4314, - .config = ALC883_TARGA_DIG }, /* MSI */ - { .pci_subvendor = 0x1462, .pci_subdevice = 0x3fcc, - .config = ALC883_TARGA_DIG }, /* MSI */ - { .pci_subvendor = 0x1462, .pci_subdevice = 0x3fc1, - .config = ALC883_TARGA_DIG }, /* MSI */ - { .pci_subvendor = 0x1462, .pci_subdevice = 0x3fc3, - .config = ALC883_TARGA_DIG }, /* MSI */ - { .pci_subvendor = 0x1462, .pci_subdevice = 0x4314, - .config = ALC883_TARGA_DIG }, /* MSI */ - { .pci_subvendor = 0x1462, .pci_subdevice = 0x4319, - .config = ALC883_TARGA_DIG }, /* MSI */ - { .pci_subvendor = 0x1462, .pci_subdevice = 0x3ef9, - .config = ALC883_TARGA_DIG }, /* MSI */ - { .pci_subvendor = 0x1462, .pci_subdevice = 0x4324, - .config = ALC883_TARGA_DIG }, /* MSI */ - { .modelname = "targa-2ch-dig", .config = ALC883_TARGA_2ch_DIG }, - { .pci_subvendor = 0x1462, .pci_subdevice = 0x0579, - .config = ALC883_TARGA_2ch_DIG }, /* MSI */ - { .pci_subvendor = 0x1462, .pci_subdevice = 0xa422, - .config = ALC883_TARGA_2ch_DIG }, /* MSI */ - { .pci_subvendor = 0x1462, .pci_subdevice = 0x3b7f, - .config = ALC883_TARGA_2ch_DIG }, /* MSI */ - { .modelname = "6stack-dig-demo", .config = ALC888_DEMO_BOARD }, - { .modelname = "acer", .config = ALC883_ACER }, - { .pci_subvendor = 0x1025, .pci_subdevice = 0/*0x0102*/, - .config = ALC883_ACER }, - { .pci_subvendor = 0x1025, .pci_subdevice = 0x0102, - .config = ALC883_ACER }, - { .pci_subvendor = 0x1025, .pci_subdevice = 0x009f, - .config = ALC883_ACER }, - { .pci_subvendor = 0x161f, .pci_subdevice = 0x2054, - .modelname = "medion", .config = ALC883_MEDION }, - { .modelname = "laptop-eapd", .config = ALC883_LAPTOP_EAPD }, - { .pci_subvendor = 0x1071, .pci_subdevice = 0x8258, - .config = ALC883_LAPTOP_EAPD }, /* Evesham Voyager C530RD */ - { .pci_subvendor = 0x1558, .pci_subdevice = 0, - .config = ALC883_LAPTOP_EAPD }, /* Clevo */ - { .modelname = "auto", .config = ALC883_AUTO }, +static const char *alc883_models[ALC883_MODEL_LAST] = { + [ALC883_3ST_2ch_DIG] = "3stack-dig", + [ALC883_3ST_6ch_DIG] = "3stack-6ch-dig", + [ALC883_3ST_6ch] = "3stack-6ch", + [ALC883_6ST_DIG] = "6stack-dig", + [ALC883_TARGA_DIG] = "targa-dig", + [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig", + [ALC888_DEMO_BOARD] = "6stack-dig-demo", + [ALC883_ACER] = "acer", + [ALC883_MEDION] = "medion", + [ALC883_LAPTOP_EAPD] = "laptop-eapd", + [ALC883_AUTO] = "auto", +}; + +static struct snd_pci_quirk alc883_cfg_tbl[] = { + SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC883_3ST_6ch_DIG), + SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch), + SND_PCI_QUIRK(0x1558, 0, "Clevo laptop", ALC883_LAPTOP_EAPD), + SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC883_6ST_DIG), + SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG), + SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG), + SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG), + SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG), + SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG), + SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG), + SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG), + SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG), + SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG), + SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG), + SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG), + SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG), + SND_PCI_QUIRK(0x1025, 0, "Acer laptop", ALC883_ACER), + SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION), + SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD), + SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch), {} }; @@ -5734,8 +5660,10 @@ static int patch_alc883(struct hda_codec *codec) codec->spec = spec; - board_config = snd_hda_check_board_config(codec, alc883_cfg_tbl); - if (board_config < 0 || board_config >= ALC883_MODEL_LAST) { + board_config = snd_hda_check_board_config(codec, ALC883_MODEL_LAST, + alc883_models, + alc883_cfg_tbl); + if (board_config < 0) { printk(KERN_INFO "hda_codec: Unknown model for ALC883, " "trying auto-probe from BIOS...\n"); board_config = ALC883_AUTO; @@ -6438,35 +6366,27 @@ static void alc262_auto_init(struct hda_codec *codec) /* * configuration and preset */ -static struct hda_board_config alc262_cfg_tbl[] = { - { .modelname = "basic", .config = ALC262_BASIC }, - { .modelname = "hippo", - .pci_subvendor =0x1002, .pci_subdevice = 0x437b, - .config = ALC262_HIPPO}, - { .modelname = "hippo", - .pci_subvendor = 0x104d, .pci_subdevice = 0x8203, - .config = ALC262_HIPPO }, /* Sony UX-90s */ - { .modelname = "hippo_1", - .pci_subvendor =0x17ff, .pci_subdevice = 0x058f, - .config = ALC262_HIPPO_1}, - { .modelname = "fujitsu", .config = ALC262_FUJITSU }, - { .pci_subvendor = 0x10cf, .pci_subdevice = 0x1397, - .config = ALC262_FUJITSU }, - { .modelname = "hp-bpc", .config = ALC262_HP_BPC }, - { .pci_subvendor = 0x103c, .pci_subdevice = 0x280c, - .config = ALC262_HP_BPC }, /* xw4400 */ - { .pci_subvendor = 0x103c, .pci_subdevice = 0x2801, - .config = ALC262_HP_BPC }, /* q965 */ - { .pci_subvendor = 0x103c, .pci_subdevice = 0x3014, - .config = ALC262_HP_BPC }, /* xw6400 */ - { .pci_subvendor = 0x103c, .pci_subdevice = 0x3015, - .config = ALC262_HP_BPC }, /* xw8400 */ - { .pci_subvendor = 0x103c, .pci_subdevice = 0x12fe, - .config = ALC262_HP_BPC }, /* xw9400 */ - { .modelname = "benq", .config = ALC262_BENQ_ED8 }, - { .pci_subvendor = 0x17ff, .pci_subdevice = 0x0560, - .config = ALC262_BENQ_ED8 }, - { .modelname = "auto", .config = ALC262_AUTO }, +static const char *alc262_models[ALC262_MODEL_LAST] = { + [ALC262_BASIC] = "basic", + [ALC262_HIPPO] = "hippo", + [ALC262_HIPPO_1] = "hippo_1", + [ALC262_FUJITSU] = "fujitsu", + [ALC262_HP_BPC] = "hp-bpc", + [ALC262_BENQ_ED8] = "benq", + [ALC262_AUTO] = "auto", +}; + +static struct snd_pci_quirk alc262_cfg_tbl[] = { + SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO), + SND_PCI_QUIRK(0x103c, 0x12fe, "HP xw9400", ALC262_HP_BPC), + SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC), + SND_PCI_QUIRK(0x103c, 0x2801, "HP q954", ALC262_HP_BPC), + SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC), + SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC), + SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO), + SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU), + SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1), + SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8), {} }; @@ -6561,9 +6481,11 @@ static int patch_alc262(struct hda_codec *codec) } #endif - board_config = snd_hda_check_board_config(codec, alc262_cfg_tbl); + board_config = snd_hda_check_board_config(codec, ALC262_MODEL_LAST, + alc262_models, + alc262_cfg_tbl); - if (board_config < 0 || board_config >= ALC262_MODEL_LAST) { + if (board_config < 0) { printk(KERN_INFO "hda_codec: Unknown model for ALC262, " "trying auto-probe from BIOS...\n"); board_config = ALC262_AUTO; @@ -7527,30 +7449,26 @@ static void alc861_auto_init(struct hda_codec *codec) /* * configuration and preset */ -static struct hda_board_config alc861_cfg_tbl[] = { - { .modelname = "3stack", .config = ALC861_3ST }, - { .pci_subvendor = 0x8086, .pci_subdevice = 0xd600, - .config = ALC861_3ST }, - { .modelname = "3stack-660", .config = ALC660_3ST }, - { .pci_subvendor = 0x1043, .pci_subdevice = 0x81e7, - .config = ALC660_3ST }, - { .modelname = "3stack-dig", .config = ALC861_3ST_DIG }, - { .modelname = "6stack-dig", .config = ALC861_6ST_DIG }, - { .modelname = "uniwill-m31", .config = ALC861_UNIWILL_M31}, - { .pci_subvendor = 0x1584, .pci_subdevice = 0x9072, - .config = ALC861_UNIWILL_M31 }, - { .modelname = "toshiba", .config = ALC861_TOSHIBA }, - { .pci_subvendor = 0x1179, .pci_subdevice = 0xff10, - .config = ALC861_TOSHIBA }, - { .modelname = "asus", .config = ALC861_ASUS}, - { .pci_subvendor = 0x1043, .pci_subdevice = 0x1393, - .config = ALC861_ASUS }, - { .modelname = "asus-laptop", .config = ALC861_ASUS_LAPTOP }, - { .pci_subvendor = 0x1043, .pci_subdevice = 0x1335, - .config = ALC861_ASUS_LAPTOP }, /* ASUS F2/F3 */ - { .pci_subvendor = 0x1043, .pci_subdevice = 0x1338, - .config = ALC861_ASUS_LAPTOP }, /* ASUS F2/F3 */ - { .modelname = "auto", .config = ALC861_AUTO }, +static const char *alc861_models[ALC861_MODEL_LAST] = { + [ALC861_3ST] = "3stack", + [ALC660_3ST] = "3stack-660", + [ALC861_3ST_DIG] = "3stack-dig", + [ALC861_6ST_DIG] = "6stack-dig", + [ALC861_UNIWILL_M31] = "uniwill-m31", + [ALC861_TOSHIBA] = "toshiba", + [ALC861_ASUS] = "asus", + [ALC861_ASUS_LAPTOP] = "asus-laptop", + [ALC861_AUTO] = "auto", +}; + +static struct snd_pci_quirk alc861_cfg_tbl[] = { + SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP), + SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP), + SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS), + SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660_3ST), + SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), + SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31), + SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST), {} }; @@ -7673,9 +7591,11 @@ static int patch_alc861(struct hda_codec *codec) codec->spec = spec; - board_config = snd_hda_check_board_config(codec, alc861_cfg_tbl); + board_config = snd_hda_check_board_config(codec, ALC861_MODEL_LAST, + alc861_models, + alc861_cfg_tbl); - if (board_config < 0 || board_config >= ALC861_MODEL_LAST) { + if (board_config < 0) { printk(KERN_INFO "hda_codec: Unknown model for ALC861, " "trying auto-probe from BIOS...\n"); board_config = ALC861_AUTO; diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index c8696ddc03a..cbaa00aa5b9 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -37,14 +37,30 @@ #define NUM_CONTROL_ALLOC 32 #define STAC_HP_EVENT 0x37 -#define STAC_REF 0 -#define STAC_D945GTP3 1 -#define STAC_D945GTP5 2 -#define STAC_MACMINI 3 -#define STAC_922X_MODELS 4 /* number of 922x models */ -#define STAC_D965_3ST 4 -#define STAC_D965_5ST 5 -#define STAC_927X_MODELS 6 /* number of 927x models */ +enum { + STAC_REF, + STAC_9200_MODELS +}; + +enum { + STAC_9205_REF, + STAC_9205_MODELS +}; + +enum { + STAC_D945_REF, + STAC_D945GTP3, + STAC_D945GTP5, + STAC_MACMINI, + STAC_922X_MODELS +}; + +enum { + STAC_D965_REF, + STAC_D965_3ST, + STAC_D965_5ST, + STAC_927X_MODELS +}; struct sigmatel_spec { struct snd_kcontrol_new *mixers[4]; @@ -373,22 +389,25 @@ static unsigned int ref9200_pin_configs[8] = { 0x02a19020, 0x01a19021, 0x90100140, 0x01813122, }; -static unsigned int *stac9200_brd_tbl[] = { - ref9200_pin_configs, +static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = { + [STAC_REF] = ref9200_pin_configs, }; -static struct hda_board_config stac9200_cfg_tbl[] = { - { .modelname = "ref", - .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0x2668, /* DFI LanParty */ - .config = STAC_REF }, +static const char *stac9200_models[STAC_9200_MODELS] = { + [STAC_REF] = "ref", +}; + +static struct snd_pci_quirk stac9200_cfg_tbl[] = { + /* SigmaTel reference board */ + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, + "DFI LanParty", STAC_REF), /* Dell laptops have BIOS problem */ - { .pci_subvendor = PCI_VENDOR_ID_DELL, .pci_subdevice = 0x01b5, - .config = STAC_REF }, /* Dell Inspiron 630m */ - { .pci_subvendor = PCI_VENDOR_ID_DELL, .pci_subdevice = 0x01c2, - .config = STAC_REF }, /* Dell Latitude D620 */ - { .pci_subvendor = PCI_VENDOR_ID_DELL, .pci_subdevice = 0x01cb, - .config = STAC_REF }, /* Dell Latitude 120L */ + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01b5, + "Dell Inspiron 630m", STAC_REF), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c2, + "Dell Latitude D620", STAC_REF), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cb, + "Dell Latitude 120L", STAC_REF), {} /* terminator */ }; @@ -411,100 +430,80 @@ static unsigned int d945gtp5_pin_configs[10] = { }; static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = { - [STAC_REF] = ref922x_pin_configs, + [STAC_D945_REF] = ref922x_pin_configs, [STAC_D945GTP3] = d945gtp3_pin_configs, [STAC_D945GTP5] = d945gtp5_pin_configs, [STAC_MACMINI] = d945gtp5_pin_configs, }; -static struct hda_board_config stac922x_cfg_tbl[] = { - { .modelname = "5stack", .config = STAC_D945GTP5 }, - { .modelname = "3stack", .config = STAC_D945GTP3 }, - { .modelname = "ref", - .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0x2668, /* DFI LanParty */ - .config = STAC_REF }, /* SigmaTel reference board */ - /* Intel 945G based systems */ - { .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0x0101, - .config = STAC_D945GTP3 }, /* Intel D945GTP - 3 Stack */ - { .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0x0202, - .config = STAC_D945GTP3 }, /* Intel D945GNT - 3 Stack */ - { .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0x0606, - .config = STAC_D945GTP3 }, /* Intel D945GTP - 3 Stack */ - { .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0x0601, - .config = STAC_D945GTP3 }, /* Intel D945GTP - 3 Stack */ - { .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0x0111, - .config = STAC_D945GTP3 }, /* Intel D945GZP - 3 Stack */ - { .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0x1115, - .config = STAC_D945GTP3 }, /* Intel D945GPM - 3 Stack */ - { .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0x1116, - .config = STAC_D945GTP3 }, /* Intel D945GBO - 3 Stack */ - { .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0x1117, - .config = STAC_D945GTP3 }, /* Intel D945GPM - 3 Stack */ - { .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0x1118, - .config = STAC_D945GTP3 }, /* Intel D945GPM - 3 Stack */ - { .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0x1119, - .config = STAC_D945GTP3 }, /* Intel D945GPM - 3 Stack */ - { .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0x8826, - .config = STAC_D945GTP3 }, /* Intel D945GPM - 3 Stack */ - { .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0x5049, - .config = STAC_D945GTP3 }, /* Intel D945GCZ - 3 Stack */ - { .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0x5055, - .config = STAC_D945GTP3 }, /* Intel D945GCZ - 3 Stack */ - { .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0x5048, - .config = STAC_D945GTP3 }, /* Intel D945GPB - 3 Stack */ - { .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0x0110, - .config = STAC_D945GTP3 }, /* Intel D945GLR - 3 Stack */ - { .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0x0404, - .config = STAC_D945GTP5 }, /* Intel D945GTP - 5 Stack */ - { .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0x0303, - .config = STAC_D945GTP5 }, /* Intel D945GNT - 5 Stack */ - { .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0x0013, - .config = STAC_D945GTP5 }, /* Intel D955XBK - 5 Stack */ - { .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0x0417, - .config = STAC_D945GTP5 }, /* Intel D975XBK - 5 Stack */ - /* Intel 945P based systems */ - { .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0x0b0b, - .config = STAC_D945GTP3 }, /* Intel D945PSN - 3 Stack */ - { .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0x0112, - .config = STAC_D945GTP3 }, /* Intel D945PLN - 3 Stack */ - { .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0x0d0d, - .config = STAC_D945GTP3 }, /* Intel D945PLM - 3 Stack */ - { .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0x0909, - .config = STAC_D945GTP3 }, /* Intel D945PAW - 3 Stack */ - { .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0x0505, - .config = STAC_D945GTP3 }, /* Intel D945PLM - 3 Stack */ - { .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0x0707, - .config = STAC_D945GTP5 }, /* Intel D945PSV - 5 Stack */ - /* other systems */ - { .pci_subvendor = 0x8384, - .pci_subdevice = 0x7680, - .config = STAC_MACMINI }, /* Apple Mac Mini (early 2006) */ +static const char *stac922x_models[STAC_922X_MODELS] = { + [STAC_D945_REF] = "ref", + [STAC_D945GTP5] = "5stack", + [STAC_D945GTP3] = "3stack", + [STAC_MACMINI] = "macmini", +}; + +static struct snd_pci_quirk stac922x_cfg_tbl[] = { + /* SigmaTel reference board */ + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, + "DFI LanParty", STAC_D945_REF), + /* Intel 945G based systems */ + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0101, + "Intel D945G", STAC_D945GTP3), + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0202, + "Intel D945G", STAC_D945GTP3), + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0606, + "Intel D945G", STAC_D945GTP3), + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0601, + "Intel D945G", STAC_D945GTP3), + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0111, + "Intel D945G", STAC_D945GTP3), + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1115, + "Intel D945G", STAC_D945GTP3), + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1116, + "Intel D945G", STAC_D945GTP3), + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1117, + "Intel D945G", STAC_D945GTP3), + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1118, + "Intel D945G", STAC_D945GTP3), + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1119, + "Intel D945G", STAC_D945GTP3), + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x8826, + "Intel D945G", STAC_D945GTP3), + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5049, + "Intel D945G", STAC_D945GTP3), + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5055, + "Intel D945G", STAC_D945GTP3), + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5048, + "Intel D945G", STAC_D945GTP3), + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0110, + "Intel D945G", STAC_D945GTP3), + /* Intel D945G 5-stack systems */ + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0404, + "Intel D945G", STAC_D945GTP5), + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0303, + "Intel D945G", STAC_D945GTP5), + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0013, + "Intel D945G", STAC_D945GTP5), + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0417, + "Intel D945G", STAC_D945GTP5), + /* Intel 945P based systems */ + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0b0b, + "Intel D945P", STAC_D945GTP3), + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0112, + "Intel D945P", STAC_D945GTP3), + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0d0d, + "Intel D945P", STAC_D945GTP3), + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0909, + "Intel D945P", STAC_D945GTP3), + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0505, + "Intel D945P", STAC_D945GTP3), + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0707, + "Intel D945P", STAC_D945GTP5), + /* other systems */ + /* Apple Mac Mini (early 2006) */ + SND_PCI_QUIRK(0x8384, 0x7680, + "Mac Mini", STAC_MACMINI), {} /* terminator */ }; @@ -530,102 +529,51 @@ static unsigned int d965_5st_pin_configs[14] = { }; static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = { - [STAC_REF] = ref927x_pin_configs, + [STAC_D965_REF] = ref927x_pin_configs, [STAC_D965_3ST] = d965_3st_pin_configs, [STAC_D965_5ST] = d965_5st_pin_configs, }; -static struct hda_board_config stac927x_cfg_tbl[] = { - { .modelname = "5stack", .config = STAC_D965_5ST }, - { .modelname = "3stack", .config = STAC_D965_3ST }, - { .modelname = "ref", - .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0x2668, /* DFI LanParty */ - .config = STAC_REF }, /* SigmaTel reference board */ +static const char *stac927x_models[STAC_927X_MODELS] = { + [STAC_D965_REF] = "ref", + [STAC_D965_3ST] = "3stack", + [STAC_D965_5ST] = "5stack", +}; + +static struct snd_pci_quirk stac927x_cfg_tbl[] = { + /* SigmaTel reference board */ + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, + "DFI LanParty", STAC_D965_REF), /* Intel 946 based systems */ - { .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0x3d01, - .config = STAC_D965_3ST }, /* D946 configuration */ - { .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0xa301, - .config = STAC_D965_3ST }, /* Intel D946GZT - 3 stack */ + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x3d01, "Intel D946", STAC_D965_3ST), + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xa301, "Intel D946", STAC_D965_3ST), /* 965 based 3 stack systems */ - { .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0x2116, - .config = STAC_D965_3ST }, /* Intel D965 3Stack config */ - { .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0x2115, - .config = STAC_D965_3ST }, /* Intel DQ965WC - 3 Stack */ - { .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0x2114, - .config = STAC_D965_3ST }, /* Intel D965 3Stack config */ - { .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0x2113, - .config = STAC_D965_3ST }, /* Intel D965 3Stack config */ - { .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0x2112, - .config = STAC_D965_3ST }, /* Intel DG965MS - 3 Stack */ - { .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0x2111, - .config = STAC_D965_3ST }, /* Intel D965 3Stack config */ - { .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0x2110, - .config = STAC_D965_3ST }, /* Intel D965 3Stack config */ - { .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0x2009, - .config = STAC_D965_3ST }, /* Intel D965 3Stack config */ - { .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0x2008, - .config = STAC_D965_3ST }, /* Intel DQ965GF - 3 Stack */ - { .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0x2007, - .config = STAC_D965_3ST }, /* Intel D965 3Stack config */ - { .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0x2006, - .config = STAC_D965_3ST }, /* Intel D965 3Stack config */ - { .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0x2005, - .config = STAC_D965_3ST }, /* Intel D965 3Stack config */ - { .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0x2004, - .config = STAC_D965_3ST }, /* Intel D965 3Stack config */ - { .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0x2003, - .config = STAC_D965_3ST }, /* Intel D965 3Stack config */ - { .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0x2002, - .config = STAC_D965_3ST }, /* Intel D965 3Stack config */ - { .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0x2001, - .config = STAC_D965_3ST }, /* Intel DQ965GF - 3 Stack */ + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2116, "Intel D965", STAC_D965_3ST), + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2115, "Intel D965", STAC_D965_3ST), + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2114, "Intel D965", STAC_D965_3ST), + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2113, "Intel D965", STAC_D965_3ST), + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2112, "Intel D965", STAC_D965_3ST), + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2111, "Intel D965", STAC_D965_3ST), + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2110, "Intel D965", STAC_D965_3ST), + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2009, "Intel D965", STAC_D965_3ST), + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2008, "Intel D965", STAC_D965_3ST), + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2007, "Intel D965", STAC_D965_3ST), + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2006, "Intel D965", STAC_D965_3ST), + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2005, "Intel D965", STAC_D965_3ST), + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2004, "Intel D965", STAC_D965_3ST), + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2003, "Intel D965", STAC_D965_3ST), + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2002, "Intel D965", STAC_D965_3ST), + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2001, "Intel D965", STAC_D965_3ST), /* 965 based 5 stack systems */ - { .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0x2301, - .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */ - { .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0x2302, - .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */ - { .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0x2303, - .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */ - { .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0x2304, - .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */ - { .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0x2305, - .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */ - { .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0x2501, - .config = STAC_D965_5ST }, /* Intel DG965MQ - 5 Stack */ - { .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0x2502, - .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */ - { .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0x2503, - .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */ - { .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0x2504, - .config = STAC_D965_5ST }, /* Intel DQ965GF - 5 Stack */ + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2301, "Intel D965", STAC_D965_5ST), + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2302, "Intel D965", STAC_D965_5ST), + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2303, "Intel D965", STAC_D965_5ST), + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2304, "Intel D965", STAC_D965_5ST), + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2305, "Intel D965", STAC_D965_5ST), + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2501, "Intel D965", STAC_D965_5ST), + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2502, "Intel D965", STAC_D965_5ST), + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2503, "Intel D965", STAC_D965_5ST), + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2504, "Intel D965", STAC_D965_5ST), {} /* terminator */ }; @@ -635,15 +583,18 @@ static unsigned int ref9205_pin_configs[12] = { 0x90a000f0, 0x90a000f0, 0x01441030, 0x01c41030 }; -static unsigned int *stac9205_brd_tbl[] = { +static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = { ref9205_pin_configs, }; -static struct hda_board_config stac9205_cfg_tbl[] = { - { .modelname = "ref", - .pci_subvendor = PCI_VENDOR_ID_INTEL, - .pci_subdevice = 0x2668, /* DFI LanParty */ - .config = STAC_REF }, /* SigmaTel reference board */ +static const char *stac9205_models[STAC_9205_MODELS] = { + [STAC_9205_REF] = "ref", +}; + +static struct snd_pci_quirk stac9205_cfg_tbl[] = { + /* SigmaTel reference board */ + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, + "DFI LanParty", STAC_9205_REF), {} /* terminator */ }; @@ -1710,7 +1661,9 @@ static int patch_stac9200(struct hda_codec *codec) codec->spec = spec; spec->num_pins = 8; spec->pin_nids = stac9200_pin_nids; - spec->board_config = snd_hda_check_board_config(codec, stac9200_cfg_tbl); + spec->board_config = snd_hda_check_board_config(codec, STAC_9200_MODELS, + stac9200_models, + stac9200_cfg_tbl); if (spec->board_config < 0) { snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n"); err = stac92xx_save_bios_config_regs(codec); @@ -1758,7 +1711,9 @@ static int patch_stac922x(struct hda_codec *codec) codec->spec = spec; spec->num_pins = 10; spec->pin_nids = stac922x_pin_nids; - spec->board_config = snd_hda_check_board_config(codec, stac922x_cfg_tbl); + spec->board_config = snd_hda_check_board_config(codec, STAC_922X_MODELS, + stac922x_models, + stac922x_cfg_tbl); if (spec->board_config < 0) { snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, " "using BIOS defaults\n"); @@ -1809,7 +1764,9 @@ static int patch_stac927x(struct hda_codec *codec) codec->spec = spec; spec->num_pins = 14; spec->pin_nids = stac927x_pin_nids; - spec->board_config = snd_hda_check_board_config(codec, stac927x_cfg_tbl); + spec->board_config = snd_hda_check_board_config(codec, STAC_927X_MODELS, + stac927x_models, + stac927x_cfg_tbl); if (spec->board_config < 0) { snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC927x, using BIOS defaults\n"); err = stac92xx_save_bios_config_regs(codec); @@ -1874,7 +1831,9 @@ static int patch_stac9205(struct hda_codec *codec) codec->spec = spec; spec->num_pins = 14; spec->pin_nids = stac9205_pin_nids; - spec->board_config = snd_hda_check_board_config(codec, stac9205_cfg_tbl); + spec->board_config = snd_hda_check_board_config(codec, STAC_9205_MODELS, + stac9205_models, + stac9205_cfg_tbl); if (spec->board_config < 0) { snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9205, using BIOS defaults\n"); err = stac92xx_save_bios_config_regs(codec); @@ -2083,18 +2042,19 @@ enum { /* FE and SZ series. id=0x83847661 and subsys=0x104D0700 or 104D1000. */ /* Unknown. id=0x83847661 and subsys=0x104D1200. */ STAC9872K_VAIO, /* AR Series. id=0x83847664 and subsys=104D1300 */ - CXD9872AKD_VAIO - }; - -static struct hda_board_config stac9872_cfg_tbl[] = { - { .modelname = "vaio", .config = CXD9872RD_VAIO }, - { .modelname = "vaio-ar", .config = CXD9872AKD_VAIO }, - { .pci_subvendor = 0x104d, .pci_subdevice = 0x81e6, - .config = CXD9872RD_VAIO }, - { .pci_subvendor = 0x104d, .pci_subdevice = 0x81ef, - .config = CXD9872RD_VAIO }, - { .pci_subvendor = 0x104d, .pci_subdevice = 0x81fd, - .config = CXD9872AKD_VAIO }, + CXD9872AKD_VAIO, + STAC_9872_MODELS, +}; + +static const char *stac9872_models[STAC_9872_MODELS] = { + [CXD9872RD_VAIO] = "vaio", + [CXD9872AKD_VAIO] = "vaio-ar", +}; + +static struct snd_pci_quirk stac9872_cfg_tbl[] = { + SND_PCI_QUIRK(0x104d, 0x81e6, "Sony VAIO F/S", CXD9872RD_VAIO), + SND_PCI_QUIRK(0x104d, 0x81ef, "Sony VAIO F/S", CXD9872RD_VAIO), + SND_PCI_QUIRK(0x104d, 0x81fd, "Sony VAIO AR", CXD9872AKD_VAIO), {} }; @@ -2103,7 +2063,9 @@ static int patch_stac9872(struct hda_codec *codec) struct sigmatel_spec *spec; int board_config; - board_config = snd_hda_check_board_config(codec, stac9872_cfg_tbl); + board_config = snd_hda_check_board_config(codec, STAC_9872_MODELS, + stac9872_models, + stac9872_cfg_tbl); if (board_config < 0) /* unknown config, let generic-parser do its job... */ return snd_hda_parse_generic_codec(codec); -- cgit v1.2.3 From 2e26e483694059d63bda7bb89d5a464c952d1d44 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Mon, 27 Nov 2006 12:05:04 +0100 Subject: [ALSA] ASoC - Bit clock matching error This patch by Philipp Zabel fixes a bug whereby the BCLK matching fails when the Codec BCLK is constant and the CPU BCLK is based upon a divider. Signed-off-by: Philipp Zabel Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/soc-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 6da1616bf77..90e8841e7e3 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -424,7 +424,7 @@ static int soc_hw_match_params(struct snd_pcm_substream *substream, /* normalise cpu bfs div & codec const mult */ codec_bfs = soc_bfs_rate_to_div(codec_dai_mode->bfs, rate, mclk, rtd->codec_dai->dai_runtime.pcmfmt, chn); - if(codec_dai_mode->bfs & codec_bfs) { + if(cpu_dai_mode->bfs & codec_bfs) { rtd->cpu_dai->dai_runtime.bfs = codec_bfs; rtd->codec_dai->dai_runtime.bfs = codec_dai_mode->bfs; } else -- cgit v1.2.3 From 86d72bdfcd34c9cd8acddf749ff130d5365fe279 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 28 Nov 2006 11:33:10 +0100 Subject: [ALSA] hda-codec - Fix compile warnings without CONFIG_SND_DEBUG Fix compile warnings (unused variables) in patch_conexant.c without CONFIG_SND_DEBUG. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_conexant.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index dec8f9747fc..73f4668238c 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -397,6 +397,9 @@ static int conexant_eapd_put(struct snd_kcontrol *kcontrol, return 1; } +/* controls for test mode */ +#ifdef CONFIG_SND_DEBUG + static int conexant_ch_mode_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -545,6 +548,8 @@ static int cxt_spdif_ctrl_put(struct snd_kcontrol *kcontrol, .put = cxt_spdif_ctrl_put, \ .private_value = nid | (mask<<16) } +#endif /* CONFIG_SND_DEBUG */ + /* Conexant 5045 specific */ static hda_nid_t cxt5045_dac_nids[1] = { 0x19 }; -- cgit v1.2.3 From bd869485993f73c303b565da5548bb4e77063c54 Mon Sep 17 00:00:00 2001 From: Jonathan Woithe Date: Tue, 28 Nov 2006 11:35:52 +0100 Subject: [ALSA] hda-codec - Make internal speaker work on Acer C20x tablets The following patch creates a new 'Mono speaker' control in alsamixer when the Realtek 'acer' model is used with hda_intel. This is needed so the internal mono speaker (when present) can be controlled. This new control won't do anything in Acer laptops which are not fitted with a mono speaker. Acer models which are known to have a mono speaker are the C20x tablet series but there may be others. I guess we could define a new model specifically for Acers with mono speakers but this seems a bit silly given that such a model will be identical to the normal 'acer' model except for this added control. This patch also adds the C20x tablets to the list of PCI ids associated with the 'acer' model. This means that owners of C20x machines will no longer have to supply 'model=acer' when loading hda_intel. Signed-off-by: Jonathan Woithe Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 415a6db4c90..a1b6c9661d4 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -3271,11 +3271,20 @@ static struct snd_kcontrol_new alc260_fujitsu_mixer[] = { * and the output jack. If this turns out to be the case for all such * models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT * to ALC_PIN_DIR_INOUT_NOMICBIAS. + * + * The C20x Tablet series have a mono internal speaker which is controlled + * via the chip's Mono sum widget and pin complex, so include the necessary + * controls for such models. On models without a "mono speaker" the control + * won't do anything. */ static struct snd_kcontrol_new alc260_acer_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT), ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT), + HDA_CODEC_VOLUME_MONO("Mono Speaker Playback Volume", 0x0a, 1, 0x0, + HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Mono Speaker Playback Switch", 0x0a, 1, 2, + HDA_INPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT), @@ -3590,11 +3599,11 @@ static struct hda_verb alc260_acer_init_verbs[] = { {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, /* Line In jack is connected to Line1 pin */ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + /* Some Acers (eg: C20x Tablets) use Mono pin for internal speaker */ + {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, /* Ensure all other unused pins are disabled and muted. */ {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, @@ -3622,6 +3631,8 @@ static struct hda_verb alc260_acer_init_verbs[] = { /* Unmute Line-out pin widget amp left and right (no equiv mixer ctrl) */ {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Unmute mono pin widget amp output (no equiv mixer ctrl) */ + {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Unmute Mic1 and Line1 pin widget input buffers since they start as * inputs. If the pin mode is changed by the user the pin mode control * will take care of enabling the pin's input/output buffers as needed. @@ -4122,6 +4133,7 @@ static const char *alc260_models[ALC260_MODEL_LAST] = { }; static struct snd_pci_quirk alc260_cfg_tbl[] = { + SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER), SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER), SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013), SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP), -- cgit v1.2.3 From d9c96cf35b70b484483446c92f27652f3aef977e Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 28 Nov 2006 12:10:09 +0100 Subject: [ALSA] sound/soc/soc-dapm.c: make 4 functions static Make the following needlessly global functions static: - dapm_power_widgets() - dapm_mux_update_power() - dapm_mixer_update_power() - dapm_free_widgets() Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/soc-dapm.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 2c2c27f4e9c..411651dc9d1 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -463,7 +463,7 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget) * o Input pin to Output pin (bypass, sidetone) * o DAC to ADC (loopback). */ -int dapm_power_widgets(struct snd_soc_codec *codec, int event) +static int dapm_power_widgets(struct snd_soc_codec *codec, int event) { struct snd_soc_dapm_widget *w; int in, out, i, c = 1, *seq = NULL, ret = 0, power_change, power; @@ -664,8 +664,9 @@ static void dbg_dump_dapm(struct snd_soc_codec* codec, const char *action) #endif /* test and update the power status of a mux widget */ -int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, - struct snd_kcontrol *kcontrol, int mask, int val, struct soc_enum* e) +static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, + struct snd_kcontrol *kcontrol, int mask, + int val, struct soc_enum* e) { struct snd_soc_dapm_path *path; int found = 0; @@ -697,11 +698,11 @@ int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, return 0; } -EXPORT_SYMBOL_GPL(dapm_mux_update_power); /* test and update the power status of a mixer widget */ -int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, - struct snd_kcontrol *kcontrol, int reg, int val_mask, int val, int invert) +static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, + struct snd_kcontrol *kcontrol, int reg, + int val_mask, int val, int invert) { struct snd_soc_dapm_path *path; int found = 0; @@ -733,7 +734,6 @@ int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, return 0; } -EXPORT_SYMBOL_GPL(dapm_mixer_update_power); /* show dapm widget status in sys fs */ static ssize_t dapm_widget_show(struct device *dev, @@ -808,7 +808,7 @@ static void snd_soc_dapm_sys_remove(struct device *dev) } /* free all dapm widgets and resources */ -void dapm_free_widgets(struct snd_soc_codec *codec) +static void dapm_free_widgets(struct snd_soc_codec *codec) { struct snd_soc_dapm_widget *w, *next_w; struct snd_soc_dapm_path *p, *next_p; -- cgit v1.2.3 From c577b8a16fd19a33a8865ca6451287d284a0faf6 Mon Sep 17 00:00:00 2001 From: Joseph Chan Date: Wed, 29 Nov 2006 15:29:40 +0100 Subject: [ALSA] hda-codec - Add support for VIA VT1708(A) HD audio codec This patch is VIA first release for HD audio codec, VT1708(A) and it provides geneneral HD audio driver features. Signed-off-by: Joseph Chan Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/Makefile | 3 +- sound/pci/hda/hda_codec.c | 1 + sound/pci/hda/hda_patch.h | 3 + sound/pci/hda/patch_via.c | 1396 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 1402 insertions(+), 1 deletion(-) create mode 100644 sound/pci/hda/patch_via.c (limited to 'sound') diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index 148140bb86b..60d7b05a204 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile @@ -7,7 +7,8 @@ snd-hda-codec-objs := hda_codec.o \ patch_sigmatel.o \ patch_si3054.o \ patch_atihdmi.o \ - patch_conexant.o + patch_conexant.o \ + patch_via.o ifdef CONFIG_PROC_FS snd-hda-codec-objs += hda_proc.o endif diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index c07d5db6b05..e14faf5d505 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -52,6 +52,7 @@ struct hda_vendor_id { static struct hda_vendor_id hda_vendor_ids[] = { { 0x10ec, "Realtek" }, { 0x1057, "Motorola" }, + { 0x1106, "VIA" }, { 0x11d4, "Analog Devices" }, { 0x13f6, "C-Media" }, { 0x14f1, "Conexant" }, diff --git a/sound/pci/hda/hda_patch.h b/sound/pci/hda/hda_patch.h index 5904ecd88a5..9f9e9ae44a9 100644 --- a/sound/pci/hda/hda_patch.h +++ b/sound/pci/hda/hda_patch.h @@ -16,6 +16,8 @@ extern struct hda_codec_preset snd_hda_preset_si3054[]; extern struct hda_codec_preset snd_hda_preset_atihdmi[]; /* Conexant audio codec */ extern struct hda_codec_preset snd_hda_preset_conexant[]; +/* VIA codecs */ +extern struct hda_codec_preset snd_hda_preset_via[]; static const struct hda_codec_preset *hda_preset_tables[] = { snd_hda_preset_realtek, @@ -25,5 +27,6 @@ static const struct hda_codec_preset *hda_preset_tables[] = { snd_hda_preset_si3054, snd_hda_preset_atihdmi, snd_hda_preset_conexant, + snd_hda_preset_via, NULL }; diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c new file mode 100644 index 00000000000..4c839b03172 --- /dev/null +++ b/sound/pci/hda/patch_via.c @@ -0,0 +1,1396 @@ +/* + * Universal Interface for Intel High Definition Audio Codec + * + * HD audio interface patch for VIA VT1708 codec + * + * Copyright (c) 2006 Lydia Wang + * Takashi Iwai + * + * This driver is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This driver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* * * * * * * * * * * * * * Release History * * * * * * * * * * * * * * * * */ +/* */ +/* 2006-03-03 Lydia Wang Create the basic patch to support VT1708 codec */ +/* 2006-03-14 Lydia Wang Modify hard code for some pin widget nid */ +/* 2006-08-02 Lydia Wang Add support to VT1709 codec */ +/* 2006-09-08 Lydia Wang Fix internal loopback recording source select bug */ +/* */ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + +#include +#include +#include +#include +#include +#include +#include "hda_codec.h" +#include "hda_local.h" + + +/* amp values */ +#define AMP_VAL_IDX_SHIFT 19 +#define AMP_VAL_IDX_MASK (0x0f<<19) + +#define NUM_CONTROL_ALLOC 32 +#define NUM_VERB_ALLOC 32 + +/* Pin Widget NID */ +#define VT1708_HP_NID 0x13 +#define VT1708_DIGOUT_NID 0x14 +#define VT1708_DIGIN_NID 0x16 + +#define VT1709_HP_DAC_NID 0x28 +#define VT1709_DIGOUT_NID 0x13 +#define VT1709_DIGIN_NID 0x17 + +#define IS_VT1708_VENDORID(x) ((x) >= 0x11061708 && (x) <= 0x1106170b) +#define IS_VT1709_10CH_VENDORID(x) ((x) >= 0x1106e710 && (x) <= 0x1106e713) +#define IS_VT1709_6CH_VENDORID(x) ((x) >= 0x1106e714 && (x) <= 0x1106e717) + + +enum { + VIA_CTL_WIDGET_VOL, + VIA_CTL_WIDGET_MUTE, +}; + +enum { + AUTO_SEQ_FRONT, + AUTO_SEQ_SURROUND, + AUTO_SEQ_CENLFE, + AUTO_SEQ_SIDE +}; + +static struct snd_kcontrol_new vt1708_control_templates[] = { + HDA_CODEC_VOLUME(NULL, 0, 0, 0), + HDA_CODEC_MUTE(NULL, 0, 0, 0), +}; + + +struct via_spec { + /* codec parameterization */ + struct snd_kcontrol_new *mixers[3]; + unsigned int num_mixers; + + struct hda_verb *init_verbs; + + char *stream_name_analog; + struct hda_pcm_stream *stream_analog_playback; + struct hda_pcm_stream *stream_analog_capture; + + char *stream_name_digital; + struct hda_pcm_stream *stream_digital_playback; + struct hda_pcm_stream *stream_digital_capture; + + /* playback */ + struct hda_multi_out multiout; + + /* capture */ + unsigned int num_adc_nids; + hda_nid_t *adc_nids; + hda_nid_t dig_in_nid; + + /* capture source */ + const struct hda_input_mux *input_mux; + unsigned int cur_mux[3]; + + /* PCM information */ + struct hda_pcm pcm_rec[2]; + + /* dynamic controls, init_verbs and input_mux */ + struct auto_pin_cfg autocfg; + unsigned int num_kctl_alloc, num_kctl_used; + struct snd_kcontrol_new *kctl_alloc; + struct hda_input_mux private_imux; + hda_nid_t private_dac_nids[4]; +}; + +static hda_nid_t vt1708_adc_nids[2] = { + /* ADC1-2 */ + 0x15, 0x27 +}; + +static hda_nid_t vt1709_adc_nids[3] = { + /* ADC1-2 */ + 0x14, 0x15, 0x16 +}; + +/* add dynamic controls */ +static int via_add_control(struct via_spec *spec, int type, const char *name, + unsigned long val) +{ + struct snd_kcontrol_new *knew; + + if (spec->num_kctl_used >= spec->num_kctl_alloc) { + int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC; + + /* array + terminator */ + knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); + if (!knew) + return -ENOMEM; + if (spec->kctl_alloc) { + memcpy(knew, spec->kctl_alloc, + sizeof(*knew) * spec->num_kctl_alloc); + kfree(spec->kctl_alloc); + } + spec->kctl_alloc = knew; + spec->num_kctl_alloc = num; + } + + knew = &spec->kctl_alloc[spec->num_kctl_used]; + *knew = vt1708_control_templates[type]; + knew->name = kstrdup(name, GFP_KERNEL); + + if (!knew->name) + return -ENOMEM; + knew->private_value = val; + spec->num_kctl_used++; + return 0; +} + +/* create input playback/capture controls for the given pin */ +static int via_new_analog_input(struct via_spec *spec, hda_nid_t pin, + const char *ctlname, int idx, int mix_nid) +{ + char name[32]; + int err; + + sprintf(name, "%s Playback Volume", ctlname); + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, + HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT)); + if (err < 0) + return err; + sprintf(name, "%s Playback Switch", ctlname); + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, + HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT)); + if (err < 0) + return err; + return 0; +} + +static void via_auto_set_output_and_unmute(struct hda_codec *codec, + hda_nid_t nid, int pin_type, + int dac_idx) +{ + /* set as output */ + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + pin_type); + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, + AMP_OUT_UNMUTE); +} + + +static void via_auto_init_multi_out(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + int i; + + for (i = 0; i <= AUTO_SEQ_SIDE; i++) { + hda_nid_t nid = spec->autocfg.line_out_pins[i]; + if (nid) + via_auto_set_output_and_unmute(codec, nid, PIN_OUT, i); + } +} + +static void via_auto_init_hp_out(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + hda_nid_t pin; + + pin = spec->autocfg.hp_pins[0]; + if (pin) /* connect to front */ + via_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); +} + +static void via_auto_init_analog_input(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + int i; + + for (i = 0; i < AUTO_PIN_LAST; i++) { + hda_nid_t nid = spec->autocfg.input_pins[i]; + + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + (i <= AUTO_PIN_FRONT_MIC ? + PIN_VREF50 : PIN_IN)); + + } +} +/* + * input MUX handling + */ +static int via_mux_enum_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct via_spec *spec = codec->spec; + return snd_hda_input_mux_info(spec->input_mux, uinfo); +} + +static int via_mux_enum_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct via_spec *spec = codec->spec; + unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + + ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx]; + return 0; +} + +static int via_mux_enum_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct via_spec *spec = codec->spec; + unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + unsigned int vendor_id = codec->vendor_id; + + /* AIW0 lydia 060801 add for correct sw0 input select */ + if (IS_VT1708_VENDORID(vendor_id) && (adc_idx == 0)) + return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, + 0x18, &spec->cur_mux[adc_idx]); + else if ((IS_VT1709_10CH_VENDORID(vendor_id) || + IS_VT1709_6CH_VENDORID(vendor_id)) && (adc_idx == 0) ) + return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, + 0x19, &spec->cur_mux[adc_idx]); + else + return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, + spec->adc_nids[adc_idx], + &spec->cur_mux[adc_idx]); +} + +/* capture mixer elements */ +static struct snd_kcontrol_new vt1708_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x27, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x27, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* The multiple "Capture Source" controls confuse alsamixer + * So call somewhat different.. + * FIXME: the controls appear in the "playback" view! + */ + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 1, + .info = via_mux_enum_info, + .get = via_mux_enum_get, + .put = via_mux_enum_put, + }, + { } /* end */ +}; +/* + * generic initialization of ADC, input mixers and output mixers + */ +static struct hda_verb vt1708_volume_init_verbs[] = { + /* + * Unmute ADC0-1 and set the default input to mic-in + */ + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + + /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + * mixer widget + */ + /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + + /* + * Set up output mixers (0x19 - 0x1b) + */ + /* set vol=0 to output mixers */ + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + /* Setup default input to PW4 */ + {0x20, AC_VERB_SET_CONNECT_SEL, 0x1}, + /* Set mic as default input of sw0 */ + {0x18, AC_VERB_SET_CONNECT_SEL, 0x2}, + /* PW9 Output enable */ + {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, +}; + +static int via_playback_pcm_open(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct via_spec *spec = codec->spec; + return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream); +} + +static int via_playback_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + struct snd_pcm_substream *substream) +{ + struct via_spec *spec = codec->spec; + return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, + stream_tag, format, substream); +} + +static int via_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct via_spec *spec = codec->spec; + return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); +} + +/* + * Digital out + */ +static int via_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct via_spec *spec = codec->spec; + return snd_hda_multi_out_dig_open(codec, &spec->multiout); +} + +static int via_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct via_spec *spec = codec->spec; + return snd_hda_multi_out_dig_close(codec, &spec->multiout); +} + +/* + * Analog capture + */ +static int via_capture_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + struct snd_pcm_substream *substream) +{ + struct via_spec *spec = codec->spec; + + snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], + stream_tag, 0, format); + return 0; +} + +static int via_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct via_spec *spec = codec->spec; + snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], + 0, 0, 0); + return 0; +} + +static struct hda_pcm_stream vt1708_pcm_analog_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 8, + .nid = 0x10, /* NID to query formats and rates */ + .ops = { + .open = via_playback_pcm_open, + .prepare = via_playback_pcm_prepare, + .cleanup = via_playback_pcm_cleanup + }, +}; + +static struct hda_pcm_stream vt1708_pcm_analog_capture = { + .substreams = 2, + .channels_min = 2, + .channels_max = 2, + .nid = 0x15, /* NID to query formats and rates */ + .ops = { + .prepare = via_capture_pcm_prepare, + .cleanup = via_capture_pcm_cleanup + }, +}; + +static struct hda_pcm_stream vt1708_pcm_digital_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + /* NID is set in via_build_pcms */ + .ops = { + .open = via_dig_playback_pcm_open, + .close = via_dig_playback_pcm_close + }, +}; + +static struct hda_pcm_stream vt1708_pcm_digital_capture = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, +}; + +static int via_build_controls(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + int err; + int i; + + for (i = 0; i < spec->num_mixers; i++) { + err = snd_hda_add_new_ctls(codec, spec->mixers[i]); + if (err < 0) + return err; + } + + if (spec->multiout.dig_out_nid) { + err = snd_hda_create_spdif_out_ctls(codec, + spec->multiout.dig_out_nid); + if (err < 0) + return err; + } + if (spec->dig_in_nid) { + err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); + if (err < 0) + return err; + } + return 0; +} + +static int via_build_pcms(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + struct hda_pcm *info = spec->pcm_rec; + + codec->num_pcms = 1; + codec->pcm_info = info; + + info->name = spec->stream_name_analog; + info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback); + info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0]; + info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture); + info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; + + info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = + spec->multiout.max_channels; + + if (spec->multiout.dig_out_nid || spec->dig_in_nid) { + codec->num_pcms++; + info++; + info->name = spec->stream_name_digital; + if (spec->multiout.dig_out_nid) { + info->stream[SNDRV_PCM_STREAM_PLAYBACK] = + *(spec->stream_digital_playback); + info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = + spec->multiout.dig_out_nid; + } + if (spec->dig_in_nid) { + info->stream[SNDRV_PCM_STREAM_CAPTURE] = + *(spec->stream_digital_capture); + info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = + spec->dig_in_nid; + } + } + + return 0; +} + +static void via_free(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + unsigned int i; + + if (!spec) + return; + + if (spec->kctl_alloc) { + for (i = 0; i < spec->num_kctl_used; i++) + kfree(spec->kctl_alloc[i].name); + kfree(spec->kctl_alloc); + } + + kfree(codec->spec); +} + +static int via_init(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + snd_hda_sequence_write(codec, spec->init_verbs); + return 0; +} + +#ifdef CONFIG_PM +/* + * resume + */ +static int via_resume(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + int i; + + via_init(codec); + for (i = 0; i < spec->num_mixers; i++) + snd_hda_resume_ctls(codec, spec->mixers[i]); + if (spec->multiout.dig_out_nid) + snd_hda_resume_spdif_out(codec); + if (spec->dig_in_nid) + snd_hda_resume_spdif_in(codec); + + return 0; +} +#endif + +/* + */ +static struct hda_codec_ops via_patch_ops = { + .build_controls = via_build_controls, + .build_pcms = via_build_pcms, + .init = via_init, + .free = via_free, +#ifdef CONFIG_PM + .resume = via_resume, +#endif +}; + +/* fill in the dac_nids table from the parsed pin configuration */ +static int vt1708_auto_fill_dac_nids(struct via_spec *spec, + const struct auto_pin_cfg *cfg) +{ + int i; + hda_nid_t nid; + + spec->multiout.num_dacs = cfg->line_outs; + + spec->multiout.dac_nids = spec->private_dac_nids; + + for(i = 0; i < 4; i++) { + nid = cfg->line_out_pins[i]; + if (nid) { + /* config dac list */ + switch (i) { + case AUTO_SEQ_FRONT: + spec->multiout.dac_nids[i] = 0x10; + break; + case AUTO_SEQ_CENLFE: + spec->multiout.dac_nids[i] = 0x12; + break; + case AUTO_SEQ_SURROUND: + spec->multiout.dac_nids[i] = 0x13; + break; + case AUTO_SEQ_SIDE: + spec->multiout.dac_nids[i] = 0x11; + break; + } + } + } + + return 0; +} + +/* add playback controls from the parsed DAC table */ +static int vt1708_auto_create_multi_out_ctls(struct via_spec *spec, + const struct auto_pin_cfg *cfg) +{ + char name[32]; + static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" }; + hda_nid_t nid, nid_vol = 0; + int i, err; + + for (i = 0; i <= AUTO_SEQ_SIDE; i++) { + nid = cfg->line_out_pins[i]; + + if (!nid) + continue; + + if (i != AUTO_SEQ_FRONT) + nid_vol = 0x1b - i + 1; + + if (i == AUTO_SEQ_CENLFE) { + /* Center/LFE */ + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Center Playback Volume", + HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "LFE Playback Volume", + HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Center Playback Switch", + HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "LFE Playback Switch", + HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT)); + if (err < 0) + return err; + } else if (i == AUTO_SEQ_FRONT){ + /* add control to mixer index 0 */ + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Master Front Playback Volume", + HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_INPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Master Front Playback Switch", + HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_INPUT)); + if (err < 0) + return err; + + /* add control to PW3 */ + sprintf(name, "%s Playback Volume", chname[i]); + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, + HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + sprintf(name, "%s Playback Switch", chname[i]); + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, + HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + } else { + sprintf(name, "%s Playback Volume", chname[i]); + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + sprintf(name, "%s Playback Switch", chname[i]); + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + } + } + + return 0; +} + +static int vt1708_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) +{ + int err; + + if (!pin) + return 0; + + spec->multiout.hp_nid = VT1708_HP_NID; /* AOW3 */ + + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Headphone Playback Volume", + HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Headphone Playback Switch", + HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + + return 0; +} + +/* create playback/capture controls for input pins */ +static int vt1708_auto_create_analog_input_ctls(struct via_spec *spec, + const struct auto_pin_cfg *cfg) +{ + static char *labels[] = { + "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL + }; + struct hda_input_mux *imux = &spec->private_imux; + int i, err, idx = 0; + + /* for internal loopback recording select */ + imux->items[imux->num_items].label = "Stereo Mixer"; + imux->items[imux->num_items].index = idx; + imux->num_items++; + + for (i = 0; i < AUTO_PIN_LAST; i++) { + if (!cfg->input_pins[i]) + continue; + + switch (cfg->input_pins[i]) { + case 0x1d: /* Mic */ + idx = 2; + break; + + case 0x1e: /* Line In */ + idx = 3; + break; + + case 0x21: /* Front Mic */ + idx = 4; + break; + + case 0x24: /* CD */ + idx = 1; + break; + } + err = via_new_analog_input(spec, cfg->input_pins[i], labels[i], + idx, 0x17); + if (err < 0) + return err; + imux->items[imux->num_items].label = labels[i]; + imux->items[imux->num_items].index = idx; + imux->num_items++; + } + return 0; +} + +static int vt1708_parse_auto_config(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + int err; + + err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); + if (err < 0) + return err; + err = vt1708_auto_fill_dac_nids(spec, &spec->autocfg); + if (err < 0) + return err; + if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0]) + return 0; /* can't find valid BIOS pin config */ + + err = vt1708_auto_create_multi_out_ctls(spec, &spec->autocfg); + if (err < 0) + return err; + err = vt1708_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); + if (err < 0) + return err; + err = vt1708_auto_create_analog_input_ctls(spec, &spec->autocfg); + if (err < 0) + return err; + + spec->multiout.max_channels = spec->multiout.num_dacs * 2; + + if (spec->autocfg.dig_out_pin) + spec->multiout.dig_out_nid = VT1708_DIGOUT_NID; + if (spec->autocfg.dig_in_pin) + spec->dig_in_nid = VT1708_DIGIN_NID; + + if (spec->kctl_alloc) + spec->mixers[spec->num_mixers++] = spec->kctl_alloc; + + spec->init_verbs = vt1708_volume_init_verbs; + + spec->input_mux = &spec->private_imux; + + return 1; +} + +/* init callback for auto-configuration model -- overriding the default init */ +static int via_auto_init(struct hda_codec *codec) +{ + via_init(codec); + via_auto_init_multi_out(codec); + via_auto_init_hp_out(codec); + via_auto_init_analog_input(codec); + return 0; +} + +static int patch_vt1708(struct hda_codec *codec) +{ + struct via_spec *spec; + int err; + + /* create a codec specific record */ + spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; + + codec->spec = spec; + + /* automatic parse from the BIOS config */ + err = vt1708_parse_auto_config(codec); + if (err < 0) { + via_free(codec); + return err; + } else if (!err) { + printk(KERN_INFO "hda_codec: Cannot set up configuration " + "from BIOS. Using genenic mode...\n"); + } + + + spec->stream_name_analog = "VT1708 Analog"; + spec->stream_analog_playback = &vt1708_pcm_analog_playback; + spec->stream_analog_capture = &vt1708_pcm_analog_capture; + + spec->stream_name_digital = "VT1708 Digital"; + spec->stream_digital_playback = &vt1708_pcm_digital_playback; + spec->stream_digital_capture = &vt1708_pcm_digital_capture; + + + if (!spec->adc_nids && spec->input_mux) { + spec->adc_nids = vt1708_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(vt1708_adc_nids); + spec->mixers[spec->num_mixers] = vt1708_capture_mixer; + spec->num_mixers++; + } + + codec->patch_ops = via_patch_ops; + + codec->patch_ops.init = via_auto_init; + + return 0; +} + +/* capture mixer elements */ +static struct snd_kcontrol_new vt1709_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x14, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x15, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x15, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x16, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x16, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* The multiple "Capture Source" controls confuse alsamixer + * So call somewhat different.. + * FIXME: the controls appear in the "playback" view! + */ + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 1, + .info = via_mux_enum_info, + .get = via_mux_enum_get, + .put = via_mux_enum_put, + }, + { } /* end */ +}; + +/* + * generic initialization of ADC, input mixers and output mixers + */ +static struct hda_verb vt1709_10ch_volume_init_verbs[] = { + /* + * Unmute ADC0-2 and set the default input to mic-in + */ + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + + /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + * mixer widget + */ + /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + + /* + * Set up output selector (0x1a, 0x1b, 0x29) + */ + /* set vol=0 to output mixers */ + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + /* + * Unmute PW3 and PW4 + */ + {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + /* Set input of PW4 as AOW4 */ + {0x20, AC_VERB_SET_CONNECT_SEL, 0x1}, + /* Set mic as default input of sw0 */ + {0x19, AC_VERB_SET_CONNECT_SEL, 0x2}, + /* PW9 Output enable */ + {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + { } +}; + +static struct hda_pcm_stream vt1709_10ch_pcm_analog_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 10, + .nid = 0x10, /* NID to query formats and rates */ + .ops = { + .open = via_playback_pcm_open, + .prepare = via_playback_pcm_prepare, + .cleanup = via_playback_pcm_cleanup + }, +}; + +static struct hda_pcm_stream vt1709_6ch_pcm_analog_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 6, + .nid = 0x10, /* NID to query formats and rates */ + .ops = { + .open = via_playback_pcm_open, + .prepare = via_playback_pcm_prepare, + .cleanup = via_playback_pcm_cleanup + }, +}; + +static struct hda_pcm_stream vt1709_pcm_analog_capture = { + .substreams = 2, + .channels_min = 2, + .channels_max = 2, + .nid = 0x14, /* NID to query formats and rates */ + .ops = { + .prepare = via_capture_pcm_prepare, + .cleanup = via_capture_pcm_cleanup + }, +}; + +static struct hda_pcm_stream vt1709_pcm_digital_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + /* NID is set in via_build_pcms */ + .ops = { + .open = via_dig_playback_pcm_open, + .close = via_dig_playback_pcm_close + }, +}; + +static struct hda_pcm_stream vt1709_pcm_digital_capture = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, +}; + +static int vt1709_auto_fill_dac_nids(struct via_spec *spec, + const struct auto_pin_cfg *cfg) +{ + int i; + hda_nid_t nid; + + if (cfg->line_outs == 4) /* 10 channels */ + spec->multiout.num_dacs = cfg->line_outs+1; /* AOW0~AOW4 */ + else if (cfg->line_outs == 3) /* 6 channels */ + spec->multiout.num_dacs = cfg->line_outs; /* AOW0~AOW2 */ + + spec->multiout.dac_nids = spec->private_dac_nids; + + if (cfg->line_outs == 4) { /* 10 channels */ + for (i = 0; i < cfg->line_outs; i++) { + nid = cfg->line_out_pins[i]; + if (nid) { + /* config dac list */ + switch (i) { + case AUTO_SEQ_FRONT: + /* AOW0 */ + spec->multiout.dac_nids[i] = 0x10; + break; + case AUTO_SEQ_CENLFE: + /* AOW2 */ + spec->multiout.dac_nids[i] = 0x12; + break; + case AUTO_SEQ_SURROUND: + /* AOW3 */ + spec->multiout.dac_nids[i] = 0x27; + break; + case AUTO_SEQ_SIDE: + /* AOW1 */ + spec->multiout.dac_nids[i] = 0x11; + break; + default: + break; + } + } + } + spec->multiout.dac_nids[cfg->line_outs] = 0x28; /* AOW4 */ + + } else if (cfg->line_outs == 3) { /* 6 channels */ + for(i = 0; i < cfg->line_outs; i++) { + nid = cfg->line_out_pins[i]; + if (nid) { + /* config dac list */ + switch(i) { + case AUTO_SEQ_FRONT: + /* AOW0 */ + spec->multiout.dac_nids[i] = 0x10; + break; + case AUTO_SEQ_CENLFE: + /* AOW2 */ + spec->multiout.dac_nids[i] = 0x12; + break; + case AUTO_SEQ_SURROUND: + /* AOW1 */ + spec->multiout.dac_nids[i] = 0x11; + break; + default: + break; + } + } + } + } + + return 0; +} + +/* add playback controls from the parsed DAC table */ +static int vt1709_auto_create_multi_out_ctls(struct via_spec *spec, + const struct auto_pin_cfg *cfg) +{ + char name[32]; + static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" }; + hda_nid_t nid = 0; + int i, err; + + for (i = 0; i <= AUTO_SEQ_SIDE; i++) { + nid = cfg->line_out_pins[i]; + + if (!nid) + continue; + + if (i == AUTO_SEQ_CENLFE) { + /* Center/LFE */ + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Center Playback Volume", + HDA_COMPOSE_AMP_VAL(0x1b, 1, 0, HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "LFE Playback Volume", + HDA_COMPOSE_AMP_VAL(0x1b, 2, 0, HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Center Playback Switch", + HDA_COMPOSE_AMP_VAL(0x1b, 1, 0, HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "LFE Playback Switch", + HDA_COMPOSE_AMP_VAL(0x1b, 2, 0, HDA_OUTPUT)); + if (err < 0) + return err; + } else if (i == AUTO_SEQ_FRONT){ + /* add control to mixer index 0 */ + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Master Front Playback Volume", + HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Master Front Playback Switch", + HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT)); + if (err < 0) + return err; + + /* add control to PW3 */ + sprintf(name, "%s Playback Volume", chname[i]); + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, + HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + sprintf(name, "%s Playback Switch", chname[i]); + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, + HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + } else if (i == AUTO_SEQ_SURROUND) { + sprintf(name, "%s Playback Volume", chname[i]); + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, + HDA_COMPOSE_AMP_VAL(0x29, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + sprintf(name, "%s Playback Switch", chname[i]); + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, + HDA_COMPOSE_AMP_VAL(0x29, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + } else if (i == AUTO_SEQ_SIDE) { + sprintf(name, "%s Playback Volume", chname[i]); + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, + HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + sprintf(name, "%s Playback Switch", chname[i]); + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, + HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + } + } + + return 0; +} + +static int vt1709_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) +{ + int err; + + if (!pin) + return 0; + + if (spec->multiout.num_dacs == 5) /* 10 channels */ + spec->multiout.hp_nid = VT1709_HP_DAC_NID; + else if (spec->multiout.num_dacs == 3) /* 6 channels */ + spec->multiout.hp_nid = 0; + + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Headphone Playback Volume", + HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Headphone Playback Switch", + HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + + return 0; +} + +/* create playback/capture controls for input pins */ +static int vt1709_auto_create_analog_input_ctls(struct via_spec *spec, + const struct auto_pin_cfg *cfg) +{ + static char *labels[] = { + "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL + }; + struct hda_input_mux *imux = &spec->private_imux; + int i, err, idx = 0; + + /* for internal loopback recording select */ + imux->items[imux->num_items].label = "Stereo Mixer"; + imux->items[imux->num_items].index = idx; + imux->num_items++; + + for (i = 0; i < AUTO_PIN_LAST; i++) { + if (!cfg->input_pins[i]) + continue; + + switch (cfg->input_pins[i]) { + case 0x1d: /* Mic */ + idx = 2; + break; + + case 0x1e: /* Line In */ + idx = 3; + break; + + case 0x21: /* Front Mic */ + idx = 4; + break; + + case 0x23: /* CD */ + idx = 1; + break; + } + err = via_new_analog_input(spec, cfg->input_pins[i], labels[i], + idx, 0x18); + if (err < 0) + return err; + imux->items[imux->num_items].label = labels[i]; + imux->items[imux->num_items].index = idx; + imux->num_items++; + } + return 0; +} + +static int vt1709_parse_auto_config(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + int err; + + err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); + if (err < 0) + return err; + err = vt1709_auto_fill_dac_nids(spec, &spec->autocfg); + if (err < 0) + return err; + if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0]) + return 0; /* can't find valid BIOS pin config */ + + err = vt1709_auto_create_multi_out_ctls(spec, &spec->autocfg); + if (err < 0) + return err; + err = vt1709_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); + if (err < 0) + return err; + err = vt1709_auto_create_analog_input_ctls(spec, &spec->autocfg); + if (err < 0) + return err; + + spec->multiout.max_channels = spec->multiout.num_dacs * 2; + + if (spec->autocfg.dig_out_pin) + spec->multiout.dig_out_nid = VT1709_DIGOUT_NID; + if (spec->autocfg.dig_in_pin) + spec->dig_in_nid = VT1709_DIGIN_NID; + + if (spec->kctl_alloc) + spec->mixers[spec->num_mixers++] = spec->kctl_alloc; + + spec->input_mux = &spec->private_imux; + + return 1; +} + +static int patch_vt1709_10ch(struct hda_codec *codec) +{ + struct via_spec *spec; + int err; + + /* create a codec specific record */ + spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; + + codec->spec = spec; + + err = vt1709_parse_auto_config(codec); + if (err < 0) { + via_free(codec); + return err; + } else if (!err) { + printk(KERN_INFO "hda_codec: Cannot set up configuration. " + "Using genenic mode...\n"); + } + + spec->init_verbs = vt1709_10ch_volume_init_verbs; + + spec->stream_name_analog = "VT1709 Analog"; + spec->stream_analog_playback = &vt1709_10ch_pcm_analog_playback; + spec->stream_analog_capture = &vt1709_pcm_analog_capture; + + spec->stream_name_digital = "VT1709 Digital"; + spec->stream_digital_playback = &vt1709_pcm_digital_playback; + spec->stream_digital_capture = &vt1709_pcm_digital_capture; + + + if (!spec->adc_nids && spec->input_mux) { + spec->adc_nids = vt1709_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids); + spec->mixers[spec->num_mixers] = vt1709_capture_mixer; + spec->num_mixers++; + } + + codec->patch_ops = via_patch_ops; + + codec->patch_ops.init = via_auto_init; + + return 0; +} +/* + * generic initialization of ADC, input mixers and output mixers + */ +static struct hda_verb vt1709_6ch_volume_init_verbs[] = { + /* + * Unmute ADC0-2 and set the default input to mic-in + */ + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + + /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + * mixer widget + */ + /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + + /* + * Set up output selector (0x1a, 0x1b, 0x29) + */ + /* set vol=0 to output mixers */ + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + /* + * Unmute PW3 and PW4 + */ + {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + /* Set input of PW4 as MW0 */ + {0x20, AC_VERB_SET_CONNECT_SEL, 0}, + /* Set mic as default input of sw0 */ + {0x19, AC_VERB_SET_CONNECT_SEL, 0x2}, + /* PW9 Output enable */ + {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + { } +}; + +static int patch_vt1709_6ch(struct hda_codec *codec) +{ + struct via_spec *spec; + int err; + + /* create a codec specific record */ + spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; + + codec->spec = spec; + + err = vt1709_parse_auto_config(codec); + if (err < 0) { + via_free(codec); + return err; + } else if (!err) { + printk(KERN_INFO "hda_codec: Cannot set up configuration. " + "Using genenic mode...\n"); + } + + spec->init_verbs = vt1709_6ch_volume_init_verbs; + + spec->stream_name_analog = "VT1709 Analog"; + spec->stream_analog_playback = &vt1709_6ch_pcm_analog_playback; + spec->stream_analog_capture = &vt1709_pcm_analog_capture; + + spec->stream_name_digital = "VT1709 Digital"; + spec->stream_digital_playback = &vt1709_pcm_digital_playback; + spec->stream_digital_capture = &vt1709_pcm_digital_capture; + + + if (!spec->adc_nids && spec->input_mux) { + spec->adc_nids = vt1709_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids); + spec->mixers[spec->num_mixers] = vt1709_capture_mixer; + spec->num_mixers++; + } + + codec->patch_ops = via_patch_ops; + + codec->patch_ops.init = via_auto_init; + + return 0; +} + +/* + * patch entries + */ +struct hda_codec_preset snd_hda_preset_via[] = { + { .id = 0x11061708, .name = "VIA VT1708", .patch = patch_vt1708}, + { .id = 0x11061709, .name = "VIA VT1708", .patch = patch_vt1708}, + { .id = 0x1106170A, .name = "VIA VT1708", .patch = patch_vt1708}, + { .id = 0x1106170B, .name = "VIA VT1708", .patch = patch_vt1708}, + { .id = 0x1106E710, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch}, + { .id = 0x1106E711, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch}, + { .id = 0x1106E712, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch}, + { .id = 0x1106E713, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch}, + { .id = 0x1106E714, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch}, + { .id = 0x1106E715, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch}, + { .id = 0x1106E716, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch}, + { .id = 0x1106E717, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch}, + {} /* terminator */ +}; -- cgit v1.2.3 From 9ed1261e3e617d99b0eb74041d0337ff664e4f5b Mon Sep 17 00:00:00 2001 From: Teru KAMOGASHIRA Date: Mon, 4 Dec 2006 18:03:53 +0100 Subject: [ALSA] Current driver does not utilize 44.1kHz high quality sampling rate converter. Following patch will make the driver to use the 44.1kHz SRC automatically if the pcm source is 44.1kHz signed 16bit stereo. The SRC is available in YMF754 only. Signed-off-by: Teru KAMOGASHIRA Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela --- sound/pci/ymfpci/ymfpci_main.c | 44 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c index 5bde816cd5c..8b076932f4f 100644 --- a/sound/pci/ymfpci/ymfpci_main.c +++ b/sound/pci/ymfpci/ymfpci_main.c @@ -171,6 +171,17 @@ static u32 snd_ymfpci_calc_lpfQ(u32 rate) return val[0]; } +static void snd_ymfpci_pcm_441_volume_set(struct snd_ymfpci_pcm *ypcm) +{ + unsigned int value; + struct snd_ymfpci_pcm_mixer *mixer; + + mixer = &ypcm->chip->pcm_mixer[ypcm->substream->number]; + value = min_t(unsigned int, mixer->left, 0x7fff) >> 1; + value |= (min_t(unsigned int, mixer->right, 0x7fff) >> 1) << 16; + snd_ymfpci_writel(ypcm->chip, YDSXGR_BUF441OUTVOL, value); +} + /* * Hardware start management */ @@ -282,6 +293,10 @@ static int snd_ymfpci_voice_free(struct snd_ymfpci *chip, struct snd_ymfpci_voic snd_assert(pvoice != NULL, return -EINVAL); snd_ymfpci_hw_stop(chip); spin_lock_irqsave(&chip->voice_lock, flags); + if (pvoice->number == chip->src441_used) { + chip->src441_used = -1; + pvoice->ypcm->use_441_slot = 0; + } pvoice->use = pvoice->pcm = pvoice->synth = pvoice->midi = 0; pvoice->ypcm = NULL; pvoice->interrupt = NULL; @@ -386,7 +401,7 @@ static int snd_ymfpci_playback_trigger(struct snd_pcm_substream *substream, case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_RESUME: chip->ctrl_playback[ypcm->voices[0]->number + 1] = cpu_to_le32(ypcm->voices[0]->bank_addr); - if (ypcm->voices[1] != NULL) + if (ypcm->voices[1] != NULL && !ypcm->use_441_slot) chip->ctrl_playback[ypcm->voices[1]->number + 1] = cpu_to_le32(ypcm->voices[1]->bank_addr); ypcm->running = 1; break; @@ -394,7 +409,7 @@ static int snd_ymfpci_playback_trigger(struct snd_pcm_substream *substream, case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_SUSPEND: chip->ctrl_playback[ypcm->voices[0]->number + 1] = 0; - if (ypcm->voices[1] != NULL) + if (ypcm->voices[1] != NULL && !ypcm->use_441_slot) chip->ctrl_playback[ypcm->voices[1]->number + 1] = 0; ypcm->running = 0; break; @@ -481,6 +496,7 @@ static void snd_ymfpci_pcm_init_voice(struct snd_ymfpci_pcm *ypcm, unsigned int unsigned int nbank; u32 vol_left, vol_right; u8 use_left, use_right; + unsigned long flags; snd_assert(voice != NULL, return); if (runtime->channels == 1) { @@ -499,11 +515,27 @@ static void snd_ymfpci_pcm_init_voice(struct snd_ymfpci_pcm *ypcm, unsigned int vol_left = cpu_to_le32(0x40000000); vol_right = cpu_to_le32(0x40000000); } + spin_lock_irqsave(&ypcm->chip->voice_lock, flags); format = runtime->channels == 2 ? 0x00010000 : 0; if (snd_pcm_format_width(runtime->format) == 8) format |= 0x80000000; + else if (ypcm->chip->device_id == PCI_DEVICE_ID_YAMAHA_754 && + runtime->rate == 44100 && runtime->channels == 2 && + voiceidx == 0 && (ypcm->chip->src441_used == -1 || + ypcm->chip->src441_used == voice->number)) { + ypcm->chip->src441_used = voice->number; + ypcm->use_441_slot = 1; + format |= 0x10000000; + snd_ymfpci_pcm_441_volume_set(ypcm); + } + if (ypcm->chip->src441_used == voice->number && + (format & 0x10000000) == 0) { + ypcm->chip->src441_used = -1; + ypcm->use_441_slot = 0; + } if (runtime->channels == 2 && (voiceidx & 1) != 0) format |= 1; + spin_unlock_irqrestore(&ypcm->chip->voice_lock, flags); for (nbank = 0; nbank < 2; nbank++) { bank = &voice->bank[nbank]; memset(bank, 0, sizeof(*bank)); @@ -1714,7 +1746,10 @@ static int snd_ymfpci_pcm_vol_put(struct snd_kcontrol *kcontrol, spin_lock_irqsave(&chip->voice_lock, flags); if (substream->runtime && substream->runtime->private_data) { struct snd_ymfpci_pcm *ypcm = substream->runtime->private_data; - ypcm->update_pcm_vol = 2; + if (!ypcm->use_441_slot) + ypcm->update_pcm_vol = 2; + else + snd_ymfpci_pcm_441_volume_set(ypcm); } spin_unlock_irqrestore(&chip->voice_lock, flags); return 1; @@ -2253,7 +2288,7 @@ static int saved_regs_index[] = { YDSXGR_PRIADCLOOPVOL, YDSXGR_NATIVEDACINVOL, YDSXGR_NATIVEDACOUTVOL, - // YDSXGR_BUF441OUTVOL, + YDSXGR_BUF441OUTVOL, YDSXGR_NATIVEADCINVOL, YDSXGR_SPDIFLOOPVOL, YDSXGR_SPDIFOUTVOL, @@ -2368,6 +2403,7 @@ int __devinit snd_ymfpci_create(struct snd_card *card, chip->reg_area_phys = pci_resource_start(pci, 0); chip->reg_area_virt = ioremap_nocache(chip->reg_area_phys, 0x8000); pci_set_master(pci); + chip->src441_used = -1; if ((chip->res_reg_area = request_mem_region(chip->reg_area_phys, 0x8000, "YMFPCI")) == NULL) { snd_printk(KERN_ERR "unable to grab memory region 0x%lx-0x%lx\n", chip->reg_area_phys, chip->reg_area_phys + 0x8000 - 1); -- cgit v1.2.3 From 184c1e2c4c4221c2b8d1e16c33314595373fa73f Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Wed, 6 Dec 2006 15:58:02 +0000 Subject: [ALSA] emu10k1: Add Audio capture support for Audigy 2 ZS Notebook. Implement functionallity in order to fixe ALSA bug#2058. Signed-off-by: James Courtier-Dutton Signed-off-by: Jaroslav Kysela --- sound/pci/emu10k1/emu10k1_main.c | 70 ++++++++++++-- sound/pci/emu10k1/emumixer.c | 201 ++++++++++++++++++++++++++++++++++++++- sound/pci/emu10k1/io.c | 59 ++++++++++++ sound/pci/emu10k1/p17v.h | 47 +++++++++ 4 files changed, 370 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 711e819e4a0..80aa585eade 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -46,6 +46,7 @@ #include #include "p16v.h" #include "tina2.h" +#include "p17v.h" /************************************************************************* @@ -120,11 +121,28 @@ static unsigned int spi_dac_init[] = { 0x0622, 0x1400, }; + +static unsigned int i2c_adc_init[][2] = { + { 0x17, 0x00 }, /* Reset */ + { 0x07, 0x00 }, /* Timeout */ + { 0x0b, 0x22 }, /* Interface control */ + { 0x0c, 0x22 }, /* Master mode control */ + { 0x0d, 0x08 }, /* Powerdown control */ + { 0x0e, 0xcf }, /* Attenuation Left 0x01 = -103dB, 0xff = 24dB */ + { 0x0f, 0xcf }, /* Attenuation Right 0.5dB steps */ + { 0x10, 0x7b }, /* ALC Control 1 */ + { 0x11, 0x00 }, /* ALC Control 2 */ + { 0x12, 0x32 }, /* ALC Control 3 */ + { 0x13, 0x00 }, /* Noise gate control */ + { 0x14, 0xa6 }, /* Limiter control */ + { 0x15, ADC_MUX_2 }, /* ADC Mixer control. Mic for Audigy 2 ZS Notebook */ +}; static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) { unsigned int silent_page; int ch; + u32 tmp; /* disable audio and lock cache */ outl(HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK | HCFG_MUTEBUTTONENABLE, @@ -163,8 +181,6 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) if (emu->card_capabilities->ca0151_chip) { /* audigy2 */ /* Hacks for Alice3 to work independent of haP16V driver */ - u32 tmp; - //Setup SRCMulti_I2S SamplingRate tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); tmp &= 0xfffff1ff; @@ -184,8 +200,6 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) } if (emu->card_capabilities->ca0108_chip) { /* audigy2 Value */ /* Hacks for Alice3 to work independent of haP16V driver */ - u32 tmp; - snd_printk(KERN_INFO "Audigy2 value: Special config.\n"); //Setup SRCMulti_I2S SamplingRate tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); @@ -231,6 +245,23 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) outl(0x76, emu->port + A_IOCFG); /* Windows uses 0x3f76 */ } + if (emu->card_capabilities->i2c_adc) { /* Audigy 2 ZS Notebook with ADC Wolfson WM8775 */ + int size, n; + + snd_emu10k1_ptr20_write(emu, P17V_I2S_SRC_SEL, 0, 0x2020205f); + tmp = inl(emu->port + A_IOCFG); + outl(tmp | 0x4, emu->port + A_IOCFG); /* Set bit 2 for mic input */ + tmp = inl(emu->port + A_IOCFG); + size = ARRAY_SIZE(i2c_adc_init); + for (n = 0; n < size; n++) + snd_emu10k1_i2c_write(emu, i2c_adc_init[n][0], i2c_adc_init[n][1]); + for (n=0; n < 4; n++) { + emu->i2c_capture_volume[n][0]= 0xcf; + emu->i2c_capture_volume[n][1]= 0xcf; + } + + } + snd_emu10k1_ptr_write(emu, PTB, 0, emu->ptb_pages.addr); snd_emu10k1_ptr_write(emu, TCB, 0, 0); /* taken from original driver */ @@ -274,6 +305,8 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) if (enable_ir) { /* enable IR for SB Live */ if (emu->card_capabilities->emu1010) { ; /* Disable all access to A_IOCFG for the emu1010 */ + } else if (emu->card_capabilities->i2c_adc) { + ; /* Disable A_IOCFG for Audigy 2 ZS Notebook */ } else if (emu->audigy) { unsigned int reg = inl(emu->port + A_IOCFG); outl(reg | A_IOCFG_GPOUT2, emu->port + A_IOCFG); @@ -293,6 +326,8 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) if (emu->card_capabilities->emu1010) { ; /* Disable all access to A_IOCFG for the emu1010 */ + } else if (emu->card_capabilities->i2c_adc) { + ; /* Disable A_IOCFG for Audigy 2 ZS Notebook */ } else if (emu->audigy) { /* enable analog output */ unsigned int reg = inl(emu->port + A_IOCFG); outl(reg | A_IOCFG_GPOUT0, emu->port + A_IOCFG); @@ -311,6 +346,8 @@ static void snd_emu10k1_audio_enable(struct snd_emu10k1 *emu) /* Enable analog/digital outs on audigy */ if (emu->card_capabilities->emu1010) { ; /* Disable all access to A_IOCFG for the emu1010 */ + } else if (emu->card_capabilities->i2c_adc) { + ; /* Disable A_IOCFG for Audigy 2 ZS Notebook */ } else if (emu->audigy) { outl(inl(emu->port + A_IOCFG) & ~0x44, emu->port + A_IOCFG); @@ -1139,10 +1176,11 @@ static struct snd_emu_chip_details emu_chip_details[] = { .adc_1361t = 1, /* 24 bit capture instead of 16bit */ .ac97_chip = 1} , /* Audigy 2 ZS Notebook Cardbus card.*/ - /* Tested by James@superbug.co.uk 22th December 2005 */ + /* Tested by James@superbug.co.uk 6th November 2006 */ /* Audio output 7.1/Headphones working. * Digital output working. (AC3 not checked, only PCM) - * Audio inputs not tested. + * Audio Mic/Line inputs working. + * Digital input not tested. */ /* DSP: Tina2 * DAC: Wolfson WM8768/WM8568 @@ -1150,6 +1188,25 @@ static struct snd_emu_chip_details emu_chip_details[] = { * AC97: None * CA0151: None */ + /* Tested by James@superbug.co.uk 4th April 2006 */ + /* A_IOCFG bits + * Output + * 0: Not Used + * 1: 0 = Mute all the 7.1 channel out. 1 = unmute. + * 2: Analog input 0 = line in, 1 = mic in + * 3: Not Used + * 4: Digital output 0 = off, 1 = on. + * 5: Not Used + * 6: Not Used + * 7: Not Used + * Input + * All bits 1 (0x3fxx) means nothing plugged in. + * 8-9: 0 = Line in/Mic, 2 = Optical in, 3 = Nothing. + * A-B: 0 = Headphones, 2 = Optical out, 3 = Nothing. + * C-D: 2 = Front/Rear/etc, 3 = nothing. + * E-F: Always 0 + * + */ {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x20011102, .driver = "Audigy2", .name = "Audigy 2 ZS Notebook [SB0530]", .id = "Audigy2", @@ -1157,6 +1214,7 @@ static struct snd_emu_chip_details emu_chip_details[] = { .ca0108_chip = 1, .ca_cardbus_chip = 1, .spi_dac = 1, + .i2c_adc = 1, .spk71 = 1} , {.vendor = 0x1102, .device = 0x0008, .driver = "Audigy2", .name = "Audigy 2 Value [Unknown]", diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index 9b7fd564343..b8221f385ff 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c @@ -36,9 +36,14 @@ #include #include #include +#include + +#include "p17v.h" #define AC97_ID_STAC9758 0x83847658 +static DECLARE_TLV_DB_SCALE(snd_audigy_db_scale2, -10350, 50, 1); /* WM8775 gain scale */ + static int snd_emu10k1_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; @@ -579,6 +584,162 @@ static struct snd_kcontrol_new snd_emu1010_internal_clock = .put = snd_emu1010_internal_clock_put }; +static int snd_audigy_i2c_capture_source_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ +#if 0 + static char *texts[4] = { + "Unknown1", "Unknown2", "Mic", "Line" + }; +#endif + static char *texts[2] = { + "Mic", "Line" + }; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 2; + if (uinfo->value.enumerated.item > 1) + uinfo->value.enumerated.item = 1; + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + return 0; +} + +static int snd_audigy_i2c_capture_source_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); + + ucontrol->value.enumerated.item[0] = emu->i2c_capture_source; + return 0; +} + +static int snd_audigy_i2c_capture_source_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); + unsigned int source_id; + unsigned int ngain, ogain; + u32 gpio; + int change = 0; + unsigned long flags; + u32 source; + /* If the capture source has changed, + * update the capture volume from the cached value + * for the particular source. + */ + source_id = ucontrol->value.enumerated.item[0]; /* Use 2 and 3 */ + change = (emu->i2c_capture_source != source_id); + if (change) { + snd_emu10k1_i2c_write(emu, ADC_MUX, 0); /* Mute input */ + spin_lock_irqsave(&emu->emu_lock, flags); + gpio = inl(emu->port + A_IOCFG); + if (source_id==0) + outl(gpio | 0x4, emu->port + A_IOCFG); + else + outl(gpio & ~0x4, emu->port + A_IOCFG); + spin_unlock_irqrestore(&emu->emu_lock, flags); + + ngain = emu->i2c_capture_volume[source_id][0]; /* Left */ + ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */ + if (ngain != ogain) + snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff)); + ngain = emu->i2c_capture_volume[source_id][1]; /* Right */ + ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Right */ + if (ngain != ogain) + snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff)); + + source = 1 << (source_id + 2); + snd_emu10k1_i2c_write(emu, ADC_MUX, source); /* Set source */ + emu->i2c_capture_source = source_id; + } + return change; +} + +static struct snd_kcontrol_new snd_audigy_i2c_capture_source = +{ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Source", + .info = snd_audigy_i2c_capture_source_info, + .get = snd_audigy_i2c_capture_source_get, + .put = snd_audigy_i2c_capture_source_put +}; + +static int snd_audigy_i2c_volume_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 2; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 255; + return 0; +} + +static int snd_audigy_i2c_volume_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); + int source_id; + + source_id = kcontrol->private_value; + + ucontrol->value.integer.value[0] = emu->i2c_capture_volume[source_id][0]; + ucontrol->value.integer.value[1] = emu->i2c_capture_volume[source_id][1]; + return 0; +} + +static int snd_audigy_i2c_volume_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); + unsigned int ogain; + unsigned int ngain; + int source_id; + int change = 0; + + source_id = kcontrol->private_value; + ogain = emu->i2c_capture_volume[source_id][0]; /* Left */ + ngain = ucontrol->value.integer.value[0]; + if (ngain > 0xff) + return 0; + if (ogain != ngain) { + if (emu->i2c_capture_source == source_id) + snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff) ); + emu->i2c_capture_volume[source_id][0] = ucontrol->value.integer.value[0]; + change = 1; + } + ogain = emu->i2c_capture_volume[source_id][1]; /* Right */ + ngain = ucontrol->value.integer.value[1]; + if (ngain > 0xff) + return 0; + if (ogain != ngain) { + if (emu->i2c_capture_source == source_id) + snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff)); + emu->i2c_capture_volume[source_id][1] = ucontrol->value.integer.value[1]; + change = 1; + } + + return change; +} + +#define I2C_VOLUME(xname,chid) \ +{ \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ + SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ + .info = snd_audigy_i2c_volume_info, \ + .get = snd_audigy_i2c_volume_get, \ + .put = snd_audigy_i2c_volume_put, \ + .tlv = { .p = snd_audigy_db_scale2 }, \ + .private_value = chid \ +} + + +static struct snd_kcontrol_new snd_audigy_i2c_volume_ctls[] __devinitdata = { + I2C_VOLUME("Mic Capture Volume", 0), + I2C_VOLUME("Line Capture Volume", 0) +}; + #if 0 static int snd_audigy_spdif_output_rate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -1179,7 +1340,9 @@ static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol, int change = 0; spin_lock_irqsave(&emu->reg_lock, flags); - if (emu->audigy) { + if ( emu->card_capabilities->i2c_adc) { + /* Do nothing for Audigy 2 ZS Notebook */ + } else if (emu->audigy) { reg = inl(emu->port + A_IOCFG); val = ucontrol->value.integer.value[0] ? A_IOCFG_GPOUT0 : 0; change = (reg & A_IOCFG_GPOUT0) != val; @@ -1317,6 +1480,22 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, "AMic Playback Volume", "Mic Playback Volume", NULL }; + static char *audigy_rename_ctls_i2c_adc[] = { + //"Analog Mix Capture Volume","OLD Analog Mix Capture Volume", + "Line Capture Volume", "Analog Mix Capture Volume", + "Wave Playback Volume", "OLD PCM Playback Volume", + "Wave Master Playback Volume", "Master Playback Volume", + "AMic Playback Volume", "Old Mic Playback Volume", + NULL + }; + static char *audigy_remove_ctls_i2c_adc[] = { + /* On the Audigy2 ZS Notebook + * Capture via WM8775 */ + "Mic Capture Volume", + "Analog Mix Capture Volume", + "Aux Capture Volume", + NULL + }; static char *audigy_remove_ctls_1361t_adc[] = { /* On the Audigy2 the AC97 playback is piped into * the Philips ADC for 24bit capture */ @@ -1409,6 +1588,10 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, } for (; *c; c++) remove_ctl(card, *c); + } else if (emu->card_capabilities->i2c_adc) { + c = audigy_remove_ctls_i2c_adc; + for (; *c; c++) + remove_ctl(card, *c); } else { no_ac97: if (emu->card_capabilities->ecard) @@ -1422,6 +1605,8 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, if (emu->audigy) if (emu->card_capabilities->adc_1361t) c = audigy_rename_ctls_1361t_adc; + else if (emu->card_capabilities->i2c_adc) + c = audigy_rename_ctls_i2c_adc; else c = audigy_rename_ctls; else @@ -1584,6 +1769,20 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, if (err < 0) return err; } + + if ( emu->card_capabilities->i2c_adc) { + int i; + + err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_capture_source, emu)); + if (err < 0) + return err; + + for (i = 0; i < ARRAY_SIZE(snd_audigy_i2c_volume_ctls); i++) { + err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_volume_ctls[i], emu)); + if (err < 0) + return err; + } + } return 0; } diff --git a/sound/pci/emu10k1/io.c b/sound/pci/emu10k1/io.c index 27ab7d1788a..116e1c8d936 100644 --- a/sound/pci/emu10k1/io.c +++ b/sound/pci/emu10k1/io.c @@ -30,6 +30,7 @@ #include #include #include +#include "p17v.h" unsigned int snd_emu10k1_ptr_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn) { @@ -167,6 +168,64 @@ int snd_emu10k1_spi_write(struct snd_emu10k1 * emu, return 0; } +/* The ADC does not support i2c read, so only write is implemented */ +int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu, + u32 reg, + u32 value) +{ + u32 tmp; + int timeout = 0; + int status; + int retry; + if ((reg > 0x7f) || (value > 0x1ff)) { + snd_printk(KERN_ERR "i2c_write: invalid values.\n"); + return -EINVAL; + } + + tmp = reg << 25 | value << 16; + // snd_printk("I2C-write:reg=0x%x, value=0x%x\n", reg, value); + /* Not sure what this I2C channel controls. */ + /* snd_emu10k1_ptr_write(emu, P17V_I2C_0, 0, tmp); */ + + /* This controls the I2C connected to the WM8775 ADC Codec */ + snd_emu10k1_ptr20_write(emu, P17V_I2C_1, 0, tmp); + tmp = snd_emu10k1_ptr20_read(emu, P17V_I2C_1, 0); /* write post */ + + for (retry = 0; retry < 10; retry++) { + /* Send the data to i2c */ + //tmp = snd_emu10k1_ptr_read(emu, P17V_I2C_ADDR, 0); + //tmp = tmp & ~(I2C_A_ADC_READ|I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD_MASK); + tmp = 0; + tmp = tmp | (I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD); + snd_emu10k1_ptr20_write(emu, P17V_I2C_ADDR, 0, tmp); + + /* Wait till the transaction ends */ + while (1) { + udelay(10); + status = snd_emu10k1_ptr20_read(emu, P17V_I2C_ADDR, 0); + // snd_printk("I2C:status=0x%x\n", status); + timeout++; + if ((status & I2C_A_ADC_START) == 0) + break; + + if (timeout > 1000) { + snd_printk("emu10k1:I2C:timeout status=0x%x\n", status); + break; + } + } + //Read back and see if the transaction is successful + if ((status & I2C_A_ADC_ABORT) == 0) + break; + } + + if (retry == 10) { + snd_printk(KERN_ERR "Writing to ADC failed!\n"); + return -EINVAL; + } + + return 0; +} + int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, int reg, int value) { if (reg < 0 || reg > 0x3f) diff --git a/sound/pci/emu10k1/p17v.h b/sound/pci/emu10k1/p17v.h index 7ddb5be632c..4ef5f68a9cd 100644 --- a/sound/pci/emu10k1/p17v.h +++ b/sound/pci/emu10k1/p17v.h @@ -43,6 +43,53 @@ #define P17V_I2C_ADDR 0x3d /* I2C Address */ #define P17V_I2C_0 0x3e /* I2C Data */ #define P17V_I2C_1 0x3f /* I2C Data */ +/* I2C values */ +#define I2C_A_ADC_ADD_MASK 0x000000fe /*The address is a 7 bit address */ +#define I2C_A_ADC_RW_MASK 0x00000001 /*bit mask for R/W */ +#define I2C_A_ADC_TRANS_MASK 0x00000010 /*Bit mask for I2c address DAC value */ +#define I2C_A_ADC_ABORT_MASK 0x00000020 /*Bit mask for I2C transaction abort flag */ +#define I2C_A_ADC_LAST_MASK 0x00000040 /*Bit mask for Last word transaction */ +#define I2C_A_ADC_BYTE_MASK 0x00000080 /*Bit mask for Byte Mode */ + +#define I2C_A_ADC_ADD 0x00000034 /*This is the Device address for ADC */ +#define I2C_A_ADC_READ 0x00000001 /*To perform a read operation */ +#define I2C_A_ADC_START 0x00000100 /*Start I2C transaction */ +#define I2C_A_ADC_ABORT 0x00000200 /*I2C transaction abort */ +#define I2C_A_ADC_LAST 0x00000400 /*I2C last transaction */ +#define I2C_A_ADC_BYTE 0x00000800 /*I2C one byte mode */ + +#define I2C_D_ADC_REG_MASK 0xfe000000 /*ADC address register */ +#define I2C_D_ADC_DAT_MASK 0x01ff0000 /*ADC data register */ + +#define ADC_TIMEOUT 0x00000007 /*ADC Timeout Clock Disable */ +#define ADC_IFC_CTRL 0x0000000b /*ADC Interface Control */ +#define ADC_MASTER 0x0000000c /*ADC Master Mode Control */ +#define ADC_POWER 0x0000000d /*ADC PowerDown Control */ +#define ADC_ATTEN_ADCL 0x0000000e /*ADC Attenuation ADCL */ +#define ADC_ATTEN_ADCR 0x0000000f /*ADC Attenuation ADCR */ +#define ADC_ALC_CTRL1 0x00000010 /*ADC ALC Control 1 */ +#define ADC_ALC_CTRL2 0x00000011 /*ADC ALC Control 2 */ +#define ADC_ALC_CTRL3 0x00000012 /*ADC ALC Control 3 */ +#define ADC_NOISE_CTRL 0x00000013 /*ADC Noise Gate Control */ +#define ADC_LIMIT_CTRL 0x00000014 /*ADC Limiter Control */ +#define ADC_MUX 0x00000015 /*ADC Mux offset */ +#if 0 +/* FIXME: Not tested yet. */ +#define ADC_GAIN_MASK 0x000000ff //Mask for ADC Gain +#define ADC_ZERODB 0x000000cf //Value to set ADC to 0dB +#define ADC_MUTE_MASK 0x000000c0 //Mask for ADC mute +#define ADC_MUTE 0x000000c0 //Value to mute ADC +#define ADC_OSR 0x00000008 //Mask for ADC oversample rate select +#define ADC_TIMEOUT_DISABLE 0x00000008 //Value and mask to disable Timeout clock +#define ADC_HPF_DISABLE 0x00000100 //Value and mask to disable High pass filter +#define ADC_TRANWIN_MASK 0x00000070 //Mask for Length of Transient Window +#endif + +#define ADC_MUX_MASK 0x0000000f //Mask for ADC Mux +#define ADC_MUX_0 0x00000001 //Value to select Unknown at ADC Mux (Not used) +#define ADC_MUX_1 0x00000002 //Value to select Unknown at ADC Mux (Not used) +#define ADC_MUX_2 0x00000004 //Value to select Mic at ADC Mux +#define ADC_MUX_3 0x00000008 //Value to select Line-In at ADC Mux #define P17V_START_AUDIO 0x40 /* Start Audio bit */ /* 41 - 47: Reserved */ -- cgit v1.2.3 From eb41dab6e10332c1c9008f3cfc5b88ff1e392cb9 Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Wed, 6 Dec 2006 20:38:45 +0000 Subject: [ALSA] emu10k1: Rename the digital optical capture control for the Audigy 2 ZS Notebook. Digital playback and capture now works, but it is not bit accurate because it passes through a resampler. Bit accurate playback and capture will be implemented later via the p17v. Signed-off-by: James Courtier-Dutton Signed-off-by: Jaroslav Kysela --- sound/pci/emu10k1/emumixer.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index b8221f385ff..0469546fc33 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c @@ -1486,6 +1486,7 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, "Wave Playback Volume", "OLD PCM Playback Volume", "Wave Master Playback Volume", "Master Playback Volume", "AMic Playback Volume", "Old Mic Playback Volume", + "CD Capture Volume", "IEC958 Optical Capture Volume", NULL }; static char *audigy_remove_ctls_i2c_adc[] = { @@ -1494,6 +1495,7 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, "Mic Capture Volume", "Analog Mix Capture Volume", "Aux Capture Volume", + "IEC958 Optical Capture Volume", NULL }; static char *audigy_remove_ctls_1361t_adc[] = { -- cgit v1.2.3 From 61e77107fa849b69f50ebe96217ba3468a216ba8 Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Thu, 7 Dec 2006 08:24:12 +0100 Subject: [ALSA] create device symlink in snd-aoa create sysfs device symlinks for snd-aoa in /sys/class/sound/controlC0 This allows hald to recognize the device as sound device. Furthermore it allows the desktop user to actually access the sound device nodes. hald and related packages will modify the acl attributes. Fixes https://bugzilla.novell.com/show_bug.cgi?id=106294 Acked-by: Johannes Berg Signed-off-by: Olaf Hering Signed-off-by: Andrew Morton Signed-off-by: Jaroslav Kysela --- sound/aoa/aoa.h | 2 +- sound/aoa/core/snd-aoa-alsa.c | 3 ++- sound/aoa/core/snd-aoa-alsa.h | 2 +- sound/aoa/core/snd-aoa-core.c | 4 ++-- sound/aoa/fabrics/snd-aoa-fabric-layout.c | 2 +- 5 files changed, 7 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/aoa/aoa.h b/sound/aoa/aoa.h index 378ef1e9879..541b908f3cd 100644 --- a/sound/aoa/aoa.h +++ b/sound/aoa/aoa.h @@ -99,7 +99,7 @@ struct aoa_fabric { * that are not assigned yet are passed to the fabric * again for reconsideration. */ extern int -aoa_fabric_register(struct aoa_fabric *fabric); +aoa_fabric_register(struct aoa_fabric *fabric, struct device *dev); /* it is vital to call this when the fabric exits! * When calling, the remove_codec will be called diff --git a/sound/aoa/core/snd-aoa-alsa.c b/sound/aoa/core/snd-aoa-alsa.c index 8c5a19bd602..17fe689ed28 100644 --- a/sound/aoa/core/snd-aoa-alsa.c +++ b/sound/aoa/core/snd-aoa-alsa.c @@ -14,7 +14,7 @@ MODULE_PARM_DESC(index, "index for AOA sound card."); static struct aoa_card *aoa_card; -int aoa_alsa_init(char *name, struct module *mod) +int aoa_alsa_init(char *name, struct module *mod, struct device *dev) { struct snd_card *alsa_card; int err; @@ -28,6 +28,7 @@ int aoa_alsa_init(char *name, struct module *mod) return -ENOMEM; aoa_card = alsa_card->private_data; aoa_card->alsa_card = alsa_card; + alsa_card->dev = dev; strlcpy(alsa_card->driver, "AppleOnbdAudio", sizeof(alsa_card->driver)); strlcpy(alsa_card->shortname, name, sizeof(alsa_card->shortname)); strlcpy(alsa_card->longname, name, sizeof(alsa_card->longname)); diff --git a/sound/aoa/core/snd-aoa-alsa.h b/sound/aoa/core/snd-aoa-alsa.h index 660d2f1793b..9669e4489ca 100644 --- a/sound/aoa/core/snd-aoa-alsa.h +++ b/sound/aoa/core/snd-aoa-alsa.h @@ -10,7 +10,7 @@ #define __SND_AOA_ALSA_H #include "../aoa.h" -extern int aoa_alsa_init(char *name, struct module *mod); +extern int aoa_alsa_init(char *name, struct module *mod, struct device *dev); extern void aoa_alsa_cleanup(void); #endif /* __SND_AOA_ALSA_H */ diff --git a/sound/aoa/core/snd-aoa-core.c b/sound/aoa/core/snd-aoa-core.c index ecd2d8263f2..19fdae40068 100644 --- a/sound/aoa/core/snd-aoa-core.c +++ b/sound/aoa/core/snd-aoa-core.c @@ -82,7 +82,7 @@ void aoa_codec_unregister(struct aoa_codec *codec) } EXPORT_SYMBOL_GPL(aoa_codec_unregister); -int aoa_fabric_register(struct aoa_fabric *new_fabric) +int aoa_fabric_register(struct aoa_fabric *new_fabric, struct device *dev) { struct aoa_codec *c; int err; @@ -98,7 +98,7 @@ int aoa_fabric_register(struct aoa_fabric *new_fabric) if (!new_fabric) return -EINVAL; - err = aoa_alsa_init(new_fabric->name, new_fabric->owner); + err = aoa_alsa_init(new_fabric->name, new_fabric->owner, dev); if (err) return err; diff --git a/sound/aoa/fabrics/snd-aoa-fabric-layout.c b/sound/aoa/fabrics/snd-aoa-fabric-layout.c index 172eb95476c..4b8e32d1ebf 100644 --- a/sound/aoa/fabrics/snd-aoa-fabric-layout.c +++ b/sound/aoa/fabrics/snd-aoa-fabric-layout.c @@ -1014,7 +1014,7 @@ static int aoa_fabric_layout_probe(struct soundbus_dev *sdev) ldev->gpio.methods->init(&ldev->gpio); - err = aoa_fabric_register(&layout_fabric); + err = aoa_fabric_register(&layout_fabric, &sdev->ofdev.dev); if (err && err != -EALREADY) { printk(KERN_INFO "snd-aoa-fabric-layout: can't use," " another fabric is active!\n"); -- cgit v1.2.3 From c17d6fd90a336d2b971dc9f51338f9540479b263 Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Thu, 7 Dec 2006 08:25:01 +0100 Subject: [ALSA] create driver symlink in snd-aoa /sys/bus/aoa-soundbus/devices/*/ create sysfs driver symlink for snd-aoa in /sys/bus/aoa-soundbus/devices/*/ Acked-by: Johannes Berg Signed-off-by: Olaf Hering Signed-off-by: Andrew Morton Signed-off-by: Jaroslav Kysela --- sound/aoa/fabrics/snd-aoa-fabric-layout.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound') diff --git a/sound/aoa/fabrics/snd-aoa-fabric-layout.c b/sound/aoa/fabrics/snd-aoa-fabric-layout.c index 4b8e32d1ebf..409809600dd 100644 --- a/sound/aoa/fabrics/snd-aoa-fabric-layout.c +++ b/sound/aoa/fabrics/snd-aoa-fabric-layout.c @@ -1107,6 +1107,9 @@ static struct soundbus_driver aoa_soundbus_driver = { .suspend = aoa_fabric_layout_suspend, .resume = aoa_fabric_layout_resume, #endif + .driver = { + .owner = THIS_MODULE, + } }; static int __init aoa_fabric_layout_init(void) -- cgit v1.2.3 From a5f65029ad5c5262ee3aff5165698e431415cf7c Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 7 Dec 2006 08:26:27 +0100 Subject: [ALSA] arm header fix Cc: Takashi Iwai Signed-off-by: Andrew Morton Signed-off-by: Jaroslav Kysela --- sound/arm/aaci.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/arm/aaci.h b/sound/arm/aaci.h index 06295190606..9175ff9ded0 100644 --- a/sound/arm/aaci.h +++ b/sound/arm/aaci.h @@ -228,7 +228,7 @@ struct aaci { /* AC'97 */ struct mutex ac97_sem; - ac97_bus_t *ac97_bus; + struct snd_ac97_bus *ac97_bus; u32 maincr; spinlock_t lock; -- cgit v1.2.3 From 7c157069bc953c3cfb5926e92d358e46423bf942 Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Sun, 10 Dec 2006 00:00:38 +0000 Subject: [ALSA] ca0106: Fix sound capture on Audigy LS via AC97. Fixes ALSA bug#2286 Signed-off-by: James Courtier-Dutton Signed-off-by: Jaroslav Kysela --- sound/pci/ca0106/ca0106_main.c | 19 ++++++++++++++++--- sound/pci/ca0106/ca0106_mixer.c | 42 +++++++++++++++++++++++------------------ 2 files changed, 40 insertions(+), 21 deletions(-) (limited to 'sound') diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index f61f052f6d1..6f781b81187 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -1382,7 +1382,6 @@ static int __devinit snd_ca0106_create(int dev, struct snd_card *card, snd_ca0106_ptr_write(chip, SPDIF_SELECT1, 0, 0xf); snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0x000f0000); /* 0x0b000000 for digital, 0x000b0000 for analog, from win2000 drivers. Use 0x000f0000 for surround71 */ chip->spdif_enable = 0; /* Set digital SPDIF output off */ - chip->capture_source = 3; /* Set CAPTURE_SOURCE */ //snd_ca0106_ptr_write(chip, 0x45, 0, 0); /* Analogue out */ //snd_ca0106_ptr_write(chip, 0x45, 0, 0xf00); /* Digital out */ @@ -1402,8 +1401,22 @@ static int __devinit snd_ca0106_create(int dev, struct snd_card *card, snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME1, ch, 0xffffffff); /* Mute */ snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME2, ch, 0xffffffff); /* Mute */ } - snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4); /* Select MIC, Line in, TAD in, AUX in */ - chip->capture_source = 3; /* Set CAPTURE_SOURCE */ + if (chip->details->i2c_adc == 1) { + /* Select MIC, Line in, TAD in, AUX in */ + snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4); + /* Default to CAPTURE_SOURCE to i2s in */ + chip->capture_source = 3; + } else if (chip->details->ac97 == 1) { + /* Default to AC97 in */ + snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x444400e4); + /* Default to CAPTURE_SOURCE to AC97 in */ + chip->capture_source = 4; + } else { + /* Select MIC, Line in, TAD in, AUX in */ + snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4); + /* Default to Set CAPTURE_SOURCE to i2s in */ + chip->capture_source = 3; + } if (chip->details->gpio_type == 2) { /* The SB0438 use GPIO differently. */ /* FIXME: Still need to find out what the other GPIO bits do. E.g. For digital spdif out. */ diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c index bd2a054c673..289f78a4160 100644 --- a/sound/pci/ca0106/ca0106_mixer.c +++ b/sound/pci/ca0106/ca0106_mixer.c @@ -482,19 +482,6 @@ static int snd_ca0106_i2c_volume_put(struct snd_kcontrol *kcontrol, .private_value = ((chid) << 8) | (reg) \ } -#define I2C_VOLUME(xname,chid) \ -{ \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ - SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ - .info = snd_ca0106_i2c_volume_info, \ - .get = snd_ca0106_i2c_volume_get, \ - .put = snd_ca0106_i2c_volume_put, \ - .tlv = { .p = snd_ca0106_db_scale2 }, \ - .private_value = chid \ -} - - static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = { CA_VOLUME("Analog Front Playback Volume", CONTROL_FRONT_CHANNEL, PLAYBACK_VOLUME2), @@ -517,11 +504,6 @@ static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = { CA_VOLUME("CAPTURE feedback Playback Volume", 1, CAPTURE_CONTROL), - I2C_VOLUME("Phone Capture Volume", 0), - I2C_VOLUME("Mic Capture Volume", 1), - I2C_VOLUME("Line in Capture Volume", 2), - I2C_VOLUME("Aux Capture Volume", 3), - { .access = SNDRV_CTL_ELEM_ACCESS_READ, .iface = SNDRV_CTL_ELEM_IFACE_PCM, @@ -561,6 +543,25 @@ static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = { }, }; +#define I2C_VOLUME(xname,chid) \ +{ \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ + SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ + .info = snd_ca0106_i2c_volume_info, \ + .get = snd_ca0106_i2c_volume_get, \ + .put = snd_ca0106_i2c_volume_put, \ + .tlv = { .p = snd_ca0106_db_scale2 }, \ + .private_value = chid \ +} + +static struct snd_kcontrol_new snd_ca0106_volume_i2c_adc_ctls[] __devinitdata = { + I2C_VOLUME("Phone Capture Volume", 0), + I2C_VOLUME("Mic Capture Volume", 1), + I2C_VOLUME("Line in Capture Volume", 2), + I2C_VOLUME("Aux Capture Volume", 3), +}; + static int __devinit remove_ctl(struct snd_card *card, const char *name) { struct snd_ctl_elem_id id; @@ -645,6 +646,11 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu) return err; } if (emu->details->i2c_adc == 1) { + for (i = 0; i < ARRAY_SIZE(snd_ca0106_volume_i2c_adc_ctls); i++) { + err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_volume_i2c_adc_ctls[i], emu)); + if (err < 0) + return err; + } if (emu->details->gpio_type == 1) err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_capture_mic_line_in, emu)); else /* gpio_type == 2 */ -- cgit v1.2.3 From 4484bb2e93a9ab636d149edc6515c75ea224e2b0 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Fri, 15 Dec 2006 09:30:07 +0100 Subject: [ALSA] Fix the soc code after dhowells workqueue changes. From: Andrew Morton I converted the workqueues to per-device while I was there. It seems strange to create a new kernel thread (on each CPU!) and to then only have a single global work to ever be queued upon it. Plus without this, I'd have to use the _NAR stuff, gawd help me. Does that workqueue really need to be per-cpu? Does that workqueue really need to exist? Why not use keventd? Cc: Takashi Iwai Cc: David Howells Signed-off-by: Andrew Morton Signed-off-by: Jaroslav Kysela --- sound/soc/soc-core.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 90e8841e7e3..0bae14145a0 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -56,7 +56,6 @@ static DEFINE_MUTEX(pcm_mutex); static DEFINE_MUTEX(io_mutex); static struct workqueue_struct *soc_workq; -static struct work_struct soc_stream_work; static DECLARE_WAIT_QUEUE_HEAD(soc_pm_waitq); /* supported sample rates */ @@ -728,9 +727,10 @@ out: * This is to ensure there are no pops or clicks in between any music tracks * due to DAPM power cycling. */ -static void close_delayed_work(void *data) +static void close_delayed_work(struct work_struct *work) { - struct snd_soc_device *socdev = data; + struct snd_soc_device *socdev = + container_of(work, struct snd_soc_device, delayed_work.work); struct snd_soc_codec *codec = socdev->codec; struct snd_soc_codec_dai *codec_dai; int i; @@ -805,7 +805,7 @@ static int soc_codec_close(struct snd_pcm_substream *substream) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { /* start delayed pop wq here for playback streams */ rtd->codec_dai->pop_wait = 1; - queue_delayed_work(soc_workq, &soc_stream_work, + queue_delayed_work(soc_workq, &socdev->delayed_work, msecs_to_jiffies(pmdown_time)); } else { /* capture streams can be powered down now */ @@ -865,7 +865,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) SND_SOC_DAPM_STREAM_START); else { rtd->codec_dai->pop_wait = 0; - cancel_delayed_work(&soc_stream_work); + cancel_delayed_work(&socdev->delayed_work); if (rtd->codec_dai->digital_mute) rtd->codec_dai->digital_mute(codec, rtd->codec_dai, 0); } @@ -1225,7 +1225,7 @@ static int soc_probe(struct platform_device *pdev) soc_workq = create_workqueue("kdapm"); if (soc_workq == NULL) goto work_err; - INIT_WORK(&soc_stream_work, close_delayed_work, socdev); + INIT_DELAYED_WORK(&socdev->delayed_work, close_delayed_work); return 0; work_err: -- cgit v1.2.3 From 9102cd1c35c9be223e0f60b7c42cb581f0d42f1a Mon Sep 17 00:00:00 2001 From: Tobin Davis Date: Fri, 15 Dec 2006 10:02:12 +0100 Subject: [ALSA] hda-codec (realtek): add support for MacPro series workstations This patch adds limited support for Intel-based MacPro workstations. Currently, the front headphone jack is not functioning, but line out and line in are working. S/PDIF not tested. Signed-off-by: Tobin Davis Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 112 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index a1b6c9661d4..c4a06c5f7d9 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -112,6 +112,7 @@ enum { ALC882_6ST_DIG, ALC882_ARIMA, ALC882_AUTO, + ALC885_MACPRO, ALC882_MODEL_LAST, }; @@ -4507,6 +4508,100 @@ static struct hda_verb alc882_eapd_verbs[] = { { } }; +/* Mac Pro test */ +static struct snd_kcontrol_new alc882_macpro_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x02, HDA_INPUT), + { } /* end */ +}; + +static struct hda_verb alc882_macpro_init_verbs[] = { + /* Front mixer: unmute input/output amp left and right (volume = 0) */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* Front Pin: output 0 (0x0c) */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* Front Mic pin: input vref at 80% */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Speaker: output */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x04}, + /* Headphone output (output 0 - 0x0c) */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x18, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* FIXME: use matrix-type input source selection */ + /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ + /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + /* Input mixer2 */ + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + /* Input mixer3 */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + /* ADC1: mute amp left and right */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* ADC2: mute amp left and right */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* ADC3: mute amp left and right */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, + + { } +}; +static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted) +{ + unsigned int gpiostate, gpiomask, gpiodir; + + gpiostate = snd_hda_codec_read(codec, codec->afg, 0, + AC_VERB_GET_GPIO_DATA, 0); + + if (!muted) + gpiostate |= (1 << pin); + else + gpiostate &= ~(1 << pin); + + gpiomask = snd_hda_codec_read(codec, codec->afg, 0, + AC_VERB_GET_GPIO_MASK, 0); + gpiomask |= (1 << pin); + + gpiodir = snd_hda_codec_read(codec, codec->afg, 0, + AC_VERB_GET_GPIO_DIRECTION, 0); + gpiodir |= (1 << pin); + + + snd_hda_codec_write(codec, codec->afg, 0, + AC_VERB_SET_GPIO_MASK, gpiomask); + snd_hda_codec_write(codec, codec->afg, 0, + AC_VERB_SET_GPIO_DIRECTION, gpiodir); + + msleep(1); + + snd_hda_codec_write(codec, codec->afg, 0, + AC_VERB_SET_GPIO_DATA, gpiostate); +} + /* * generic initialization of ADC, input mixers and output mixers */ @@ -4633,6 +4728,7 @@ static const char *alc882_models[ALC882_MODEL_LAST] = { [ALC882_3ST_DIG] = "3stack-dig", [ALC882_6ST_DIG] = "6stack-dig", [ALC882_ARIMA] = "arima", + [ALC885_MACPRO] = "macpro", [ALC882_AUTO] = "auto", }; @@ -4677,6 +4773,17 @@ static struct alc_config_preset alc882_presets[] = { .channel_mode = alc882_sixstack_modes, .input_mux = &alc882_capture_source, }, + [ALC885_MACPRO] = { + .mixers = { alc882_macpro_mixer }, + .init_verbs = { alc882_macpro_init_verbs }, + .num_dacs = ARRAY_SIZE(alc882_dac_nids), + .dac_nids = alc882_dac_nids, + .dig_out_nid = ALC882_DIGOUT_NID, + .dig_in_nid = ALC882_DIGIN_NID, + .num_channel_mode = ARRAY_SIZE(alc882_ch_modes), + .channel_mode = alc882_ch_modes, + .input_mux = &alc882_capture_source, + }, }; @@ -4804,6 +4911,11 @@ static int patch_alc882(struct hda_codec *codec) if (board_config != ALC882_AUTO) setup_preset(spec, &alc882_presets[board_config]); + if (board_config == ALC885_MACPRO) { + alc882_gpio_mute(codec, 0, 0); + alc882_gpio_mute(codec, 1, 0); + } + spec->stream_name_analog = "ALC882 Analog"; spec->stream_analog_playback = &alc882_pcm_analog_playback; spec->stream_analog_capture = &alc882_pcm_analog_capture; -- cgit v1.2.3 From 1a5965b72209db9db453bc0049393e0d54cf85cb Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 18 Dec 2006 13:07:35 +0100 Subject: [ALSA] Fix AC97_BUS in soc/pxa/Kconfig Fixed the renamed AC97_BUS in soc/pxa/Kconfig file. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/pxa/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig index a07598cdab3..579e1c8d2b2 100644 --- a/sound/soc/pxa/Kconfig +++ b/sound/soc/pxa/Kconfig @@ -15,7 +15,7 @@ config SND_PXA2XX_AC97 config SND_PXA2XX_SOC_AC97 tristate - select SND_AC97_BUS + select AC97_BUS select SND_SOC_AC97_BUS config SND_PXA2XX_SOC_I2S -- cgit v1.2.3 From cdf88efa03907a884177b226321bb41bc17c407f Mon Sep 17 00:00:00 2001 From: Toshimune Konno Date: Mon, 18 Dec 2006 13:12:18 +0100 Subject: [ALSA] ice1724 - Add support for Prodigy 7.1 XT This patch supports Audiotrack 7.1 XT. 7.1XT is almost same hardware as 7.1LT. so using 7.1 LT's code. Signed-off-by: Toshimune Konno Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/ice1712/aureon.c | 52 ++++++++++++++++++++++++++++++++++++++-------- sound/pci/ice1712/aureon.h | 4 +++- 2 files changed, 46 insertions(+), 10 deletions(-) (limited to 'sound') diff --git a/sound/pci/ice1712/aureon.c b/sound/pci/ice1712/aureon.c index 9e76cebd2d2..a085618d33f 100644 --- a/sound/pci/ice1712/aureon.c +++ b/sound/pci/ice1712/aureon.c @@ -474,7 +474,8 @@ static void aureon_spi_write(struct snd_ice1712 *ice, unsigned int cs, unsigned tmp = snd_ice1712_gpio_read(ice); - if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT) { + if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT || + ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71XT) { snd_ice1712_gpio_set_mask(ice, ~(PRODIGY_SPI_MOSI|PRODIGY_SPI_CLK|PRODIGY_WM_CS)); mosi = PRODIGY_SPI_MOSI; clk = PRODIGY_SPI_CLK; @@ -601,7 +602,9 @@ static unsigned short wm_get(struct snd_ice1712 *ice, int reg) static void wm_put_nocache(struct snd_ice1712 *ice, int reg, unsigned short val) { aureon_spi_write(ice, - (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT ? PRODIGY_WM_CS : AUREON_WM_CS), + ((ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT || + ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71XT) ? + PRODIGY_WM_CS : AUREON_WM_CS), (reg << 9) | (val & 0x1ff), 16); } @@ -1288,12 +1291,14 @@ static int aureon_set_headphone_amp(struct snd_ice1712 *ice, int enable) tmp2 = tmp = snd_ice1712_gpio_read(ice); if (enable) - if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT) + if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT && + ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT) tmp |= AUREON_HP_SEL; else tmp |= PRODIGY_HP_SEL; else - if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT) + if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT && + ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT) tmp &= ~ AUREON_HP_SEL; else tmp &= ~ PRODIGY_HP_SEL; @@ -1898,7 +1903,8 @@ static int __devinit aureon_add_controls(struct snd_ice1712 *ice) return err; } } - else if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT) { + else if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT && + ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT) { for (i = 0; i < ARRAY_SIZE(ac97_controls); i++) { err = snd_ctl_add(ice->card, snd_ctl_new1(&ac97_controls[i], ice)); if (err < 0) @@ -1906,7 +1912,8 @@ static int __devinit aureon_add_controls(struct snd_ice1712 *ice) } } - if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT) { + if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT && + ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT) { unsigned char id; snd_ice1712_save_gpio_status(ice); id = aureon_cs8415_get(ice, CS8415_ID); @@ -2062,7 +2069,8 @@ static int __devinit aureon_init(struct snd_ice1712 *ice) /* initialize WM8770 codec */ if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71 || - ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT) + ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT || + ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71XT) p = wm_inits_prodigy; else p = wm_inits_aureon; @@ -2070,7 +2078,8 @@ static int __devinit aureon_init(struct snd_ice1712 *ice) wm_put(ice, p[0], p[1]); /* initialize CS8415A codec */ - if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT) { + if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT && + ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT) { for (p = cs_inits; *p != (unsigned short)-1; p++) aureon_spi_write(ice, AUREON_CS8415_CS, *p | 0x200000, 24); ice->spec.aureon.cs8415_mux = 1; @@ -2163,7 +2172,22 @@ static unsigned char prodigy71lt_eeprom[] __devinitdata = { 0x00, /* GPIO_STATE1 */ 0x00, /* GPIO_STATE2 */ }; - + +static unsigned char prodigy71xt_eeprom[] __devinitdata = { + 0x4b, /* SYSCINF: clock 512, spdif-in/ADC, 4DACs */ + 0x80, /* ACLINK: I2S */ + 0xfc, /* I2S: vol, 96k, 24bit, 192k */ + 0xc3, /* SPDIF: out-en, out-int, spdif-in */ + 0xff, /* GPIO_DIR */ + 0xff, /* GPIO_DIR1 */ + 0x5f, /* GPIO_DIR2 */ + 0x00, /* GPIO_MASK */ + 0x00, /* GPIO_MASK1 */ + 0x00, /* GPIO_MASK2 */ + 0x00, /* GPIO_STATE */ + 0x00, /* GPIO_STATE1 */ + 0x00, /* GPIO_STATE2 */ +}; /* entry point */ struct snd_ice1712_card_info snd_vt1724_aureon_cards[] __devinitdata = { @@ -2217,5 +2241,15 @@ struct snd_ice1712_card_info snd_vt1724_aureon_cards[] __devinitdata = { .eeprom_data = prodigy71lt_eeprom, .driver = "Prodigy71LT", }, + { + .subvendor = VT1724_SUBDEVICE_PRODIGY71XT, + .name = "Audiotrak Prodigy 7.1 XT", + .model = "prodigy71xt", + .chip_init = aureon_init, + .build_controls = aureon_add_controls, + .eeprom_size = sizeof(prodigy71xt_eeprom), + .eeprom_data = prodigy71xt_eeprom, + .driver = "Prodigy71LT", + }, { } /* terminator */ }; diff --git a/sound/pci/ice1712/aureon.h b/sound/pci/ice1712/aureon.h index 3b7bea656c5..c253b8e2c78 100644 --- a/sound/pci/ice1712/aureon.h +++ b/sound/pci/ice1712/aureon.h @@ -28,13 +28,15 @@ "{Terratec,Aureon 7.1 Space},"\ "{Terratec,Aureon 7.1 Universe}," \ "{AudioTrak,Prodigy 7.1}," \ - "{AudioTrak,Prodigy 7.1 LT}," + "{AudioTrak,Prodigy 7.1 LT},"\ + "{AudioTrak,Prodigy 7.1 XT}," #define VT1724_SUBDEVICE_AUREON51_SKY 0x3b154711 /* Aureon 5.1 Sky */ #define VT1724_SUBDEVICE_AUREON71_SPACE 0x3b154511 /* Aureon 7.1 Space */ #define VT1724_SUBDEVICE_AUREON71_UNIVERSE 0x3b155311 /* Aureon 7.1 Universe */ #define VT1724_SUBDEVICE_PRODIGY71 0x33495345 /* PRODIGY 7.1 */ #define VT1724_SUBDEVICE_PRODIGY71LT 0x32315441 /* PRODIGY 7.1 LT */ +#define VT1724_SUBDEVICE_PRODIGY71XT 0x36315441 /* PRODIGY 7.1 XT*/ extern struct snd_ice1712_card_info snd_vt1724_aureon_cards[]; -- cgit v1.2.3 From 333824034a19baf71b2bd5fe2153630982f379b0 Mon Sep 17 00:00:00 2001 From: Matt Porter Date: Mon, 18 Dec 2006 13:17:28 +0100 Subject: [ALSA] hda: add sigmatel 9205 eapd support Adds support for handling EAPD on 9205 codecs Signed-off-by: Matt Porter Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_sigmatel.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index cbaa00aa5b9..4e3fc95b7b4 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -1859,6 +1859,18 @@ static int patch_stac9205(struct hda_codec *codec) spec->multiout.dac_nids = spec->dac_nids; + /* Configure GPIO0 as EAPD output */ + snd_hda_codec_write(codec, codec->afg, 0, + AC_VERB_SET_GPIO_DIRECTION, 0x00000001); + /* Configure GPIO0 as CMOS */ + snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0x00000000); + /* Assert GPIO0 high */ + snd_hda_codec_write(codec, codec->afg, 0, + AC_VERB_SET_GPIO_DATA, 0x00000001); + /* Enable GPIO0 */ + snd_hda_codec_write(codec, codec->afg, 0, + AC_VERB_SET_GPIO_MASK, 0x00000001); + err = stac92xx_parse_auto_config(codec, 0x1f, 0x20); if (err < 0) { stac92xx_free(codec); -- cgit v1.2.3 From b0148a98ec5151fec82064d95f11eb9efbc628ea Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 18 Dec 2006 13:20:06 +0100 Subject: [ALSA] snd-aoa: fix onyx resume When the machine resumes the onyx codec might be in a weird state. Hence, simply fully reset it once (and keep the code to take it out of suspend in case the suspend of the codec chip survives a reset). Signed-off-by: Johannes Berg Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/aoa/codecs/snd-aoa-codec-onyx.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/aoa/codecs/snd-aoa-codec-onyx.c b/sound/aoa/codecs/snd-aoa-codec-onyx.c index 0b7650788f1..b00fc4842c9 100644 --- a/sound/aoa/codecs/snd-aoa-codec-onyx.c +++ b/sound/aoa/codecs/snd-aoa-codec-onyx.c @@ -825,7 +825,16 @@ static int onyx_resume(struct codec_info_item *cii) int err = -ENXIO; mutex_lock(&onyx->mutex); - /* take codec out of suspend */ + + /* reset codec */ + onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 0); + msleep(1); + onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 1); + msleep(1); + onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 0); + msleep(1); + + /* take codec out of suspend (if it still is after reset) */ if (onyx_read_register(onyx, ONYX_REG_CONTROL, &v)) goto out_unlock; onyx_write_register(onyx, ONYX_REG_CONTROL, v & ~(ONYX_ADPSV | ONYX_DAPSV)); -- cgit v1.2.3 From 4dc53e28e2e5cccb3521466be8f2ab4689ca9143 Mon Sep 17 00:00:00 2001 From: Tobin Davis Date: Mon, 18 Dec 2006 13:24:37 +0100 Subject: [ALSA] hda-codec - Add quirk for Turbo-X Coeus G610P This patch adds the Turbo-X Coeus G610P to the alc880 config table, based on user provided information. Signed-off-by: Tobin Davis Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index c4a06c5f7d9..18bfc3993b8 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -2361,6 +2361,7 @@ static struct snd_pci_quirk alc880_cfg_tbl[] = { SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG), SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST), + SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810), SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG), SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG), SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG), -- cgit v1.2.3 From 659eacc55a378066b60896b2bbd261ca32a10c04 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Mon, 18 Dec 2006 14:38:37 +0100 Subject: [ALSA] Remove trailing white space from wm9712.c This patch removes some trailing white space from the WM9712 ASoC codec driver. Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/codecs/wm9712.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index c6b7de42646..36c6a38a0f9 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -45,7 +45,7 @@ static int ac97_write(struct snd_soc_codec *codec, /* may need to expand this */ static struct snd_soc_dai_mode ac97_modes[] = { { - .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE, + .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE, .pcmrate = AC97_RATES, .pcmdir = AC97_DIR, }, -- cgit v1.2.3 From 0664d888a55ff99c8556690a3ae7c76dc1389008 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Mon, 18 Dec 2006 14:39:02 +0100 Subject: [ALSA] Additional credits to soc-core This patch adds copyright and credit for my good friend Richard Purdie from OpenedHand for his help and code contribution throughout the development of the core code. Many thanks Richard (I guess we overlooked this in trying to get everything working well). It also adds some extra comments wrt to DAI clock matching. Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/soc-core.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 0bae14145a0..9f23901fc85 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2,8 +2,12 @@ * soc-core.c -- ALSA SoC Audio Layer * * Copyright 2005 Wolfson Microelectronics PLC. + * Copyright 2005 Openedhand Ltd. + * * Author: Liam Girdwood * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com + * with code, comments and ideas from :- + * Richard Purdie * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -517,7 +521,8 @@ found: * Check we have matching bitclocks. If we don't then it means the * sysclock returned by either the codec or cpu DAI (selected by the * machine sysclock function) is wrong compared with the supported DAI - * modes for the codec or cpu DAI. + * modes for the codec or cpu DAI. Check your codec or CPU DAI + * config_sysclock() functions. */ if (cpu_bclk != codec_bclk && cpu_bclk){ printk(KERN_ERR -- cgit v1.2.3 From ca40587087fc05c670f4f2650cc466d557377f6d Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Mon, 18 Dec 2006 14:41:03 +0100 Subject: [ALSA] sparc dbri comment fix This is a comment fix to avoid misleading about locking in the dbri_cmdsend. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/sparc/dbri.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c index 4ceb09d215d..25a2a733300 100644 --- a/sound/sparc/dbri.c +++ b/sound/sparc/dbri.c @@ -678,7 +678,7 @@ static s32 *dbri_cmdlock(struct snd_dbri * dbri, int len) * The JUMP cmd points to the new cmd string. * It also releases the cmdlock spinlock. * - * Lock must not be held before calling this. + * Lock must be held before calling this. */ static void dbri_cmdsend(struct snd_dbri * dbri, s32 * cmd,int len) { -- cgit v1.2.3 From e4c3bf0f65ec9da8b067a722f734d1012ef12ceb Mon Sep 17 00:00:00 2001 From: James C Georgas Date: Tue, 19 Dec 2006 11:09:41 +0100 Subject: [ALSA] Remove AC97 POP control for STAC9708/11 The STAC9708/11 AC97 codecs implement the PCM Out Path & Mute bit in the General Purpose register (0x20:F), even though they don't implement the actual function in the mixer. Since the alsa tests for the function by toggling the bit and reading it back to see if it changed, it mistakenly creates a useless control. This patch explicitly removes the control when the codec is an STAC9708/11. I put the check in patch_sigmatel_stac9708_specific(), because I have an SBLive with this chip on it. I don't know if the STAC9758 or other codecs also behave this way. If they do, then this check could maybe go in patch_sigmatel_stac97xx_specific(), or some other more general function. Signed-off-by: James C Georgas Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/ac97/ac97_patch.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound') diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 123de550d1f..818a77d2def 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -941,6 +941,9 @@ static int patch_sigmatel_stac9708_specific(struct snd_ac97 *ac97) { int err; + /* the register bit is writable, but the function is not implemented: */ + snd_ac97_remove_ctl(ac97, "PCM Out Path & Mute", NULL); + snd_ac97_rename_vol_ctl(ac97, "Headphone Playback", "Sigmatel Surround Playback"); if ((err = patch_build_controls(ac97, &snd_ac97_stac9708_bias_control, 1)) < 0) return err; -- cgit v1.2.3 From dc041e0b1fc918562aa3803cda166fee219a34d2 Mon Sep 17 00:00:00 2001 From: "Robert P. J. Day" Date: Tue, 19 Dec 2006 14:44:15 +0100 Subject: [ALSA] sound: Change final two instances of kcalloc(1,...) to kzalloc() Change the two remaining instances in the tree of kcalloc(1,...) to the corresponding kzalloc() call. Signed-off-by: Robert P. J. Day Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 18bfc3993b8..2be0ef9023b 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6590,7 +6590,7 @@ static int patch_alc262(struct hda_codec *codec) int board_config; int err; - spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); + spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (spec == NULL) return -ENOMEM; @@ -7710,7 +7710,7 @@ static int patch_alc861(struct hda_codec *codec) int board_config; int err; - spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); + spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (spec == NULL) return -ENOMEM; -- cgit v1.2.3 From e250af291d6759518b574b33317eb3003012bfa2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 19 Dec 2006 17:08:52 +0100 Subject: [ALSA] hda-codec - Use global workqueue Use global workqueue for simplicity. The unsolicited event frequency isn't so high to have own queue. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/hda_codec.c | 10 ++-------- sound/pci/hda/hda_local.h | 1 - 2 files changed, 2 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index e14faf5d505..8f34fb44798 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -263,7 +263,7 @@ int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex) unsol->queue[wp] = res; unsol->queue[wp + 1] = res_ex; - queue_work(unsol->workq, &unsol->work); + schedule_work(&unsol->work); return 0; } @@ -310,12 +310,6 @@ static int init_unsol_queue(struct hda_bus *bus) snd_printk(KERN_ERR "hda_codec: can't allocate unsolicited queue\n"); return -ENOMEM; } - unsol->workq = create_singlethread_workqueue("hda_codec"); - if (! unsol->workq) { - snd_printk(KERN_ERR "hda_codec: can't create workqueue\n"); - kfree(unsol); - return -ENOMEM; - } INIT_WORK(&unsol->work, process_unsol_events); unsol->bus = bus; bus->unsol = unsol; @@ -334,7 +328,7 @@ static int snd_hda_bus_free(struct hda_bus *bus) if (! bus) return 0; if (bus->unsol) { - destroy_workqueue(bus->unsol->workq); + flush_scheduled_work(); kfree(bus->unsol); } list_for_each_safe(p, n, &bus->codec_list) { diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index b2f56d68885..39718d6cdad 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -199,7 +199,6 @@ struct hda_bus_unsolicited { unsigned int rp, wp; /* workqueue */ - struct workqueue_struct *workq; struct work_struct work; struct hda_bus *bus; }; -- cgit v1.2.3 From 4014c38bd94156c10986a11d890bdae99437dc9a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 19 Dec 2006 17:13:16 +0100 Subject: [ALSA] ak4114 - Use global workqueue Use global workqueue for simplicity instead of own workqueue. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/i2c/other/ak4114.c | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) (limited to 'sound') diff --git a/sound/i2c/other/ak4114.c b/sound/i2c/other/ak4114.c index d2f2c5078e6..69dcaf8ac79 100644 --- a/sound/i2c/other/ak4114.c +++ b/sound/i2c/other/ak4114.c @@ -66,10 +66,7 @@ static void snd_ak4114_free(struct ak4114 *chip) { chip->init = 1; /* don't schedule new work */ mb(); - if (chip->workqueue != NULL) { - flush_workqueue(chip->workqueue); - destroy_workqueue(chip->workqueue); - } + flush_scheduled_work(); kfree(chip); } @@ -106,12 +103,6 @@ int snd_ak4114_create(struct snd_card *card, for (reg = 0; reg < 5; reg++) chip->txcsb[reg] = txcsb[reg]; - chip->workqueue = create_workqueue("snd-ak4114"); - if (chip->workqueue == NULL) { - kfree(chip); - return -ENOMEM; - } - snd_ak4114_reinit(chip); chip->rcs0 = reg_read(chip, AK4114_REG_RCS0) & ~(AK4114_QINT | AK4114_CINT); @@ -143,7 +134,7 @@ void snd_ak4114_reinit(struct ak4114 *chip) chip->init = 1; mb(); - flush_workqueue(chip->workqueue); + flush_scheduled_work(); /* bring the chip to reset state and powerdown state */ reg_write(chip, AK4114_REG_PWRDN, old & ~(AK4114_RST|AK4114_PWN)); udelay(200); @@ -159,7 +150,7 @@ void snd_ak4114_reinit(struct ak4114 *chip) /* bring up statistics / event queing */ chip->init = 0; INIT_DELAYED_WORK(&chip->work, ak4114_stats); - queue_delayed_work(chip->workqueue, &chip->work, HZ / 10); + schedule_delayed_work(&chip->work, HZ / 10); } static unsigned int external_rate(unsigned char rcs1) @@ -568,7 +559,7 @@ static void ak4114_stats(struct work_struct *work) if (chip->init) return; snd_ak4114_check_rate_and_errors(chip, 0); - queue_delayed_work(chip->workqueue, &chip->work, HZ / 10); + schedule_delayed_work(&chip->work, HZ / 10); } EXPORT_SYMBOL(snd_ak4114_create); -- cgit v1.2.3 From 4bb09523de50dcf1afc5d3099b9da0381f01b04c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 19 Dec 2006 17:16:14 +0100 Subject: [ALSA] soc - Use global workqueue Use global workqueue for simplicity instead of own workqueue in SoC core and wm8750 codes. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/codecs/wm8750.c | 14 +++----------- sound/soc/soc-core.c | 15 ++------------- 2 files changed, 5 insertions(+), 24 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index 4cc85128dc5..069b66cb18e 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c @@ -51,7 +51,6 @@ #define warn(format, arg...) \ printk(KERN_WARNING AUDIO_NAME ": " format "\n" , ## arg) -static struct workqueue_struct *wm8750_workq = NULL; static struct work_struct wm8750_dapm_work; /* @@ -1039,7 +1038,7 @@ static int wm8750_resume(struct platform_device *pdev) if (codec->suspend_dapm_state == SNDRV_CTL_POWER_D0) { wm8750_dapm_event(codec, SNDRV_CTL_POWER_D2); codec->dapm_state = SNDRV_CTL_POWER_D0; - queue_delayed_work(wm8750_workq, &wm8750_dapm_work, + schedule_delayed_work(&wm8750_dapm_work, msecs_to_jiffies(1000)); } @@ -1084,8 +1083,7 @@ static int wm8750_init(struct snd_soc_device *socdev) /* charge output caps */ wm8750_dapm_event(codec, SNDRV_CTL_POWER_D2); codec->dapm_state = SNDRV_CTL_POWER_D3hot; - queue_delayed_work(wm8750_workq, &wm8750_dapm_work, - msecs_to_jiffies(1000)); + schedule_delayed_work(&wm8750_dapm_work, msecs_to_jiffies(1000)); /* set the update bits */ reg = wm8750_read_reg_cache(codec, WM8750_LDAC); @@ -1228,11 +1226,6 @@ static int wm8750_probe(struct platform_device *pdev) INIT_LIST_HEAD(&codec->dapm_paths); wm8750_socdev = socdev; INIT_WORK(&wm8750_dapm_work, wm8750_work, codec); - wm8750_workq = create_workqueue("wm8750"); - if (wm8750_workq == NULL) { - kfree(codec); - return -ENOMEM; - } #if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE) if (setup->i2c_address) { normal_i2c[0] = setup->i2c_address; @@ -1256,8 +1249,7 @@ static int wm8750_remove(struct platform_device *pdev) if (codec->control_data) wm8750_dapm_event(codec, SNDRV_CTL_POWER_D3cold); - if (wm8750_workq) - destroy_workqueue(wm8750_workq); + flush_scheduled_work(); snd_soc_free_pcms(socdev); snd_soc_dapm_free(socdev); #if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 9f23901fc85..cf84d825171 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -59,7 +59,6 @@ static DEFINE_MUTEX(pcm_mutex); static DEFINE_MUTEX(io_mutex); -static struct workqueue_struct *soc_workq; static DECLARE_WAIT_QUEUE_HEAD(soc_pm_waitq); /* supported sample rates */ @@ -810,7 +809,7 @@ static int soc_codec_close(struct snd_pcm_substream *substream) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { /* start delayed pop wq here for playback streams */ rtd->codec_dai->pop_wait = 1; - queue_delayed_work(soc_workq, &socdev->delayed_work, + schedule_delayed_work(&socdev->delayed_work, msecs_to_jiffies(pmdown_time)); } else { /* capture streams can be powered down now */ @@ -1102,7 +1101,7 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) } /* close any waiting streams and save state */ - flush_workqueue(soc_workq); + flush_scheduled_work(); codec->suspend_dapm_state = codec->dapm_state; for(i = 0; i < codec->num_dai; i++) { @@ -1227,16 +1226,9 @@ static int soc_probe(struct platform_device *pdev) } /* DAPM stream work */ - soc_workq = create_workqueue("kdapm"); - if (soc_workq == NULL) - goto work_err; INIT_DELAYED_WORK(&socdev->delayed_work, close_delayed_work); return 0; -work_err: - if (platform->remove) - platform->remove(pdev); - platform_err: if (codec_dev->remove) codec_dev->remove(pdev); @@ -1263,9 +1255,6 @@ static int soc_remove(struct platform_device *pdev) struct snd_soc_platform *platform = socdev->platform; struct snd_soc_codec_device *codec_dev = socdev->codec_dev; - if (soc_workq) - destroy_workqueue(soc_workq); - if (platform->remove) platform->remove(pdev); -- cgit v1.2.3 From 831466f4ad2b5fe23dff77edbe6a7c244435e973 Mon Sep 17 00:00:00 2001 From: Randy Cushman Date: Tue, 19 Dec 2006 18:42:16 +0100 Subject: [ALSA] ac97 - fix microphone and line_in selection logic This patch fixes the Microphone and LINE_IN select logic for Analog Devices surround codecs with shared jacks. The existing code can never utilize the shared jacks for Microphone and LINE_IN due to the reversed jack selection logic. The patched code correctly selects the shared jack for input if the 'Channel Mode' selector does not specify that the jack is to be used for output. Specifically, in '2ch' mode the Center/LFE jack is used for microphone input and the Surround jack is used for LINE_IN, in '4ch' mode the Center/LFE jack is used for microphone input and the Surround jack is used for output, and in '6ch' mode both jacks are used for output. Signed-off-by: Randy Cushman Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/ac97/ac97_patch.c | 66 +++++++++++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 26 deletions(-) (limited to 'sound') diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 818a77d2def..5f69b9c9f1b 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -190,14 +190,28 @@ static inline int is_clfe_on(struct snd_ac97 *ac97) return ac97->channel_mode >= 2; } +/* system has shared jacks with surround out enabled */ +static inline int is_shared_surrout(struct snd_ac97 *ac97) +{ + return !ac97->indep_surround && is_surround_on(ac97); +} + +/* system has shared jacks with center/lfe out enabled */ +static inline int is_shared_clfeout(struct snd_ac97 *ac97) +{ + return !ac97->indep_surround && is_clfe_on(ac97); +} + +/* system has shared jacks with line in enabled */ static inline int is_shared_linein(struct snd_ac97 *ac97) { - return ! ac97->indep_surround && is_surround_on(ac97); + return !ac97->indep_surround && !is_surround_on(ac97); } +/* system has shared jacks with mic in enabled */ static inline int is_shared_micin(struct snd_ac97 *ac97) { - return ! ac97->indep_surround && is_clfe_on(ac97); + return !ac97->indep_surround && !is_clfe_on(ac97); } @@ -2017,12 +2031,12 @@ static void alc650_update_jacks(struct snd_ac97 *ac97) { int shared; - /* shared Line-In */ - shared = is_shared_linein(ac97); + /* shared Line-In / Surround Out */ + shared = is_shared_surrout(ac97); snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 1 << 9, shared ? (1 << 9) : 0); - /* update shared Mic */ - shared = is_shared_micin(ac97); + /* update shared Mic In / Center/LFE Out */ + shared = is_shared_clfeout(ac97); /* disable/enable vref */ snd_ac97_update_bits(ac97, AC97_ALC650_CLOCK, 1 << 12, shared ? (1 << 12) : 0); @@ -2152,12 +2166,12 @@ static void alc655_update_jacks(struct snd_ac97 *ac97) { int shared; - /* shared Line-In */ - shared = is_shared_linein(ac97); + /* shared Line-In / Surround Out */ + shared = is_shared_surrout(ac97); ac97_update_bits_page(ac97, AC97_ALC650_MULTICH, 1 << 9, shared ? (1 << 9) : 0, 0); - /* update shared mic */ - shared = is_shared_micin(ac97); + /* update shared Mic In / Center/LFE Out */ + shared = is_shared_clfeout(ac97); /* misc control; vrefout disable */ snd_ac97_update_bits(ac97, AC97_ALC650_CLOCK, 1 << 12, shared ? (1 << 12) : 0); @@ -2301,16 +2315,16 @@ static void alc850_update_jacks(struct snd_ac97 *ac97) { int shared; - /* shared Line-In */ - shared = is_shared_linein(ac97); + /* shared Line-In / Surround Out */ + shared = is_shared_surrout(ac97); /* SURR 1kOhm (bit4), Amp (bit5) */ snd_ac97_update_bits(ac97, AC97_ALC850_MISC1, (1<<4)|(1<<5), shared ? (1<<5) : (1<<4)); /* LINE-IN = 0, SURROUND = 2 */ snd_ac97_update_bits(ac97, AC97_ALC850_JACK_SELECT, 7 << 12, shared ? (2<<12) : (0<<12)); - /* update shared mic */ - shared = is_shared_micin(ac97); + /* update shared Mic In / Center/LFE Out */ + shared = is_shared_clfeout(ac97); /* Vref disable (bit12), 1kOhm (bit13) */ snd_ac97_update_bits(ac97, AC97_ALC850_MISC1, (1<<12)|(1<<13), shared ? (1<<12) : (1<<13)); @@ -2383,9 +2397,9 @@ int patch_alc850(struct snd_ac97 *ac97) */ static void cm9738_update_jacks(struct snd_ac97 *ac97) { - /* shared Line-In */ + /* shared Line-In / Surround Out */ snd_ac97_update_bits(ac97, AC97_CM9738_VENDOR_CTRL, 1 << 10, - is_shared_linein(ac97) ? (1 << 10) : 0); + is_shared_surrout(ac97) ? (1 << 10) : 0); } static const struct snd_kcontrol_new snd_ac97_cm9738_controls[] = { @@ -2467,12 +2481,12 @@ static const struct snd_kcontrol_new snd_ac97_cm9739_controls_spdif[] = { static void cm9739_update_jacks(struct snd_ac97 *ac97) { - /* shared Line-In */ + /* shared Line-In / Surround Out */ snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 1 << 10, - is_shared_linein(ac97) ? (1 << 10) : 0); - /* shared Mic */ + is_shared_surrout(ac97) ? (1 << 10) : 0); + /* shared Mic In / Center/LFE Out **/ snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 0x3000, - is_shared_micin(ac97) ? 0x1000 : 0x2000); + is_shared_clfeout(ac97) ? 0x1000 : 0x2000); } static const struct snd_kcontrol_new snd_ac97_cm9739_controls[] = { @@ -2584,8 +2598,8 @@ static void cm9761_update_jacks(struct snd_ac97 *ac97) val |= surr_on[ac97->spec.dev_flags][is_surround_on(ac97)]; val |= clfe_on[ac97->spec.dev_flags][is_clfe_on(ac97)]; - val |= surr_shared[ac97->spec.dev_flags][is_shared_linein(ac97)]; - val |= clfe_shared[ac97->spec.dev_flags][is_shared_micin(ac97)]; + val |= surr_shared[ac97->spec.dev_flags][is_shared_surrout(ac97)]; + val |= clfe_shared[ac97->spec.dev_flags][is_shared_clfeout(ac97)]; snd_ac97_update_bits(ac97, AC97_CM9761_MULTI_CHAN, 0x3c88, val); } @@ -2832,12 +2846,12 @@ int patch_vt1617a(struct snd_ac97 * ac97) */ static void it2646_update_jacks(struct snd_ac97 *ac97) { - /* shared Line-In */ + /* shared Line-In / Surround Out */ snd_ac97_update_bits(ac97, 0x76, 1 << 9, - is_shared_linein(ac97) ? (1<<9) : 0); - /* shared Mic */ + is_shared_surrout(ac97) ? (1<<9) : 0); + /* shared Mic / Center/LFE Out */ snd_ac97_update_bits(ac97, 0x76, 1 << 10, - is_shared_micin(ac97) ? (1<<10) : 0); + is_shared_clfeout(ac97) ? (1<<10) : 0); } static const struct snd_kcontrol_new snd_ac97_controls_it2646[] = { -- cgit v1.2.3 From 1321b160fa1cf63fa841d954fe31220366b6647a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 21 Dec 2006 11:02:06 +0100 Subject: [ALSA] soc - Fix delayed_work related changes on 2.6.20 kernel Fix the changes realted to delayed_work in soc/codecs/wm8750.c. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/codecs/wm8750.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index 069b66cb18e..e7f04b89c8a 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c @@ -51,8 +51,6 @@ #define warn(format, arg...) \ printk(KERN_WARNING AUDIO_NAME ": " format "\n" , ## arg) -static struct work_struct wm8750_dapm_work; - /* * wm8750 register cache * We can't read the WM8750 register space when we @@ -1000,9 +998,10 @@ struct snd_soc_codec_dai wm8750_dai = { }; EXPORT_SYMBOL_GPL(wm8750_dai); -static void wm8750_work(void *data) +static void wm8750_work(struct work_struct *work) { - struct snd_soc_codec *codec = (struct snd_soc_codec *)data; + struct snd_soc_codec *codec = + container_of(work, struct snd_soc_codec, delayed_work.work); wm8750_dapm_event(codec, codec->dapm_state); } @@ -1038,7 +1037,7 @@ static int wm8750_resume(struct platform_device *pdev) if (codec->suspend_dapm_state == SNDRV_CTL_POWER_D0) { wm8750_dapm_event(codec, SNDRV_CTL_POWER_D2); codec->dapm_state = SNDRV_CTL_POWER_D0; - schedule_delayed_work(&wm8750_dapm_work, + schedule_delayed_work(&codec->delayed_work, msecs_to_jiffies(1000)); } @@ -1083,7 +1082,7 @@ static int wm8750_init(struct snd_soc_device *socdev) /* charge output caps */ wm8750_dapm_event(codec, SNDRV_CTL_POWER_D2); codec->dapm_state = SNDRV_CTL_POWER_D3hot; - schedule_delayed_work(&wm8750_dapm_work, msecs_to_jiffies(1000)); + schedule_delayed_work(&codec->delayed_work, msecs_to_jiffies(1000)); /* set the update bits */ reg = wm8750_read_reg_cache(codec, WM8750_LDAC); @@ -1225,7 +1224,7 @@ static int wm8750_probe(struct platform_device *pdev) INIT_LIST_HEAD(&codec->dapm_widgets); INIT_LIST_HEAD(&codec->dapm_paths); wm8750_socdev = socdev; - INIT_WORK(&wm8750_dapm_work, wm8750_work, codec); + INIT_DELAYED_WORK(&codec->delayed_work, wm8750_work); #if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE) if (setup->i2c_address) { normal_i2c[0] = setup->i2c_address; -- cgit v1.2.3 From 6428ea1b733e4795209ff272be32732ec152594a Mon Sep 17 00:00:00 2001 From: Randy Cushman Date: Thu, 21 Dec 2006 19:17:29 +0100 Subject: [ALSA] ac97 - fix malfunctioning mixer controls for AD1985 This patch replaces the 'V_REFOUT Enable' mixer switch control with a listbox control for the AD1985 CODEC. Previous patch 'AD1888 mixer controls for DC mode' added controls that were propogated to multiple codecs. For the AD1985 codec, the bits VREFH and VREFD function differently, preventing the 'V_REFOUT Enable' control from setting V_REFOUT to Hi-Z. This patch also corrects an issue in which register bits relating to mixer controls 'Surround Jack Mode' and 'Channel Mode'. The register bits controlled by these controls were being set at boot time to states inconsistent with the stored values of these controls. Signed-off-by: Randy Cushman Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/ac97/ac97_patch.c | 103 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 92 insertions(+), 11 deletions(-) (limited to 'sound') diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 5f69b9c9f1b..bd27531a0f0 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -1632,13 +1632,16 @@ int patch_ad1886(struct snd_ac97 * ac97) #define AC97_AD198X_MBC_10 0x0001 /* +10dB */ #define AC97_AD198X_MBC_30 0x0002 /* +30dB */ #define AC97_AD198X_VREFD 0x0004 /* VREF high-Z */ -#define AC97_AD198X_VREFH 0x0008 /* 2.25V, 3.7V */ -#define AC97_AD198X_VREF_0 0x000c /* 0V */ +#define AC97_AD198X_VREFH 0x0008 /* 0=2.25V, 1=3.7V */ +#define AC97_AD198X_VREF_0 0x000c /* 0V (AD1985 only) */ +#define AC97_AD198X_VREF_MASK (AC97_AD198X_VREFH | AC97_AD198X_VREFD) +#define AC97_AD198X_VREF_SHIFT 2 #define AC97_AD198X_SRU 0x0010 /* sample rate unlock */ #define AC97_AD198X_LOSEL 0x0020 /* LINE_OUT amplifiers input select */ #define AC97_AD198X_2MIC 0x0040 /* 2-channel mic select */ #define AC97_AD198X_SPRD 0x0080 /* SPREAD enable */ -#define AC97_AD198X_DMIX0 0x0100 /* downmix mode: 0 = 6-to-4, 1 = 6-to-2 downmix */ +#define AC97_AD198X_DMIX0 0x0100 /* downmix mode: */ + /* 0 = 6-to-4, 1 = 6-to-2 downmix */ #define AC97_AD198X_DMIX1 0x0200 /* downmix mode: 1 = enabled */ #define AC97_AD198X_HPSEL 0x0400 /* headphone amplifier input select */ #define AC97_AD198X_CLDIS 0x0800 /* center/lfe disable */ @@ -1969,8 +1972,80 @@ int patch_ad1980(struct snd_ac97 * ac97) return 0; } +static int snd_ac97_ad1985_vrefout_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + static char *texts[4] = {"High-Z", "3.7 V", "2.25 V", "0 V"}; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 4; + if (uinfo->value.enumerated.item > 3) + uinfo->value.enumerated.item = 3; + strcpy(uinfo->value.enumerated.name, + texts[uinfo->value.enumerated.item]); + return 0; +} + +static int snd_ac97_ad1985_vrefout_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + static const int reg2ctrl[4] = {2, 0, 1, 3}; + struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); + unsigned short val; + val = (ac97->regs[AC97_AD_MISC] & AC97_AD198X_VREF_MASK) + >> AC97_AD198X_VREF_SHIFT; + ucontrol->value.enumerated.item[0] = reg2ctrl[val]; + return 0; +} + +static int snd_ac97_ad1985_vrefout_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + static const int ctrl2reg[4] = {1, 2, 0, 3}; + struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); + unsigned short val; + + if (ucontrol->value.enumerated.item[0] > 3 + || ucontrol->value.enumerated.item[0] < 0) + return -EINVAL; + val = ctrl2reg[ucontrol->value.enumerated.item[0]] + << AC97_AD198X_VREF_SHIFT; + return snd_ac97_update_bits(ac97, AC97_AD_MISC, + AC97_AD198X_VREF_MASK, val); +} + static const struct snd_kcontrol_new snd_ac97_ad1985_controls[] = { - AC97_SINGLE("Exchange Center/LFE", AC97_AD_SERIAL_CFG, 3, 1, 0) + AC97_SINGLE("Exchange Center/LFE", AC97_AD_SERIAL_CFG, 3, 1, 0), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Exchange Front/Surround", + .info = snd_ac97_ad1888_lohpsel_info, + .get = snd_ac97_ad1888_lohpsel_get, + .put = snd_ac97_ad1888_lohpsel_put + }, + AC97_SINGLE("High Pass Filter Enable", AC97_AD_TEST2, 12, 1, 1), + AC97_SINGLE("Spread Front to Surround and Center/LFE", + AC97_AD_MISC, 7, 1, 0), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Downmix", + .info = snd_ac97_ad1888_downmix_info, + .get = snd_ac97_ad1888_downmix_get, + .put = snd_ac97_ad1888_downmix_put + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "V_REFOUT", + .info = snd_ac97_ad1985_vrefout_info, + .get = snd_ac97_ad1985_vrefout_get, + .put = snd_ac97_ad1985_vrefout_put + }, + AC97_SURROUND_JACK_MODE_CTL, + AC97_CHANNEL_MODE_CTL, + + AC97_SINGLE("Headphone Jack Sense", AC97_AD_JACK_SPDIF, 10, 1, 0), + AC97_SINGLE("Line Jack Sense", AC97_AD_JACK_SPDIF, 12, 1, 0), }; static void ad1985_update_jacks(struct snd_ac97 *ac97) @@ -1984,9 +2059,16 @@ static int patch_ad1985_specific(struct snd_ac97 *ac97) { int err; - if ((err = patch_ad1980_specific(ac97)) < 0) + /* rename 0x04 as "Master" and 0x02 as "Master Surround" */ + snd_ac97_rename_vol_ctl(ac97, "Master Playback", + "Master Surround Playback"); + snd_ac97_rename_vol_ctl(ac97, "Headphone Playback", "Master Playback"); + + if ((err = patch_build_controls(ac97, &snd_ac97_ad198x_2cmic, 1)) < 0) return err; - return patch_build_controls(ac97, snd_ac97_ad1985_controls, ARRAY_SIZE(snd_ac97_ad1985_controls)); + + return patch_build_controls(ac97, snd_ac97_ad1985_controls, + ARRAY_SIZE(snd_ac97_ad1985_controls)); } static struct snd_ac97_build_ops patch_ad1985_build_ops = { @@ -2006,19 +2088,18 @@ int patch_ad1985(struct snd_ac97 * ac97) ac97->build_ops = &patch_ad1985_build_ops; misc = snd_ac97_read(ac97, AC97_AD_MISC); /* switch front/surround line-out/hp-out */ - /* center/LFE, mic in 3.75V mode */ /* AD-compatible mode */ /* Stereo mutes enabled */ - /* in accordance with ADI driver: misc | 0x5c28 */ snd_ac97_write_cache(ac97, AC97_AD_MISC, misc | - AC97_AD198X_VREFH | AC97_AD198X_LOSEL | AC97_AD198X_HPSEL | - AC97_AD198X_CLDIS | - AC97_AD198X_LODIS | AC97_AD198X_MSPLT | AC97_AD198X_AC97NC); ac97->flags |= AC97_STEREO_MUTES; + + /* update current jack configuration */ + ad1985_update_jacks(ac97); + /* on AD1985 rev. 3, AC'97 revision bits are zero */ ac97->ext_id = (ac97->ext_id & ~AC97_EI_REV_MASK) | AC97_EI_REV_23; return 0; -- cgit v1.2.3 From 67e9f4b68c9d1820132c559c0f9b296dafdf631e Mon Sep 17 00:00:00 2001 From: Randy Cushman Date: Fri, 22 Dec 2006 12:44:25 +0100 Subject: [ALSA] ac97 - fix various issues with AD1986/AD1986A support Previously, ac97_codec.c was coded to support AD1986 and AD1986A CODECs using code written for the AD1985 CODEC. This allowed the LINE_OUT and HEADPHONE jacks to function properly, however register differences between the CODECs prevented line and microphone inputs from functioning. Specifically, this patch fixes issues with the following mixer controls: 'V_REFOUT', 'Spread Front to Surround and Center/LFE', 'Exchange Front/Surround', 'Surround Jack Mode', and 'Channel Mode'. This patch removes the undocumented AD1888 control 'High Pass Filter Enable' and adds the new control 'Exchange Mic/Line In'. Signed-off-by: Randy Cushman Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/ac97/ac97_codec.c | 2 +- sound/pci/ac97/ac97_patch.c | 367 +++++++++++++++++++++++++++++++++++++++++++- sound/pci/ac97/ac97_patch.h | 1 + 3 files changed, 368 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 9da4977c0a0..bd8cfdcfbdf 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -111,7 +111,7 @@ static const struct ac97_codec_id snd_ac97_codec_ids[] = { { 0x41445372, 0xffffffff, "AD1981A", patch_ad1981a, NULL }, { 0x41445374, 0xffffffff, "AD1981B", patch_ad1981b, NULL }, { 0x41445375, 0xffffffff, "AD1985", patch_ad1985, NULL }, -{ 0x41445378, 0xffffffff, "AD1986", patch_ad1985, NULL }, +{ 0x41445378, 0xffffffff, "AD1986", patch_ad1986, NULL }, { 0x414c4300, 0xffffff00, "ALC100,100P", NULL, NULL }, { 0x414c4710, 0xfffffff0, "ALC200,200P", NULL, NULL }, { 0x414c4721, 0xffffffff, "ALC650D", NULL, NULL }, /* already patched */ diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index bd27531a0f0..f5b4b44bbda 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -1626,7 +1626,7 @@ int patch_ad1886(struct snd_ac97 * ac97) return 0; } -/* MISC bits */ +/* MISC bits (AD1888/AD1980/AD1985 register 0x76) */ #define AC97_AD198X_MBC 0x0003 /* mic boost */ #define AC97_AD198X_MBC_20 0x0000 /* +20dB */ #define AC97_AD198X_MBC_10 0x0001 /* +10dB */ @@ -1650,6 +1650,83 @@ int patch_ad1886(struct snd_ac97 * ac97) #define AC97_AD198X_AC97NC 0x4000 /* AC97 no compatible mode */ #define AC97_AD198X_DACZ 0x8000 /* DAC zero-fill mode */ +/* MISC 1 bits (AD1986 register 0x76) */ +#define AC97_AD1986_MBC 0x0003 /* mic boost */ +#define AC97_AD1986_MBC_20 0x0000 /* +20dB */ +#define AC97_AD1986_MBC_10 0x0001 /* +10dB */ +#define AC97_AD1986_MBC_30 0x0002 /* +30dB */ +#define AC97_AD1986_LISEL0 0x0004 /* LINE_IN select bit 0 */ +#define AC97_AD1986_LISEL1 0x0008 /* LINE_IN select bit 1 */ +#define AC97_AD1986_LISEL_MASK (AC97_AD1986_LISEL1 | AC97_AD1986_LISEL0) +#define AC97_AD1986_LISEL_LI 0x0000 /* LINE_IN pins as LINE_IN source */ +#define AC97_AD1986_LISEL_SURR 0x0004 /* SURROUND pins as LINE_IN source */ +#define AC97_AD1986_LISEL_MIC 0x0008 /* MIC_1/2 pins as LINE_IN source */ +#define AC97_AD1986_SRU 0x0010 /* sample rate unlock */ +#define AC97_AD1986_SOSEL 0x0020 /* SURROUND_OUT amplifiers input sel */ +#define AC97_AD1986_2MIC 0x0040 /* 2-channel mic select */ +#define AC97_AD1986_SPRD 0x0080 /* SPREAD enable */ +#define AC97_AD1986_DMIX0 0x0100 /* downmix mode: */ + /* 0 = 6-to-4, 1 = 6-to-2 downmix */ +#define AC97_AD1986_DMIX1 0x0200 /* downmix mode: 1 = enabled */ +#define AC97_AD1986_CLDIS 0x0800 /* center/lfe disable */ +#define AC97_AD1986_SODIS 0x1000 /* SURROUND_OUT disable */ +#define AC97_AD1986_MSPLT 0x2000 /* mute split (read only 1) */ +#define AC97_AD1986_AC97NC 0x4000 /* AC97 no compatible mode (r/o 1) */ +#define AC97_AD1986_DACZ 0x8000 /* DAC zero-fill mode */ + +/* MISC 2 bits (AD1986 register 0x70) */ +#define AC97_AD_MISC2 0x70 /* Misc Control Bits 2 (AD1986) */ + +#define AC97_AD1986_CVREF0 0x0004 /* C/LFE VREF_OUT 2.25V */ +#define AC97_AD1986_CVREF1 0x0008 /* C/LFE VREF_OUT 0V */ +#define AC97_AD1986_CVREF2 0x0010 /* C/LFE VREF_OUT 3.7V */ +#define AC97_AD1986_CVREF_MASK \ + (AC97_AD1986_CVREF2 | AC97_AD1986_CVREF1 | AC97_AD1986_CVREF0) +#define AC97_AD1986_JSMAP 0x0020 /* Jack Sense Mapping 1 = alternate */ +#define AC97_AD1986_MMDIS 0x0080 /* Mono Mute Disable */ +#define AC97_AD1986_MVREF0 0x0400 /* MIC VREF_OUT 2.25V */ +#define AC97_AD1986_MVREF1 0x0800 /* MIC VREF_OUT 0V */ +#define AC97_AD1986_MVREF2 0x1000 /* MIC VREF_OUT 3.7V */ +#define AC97_AD1986_MVREF_MASK \ + (AC97_AD1986_MVREF2 | AC97_AD1986_MVREF1 | AC97_AD1986_MVREF0) + +/* MISC 3 bits (AD1986 register 0x7a) */ +#define AC97_AD_MISC3 0x7a /* Misc Control Bits 3 (AD1986) */ + +#define AC97_AD1986_MMIX 0x0004 /* Mic Mix, left/right */ +#define AC97_AD1986_GPO 0x0008 /* General Purpose Out */ +#define AC97_AD1986_LOHPEN 0x0010 /* LINE_OUT headphone drive */ +#define AC97_AD1986_LVREF0 0x0100 /* LINE_OUT VREF_OUT 2.25V */ +#define AC97_AD1986_LVREF1 0x0200 /* LINE_OUT VREF_OUT 0V */ +#define AC97_AD1986_LVREF2 0x0400 /* LINE_OUT VREF_OUT 3.7V */ +#define AC97_AD1986_LVREF_MASK \ + (AC97_AD1986_LVREF2 | AC97_AD1986_LVREF1 | AC97_AD1986_LVREF0) +#define AC97_AD1986_JSINVA 0x0800 /* Jack Sense Invert SENSE_A */ +#define AC97_AD1986_LOSEL 0x1000 /* LINE_OUT amplifiers input select */ +#define AC97_AD1986_HPSEL0 0x2000 /* Headphone amplifiers */ + /* input select Surround DACs */ +#define AC97_AD1986_HPSEL1 0x4000 /* Headphone amplifiers input */ + /* select C/LFE DACs */ +#define AC97_AD1986_JSINVB 0x8000 /* Jack Sense Invert SENSE_B */ + +/* Serial Config bits (AD1986 register 0x74) (incomplete) */ +#define AC97_AD1986_OMS0 0x0100 /* Optional Mic Selector bit 0 */ +#define AC97_AD1986_OMS1 0x0200 /* Optional Mic Selector bit 1 */ +#define AC97_AD1986_OMS2 0x0400 /* Optional Mic Selector bit 2 */ +#define AC97_AD1986_OMS_MASK \ + (AC97_AD1986_OMS2 | AC97_AD1986_OMS1 | AC97_AD1986_OMS0) +#define AC97_AD1986_OMS_M 0x0000 /* MIC_1/2 pins are MIC sources */ +#define AC97_AD1986_OMS_L 0x0100 /* LINE_IN pins are MIC sources */ +#define AC97_AD1986_OMS_C 0x0200 /* Center/LFE pins are MCI sources */ +#define AC97_AD1986_OMS_MC 0x0400 /* Mix of MIC and C/LFE pins */ + /* are MIC sources */ +#define AC97_AD1986_OMS_ML 0x0500 /* MIX of MIC and LINE_IN pins */ + /* are MIC sources */ +#define AC97_AD1986_OMS_LC 0x0600 /* MIX of LINE_IN and C/LFE pins */ + /* are MIC sources */ +#define AC97_AD1986_OMS_MLC 0x0700 /* MIX of MIC, LINE_IN, C/LFE pins */ + /* are MIC sources */ + static int snd_ac97_ad198x_spdif_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -2105,6 +2182,294 @@ int patch_ad1985(struct snd_ac97 * ac97) return 0; } +static int snd_ac97_ad1986_bool_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int snd_ac97_ad1986_lososel_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); + unsigned short val; + + val = ac97->regs[AC97_AD_MISC3]; + ucontrol->value.integer.value[0] = (val & AC97_AD1986_LOSEL) != 0; + return 0; +} + +static int snd_ac97_ad1986_lososel_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); + int ret0; + int ret1; + int sprd = (ac97->regs[AC97_AD_MISC] & AC97_AD1986_SPRD) != 0; + + ret0 = snd_ac97_update_bits(ac97, AC97_AD_MISC3, AC97_AD1986_LOSEL, + ucontrol->value.integer.value[0] != 0 + ? AC97_AD1986_LOSEL : 0); + if (ret0 < 0) + return ret0; + + /* SOSEL is set to values of "Spread" or "Exchange F/S" controls */ + ret1 = snd_ac97_update_bits(ac97, AC97_AD_MISC, AC97_AD1986_SOSEL, + (ucontrol->value.integer.value[0] != 0 + || sprd) + ? AC97_AD1986_SOSEL : 0); + if (ret1 < 0) + return ret1; + + return (ret0 > 0 || ret1 > 0) ? 1 : 0; +} + +static int snd_ac97_ad1986_spread_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); + unsigned short val; + + val = ac97->regs[AC97_AD_MISC]; + ucontrol->value.integer.value[0] = (val & AC97_AD1986_SPRD) != 0; + return 0; +} + +static int snd_ac97_ad1986_spread_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); + int ret0; + int ret1; + int sprd = (ac97->regs[AC97_AD_MISC3] & AC97_AD1986_LOSEL) != 0; + + ret0 = snd_ac97_update_bits(ac97, AC97_AD_MISC, AC97_AD1986_SPRD, + ucontrol->value.integer.value[0] != 0 + ? AC97_AD1986_SPRD : 0); + if (ret0 < 0) + return ret0; + + /* SOSEL is set to values of "Spread" or "Exchange F/S" controls */ + ret1 = snd_ac97_update_bits(ac97, AC97_AD_MISC, AC97_AD1986_SOSEL, + (ucontrol->value.integer.value[0] != 0 + || sprd) + ? AC97_AD1986_SOSEL : 0); + if (ret1 < 0) + return ret1; + + return (ret0 > 0 || ret1 > 0) ? 1 : 0; +} + +static int snd_ac97_ad1986_miclisel_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); + + ucontrol->value.integer.value[0] = ac97->spec.ad18xx.swap_mic_linein; + return 0; +} + +static int snd_ac97_ad1986_miclisel_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); + unsigned char swap = ucontrol->value.integer.value[0] != 0; + + if (swap != ac97->spec.ad18xx.swap_mic_linein) { + ac97->spec.ad18xx.swap_mic_linein = swap; + if (ac97->build_ops->update_jacks) + ac97->build_ops->update_jacks(ac97); + return 1; + } + return 0; +} + +static int snd_ac97_ad1986_vrefout_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + /* Use MIC_1/2 V_REFOUT as the "get" value */ + struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); + unsigned short val; + unsigned short reg = ac97->regs[AC97_AD_MISC2]; + if ((reg & AC97_AD1986_MVREF0) != 0) + val = 2; + else if ((reg & AC97_AD1986_MVREF1) != 0) + val = 3; + else if ((reg & AC97_AD1986_MVREF2) != 0) + val = 1; + else + val = 0; + ucontrol->value.enumerated.item[0] = val; + return 0; +} + +static int snd_ac97_ad1986_vrefout_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); + unsigned short cval; + unsigned short lval; + unsigned short mval; + int cret; + int lret; + int mret; + + switch (ucontrol->value.enumerated.item[0]) + { + case 0: /* High-Z */ + cval = 0; + lval = 0; + mval = 0; + break; + case 1: /* 3.7 V */ + cval = AC97_AD1986_CVREF2; + lval = AC97_AD1986_LVREF2; + mval = AC97_AD1986_MVREF2; + break; + case 2: /* 2.25 V */ + cval = AC97_AD1986_CVREF0; + lval = AC97_AD1986_LVREF0; + mval = AC97_AD1986_MVREF0; + break; + case 3: /* 0 V */ + cval = AC97_AD1986_CVREF1; + lval = AC97_AD1986_LVREF1; + mval = AC97_AD1986_MVREF1; + break; + default: + return -EINVAL; + } + + cret = snd_ac97_update_bits(ac97, AC97_AD_MISC2, + AC97_AD1986_CVREF_MASK, cval); + if (cret < 0) + return cret; + lret = snd_ac97_update_bits(ac97, AC97_AD_MISC3, + AC97_AD1986_LVREF_MASK, lval); + if (lret < 0) + return lret; + mret = snd_ac97_update_bits(ac97, AC97_AD_MISC2, + AC97_AD1986_MVREF_MASK, mval); + if (mret < 0) + return mret; + + return (cret > 0 || lret > 0 || mret > 0) ? 1 : 0; +} + +static const struct snd_kcontrol_new snd_ac97_ad1986_controls[] = { + AC97_SINGLE("Exchange Center/LFE", AC97_AD_SERIAL_CFG, 3, 1, 0), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Exchange Front/Surround", + .info = snd_ac97_ad1986_bool_info, + .get = snd_ac97_ad1986_lososel_get, + .put = snd_ac97_ad1986_lososel_put + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Exchange Mic/Line In", + .info = snd_ac97_ad1986_bool_info, + .get = snd_ac97_ad1986_miclisel_get, + .put = snd_ac97_ad1986_miclisel_put + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Spread Front to Surround and Center/LFE", + .info = snd_ac97_ad1986_bool_info, + .get = snd_ac97_ad1986_spread_get, + .put = snd_ac97_ad1986_spread_put + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Downmix", + .info = snd_ac97_ad1888_downmix_info, + .get = snd_ac97_ad1888_downmix_get, + .put = snd_ac97_ad1888_downmix_put + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "V_REFOUT", + .info = snd_ac97_ad1985_vrefout_info, + .get = snd_ac97_ad1986_vrefout_get, + .put = snd_ac97_ad1986_vrefout_put + }, + AC97_SURROUND_JACK_MODE_CTL, + AC97_CHANNEL_MODE_CTL, + + AC97_SINGLE("Headphone Jack Sense", AC97_AD_JACK_SPDIF, 10, 1, 0), + AC97_SINGLE("Line Jack Sense", AC97_AD_JACK_SPDIF, 12, 1, 0) +}; + +static void ad1986_update_jacks(struct snd_ac97 *ac97) +{ + unsigned short misc_val = 0; + unsigned short ser_val; + + /* disable SURROUND and CENTER/LFE if not surround mode */ + if (! is_surround_on(ac97)) + misc_val |= AC97_AD1986_SODIS; + if (! is_clfe_on(ac97)) + misc_val |= AC97_AD1986_CLDIS; + + /* select line input (default=LINE_IN, SURROUND or MIC_1/2) */ + if (is_shared_linein(ac97)) + misc_val |= AC97_AD1986_LISEL_SURR; + else if (ac97->spec.ad18xx.swap_mic_linein != 0) + misc_val |= AC97_AD1986_LISEL_MIC; + snd_ac97_update_bits(ac97, AC97_AD_MISC, + AC97_AD1986_SODIS | AC97_AD1986_CLDIS | + AC97_AD1986_LISEL_MASK, + misc_val); + + /* select microphone input (MIC_1/2, Center/LFE or LINE_IN) */ + if (is_shared_micin(ac97)) + ser_val = AC97_AD1986_OMS_C; + else if (ac97->spec.ad18xx.swap_mic_linein != 0) + ser_val = AC97_AD1986_OMS_L; + else + ser_val = AC97_AD1986_OMS_M; + snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, + AC97_AD1986_OMS_MASK, + ser_val); +} + +static int patch_ad1986_specific(struct snd_ac97 *ac97) +{ + int err; + + if ((err = patch_build_controls(ac97, &snd_ac97_ad198x_2cmic, 1)) < 0) + return err; + + return patch_build_controls(ac97, snd_ac97_ad1986_controls, + ARRAY_SIZE(snd_ac97_ad1985_controls)); +} + +static struct snd_ac97_build_ops patch_ad1986_build_ops = { + .build_post_spdif = patch_ad198x_post_spdif, + .build_specific = patch_ad1986_specific, +#ifdef CONFIG_PM + .resume = ad18xx_resume, +#endif + .update_jacks = ad1986_update_jacks, +}; + +int patch_ad1986(struct snd_ac97 * ac97) +{ + patch_ad1881(ac97); + ac97->build_ops = &patch_ad1986_build_ops; + ac97->flags |= AC97_STEREO_MUTES; + + /* update current jack configuration */ + ad1986_update_jacks(ac97); + + return 0; +} + + /* * realtek ALC65x/850 codecs */ diff --git a/sound/pci/ac97/ac97_patch.h b/sound/pci/ac97/ac97_patch.h index 74197921720..94340daaaf1 100644 --- a/sound/pci/ac97/ac97_patch.h +++ b/sound/pci/ac97/ac97_patch.h @@ -48,6 +48,7 @@ int patch_ad1980(struct snd_ac97 * ac97); int patch_ad1981a(struct snd_ac97 * ac97); int patch_ad1981b(struct snd_ac97 * ac97); int patch_ad1985(struct snd_ac97 * ac97); +int patch_ad1986(struct snd_ac97 * ac97); int patch_alc650(struct snd_ac97 * ac97); int patch_alc655(struct snd_ac97 * ac97); int patch_alc850(struct snd_ac97 * ac97); -- cgit v1.2.3 From 88518275e3eefe0582af1918d59325b16dfde154 Mon Sep 17 00:00:00 2001 From: John Daiker Date: Thu, 28 Dec 2006 13:55:05 +0100 Subject: [ALSA] usbaudio.c: remove unneeded casts Went rummaging through usbaudio.c and found some castings that aren't needed as far as I can see. Part of the KernelJanitors TODO list. Signed-off-by: John Daiker Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/usb/usbaudio.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'sound') diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index d2e066dc5d8..de680d095e9 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -253,7 +253,7 @@ static int prepare_capture_sync_urb(struct snd_usb_substream *subs, struct urb *urb) { unsigned char *cp = urb->transfer_buffer; - struct snd_urb_ctx *ctx = (struct snd_urb_ctx *)urb->context; + struct snd_urb_ctx *ctx = urb->context; urb->dev = ctx->subs->dev; /* we need to set this at each time */ urb->iso_frame_desc[0].length = 3; @@ -275,7 +275,7 @@ static int prepare_capture_sync_urb_hs(struct snd_usb_substream *subs, struct urb *urb) { unsigned char *cp = urb->transfer_buffer; - struct snd_urb_ctx *ctx = (struct snd_urb_ctx *)urb->context; + struct snd_urb_ctx *ctx = urb->context; urb->dev = ctx->subs->dev; /* we need to set this at each time */ urb->iso_frame_desc[0].length = 4; @@ -313,7 +313,7 @@ static int prepare_capture_urb(struct snd_usb_substream *subs, struct urb *urb) { int i, offs; - struct snd_urb_ctx *ctx = (struct snd_urb_ctx *)urb->context; + struct snd_urb_ctx *ctx = urb->context; offs = 0; urb->dev = ctx->subs->dev; /* we need to set this at each time */ @@ -412,7 +412,7 @@ static int prepare_playback_sync_urb(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *urb) { - struct snd_urb_ctx *ctx = (struct snd_urb_ctx *)urb->context; + struct snd_urb_ctx *ctx = urb->context; urb->dev = ctx->subs->dev; /* we need to set this at each time */ urb->iso_frame_desc[0].length = 3; @@ -430,7 +430,7 @@ static int prepare_playback_sync_urb_hs(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *urb) { - struct snd_urb_ctx *ctx = (struct snd_urb_ctx *)urb->context; + struct snd_urb_ctx *ctx = urb->context; urb->dev = ctx->subs->dev; /* we need to set this at each time */ urb->iso_frame_desc[0].length = 4; @@ -547,7 +547,7 @@ static int prepare_playback_urb(struct snd_usb_substream *subs, unsigned int counts; unsigned long flags; int period_elapsed = 0; - struct snd_urb_ctx *ctx = (struct snd_urb_ctx *)urb->context; + struct snd_urb_ctx *ctx = urb->context; stride = runtime->frame_bits >> 3; @@ -665,7 +665,7 @@ static struct snd_urb_ops audio_urb_ops_high_speed[2] = { */ static void snd_complete_urb(struct urb *urb) { - struct snd_urb_ctx *ctx = (struct snd_urb_ctx *)urb->context; + struct snd_urb_ctx *ctx = urb->context; struct snd_usb_substream *subs = ctx->subs; struct snd_pcm_substream *substream = ctx->subs->pcm_substream; int err = 0; @@ -688,7 +688,7 @@ static void snd_complete_urb(struct urb *urb) */ static void snd_complete_sync_urb(struct urb *urb) { - struct snd_urb_ctx *ctx = (struct snd_urb_ctx *)urb->context; + struct snd_urb_ctx *ctx = urb->context; struct snd_usb_substream *subs = ctx->subs; struct snd_pcm_substream *substream = ctx->subs->pcm_substream; int err = 0; @@ -1429,7 +1429,7 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) static int snd_usb_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { - struct snd_usb_substream *subs = (struct snd_usb_substream *)substream->runtime->private_data; + struct snd_usb_substream *subs = substream->runtime->private_data; struct audioformat *fmt; unsigned int channels, rate, format; int ret, changed; @@ -1485,7 +1485,7 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, */ static int snd_usb_hw_free(struct snd_pcm_substream *substream) { - struct snd_usb_substream *subs = (struct snd_usb_substream *)substream->runtime->private_data; + struct snd_usb_substream *subs = substream->runtime->private_data; subs->cur_audiofmt = NULL; subs->cur_rate = 0; -- cgit v1.2.3 From 7b9470d88492d8be22d1f5307fe28642db9affe5 Mon Sep 17 00:00:00 2001 From: Tobin Davis Date: Thu, 28 Dec 2006 13:56:48 +0100 Subject: [ALSA] hda-codec - Add Asus P5W DH to alc882_cfg_tbl This patch adds the Asus P5W DH to the ALC882 config table as a 6stack-dig system. Signed-off-by: Tobin Davis Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 2be0ef9023b..e4e7512ed02 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4738,6 +4738,7 @@ static struct snd_pci_quirk alc882_cfg_tbl[] = { SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG), SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG), SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA), + SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG), {} }; -- cgit v1.2.3 From f6cdab5f7ed356e8a259c1f00c7991f56c234643 Mon Sep 17 00:00:00 2001 From: Clement Guedez Date: Mon, 8 Jan 2007 10:48:41 +0100 Subject: [ALSA] Add support of the ESI Waveterminal 192M to the ice1724 ALSA driver This patch adds the support of the ESI Waveterminal 192M soundcard to the ice1724 familly ALSA driver. It's a semi-professionnal soundcard for home studio : many I/O and a quality of sound is good, better than consumer cards, but less musical than professional cards. It use a Via Envy24ht chipset as ice1724 soundcard, Sigmatel stac9640 ADC/DAC for the analog I/O as Prodigy192, and Atmel ak4114 for S/PDIF as ESI Julia. Is working : the 8 analog outputs, the analog inputs 1&2, the mic input 1, the coaxial & optical digital outputs. Signed-off-by: Clement Guedez Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/ice1712/Makefile | 2 +- sound/pci/ice1712/ice1724.c | 4 +- sound/pci/ice1712/wtm.c | 542 ++++++++++++++++++++++++++++++++++++++++++++ sound/pci/ice1712/wtm.h | 20 ++ 4 files changed, 566 insertions(+), 2 deletions(-) create mode 100644 sound/pci/ice1712/wtm.c create mode 100644 sound/pci/ice1712/wtm.h (limited to 'sound') diff --git a/sound/pci/ice1712/Makefile b/sound/pci/ice1712/Makefile index 7837cef8855..6efdd62f683 100644 --- a/sound/pci/ice1712/Makefile +++ b/sound/pci/ice1712/Makefile @@ -5,7 +5,7 @@ snd-ice17xx-ak4xxx-objs := ak4xxx.o snd-ice1712-objs := ice1712.o delta.o hoontech.o ews.o -snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o vt1720_mobo.o pontis.o prodigy192.o juli.o phase.o +snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o vt1720_mobo.o pontis.o prodigy192.o juli.o phase.o wtm.o # Toplevel Module Dependency obj-$(CONFIG_SND_ICE1712) += snd-ice1712.o snd-ice17xx-ak4xxx.o diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index 3e3a102e6c3..4566c0f789a 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c @@ -50,7 +50,7 @@ #include "prodigy192.h" #include "juli.h" #include "phase.h" - +#include "wtm.h" MODULE_AUTHOR("Jaroslav Kysela "); MODULE_DESCRIPTION("VIA ICEnsemble ICE1724/1720 (Envy24HT/PT)"); @@ -64,6 +64,7 @@ MODULE_SUPPORTED_DEVICE("{" PRODIGY192_DEVICE_DESC JULI_DEVICE_DESC PHASE_DEVICE_DESC + WTM_DEVICE_DESC "{VIA,VT1720}," "{VIA,VT1724}," "{ICEnsemble,Generic ICE1724}," @@ -1958,6 +1959,7 @@ static struct snd_ice1712_card_info *card_tables[] __devinitdata = { snd_vt1724_prodigy192_cards, snd_vt1724_juli_cards, snd_vt1724_phase_cards, + snd_vt1724_wtm_cards, NULL, }; diff --git a/sound/pci/ice1712/wtm.c b/sound/pci/ice1712/wtm.c new file mode 100644 index 00000000000..04e535c8542 --- /dev/null +++ b/sound/pci/ice1712/wtm.c @@ -0,0 +1,542 @@ +/* + * ALSA driver for ICEnsemble VT1724 (Envy24HT) + * + * Lowlevel functions for Ego Sys Waveterminal 192M + * + * Copyright (c) 2006 Guedez Clement + * Some functions are taken from the Prodigy192 driver + * source + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + + + +#include +#include +#include +#include +#include +#include +#include + +#include "ice1712.h" +#include "envy24ht.h" +#include "wtm.h" +#include "stac946x.h" + + +/* + * 2*ADC 6*DAC no1 ringbuffer r/w on i2c bus + */ +static inline void stac9460_put(struct snd_ice1712 *ice, int reg, + unsigned char val) +{ + snd_vt1724_write_i2c(ice, STAC9460_I2C_ADDR, reg, val); +} + +static inline unsigned char stac9460_get(struct snd_ice1712 *ice, int reg) +{ + return snd_vt1724_read_i2c(ice, STAC9460_I2C_ADDR, reg); +} + +/* + * 2*ADC 2*DAC no2 ringbuffer r/w on i2c bus + */ +static inline void stac9460_2_put(struct snd_ice1712 *ice, int reg, + unsigned char val) +{ + snd_vt1724_write_i2c(ice, STAC9460_2_I2C_ADDR, reg, val); +} + +static inline unsigned char stac9460_2_get(struct snd_ice1712 *ice, int reg) +{ + return snd_vt1724_read_i2c(ice, STAC9460_2_I2C_ADDR, reg); +} + + +/* + * DAC mute control + */ +static int stac9460_dac_mute_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + return 0; +} + +static int stac9460_dac_mute_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); + unsigned char val; + int idx, id; + + if (kcontrol->private_value) { + idx = STAC946X_MASTER_VOLUME; + id = 0; + } else { + id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + idx = id + STAC946X_LF_VOLUME; + } + if (id < 6) + val = stac9460_get(ice, idx); + else + val = stac9460_2_get(ice,idx - 6); + ucontrol->value.integer.value[0] = (~val >> 7) & 0x1; + return 0; +} + +static int stac9460_dac_mute_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); + unsigned char new, old; + int id, idx; + int change; + + if (kcontrol->private_value) { + idx = STAC946X_MASTER_VOLUME; + old = stac9460_get(ice, idx); + new = (~ucontrol->value.integer.value[0]<< 7 & 0x80) | + (old & ~0x80); + change = (new != old); + if (change) { + stac9460_put(ice, idx, new); + stac9460_2_put(ice, idx, new); + } + } else { + id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + idx = id + STAC946X_LF_VOLUME; + if (id < 6) + old = stac9460_get(ice, idx); + else + old = stac9460_2_get(ice, idx - 6); + new = (~ucontrol->value.integer.value[0]<< 7 & 0x80) | + (old & ~0x80); + change = (new != old); + if (change) { + if (id < 6) + stac9460_put(ice, idx, new); + else + stac9460_2_put(ice, idx - 6, new); + } + } + return change; +} + +/* + * DAC volume attenuation mixer control + */ +static int stac9460_dac_vol_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; /* mute */ + uinfo->value.integer.max = 0x7f; /* 0dB */ + return 0; +} + +static int stac9460_dac_vol_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); + int idx, id; + unsigned char vol; + + if (kcontrol->private_value) { + idx = STAC946X_MASTER_VOLUME; + id = 0; + } else { + id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + idx = id + STAC946X_LF_VOLUME; + } + if (id < 6) + vol = stac9460_get(ice, idx) & 0x7f; + else + vol = stac9460_2_get(ice, idx - 6) & 0x7f; + ucontrol->value.integer.value[0] = 0x7f - vol; + return 0; +} + +static int stac9460_dac_vol_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); + int idx, id; + unsigned char tmp, ovol, nvol; + int change; + + if (kcontrol->private_value) { + idx = STAC946X_MASTER_VOLUME; + nvol = ucontrol->value.integer.value[0]; + tmp = stac9460_get(ice, idx); + ovol = 0x7f - (tmp & 0x7f); + change = (ovol != nvol); + if (change) { + stac9460_put(ice, idx, (0x7f - nvol) | (tmp & 0x80)); + stac9460_2_put(ice, idx, (0x7f - nvol) | (tmp & 0x80)); + } + } else { + id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + idx = id + STAC946X_LF_VOLUME; + nvol = ucontrol->value.integer.value[0]; + if (id < 6) + tmp = stac9460_get(ice, idx); + else + tmp = stac9460_2_get(ice, idx - 6); + ovol = 0x7f - (tmp & 0x7f); + change = (ovol != nvol); + if (change) { + if (id < 6) + stac9460_put(ice, idx, (0x7f - nvol) | + (tmp & 0x80)); + else + stac9460_2_put(ice, idx-6, (0x7f - nvol) | + (tmp & 0x80)); + } + } + return change; +} + +/* + * ADC mute control + */ +static int stac9460_adc_mute_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 2; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int stac9460_adc_mute_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); + unsigned char val; + int i, id; + + id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + if (id == 0) { + for (i = 0; i < 2; ++i) { + val = stac9460_get(ice, STAC946X_MIC_L_VOLUME + i); + ucontrol->value.integer.value[i] = ~val>>7 & 0x1; + } + } else { + for (i = 0; i < 2; ++i) { + val = stac9460_2_get(ice, STAC946X_MIC_L_VOLUME + i); + ucontrol->value.integer.value[i] = ~val>>7 & 0x1; + } + } + return 0; +} + +static int stac9460_adc_mute_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); + unsigned char new, old; + int i, reg, id; + int change; + + id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + if (id == 0) { + for (i = 0; i < 2; ++i) { + reg = STAC946X_MIC_L_VOLUME + i; + old = stac9460_get(ice, reg); + new = (~ucontrol->value.integer.value[i]<<7&0x80) | + (old&~0x80); + change = (new != old); + if (change) + stac9460_put(ice, reg, new); + } + } else { + for (i = 0; i < 2; ++i) { + reg = STAC946X_MIC_L_VOLUME + i; + old = stac9460_2_get(ice, reg); + new = (~ucontrol->value.integer.value[i]<<7&0x80) | + (old&~0x80); + change = (new != old); + if (change) + stac9460_2_put(ice, reg, new); + } + } + return change; +} + +/* + *ADC gain mixer control + */ +static int stac9460_adc_vol_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 2; + uinfo->value.integer.min = 0; /* 0dB */ + uinfo->value.integer.max = 0x0f; /* 22.5dB */ + return 0; +} + +static int stac9460_adc_vol_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); + int i, reg, id; + unsigned char vol; + + id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + if (id == 0) { + for (i = 0; i < 2; ++i) { + reg = STAC946X_MIC_L_VOLUME + i; + vol = stac9460_get(ice, reg) & 0x0f; + ucontrol->value.integer.value[i] = 0x0f - vol; + } + } else { + for (i = 0; i < 2; ++i) { + reg = STAC946X_MIC_L_VOLUME + i; + vol = stac9460_2_get(ice, reg) & 0x0f; + ucontrol->value.integer.value[i] = 0x0f - vol; + } + } + return 0; +} + +static int stac9460_adc_vol_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); + int i, reg, id; + unsigned char ovol, nvol; + int change; + + id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + if (id == 0) { + for (i = 0; i < 2; ++i) { + reg = STAC946X_MIC_L_VOLUME + i; + nvol = ucontrol->value.integer.value[i]; + ovol = 0x0f - stac9460_get(ice, reg); + change = ((ovol & 0x0f) != nvol); + if (change) + stac9460_put(ice, reg, (0x0f - nvol) | + (ovol & ~0x0f)); + } + } else { + for (i = 0; i < 2; ++i) { + reg = STAC946X_MIC_L_VOLUME + i; + nvol = ucontrol->value.integer.value[i]; + ovol = 0x0f - stac9460_2_get(ice, reg); + change = ((ovol & 0x0f) != nvol); + if (change) + stac9460_2_put(ice, reg, (0x0f - nvol) | + (ovol & ~0x0f)); + } + } + return change; +} + +/* + * MIC / LINE switch fonction + */ + +static int stac9460_mic_sw_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int stac9460_mic_sw_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); + unsigned char val; + int id; + + id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + if (id == 0) + val = stac9460_get(ice, STAC946X_GENERAL_PURPOSE); + else + val = stac9460_2_get(ice, STAC946X_GENERAL_PURPOSE); + ucontrol->value.integer.value[0] = ~val>>7 & 0x1; + return 0; +} + +static int stac9460_mic_sw_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); + unsigned char new, old; + int change, id; + + id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + if (id == 0) + old = stac9460_get(ice, STAC946X_GENERAL_PURPOSE); + else + old = stac9460_2_get(ice, STAC946X_GENERAL_PURPOSE); + new = (~ucontrol->value.integer.value[0]<< 7 & 0x80) | (old & ~0x80); + change = (new != old); + if (change) { + if (id == 0) + stac9460_put(ice, STAC946X_GENERAL_PURPOSE, new); + else + stac9460_2_put(ice, STAC946X_GENERAL_PURPOSE, new); + } + return change; +} + +/* + * Control tabs + */ +static struct snd_kcontrol_new stac9640_controls[] __devinitdata = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .info = stac9460_dac_mute_info, + .get = stac9460_dac_mute_get, + .put = stac9460_dac_mute_put, + .private_value = 1 + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Volume", + .info = stac9460_dac_vol_info, + .get = stac9460_dac_vol_get, + .put = stac9460_dac_vol_put, + .private_value = 1, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "MIC/Line switch", + .count = 2, + .info = stac9460_mic_sw_info, + .get = stac9460_mic_sw_get, + .put = stac9460_mic_sw_put, + + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "DAC Switch", + .count = 8, + .info = stac9460_dac_mute_info, + .get = stac9460_dac_mute_get, + .put = stac9460_dac_mute_put, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "DAC Volume", + .count = 8, + .info = stac9460_dac_vol_info, + .get = stac9460_dac_vol_get, + .put = stac9460_dac_vol_put, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "ADC Switch", + .count = 2, + .info = stac9460_adc_mute_info, + .get = stac9460_adc_mute_get, + .put = stac9460_adc_mute_put, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "ADC Volume", + .count = 2, + .info = stac9460_adc_vol_info, + .get = stac9460_adc_vol_get, + .put = stac9460_adc_vol_put, + + } +}; + + + +/*INIT*/ +static int __devinit wtm_add_controls(struct snd_ice1712 *ice) +{ + unsigned int i; + int err; + + for (i = 0; i < ARRAY_SIZE(stac9640_controls); i++) { + err = snd_ctl_add(ice->card, + snd_ctl_new1(&stac9640_controls[i], ice)); + if (err < 0) + return err; + } + return 0; +} + +static int __devinit wtm_init(struct snd_ice1712 *ice) +{ + static unsigned short stac_inits_prodigy[] = { + STAC946X_RESET, 0, + (unsigned short)-1 + }; + unsigned short *p; + + /*WTM 192M*/ + ice->num_total_dacs = 8; + ice->num_total_adcs = 4; + ice->force_rdma1 = 1; + + /*initialize codec*/ + p = stac_inits_prodigy; + for (; *p != (unsigned short)-1; p += 2) { + stac9460_put(ice, p[0], p[1]); + stac9460_2_put(ice, p[0], p[1]); + } + return 0; +} + + +static unsigned char wtm_eeprom[] __devinitdata = { + 0x47, /*SYSCONF: clock 192KHz, 4ADC, 8DAC */ + 0x80, /* ACLINK : I2S */ + 0xf8, /* I2S: vol; 96k, 24bit, 192k */ + 0xc1 /*SPDIF: out-en, spidf ext out*/, + 0x9f, /* GPIO_DIR */ + 0xff, /* GPIO_DIR1 */ + 0x7f, /* GPIO_DIR2 */ + 0x9f, /* GPIO_MASK */ + 0xff, /* GPIO_MASK1 */ + 0x7f, /* GPIO_MASK2 */ + 0x16, /* GPIO_STATE */ + 0x80, /* GPIO_STATE1 */ + 0x00, /* GPIO_STATE2 */ +}; + + +/*entry point*/ +struct snd_ice1712_card_info snd_vt1724_wtm_cards[] __devinitdata = { + { + .subvendor = VT1724_SUBDEVICE_WTM, + .name = "ESI Waveterminal 192M", + .model = "WT192M", + .chip_init = wtm_init, + .build_controls = wtm_add_controls, + .eeprom_size = sizeof(wtm_eeprom), + .eeprom_data = wtm_eeprom, + }, + {} /*terminator*/ +}; diff --git a/sound/pci/ice1712/wtm.h b/sound/pci/ice1712/wtm.h new file mode 100644 index 00000000000..03a394e442f --- /dev/null +++ b/sound/pci/ice1712/wtm.h @@ -0,0 +1,20 @@ +#ifndef __SOUND_WTM_H +#define __SOUND_WTM_H + +/* ID */ +#define WTM_DEVICE_DESC "{EGO SYS INC,WaveTerminal 192M}," +#define VT1724_SUBDEVICE_WTM 0x36495345 /* WT192M ver1.0 */ + +/* + *chip addresses on I2C bus + */ + +#define AK4114_ADDR 0x20 /*S/PDIF receiver*/ +#define STAC9460_I2C_ADDR 0x54 /* ADC*2 | DAC*6 */ +#define STAC9460_2_I2C_ADDR 0x56 /* ADC|DAC *2 */ + + +extern struct snd_ice1712_card_info snd_vt1724_wtm_cards[]; + +#endif /* __SOUND_WTM_H */ + -- cgit v1.2.3 From 0e4ceb7507111c3910a0d7e19b498b1f6081afcb Mon Sep 17 00:00:00 2001 From: Tobin Davis Date: Mon, 8 Jan 2007 10:54:26 +0100 Subject: [ALSA] hda-codec - Change default config for Asus P5GD1 This patch changes the default configuration for the Asus P5GD1 motherboard from 5stack to asus, as reported by stelek on linuxquestions.org http://www.linuxquestions.org/questions/showthread.php?p=2556497#post2556497 Signed-off-by: Tobin Davis Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index e4e7512ed02..dc01a6bab2b 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -2382,7 +2382,7 @@ static struct snd_pci_quirk alc880_cfg_tbl[] = { /* SND_PCI_QUIRK(0x1043, 0x1964, "ASUS", ALC880_ASUS_DIG), */ SND_PCI_QUIRK(0x1043, 0x1973, "ASUS", ALC880_ASUS_DIG), SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS", ALC880_ASUS_DIG), - SND_PCI_QUIRK(0x1043, 0x814e, "ASUS", ALC880_5ST), + SND_PCI_QUIRK(0x1043, 0x814e, "ASUS", ALC880_ASUS), SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG), SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST), SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST), -- cgit v1.2.3 From 751e61c47d3b4e929c93bac61c8dd6c247854993 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20S=C3=A1nchez=20Siles?= Date: Mon, 8 Jan 2007 10:56:48 +0100 Subject: [ALSA] Solve typos/compilation problems for debug functions in soc-dapm and at91-i2s MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit soc-dapm ·Removed list_for_each since the loop is list_for_each_entry() and not list_for_each(). Thanks to Liam Girdwood and Seth Forshee. at91-i2s ·Fixed typo in dai modes definition. ·Fixed struct member name in at91_ssc_info->ssc_state. ·Fixed compilation problem, ssc_state is bundled in at91_ssc_info. Signed-off-by: Raúl Sánchez Siles Signed-off-by: Seth Forshee Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/at91/at91-i2s.c | 34 +++++++++++++++++----------------- sound/soc/soc-dapm.c | 1 - 2 files changed, 17 insertions(+), 18 deletions(-) (limited to 'sound') diff --git a/sound/soc/at91/at91-i2s.c b/sound/soc/at91/at91-i2s.c index b452e8e6a72..203e6948cd9 100644 --- a/sound/soc/at91/at91-i2s.c +++ b/sound/soc/at91/at91-i2s.c @@ -101,7 +101,7 @@ static struct snd_soc_dai_mode at91_i2s[] = { .pcmdir = AT91_I2S_DIR, .flags = SND_SOC_DAI_BFS_DIV, .fs = 250, - .bfs SND_SOC_FSBD(5), + .bfs = SND_SOC_FSBD(5), .priv = (13 << 16 | 23), }, }; @@ -352,19 +352,19 @@ static int at91_i2s_suspend(struct platform_device *pdev, ssc_p = &ssc_info[dai->id]; /* Save the status register before disabling transmit and receive. */ - ssc_p->state->ssc_sr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR); + ssc_p->ssc_state.ssc_sr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR); at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR, AT91_SSC_TXDIS | AT91_SSC_RXDIS); /* Save the current interrupt mask, then disable unmasked interrupts. */ - ssc_p->state->ssc_imr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_IMR); - at91_ssc_write(ssc_p->ssc.base + AT91_SSC_IDR, ssc_p->state->ssc_imr); + ssc_p->ssc_state.ssc_imr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_IMR); + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_IDR, ssc_p->ssc_state.ssc_imr); - ssc_p->state->ssc_cmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_CMR); - ssc_p->state->ssc_rcmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_RCMR); - ssc_p->state->ssc_rfmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_RCMR); - ssc_p->state->ssc_tcmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_RCMR); - ssc_p->state->ssc_tfmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_RCMR); + ssc_p->ssc_state.ssc_cmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_CMR); + ssc_p->ssc_state.ssc_rcmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_RCMR); + ssc_p->ssc_state.ssc_rfmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_RCMR); + ssc_p->ssc_state.ssc_tcmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_RCMR); + ssc_p->ssc_state.ssc_tfmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_RCMR); return 0; } @@ -380,17 +380,17 @@ static int at91_i2s_resume(struct platform_device *pdev, ssc_p = &ssc_info[dai->id]; - at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RCMR, ssc_p->state->ssc_tfmr); - at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RCMR, ssc_p->state->ssc_tcmr); - at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RCMR, ssc_p->state->ssc_rfmr); - at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RCMR, ssc_p->state->ssc_rcmr); - at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CMR, ssc_p->state->ssc_cmr); + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RCMR, ssc_p->ssc_state.ssc_tfmr); + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RCMR, ssc_p->ssc_state.ssc_tcmr); + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RCMR, ssc_p->ssc_state.ssc_rfmr); + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RCMR, ssc_p->ssc_state.ssc_rcmr); + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CMR, ssc_p->ssc_state.ssc_cmr); - at91_ssc_write(ssc_p->ssc.base + AT91_SSC_IER, ssc_p->state->ssc_imr); + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_IER, ssc_p->ssc_state.ssc_imr); at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR, - ((ssc_p->state->ssc_sr & AT91_SSC_RXENA) ? AT91_SSC_RXEN : 0) | - ((ssc_p->state->ssc_sr & AT91_SSC_TXENA) ? AT91_SSC_TXEN : 0)); + ((ssc_p->ssc_state.ssc_sr & AT91_SSC_RXENA) ? AT91_SSC_RXEN : 0) | + ((ssc_p->ssc_state.ssc_sr & AT91_SSC_TXENA) ? AT91_SSC_TXEN : 0)); return 0; } diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 411651dc9d1..5c2a34956a5 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -651,7 +651,6 @@ static void dbg_dump_dapm(struct snd_soc_codec* codec, const char *action) p->source->name); } list_for_each_entry(p, &w->sinks, list_source) { - p = list_entry(lp, struct snd_soc_dapm_path, list_source); if (p->connect) printk(" out %s %s\n", p->name ? p->name : "static", p->sink->name); -- cgit v1.2.3 From ad5e773750aeae3ad980f94b9f3cecad5af7c53d Mon Sep 17 00:00:00 2001 From: Tobin Davis Date: Mon, 8 Jan 2007 10:57:32 +0100 Subject: [ALSA] hda-codec - Add support for Toshiba M105 to Realtek patch This patch adds support for the Toshiba M105-S3041 laptop (ALC861). Signed-off-by: Tobin Davis Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index dc01a6bab2b..468e9a09f44 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -7592,6 +7592,7 @@ static struct snd_pci_quirk alc861_cfg_tbl[] = { SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP), SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS), SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660_3ST), + SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA), SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31), SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST), -- cgit v1.2.3 From ffc26918ab5674b286a4bc07dac7e011cea83e97 Mon Sep 17 00:00:00 2001 From: Frank Mandarino Date: Mon, 8 Jan 2007 10:58:47 +0100 Subject: [ALSA] ASoC at91 - Fix NULL pointer dereference in at91_i2s_shutdown This patch fixes a NULL pointer exception which occurs when a substream is opened and immediately closed. Signed-off-by: Frank Mandarino Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/at91/at91-i2s.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'sound') diff --git a/sound/soc/at91/at91-i2s.c b/sound/soc/at91/at91-i2s.c index 203e6948cd9..876d391c701 100644 --- a/sound/soc/at91/at91-i2s.c +++ b/sound/soc/at91/at91-i2s.c @@ -296,6 +296,13 @@ static int at91_i2s_startup(struct snd_pcm_substream *substream) ssc_p->dir_mask |= dir_mask; spin_unlock_irq(&ssc_p->lock); + /* + * dma_data is not set until hw_params() is called and + * shutdown() depends on this value being NULL if hw_params() + * was not called. + */ + rtd->cpu_dai->dma_data = NULL; + return 0; } -- cgit v1.2.3 From c68487151a0dceea07db8632327e3a0ab9e25e1f Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Mon, 8 Jan 2007 10:59:51 +0100 Subject: [ALSA] sound: aoa of_node_put and kfree cleanup This patch removes redundant argument checks for of_node_put() and kfree(). Acked-by: Johannes Berg Signed-off-by: Mariusz Kozlowski Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/aoa/fabrics/snd-aoa-fabric-layout.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/aoa/fabrics/snd-aoa-fabric-layout.c b/sound/aoa/fabrics/snd-aoa-fabric-layout.c index 409809600dd..fa4a69fcdc2 100644 --- a/sound/aoa/fabrics/snd-aoa-fabric-layout.c +++ b/sound/aoa/fabrics/snd-aoa-fabric-layout.c @@ -1034,9 +1034,9 @@ static int aoa_fabric_layout_probe(struct soundbus_dev *sdev) list_del(&ldev->list); layouts_list_items--; outnodev: - if (sound) of_node_put(sound); + of_node_put(sound); layout_device = NULL; - if (ldev) kfree(ldev); + kfree(ldev); return -ENODEV; } -- cgit v1.2.3 From 8e21c34cd4742c508dcc307fdbac9b3ba6899002 Mon Sep 17 00:00:00 2001 From: Tobin Davis Date: Mon, 8 Jan 2007 11:04:17 +0100 Subject: [ALSA] hda-codec - Add support for Sigmatel STAC9202/9250/9251 codecs This patch adds support for Gateway laptops based on the Sigmatel STAC9250 codecs, as well as basic support for STAC9202/9250/9251 codecs. Some Gateway systems require probe_mask=1 to work. More work to be done prior to alsa 1.0.14 final. Signed-off-by: Tobin Davis Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_sigmatel.c | 140 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 4e3fc95b7b4..0556b7e7bb8 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -47,6 +47,13 @@ enum { STAC_9205_MODELS }; +enum { + STAC_925x_REF, + STAC_M2_2, + STAC_MA6, + STAC_925x_MODELS +}; + enum { STAC_D945_REF, STAC_D945GTP3, @@ -129,6 +136,18 @@ static hda_nid_t stac9200_dac_nids[1] = { 0x02, }; +static hda_nid_t stac925x_adc_nids[1] = { + 0x03, +}; + +static hda_nid_t stac925x_mux_nids[1] = { + 0x0f, +}; + +static hda_nid_t stac925x_dac_nids[1] = { + 0x02, +}; + static hda_nid_t stac922x_adc_nids[2] = { 0x06, 0x07, }; @@ -162,6 +181,11 @@ static hda_nid_t stac9200_pin_nids[8] = { 0x0f, 0x10, 0x11, 0x12, }; +static hda_nid_t stac925x_pin_nids[8] = { + 0x07, 0x08, 0x0a, 0x0b, + 0x0c, 0x0d, 0x10, 0x11, +}; + static hda_nid_t stac922x_pin_nids[10] = { 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x15, 0x1b, @@ -241,6 +265,12 @@ static struct hda_verb stac9200_core_init[] = { {} }; +static struct hda_verb stac925x_core_init[] = { + /* set dac0mux for dac converter */ + { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00}, + {} +}; + static struct hda_verb stac922x_core_init[] = { /* set master volume and direct control */ { 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, @@ -286,6 +316,23 @@ static struct snd_kcontrol_new stac9200_mixer[] = { { } /* end */ }; +static struct snd_kcontrol_new stac925x_mixer[] = { + HDA_CODEC_VOLUME("Master Playback Volume", 0xe, 0, HDA_OUTPUT), + HDA_CODEC_MUTE("Master Playback Switch", 0xe, 0, HDA_OUTPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Input Source", + .count = 1, + .info = stac92xx_mux_enum_info, + .get = stac92xx_mux_enum_get, + .put = stac92xx_mux_enum_put, + }, + HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT), + HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Capture Mux Volume", 0x0f, 0, HDA_OUTPUT), + { } /* end */ +}; + /* This needs to be generated dynamically based on sequence */ static struct snd_kcontrol_new stac922x_mixer[] = { { @@ -411,6 +458,43 @@ static struct snd_pci_quirk stac9200_cfg_tbl[] = { {} /* terminator */ }; +static unsigned int ref925x_pin_configs[8] = { + 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021, + 0x90a70320, 0x02214210, 0x400003f1, 0x9033032e, +}; + +static unsigned int stac925x_MA6_pin_configs[8] = { + 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021, + 0x90a70320, 0x90100211, 0x400003f1, 0x9033032e, +}; + +static unsigned int stac925xM2_2_pin_configs[8] = { + 0x40c003f3, 0x424503f2, 0x041800f4, 0x02a19020, + 0x50a103F0, 0x90100210, 0x400003f1, 0x9033032e, +}; + +static unsigned int *stac925x_brd_tbl[STAC_925x_MODELS] = { + [STAC_REF] = ref925x_pin_configs, + [STAC_M2_2] = stac925xM2_2_pin_configs, + [STAC_MA6] = stac925x_MA6_pin_configs, +}; + +static const char *stac925x_models[STAC_925x_MODELS] = { + [STAC_REF] = "ref", + [STAC_M2_2] = "m2-2", + [STAC_MA6] = "m6", +}; + +static struct snd_pci_quirk stac925x_cfg_tbl[] = { + /* SigmaTel reference board */ + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF), + SND_PCI_QUIRK(0x107b, 0x0316, "Gateway M255", STAC_REF), + SND_PCI_QUIRK(0x107b, 0x0366, "Gateway MP6954", STAC_REF), + SND_PCI_QUIRK(0x107b, 0x0461, "Gateway NX560XL", STAC_MA6), + SND_PCI_QUIRK(0x1002, 0x437b, "Gateway MX6453", STAC_M2_2), + {} /* terminator */ +}; + static unsigned int ref922x_pin_configs[10] = { 0x01014010, 0x01016011, 0x01012012, 0x0221401f, 0x01813122, 0x01011014, 0x01441030, 0x01c41030, @@ -1699,6 +1783,56 @@ static int patch_stac9200(struct hda_codec *codec) return 0; } +static int patch_stac925x(struct hda_codec *codec) +{ + struct sigmatel_spec *spec; + int err; + + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; + + codec->spec = spec; + spec->num_pins = 8; + spec->pin_nids = stac925x_pin_nids; + spec->board_config = snd_hda_check_board_config(codec, STAC_925x_MODELS, + stac925x_models, + stac925x_cfg_tbl); + if (spec->board_config < 0) { + snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x, using BIOS defaults\n"); + err = stac92xx_save_bios_config_regs(codec); + if (err < 0) { + stac92xx_free(codec); + return err; + } + spec->pin_configs = spec->bios_pin_configs; + } else if (stac925x_brd_tbl[spec->board_config] != NULL){ + spec->pin_configs = stac925x_brd_tbl[spec->board_config]; + stac92xx_set_config_regs(codec); + } + + spec->multiout.max_channels = 2; + spec->multiout.num_dacs = 1; + spec->multiout.dac_nids = stac925x_dac_nids; + spec->adc_nids = stac925x_adc_nids; + spec->mux_nids = stac925x_mux_nids; + spec->num_muxes = 1; + spec->num_dmics = 0; + + spec->init = stac925x_core_init; + spec->mixer = stac925x_mixer; + + err = stac92xx_parse_auto_config(codec, 0x8, 0x7); + if (err < 0) { + stac92xx_free(codec); + return err; + } + + codec->patch_ops = stac92xx_patch_ops; + + return 0; +} + static int patch_stac922x(struct hda_codec *codec) { struct sigmatel_spec *spec; @@ -2149,6 +2283,12 @@ struct hda_codec_preset snd_hda_preset_sigmatel[] = { { .id = 0x83847627, .name = "STAC9271D", .patch = patch_stac927x }, { .id = 0x83847628, .name = "STAC9274X5NH", .patch = patch_stac927x }, { .id = 0x83847629, .name = "STAC9274D5NH", .patch = patch_stac927x }, + { .id = 0x83847632, .name = "STAC9202", .patch = patch_stac925x }, + { .id = 0x83847633, .name = "STAC9202D", .patch = patch_stac925x }, + { .id = 0x83847634, .name = "STAC9250", .patch = patch_stac925x }, + { .id = 0x83847635, .name = "STAC9250D", .patch = patch_stac925x }, + { .id = 0x83847636, .name = "STAC9251", .patch = patch_stac925x }, + { .id = 0x83847637, .name = "STAC9250D", .patch = patch_stac925x }, /* The following does not take into account .id=0x83847661 when subsys = * 104D0C00 which is STAC9225s. Because of this, some SZ Notebooks are * currently not fully supported. -- cgit v1.2.3 From f36090fe04986dbcd304e1f4d9224be00e57ec25 Mon Sep 17 00:00:00 2001 From: Tobin Davis Date: Mon, 8 Jan 2007 11:07:12 +0100 Subject: [ALSA] hda-codec - Add support for Samsung Q1 Ultra This adds support for the Samsung Q1 Ultra tablet pc. Signed-off-by: Tobin Davis Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_analog.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 2e18a716a09..38977bce70e 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -782,16 +782,28 @@ static struct hda_channel_mode ad1986a_modes[3] = { /* eapd initialization */ static struct hda_verb ad1986a_eapd_init_verbs[] = { - {0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00}, + {0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 }, {} }; +/* Ultra initialization */ +static struct hda_verb ad1986a_ultra_init[] = { + /* eapd initialization */ + { 0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 }, + /* CLFE -> Mic in */ + { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2 }, + { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + { 0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 }, + { } /* end */ +}; + /* models */ enum { AD1986A_6STACK, AD1986A_3STACK, AD1986A_LAPTOP, AD1986A_LAPTOP_EAPD, + AD1986A_ULTRA, AD1986A_MODELS }; @@ -800,6 +812,7 @@ static const char *ad1986a_models[AD1986A_MODELS] = { [AD1986A_3STACK] = "3stack", [AD1986A_LAPTOP] = "laptop", [AD1986A_LAPTOP_EAPD] = "laptop-eapd", + [AD1986A_ULTRA] = "ultra", }; static struct snd_pci_quirk ad1986a_cfg_tbl[] = { @@ -821,6 +834,8 @@ static struct snd_pci_quirk ad1986a_cfg_tbl[] = { SND_PCI_QUIRK(0x144d, 0xc023, "Samsung X60", AD1986A_LAPTOP_EAPD), SND_PCI_QUIRK(0x144d, 0xc024, "Samsung R65", AD1986A_LAPTOP_EAPD), SND_PCI_QUIRK(0x144d, 0xc026, "Samsung X11", AD1986A_LAPTOP_EAPD), + SND_PCI_QUIRK(0x144d, 0xc504, "Samsung Q35", AD1986A_3STACK), + SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_ULTRA), SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_3STACK), SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_LAPTOP_EAPD), SND_PCI_QUIRK(0x17c0, 0x2017, "Samsung M50", AD1986A_LAPTOP), @@ -887,6 +902,15 @@ static int patch_ad1986a(struct hda_codec *codec) spec->multiout.dig_out_nid = 0; spec->input_mux = &ad1986a_laptop_eapd_capture_source; break; + case AD1986A_ULTRA: + spec->mixers[0] = ad1986a_laptop_eapd_mixers; + spec->num_init_verbs = 2; + spec->init_verbs[1] = ad1986a_ultra_init; + spec->multiout.max_channels = 2; + spec->multiout.num_dacs = 1; + spec->multiout.dac_nids = ad1986a_laptop_dac_nids; + spec->multiout.dig_out_nid = 0; + break; } return 0; -- cgit v1.2.3 From 2a296cb6633a719846eaf30fcec7f392c511537d Mon Sep 17 00:00:00 2001 From: Leonard Norrgard Date: Mon, 8 Jan 2007 11:28:22 +0100 Subject: [ALSA] sound: hda: detect ALC883 on MSI K9A Platinum motherboards (MS-7280) Recognize the Realtek ALC883 chip on MSI K9A Platinum motherboards (model no. MS-7280), enabling full sound capabilities. Error messages seen before this patch: cannot find the slot for index 0 (range 0-0) hda-intel: Error creating card! HDA Intel: probe of 0000:00:14.2 failed with error -12 [akpm@osdl.org: updated to match recent ALSA table changes] Signed-off-by: Leonard Norrgard Signed-off-by: Andrew Morton Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 468e9a09f44..fcd9ab8dea4 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -5524,6 +5524,7 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC883_6ST_DIG), SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG), SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG), + SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG), SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG), SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG), SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG), -- cgit v1.2.3 From 30e80a279d864385306ed4bf905f00196d1c9656 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Tue, 9 Jan 2007 09:55:54 +0100 Subject: [ALSA] hda-codec - add ASUS W7J (0x1043, 0x1205) to quirk list - 3stack See Novell-bug#228201 . Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index fcd9ab8dea4..db261bb9216 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -7589,6 +7589,7 @@ static const char *alc861_models[ALC861_MODEL_LAST] = { }; static struct snd_pci_quirk alc861_cfg_tbl[] = { + SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST}, SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP), SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP), SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS), -- cgit v1.2.3 From 687a47bd829e040094cbc103126d5f03d46fd2bb Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 Jan 2007 11:25:58 +0100 Subject: [ALSA] Fix a typo in the last patch_realtek.c change Fixed a typo in the last patch_realtek.c change. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index db261bb9216..d3d6e61abc0 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -7589,7 +7589,7 @@ static const char *alc861_models[ALC861_MODEL_LAST] = { }; static struct snd_pci_quirk alc861_cfg_tbl[] = { - SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST}, + SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST), SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP), SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP), SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS), -- cgit v1.2.3 From 9f428175a5e486b7142d3217c20481e003f3c275 Mon Sep 17 00:00:00 2001 From: Daniel Jacobowitz Date: Fri, 12 Jan 2007 19:11:47 +0100 Subject: [ALSA] ac97 - Fix vt1617a build ops This patch connects the extra vt1616 controls for the vt1617a, which is necessary to control the rear speakers on e.g. a Shuttle SN25P. Signed-off-by: Daniel Jacobowitz Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/ac97/ac97_patch.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index f5b4b44bbda..f1950fa1f0e 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -3285,6 +3285,7 @@ int patch_vt1617a(struct snd_ac97 * ac97) snd_ac97_write_cache(ac97, 0x5c, 0x20); ac97->ext_id |= AC97_EI_SPDIF; /* force the detection of spdif */ ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000; + ac97->build_ops = &patch_vt1616_ops; return 0; } -- cgit v1.2.3 From 5c33dd70b51be0617a75562aa896d5ccf1840455 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Tue, 16 Jan 2007 17:49:21 +0100 Subject: [ALSA] cleanup and error reporting for sound/core/init.c Make the control flow clear with indentation, adds some comments and improves error reporting. Signed-off-by: Oliver Neukum Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/core/init.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/core/init.c b/sound/core/init.c index a4cc6b155ae..db610373374 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -114,22 +114,28 @@ struct snd_card *snd_card_new(int idx, const char *xid, if (idx < 0) { int idx2; for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++) + /* idx == -1 == 0xffff means: take any free slot */ if (~snd_cards_lock & idx & 1<= snd_ecards_limit) snd_ecards_limit = idx + 1; break; } - } else if (idx < snd_ecards_limit) { - if (snd_cards_lock & (1 << idx)) - err = -ENODEV; /* invalid */ - } else if (idx < SNDRV_CARDS) - snd_ecards_limit = idx + 1; /* increase the limit */ - else - err = -ENODEV; + } else { + if (idx < snd_ecards_limit) { + if (snd_cards_lock & (1 << idx)) + err = -EBUSY; /* invalid */ + } else { + if (idx < SNDRV_CARDS) + snd_ecards_limit = idx + 1; /* increase the limit */ + else + err = -ENODEV; + } + } if (idx < 0 || err < 0) { mutex_unlock(&snd_card_mutex); - snd_printk(KERN_ERR "cannot find the slot for index %d (range 0-%i)\n", idx, snd_ecards_limit - 1); + snd_printk(KERN_ERR "cannot find the slot for index %d (range 0-%i), error: %d\n", + idx, snd_ecards_limit - 1, err); goto __error; } snd_cards_lock |= 1 << idx; /* lock it */ -- cgit v1.2.3 From 7ed07a740b886930a299d438947ad322272eece1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 19 Jan 2007 14:51:57 +0100 Subject: [ALSA] hda-intel - Don't try to probe invalid codecs Fix the max number of codecs detected by HD-intel (and compatible) controllers to 3. Some hardware reports extra bits as if connected, and the driver gets confused to probe unexisting codecs. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/hda_intel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index e6a1e37b373..83d1ba7f33a 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -199,7 +199,7 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; /* STATESTS int mask: SD2,SD1,SD0 */ #define STATESTS_INT_MASK 0x07 -#define AZX_MAX_CODECS 4 +#define AZX_MAX_CODECS 3 /* SD_CTL bits */ #define SD_CTL_STREAM_RESET 0x01 /* stream reset bit */ -- cgit v1.2.3 From f7ba7fc6173a9fb6d8a5bc02bf335cc358f21a09 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 19 Jan 2007 18:34:47 +0100 Subject: [ALSA] emu10k1 - Fix ABI for older ld10k1 Fix ABI for older ld10k1. When no EMU10K1_PVERSION ioctl is issued, the driver accepts ioctls with the old struct size without TLV information. Also, changed the struct field to make the conversion easier from the old to the new structs. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/emu10k1/emufx.c | 100 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 79 insertions(+), 21 deletions(-) (limited to 'sound') diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c index d8e8db89535..7b173c49695 100644 --- a/sound/pci/emu10k1/emufx.c +++ b/sound/pci/emu10k1/emufx.c @@ -655,13 +655,66 @@ snd_emu10k1_look_for_ctl(struct snd_emu10k1 *emu, struct snd_ctl_elem_id *id) return NULL; } +#define MAX_TLV_SIZE 256 + +static unsigned int *copy_tlv(unsigned int __user *_tlv) +{ + unsigned int data[2]; + unsigned int *tlv; + + if (!_tlv) + return NULL; + if (copy_from_user(data, _tlv, sizeof(data))) + return NULL; + if (data[1] >= MAX_TLV_SIZE) + return NULL; + tlv = kmalloc(data[1] * 4 + sizeof(data), GFP_KERNEL); + if (!tlv) + return NULL; + memcpy(tlv, data, sizeof(data)); + if (copy_from_user(tlv + 2, _tlv + 2, data[1])) { + kfree(tlv); + return NULL; + } + return tlv; +} + +static int copy_gctl(struct snd_emu10k1 *emu, + struct snd_emu10k1_fx8010_control_gpr *gctl, + struct snd_emu10k1_fx8010_control_gpr __user *_gctl, + int idx) +{ + struct snd_emu10k1_fx8010_control_old_gpr __user *octl; + + if (emu->support_tlv) + return copy_from_user(gctl, &_gctl[idx], sizeof(*gctl)); + octl = (struct snd_emu10k1_fx8010_control_old_gpr __user *)_gctl; + if (copy_from_user(gctl, &octl[idx], sizeof(*octl))) + return -EFAULT; + gctl->tlv = NULL; + return 0; +} + +static int copy_gctl_to_user(struct snd_emu10k1 *emu, + struct snd_emu10k1_fx8010_control_gpr __user *_gctl, + struct snd_emu10k1_fx8010_control_gpr *gctl, + int idx) +{ + struct snd_emu10k1_fx8010_control_old_gpr __user *octl; + + if (emu->support_tlv) + return copy_to_user(&_gctl[idx], gctl, sizeof(*gctl)); + + octl = (struct snd_emu10k1_fx8010_control_old_gpr __user *)_gctl; + return copy_to_user(&octl[idx], gctl, sizeof(*octl)); +} + static int snd_emu10k1_verify_controls(struct snd_emu10k1 *emu, struct snd_emu10k1_fx8010_code *icode) { unsigned int i; struct snd_ctl_elem_id __user *_id; struct snd_ctl_elem_id id; - struct snd_emu10k1_fx8010_control_gpr __user *_gctl; struct snd_emu10k1_fx8010_control_gpr *gctl; int err; @@ -676,9 +729,8 @@ static int snd_emu10k1_verify_controls(struct snd_emu10k1 *emu, if (! gctl) return -ENOMEM; err = 0; - for (i = 0, _gctl = icode->gpr_add_controls; - i < icode->gpr_add_control_count; i++, _gctl++) { - if (copy_from_user(gctl, _gctl, sizeof(*gctl))) { + for (i = 0; i < icode->gpr_add_control_count; i++) { + if (copy_gctl(emu, gctl, icode->gpr_add_controls, i)) { err = -EFAULT; goto __error; } @@ -697,10 +749,9 @@ static int snd_emu10k1_verify_controls(struct snd_emu10k1 *emu, goto __error; } } - for (i = 0, _gctl = icode->gpr_list_controls; - i < icode->gpr_list_control_count; i++, _gctl++) { + for (i = 0; i < icode->gpr_list_control_count; i++) { /* FIXME: we need to check the WRITE access */ - if (copy_from_user(gctl, _gctl, sizeof(*gctl))) { + if (copy_gctl(emu, gctl, icode->gpr_list_controls, i)) { err = -EFAULT; goto __error; } @@ -718,13 +769,14 @@ static void snd_emu10k1_ctl_private_free(struct snd_kcontrol *kctl) kctl->private_value = 0; list_del(&ctl->list); kfree(ctl); + if (kctl->tlv.p) + kfree(kctl->tlv.p); } static int snd_emu10k1_add_controls(struct snd_emu10k1 *emu, struct snd_emu10k1_fx8010_code *icode) { unsigned int i, j; - struct snd_emu10k1_fx8010_control_gpr __user *_gctl; struct snd_emu10k1_fx8010_control_gpr *gctl; struct snd_emu10k1_fx8010_ctl *ctl, *nctl; struct snd_kcontrol_new knew; @@ -740,9 +792,8 @@ static int snd_emu10k1_add_controls(struct snd_emu10k1 *emu, goto __error; } - for (i = 0, _gctl = icode->gpr_add_controls; - i < icode->gpr_add_control_count; i++, _gctl++) { - if (copy_from_user(gctl, _gctl, sizeof(*gctl))) { + for (i = 0; i < icode->gpr_add_control_count; i++) { + if (copy_gctl(emu, gctl, icode->gpr_add_controls, i)) { err = -EFAULT; goto __error; } @@ -763,11 +814,10 @@ static int snd_emu10k1_add_controls(struct snd_emu10k1 *emu, knew.device = gctl->id.device; knew.subdevice = gctl->id.subdevice; knew.info = snd_emu10k1_gpr_ctl_info; - if (gctl->tlv.p) { - knew.tlv.p = gctl->tlv.p; + knew.tlv.p = copy_tlv(gctl->tlv); + if (knew.tlv.p) knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ; - } knew.get = snd_emu10k1_gpr_ctl_get; knew.put = snd_emu10k1_gpr_ctl_put; memset(nctl, 0, sizeof(*nctl)); @@ -785,12 +835,14 @@ static int snd_emu10k1_add_controls(struct snd_emu10k1 *emu, ctl = kmalloc(sizeof(*ctl), GFP_KERNEL); if (ctl == NULL) { err = -ENOMEM; + kfree(knew.tlv.p); goto __error; } knew.private_value = (unsigned long)ctl; *ctl = *nctl; if ((err = snd_ctl_add(emu->card, kctl = snd_ctl_new1(&knew, emu))) < 0) { kfree(ctl); + kfree(knew.tlv.p); goto __error; } kctl->private_free = snd_emu10k1_ctl_private_free; @@ -841,7 +893,6 @@ static int snd_emu10k1_list_controls(struct snd_emu10k1 *emu, unsigned int i = 0, j; unsigned int total = 0; struct snd_emu10k1_fx8010_control_gpr *gctl; - struct snd_emu10k1_fx8010_control_gpr __user *_gctl; struct snd_emu10k1_fx8010_ctl *ctl; struct snd_ctl_elem_id *id; struct list_head *list; @@ -850,11 +901,11 @@ static int snd_emu10k1_list_controls(struct snd_emu10k1 *emu, if (! gctl) return -ENOMEM; - _gctl = icode->gpr_list_controls; list_for_each(list, &emu->fx8010.gpr_ctl) { ctl = emu10k1_gpr_ctl(list); total++; - if (_gctl && i < icode->gpr_list_control_count) { + if (icode->gpr_list_controls && + i < icode->gpr_list_control_count) { memset(gctl, 0, sizeof(*gctl)); id = &ctl->kcontrol->id; gctl->id.iface = id->iface; @@ -871,11 +922,11 @@ static int snd_emu10k1_list_controls(struct snd_emu10k1 *emu, gctl->min = ctl->min; gctl->max = ctl->max; gctl->translation = ctl->translation; - if (copy_to_user(_gctl, gctl, sizeof(*gctl))) { + if (copy_gctl_to_user(emu, icode->gpr_list_controls, + gctl, i)) { kfree(gctl); return -EFAULT; } - _gctl++; i++; } } @@ -1026,7 +1077,7 @@ snd_emu10k1_init_mono_control(struct snd_emu10k1_fx8010_control_gpr *ctl, ctl->gpr[0] = gpr + 0; ctl->value[0] = defval; ctl->min = 0; ctl->max = 100; - ctl->tlv.p = snd_emu10k1_db_scale1; + ctl->tlv = snd_emu10k1_db_scale1; ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100; } @@ -1041,7 +1092,7 @@ snd_emu10k1_init_stereo_control(struct snd_emu10k1_fx8010_control_gpr *ctl, ctl->gpr[1] = gpr + 1; ctl->value[1] = defval; ctl->min = 0; ctl->max = 100; - ctl->tlv.p = snd_emu10k1_db_scale1; + ctl->tlv = snd_emu10k1_db_scale1; ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100; } @@ -1566,7 +1617,9 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) seg = snd_enter_user(); icode->gpr_add_control_count = nctl; icode->gpr_add_controls = (struct snd_emu10k1_fx8010_control_gpr __user *)controls; + emu->support_tlv = 1; /* support TLV */ err = snd_emu10k1_icode_poke(emu, icode); + emu->support_tlv = 0; /* clear again */ snd_leave_user(seg); __err: @@ -2183,7 +2236,9 @@ static int __devinit _snd_emu10k1_init_efx(struct snd_emu10k1 *emu) seg = snd_enter_user(); icode->gpr_add_control_count = i; icode->gpr_add_controls = (struct snd_emu10k1_fx8010_control_gpr __user *)controls; + emu->support_tlv = 1; /* support TLV */ err = snd_emu10k1_icode_poke(emu, icode); + emu->support_tlv = 0; /* clear again */ snd_leave_user(seg); if (err >= 0) err = snd_emu10k1_ipcm_poke(emu, ipcm); @@ -2327,6 +2382,9 @@ static int snd_emu10k1_fx8010_ioctl(struct snd_hwdep * hw, struct file *file, un int res; switch (cmd) { + case SNDRV_EMU10K1_IOCTL_PVERSION: + emu->support_tlv = 1; + return put_user(SNDRV_EMU10K1_VERSION, (int __user *)argp); case SNDRV_EMU10K1_IOCTL_INFO: info = kmalloc(sizeof(*info), GFP_KERNEL); if (!info) -- cgit v1.2.3 From 579c84a9b225d8b9d0f32818b9959ca63b4fb57d Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 23 Jan 2007 19:22:26 +0100 Subject: [ALSA] echo3g_dsp.c shouldn't include #include Despite being under linux/, linux/irq.h shouldn't be #include'd by arch independent code. Signed-off-by: Adrian Bunk Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/echoaudio/echo3g_dsp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/echoaudio/echo3g_dsp.c b/sound/pci/echoaudio/echo3g_dsp.c index d26a1d1f3ed..48eb7c59911 100644 --- a/sound/pci/echoaudio/echo3g_dsp.c +++ b/sound/pci/echoaudio/echo3g_dsp.c @@ -39,7 +39,7 @@ static int set_phantom_power(struct echoaudio *chip, char on); static int write_control_reg(struct echoaudio *chip, u32 ctl, u32 frq, char force); -#include +#include static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) { -- cgit v1.2.3 From 32360416322ddfcd2db2f7655f606c5b86a29102 Mon Sep 17 00:00:00 2001 From: Thomas De Schampheleire Date: Wed, 24 Jan 2007 16:13:35 +0100 Subject: [ALSA] hda-codec - Missing Mic Boost on Realtek ALC882/883 This patch adds Mic Boost controls for Realtek ALC882 and ALC883 chips. Signed-off-by: Thomas De Schampheleire Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index d3d6e61abc0..a2986250903 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4403,8 +4403,10 @@ static struct snd_kcontrol_new alc882_base_mixer[] = { HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), @@ -5104,8 +5106,10 @@ static struct snd_kcontrol_new alc883_base_mixer[] = { HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), @@ -5134,8 +5138,10 @@ static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = { HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), @@ -5170,8 +5176,10 @@ static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = { HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), @@ -5206,8 +5214,10 @@ static struct snd_kcontrol_new alc883_fivestack_mixer[] = { HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), @@ -5241,6 +5251,7 @@ static struct snd_kcontrol_new alc883_tagra_mixer[] = { HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), @@ -5265,6 +5276,7 @@ static struct snd_kcontrol_new alc883_tagra_2ch_mixer[] = { HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), -- cgit v1.2.3 From 757e119bf52b014b3181eed97b01f87a245b8ff9 Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Thu, 25 Jan 2007 13:15:05 +0100 Subject: [ALSA] Add snd-portman2x4 driver for Midiman Portman 2x4 MIDI device snd-portman2x4 driver supports Midiman Portman 2x4 parallel port MIDI device. Signed-off-by: Matthias Koenig Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/drivers/Kconfig | 11 + sound/drivers/Makefile | 2 + sound/drivers/portman2x4.c | 876 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 889 insertions(+) create mode 100644 sound/drivers/portman2x4.c (limited to 'sound') diff --git a/sound/drivers/Kconfig b/sound/drivers/Kconfig index 40ebd2f4405..83529b08d01 100644 --- a/sound/drivers/Kconfig +++ b/sound/drivers/Kconfig @@ -109,4 +109,15 @@ config SND_MPU401 To compile this driver as a module, choose M here: the module will be called snd-mpu401. +config SND_PORTMAN2X4 + tristate "Portman 2x4 driver" + depends on SND && PARPORT + select SND_RAWMIDI + help + Say Y here to include support for Midiman Portman 2x4 parallel + port MIDI device. + + To compile this driver as a module, choose M here: the module + will be called snd-portman2x4. + endmenu diff --git a/sound/drivers/Makefile b/sound/drivers/Makefile index c9bad6d67e7..04112642611 100644 --- a/sound/drivers/Makefile +++ b/sound/drivers/Makefile @@ -6,6 +6,7 @@ snd-dummy-objs := dummy.o snd-mtpav-objs := mtpav.o snd-mts64-objs := mts64.o +snd-portman2x4-objs := portman2x4.o snd-serial-u16550-objs := serial-u16550.o snd-virmidi-objs := virmidi.o @@ -15,5 +16,6 @@ obj-$(CONFIG_SND_VIRMIDI) += snd-virmidi.o obj-$(CONFIG_SND_SERIAL_U16550) += snd-serial-u16550.o obj-$(CONFIG_SND_MTPAV) += snd-mtpav.o obj-$(CONFIG_SND_MTS64) += snd-mts64.o +obj-$(CONFIG_SND_PORTMAN2X4) += snd-portman2x4.o obj-$(CONFIG_SND) += opl3/ opl4/ mpu401/ vx/ diff --git a/sound/drivers/portman2x4.c b/sound/drivers/portman2x4.c new file mode 100644 index 00000000000..6c48772aaef --- /dev/null +++ b/sound/drivers/portman2x4.c @@ -0,0 +1,876 @@ +/* + * Driver for Midiman Portman2x4 parallel port midi interface + * + * Copyright (c) by Levent Guendogdu + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * ChangeLog + * Jan 24 2007 Matthias Koenig + * - cleanup and rewrite + * Sep 30 2004 Tobias Gehrig + * - source code cleanup + * Sep 03 2004 Tobias Gehrig + * - fixed compilation problem with alsa 1.0.6a (removed MODULE_CLASSES, + * MODULE_PARM_SYNTAX and changed MODULE_DEVICES to + * MODULE_SUPPORTED_DEVICE) + * Mar 24 2004 Tobias Gehrig + * - added 2.6 kernel support + * Mar 18 2004 Tobias Gehrig + * - added parport_unregister_driver to the startup routine if the driver fails to detect a portman + * - added support for all 4 output ports in portman_putmidi + * Mar 17 2004 Tobias Gehrig + * - added checks for opened input device in interrupt handler + * Feb 20 2004 Tobias Gehrig + * - ported from alsa 0.5 to 1.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CARD_NAME "Portman 2x4" +#define DRIVER_NAME "portman" +#define PLATFORM_DRIVER "snd_portman2x4" + +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; +static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; +static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; + +static struct platform_device *platform_devices[SNDRV_CARDS]; +static int device_count; + +module_param_array(index, int, NULL, S_IRUGO); +MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard."); +module_param_array(id, charp, NULL, S_IRUGO); +MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard."); +module_param_array(enable, bool, NULL, S_IRUGO); +MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard."); + +MODULE_AUTHOR("Levent Guendogdu, Tobias Gehrig, Matthias Koenig"); +MODULE_DESCRIPTION("Midiman Portman2x4"); +MODULE_LICENSE("GPL"); +MODULE_SUPPORTED_DEVICE("{{Midiman,Portman2x4}}"); + +/********************************************************************* + * Chip specific + *********************************************************************/ +#define PORTMAN_NUM_INPUT_PORTS 2 +#define PORTMAN_NUM_OUTPUT_PORTS 4 + +struct portman { + spinlock_t reg_lock; + struct snd_card *card; + struct snd_rawmidi *rmidi; + struct pardevice *pardev; + int pardev_claimed; + + int open_count; + int mode[PORTMAN_NUM_INPUT_PORTS]; + struct snd_rawmidi_substream *midi_input[PORTMAN_NUM_INPUT_PORTS]; +}; + +static int portman_free(struct portman *pm) +{ + kfree(pm); + return 0; +} + +static int __devinit portman_create(struct snd_card *card, + struct pardevice *pardev, + struct portman **rchip) +{ + struct portman *pm; + + *rchip = NULL; + + pm = kzalloc(sizeof(struct portman), GFP_KERNEL); + if (pm == NULL) + return -ENOMEM; + + /* Init chip specific data */ + spin_lock_init(&pm->reg_lock); + pm->card = card; + pm->pardev = pardev; + + *rchip = pm; + + return 0; +} + +/********************************************************************* + * HW related constants + *********************************************************************/ + +/* Standard PC parallel port status register equates. */ +#define PP_STAT_BSY 0x80 /* Busy status. Inverted. */ +#define PP_STAT_ACK 0x40 /* Acknowledge. Non-Inverted. */ +#define PP_STAT_POUT 0x20 /* Paper Out. Non-Inverted. */ +#define PP_STAT_SEL 0x10 /* Select. Non-Inverted. */ +#define PP_STAT_ERR 0x08 /* Error. Non-Inverted. */ + +/* Standard PC parallel port command register equates. */ +#define PP_CMD_IEN 0x10 /* IRQ Enable. Non-Inverted. */ +#define PP_CMD_SELI 0x08 /* Select Input. Inverted. */ +#define PP_CMD_INIT 0x04 /* Init Printer. Non-Inverted. */ +#define PP_CMD_FEED 0x02 /* Auto Feed. Inverted. */ +#define PP_CMD_STB 0x01 /* Strobe. Inverted. */ + +/* Parallel Port Command Register as implemented by PCP2x4. */ +#define INT_EN PP_CMD_IEN /* Interrupt enable. */ +#define STROBE PP_CMD_STB /* Command strobe. */ + +/* The parallel port command register field (b1..b3) selects the + * various "registers" within the PC/P 2x4. These are the internal + * address of these "registers" that must be written to the parallel + * port command register. + */ +#define RXDATA0 (0 << 1) /* PCP RxData channel 0. */ +#define RXDATA1 (1 << 1) /* PCP RxData channel 1. */ +#define GEN_CTL (2 << 1) /* PCP General Control Register. */ +#define SYNC_CTL (3 << 1) /* PCP Sync Control Register. */ +#define TXDATA0 (4 << 1) /* PCP TxData channel 0. */ +#define TXDATA1 (5 << 1) /* PCP TxData channel 1. */ +#define TXDATA2 (6 << 1) /* PCP TxData channel 2. */ +#define TXDATA3 (7 << 1) /* PCP TxData channel 3. */ + +/* Parallel Port Status Register as implemented by PCP2x4. */ +#define ESTB PP_STAT_POUT /* Echoed strobe. */ +#define INT_REQ PP_STAT_ACK /* Input data int request. */ +#define BUSY PP_STAT_ERR /* Interface Busy. */ + +/* Parallel Port Status Register BUSY and SELECT lines are multiplexed + * between several functions. Depending on which 2x4 "register" is + * currently selected (b1..b3), the BUSY and SELECT lines are + * assigned as follows: + * + * SELECT LINE: A3 A2 A1 + * -------- + */ +#define RXAVAIL PP_STAT_SEL /* Rx Available, channel 0. 0 0 0 */ +// RXAVAIL1 PP_STAT_SEL /* Rx Available, channel 1. 0 0 1 */ +#define SYNC_STAT PP_STAT_SEL /* Reserved - Sync Status. 0 1 0 */ +// /* Reserved. 0 1 1 */ +#define TXEMPTY PP_STAT_SEL /* Tx Empty, channel 0. 1 0 0 */ +// TXEMPTY1 PP_STAT_SEL /* Tx Empty, channel 1. 1 0 1 */ +// TXEMPTY2 PP_STAT_SEL /* Tx Empty, channel 2. 1 1 0 */ +// TXEMPTY3 PP_STAT_SEL /* Tx Empty, channel 3. 1 1 1 */ + +/* BUSY LINE: A3 A2 A1 + * -------- + */ +#define RXDATA PP_STAT_BSY /* Rx Input Data, channel 0. 0 0 0 */ +// RXDATA1 PP_STAT_BSY /* Rx Input Data, channel 1. 0 0 1 */ +#define SYNC_DATA PP_STAT_BSY /* Reserved - Sync Data. 0 1 0 */ + /* Reserved. 0 1 1 */ +#define DATA_ECHO PP_STAT_BSY /* Parallel Port Data Echo. 1 0 0 */ +#define A0_ECHO PP_STAT_BSY /* Address 0 Echo. 1 0 1 */ +#define A1_ECHO PP_STAT_BSY /* Address 1 Echo. 1 1 0 */ +#define A2_ECHO PP_STAT_BSY /* Address 2 Echo. 1 1 1 */ + +#define PORTMAN2X4_MODE_INPUT_TRIGGERED 0x01 + +/********************************************************************* + * Hardware specific functions + *********************************************************************/ +static inline void portman_write_command(struct portman *pm, u8 value) +{ + parport_write_control(pm->pardev->port, value); +} + +static inline u8 portman_read_command(struct portman *pm) +{ + return parport_read_control(pm->pardev->port); +} + +static inline u8 portman_read_status(struct portman *pm) +{ + return parport_read_status(pm->pardev->port); +} + +static inline u8 portman_read_data(struct portman *pm) +{ + return parport_read_data(pm->pardev->port); +} + +static inline void portman_write_data(struct portman *pm, u8 value) +{ + parport_write_data(pm->pardev->port, value); +} + +static void portman_write_midi(struct portman *pm, + int port, u8 mididata) +{ + int command = ((port + 4) << 1); + + /* Get entering data byte and port number in BL and BH respectively. + * Set up Tx Channel address field for use with PP Cmd Register. + * Store address field in BH register. + * Inputs: AH = Output port number (0..3). + * AL = Data byte. + * command = TXDATA0 | INT_EN; + * Align port num with address field (b1...b3), + * set address for TXDatax, Strobe=0 + */ + command |= INT_EN; + + /* Disable interrupts so that the process is not interrupted, then + * write the address associated with the current Tx channel to the + * PP Command Reg. Do not set the Strobe signal yet. + */ + + do { + portman_write_command(pm, command); + + /* While the address lines settle, write parallel output data to + * PP Data Reg. This has no effect until Strobe signal is asserted. + */ + + portman_write_data(pm, mididata); + + /* If PCP channel's TxEmpty is set (TxEmpty is read through the PP + * Status Register), then go write data. Else go back and wait. + */ + } while ((portman_read_status(pm) & TXEMPTY) != TXEMPTY); + + /* TxEmpty is set. Maintain PC/P destination address and assert + * Strobe through the PP Command Reg. This will Strobe data into + * the PC/P transmitter and set the PC/P BUSY signal. + */ + + portman_write_command(pm, command | STROBE); + + /* Wait for strobe line to settle and echo back through hardware. + * Once it has echoed back, assume that the address and data lines + * have settled! + */ + + while ((portman_read_status(pm) & ESTB) == 0) + cpu_relax(); + + /* Release strobe and immediately re-allow interrupts. */ + portman_write_command(pm, command); + + while ((portman_read_status(pm) & ESTB) == ESTB) + cpu_relax(); + + /* PC/P BUSY is now set. We must wait until BUSY resets itself. + * We'll reenable ints while we're waiting. + */ + + while ((portman_read_status(pm) & BUSY) == BUSY) + cpu_relax(); + + /* Data sent. */ +} + + +/* + * Read MIDI byte from port + * Attempt to read input byte from specified hardware input port (0..). + * Return -1 if no data + */ +static int portman_read_midi(struct portman *pm, int port) +{ + unsigned char midi_data = 0; + unsigned char cmdout; /* Saved address+IE bit. */ + + /* Make sure clocking edge is down before starting... */ + portman_write_data(pm, 0); /* Make sure edge is down. */ + + /* Set destination address to PCP. */ + cmdout = (port << 1) | INT_EN; /* Address + IE + No Strobe. */ + portman_write_command(pm, cmdout); + + while ((portman_read_status(pm) & ESTB) == ESTB) + cpu_relax(); /* Wait for strobe echo. */ + + /* After the address lines settle, check multiplexed RxAvail signal. + * If data is available, read it. + */ + if ((portman_read_status(pm) & RXAVAIL) == 0) + return -1; /* No data. */ + + /* Set the Strobe signal to enable the Rx clocking circuitry. */ + portman_write_command(pm, cmdout | STROBE); /* Write address+IE+Strobe. */ + + while ((portman_read_status(pm) & ESTB) == 0) + cpu_relax(); /* Wait for strobe echo. */ + + /* The first data bit (msb) is already sitting on the input line. */ + midi_data = (portman_read_status(pm) & 128); + portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */ + + /* Data bit 6. */ + portman_write_data(pm, 0); /* Cause falling edge while data settles. */ + midi_data |= (portman_read_status(pm) >> 1) & 64; + portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */ + + /* Data bit 5. */ + portman_write_data(pm, 0); /* Cause falling edge while data settles. */ + midi_data |= (portman_read_status(pm) >> 2) & 32; + portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */ + + /* Data bit 4. */ + portman_write_data(pm, 0); /* Cause falling edge while data settles. */ + midi_data |= (portman_read_status(pm) >> 3) & 16; + portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */ + + /* Data bit 3. */ + portman_write_data(pm, 0); /* Cause falling edge while data settles. */ + midi_data |= (portman_read_status(pm) >> 4) & 8; + portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */ + + /* Data bit 2. */ + portman_write_data(pm, 0); /* Cause falling edge while data settles. */ + midi_data |= (portman_read_status(pm) >> 5) & 4; + portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */ + + /* Data bit 1. */ + portman_write_data(pm, 0); /* Cause falling edge while data settles. */ + midi_data |= (portman_read_status(pm) >> 6) & 2; + portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */ + + /* Data bit 0. */ + portman_write_data(pm, 0); /* Cause falling edge while data settles. */ + midi_data |= (portman_read_status(pm) >> 7) & 1; + portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */ + portman_write_data(pm, 0); /* Return data clock low. */ + + + /* De-assert Strobe and return data. */ + portman_write_command(pm, cmdout); /* Output saved address+IE. */ + + /* Wait for strobe echo. */ + while ((portman_read_status(pm) & ESTB) == ESTB) + cpu_relax(); + + return (midi_data & 255); /* Shift back and return value. */ +} + +/* + * Checks if any input data on the given channel is available + * Checks RxAvail + */ +static int portman_data_avail(struct portman *pm, int channel) +{ + int command = INT_EN; + switch (channel) { + case 0: + command |= RXDATA0; + break; + case 1: + command |= RXDATA1; + break; + } + /* Write hardware (assumme STROBE=0) */ + portman_write_command(pm, command); + /* Check multiplexed RxAvail signal */ + if ((portman_read_status(pm) & RXAVAIL) == RXAVAIL) + return 1; /* Data available */ + + /* No Data available */ + return 0; +} + + +/* + * Flushes any input + */ +static void portman_flush_input(struct portman *pm, unsigned char port) +{ + /* Local variable for counting things */ + unsigned int i = 0; + unsigned char command = 0; + + switch (port) { + case 0: + command = RXDATA0; + break; + case 1: + command = RXDATA1; + break; + default: + snd_printk(KERN_WARNING + "portman_flush_input() Won't flush port %i\n", + port); + return; + } + + /* Set address for specified channel in port and allow to settle. */ + portman_write_command(pm, command); + + /* Assert the Strobe and wait for echo back. */ + portman_write_command(pm, command | STROBE); + + /* Wait for ESTB */ + while ((portman_read_status(pm) & ESTB) == 0) + cpu_relax(); + + /* Output clock cycles to the Rx circuitry. */ + portman_write_data(pm, 0); + + /* Flush 250 bits... */ + for (i = 0; i < 250; i++) { + portman_write_data(pm, 1); + portman_write_data(pm, 0); + } + + /* Deassert the Strobe signal of the port and wait for it to settle. */ + portman_write_command(pm, command | INT_EN); + + /* Wait for settling */ + while ((portman_read_status(pm) & ESTB) == ESTB) + cpu_relax(); +} + +static int portman_probe(struct parport *p) +{ + /* Initialize the parallel port data register. Will set Rx clocks + * low in case we happen to be addressing the Rx ports at this time. + */ + /* 1 */ + parport_write_data(p, 0); + + /* Initialize the parallel port command register, thus initializing + * hardware handshake lines to midi box: + * + * Strobe = 0 + * Interrupt Enable = 0 + */ + /* 2 */ + parport_write_control(p, 0); + + /* Check if Portman PC/P 2x4 is out there. */ + /* 3 */ + parport_write_control(p, RXDATA0); /* Write Strobe=0 to command reg. */ + + /* Check for ESTB to be clear */ + /* 4 */ + if ((parport_read_status(p) & ESTB) == ESTB) + return 1; /* CODE 1 - Strobe Failure. */ + + /* Set for RXDATA0 where no damage will be done. */ + /* 5 */ + parport_write_control(p, RXDATA0 + STROBE); /* Write Strobe=1 to command reg. */ + + /* 6 */ + if ((parport_read_status(p) & ESTB) != ESTB) + return 1; /* CODE 1 - Strobe Failure. */ + + /* 7 */ + parport_write_control(p, 0); /* Reset Strobe=0. */ + + /* Check if Tx circuitry is functioning properly. If initialized + * unit TxEmpty is false, send out char and see if if goes true. + */ + /* 8 */ + parport_write_control(p, TXDATA0); /* Tx channel 0, strobe off. */ + + /* If PCP channel's TxEmpty is set (TxEmpty is read through the PP + * Status Register), then go write data. Else go back and wait. + */ + /* 9 */ + if ((parport_read_status(p) & TXEMPTY) == 0) + return 2; + + /* Return OK status. */ + return 0; +} + +static int portman_device_init(struct portman *pm) +{ + portman_flush_input(pm, 0); + portman_flush_input(pm, 1); + + return 0; +} + +/********************************************************************* + * Rawmidi + *********************************************************************/ +static int snd_portman_midi_open(struct snd_rawmidi_substream *substream) +{ + return 0; +} + +static int snd_portman_midi_close(struct snd_rawmidi_substream *substream) +{ + return 0; +} + +static void snd_portman_midi_input_trigger(struct snd_rawmidi_substream *substream, + int up) +{ + struct portman *pm = substream->rmidi->private_data; + unsigned long flags; + + spin_lock_irqsave(&pm->reg_lock, flags); + if (up) + pm->mode[substream->number] |= PORTMAN2X4_MODE_INPUT_TRIGGERED; + else + pm->mode[substream->number] &= ~PORTMAN2X4_MODE_INPUT_TRIGGERED; + spin_unlock_irqrestore(&pm->reg_lock, flags); +} + +static void snd_portman_midi_output_trigger(struct snd_rawmidi_substream *substream, + int up) +{ + struct portman *pm = substream->rmidi->private_data; + unsigned long flags; + unsigned char byte; + + spin_lock_irqsave(&pm->reg_lock, flags); + if (up) { + while ((snd_rawmidi_transmit(substream, &byte, 1) == 1)) + portman_write_midi(pm, substream->number, byte); + } + spin_unlock_irqrestore(&pm->reg_lock, flags); +} + +static struct snd_rawmidi_ops snd_portman_midi_output = { + .open = snd_portman_midi_open, + .close = snd_portman_midi_close, + .trigger = snd_portman_midi_output_trigger, +}; + +static struct snd_rawmidi_ops snd_portman_midi_input = { + .open = snd_portman_midi_open, + .close = snd_portman_midi_close, + .trigger = snd_portman_midi_input_trigger, +}; + +/* Create and initialize the rawmidi component */ +static int __devinit snd_portman_rawmidi_create(struct snd_card *card) +{ + struct portman *pm = card->private_data; + struct snd_rawmidi *rmidi; + struct snd_rawmidi_substream *substream; + int err; + + err = snd_rawmidi_new(card, CARD_NAME, 0, + PORTMAN_NUM_OUTPUT_PORTS, + PORTMAN_NUM_INPUT_PORTS, + &rmidi); + if (err < 0) + return err; + + rmidi->private_data = pm; + strcpy(rmidi->name, CARD_NAME); + rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT | + SNDRV_RAWMIDI_INFO_INPUT | + SNDRV_RAWMIDI_INFO_DUPLEX; + + pm->rmidi = rmidi; + + /* register rawmidi ops */ + snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, + &snd_portman_midi_output); + snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, + &snd_portman_midi_input); + + /* name substreams */ + /* output */ + list_for_each_entry(substream, + &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams, + list) { + sprintf(substream->name, + "Portman2x4 %d", substream->number+1); + } + /* input */ + list_for_each_entry(substream, + &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams, + list) { + pm->midi_input[substream->number] = substream; + sprintf(substream->name, + "Portman2x4 %d", substream->number+1); + } + + return err; +} + +/********************************************************************* + * parport stuff + *********************************************************************/ +static void snd_portman_interrupt(int irq, void *userdata) +{ + unsigned char midivalue = 0; + struct portman *pm = ((struct snd_card*)userdata)->private_data; + + spin_lock(&pm->reg_lock); + + /* While any input data is waiting */ + while ((portman_read_status(pm) & INT_REQ) == INT_REQ) { + /* If data available on channel 0, + read it and stuff it into the queue. */ + if (portman_data_avail(pm, 0)) { + /* Read Midi */ + midivalue = portman_read_midi(pm, 0); + /* put midi into queue... */ + if (pm->mode[0] & PORTMAN2X4_MODE_INPUT_TRIGGERED) + snd_rawmidi_receive(pm->midi_input[0], + &midivalue, 1); + + } + /* If data available on channel 1, + read it and stuff it into the queue. */ + if (portman_data_avail(pm, 1)) { + /* Read Midi */ + midivalue = portman_read_midi(pm, 1); + /* put midi into queue... */ + if (pm->mode[1] & PORTMAN2X4_MODE_INPUT_TRIGGERED) + snd_rawmidi_receive(pm->midi_input[1], + &midivalue, 1); + } + + } + + spin_unlock(&pm->reg_lock); +} + +static int __devinit snd_portman_probe_port(struct parport *p) +{ + struct pardevice *pardev; + int res; + + pardev = parport_register_device(p, DRIVER_NAME, + NULL, NULL, NULL, + 0, NULL); + if (!pardev) + return -EIO; + + if (parport_claim(pardev)) { + parport_unregister_device(pardev); + return -EIO; + } + + res = portman_probe(p); + + parport_release(pardev); + parport_unregister_device(pardev); + + return res; +} + +static void __devinit snd_portman_attach(struct parport *p) +{ + struct platform_device *device; + + device = platform_device_alloc(PLATFORM_DRIVER, device_count); + if (!device) + return; + + /* Temporary assignment to forward the parport */ + platform_set_drvdata(device, p); + + if (platform_device_register(device) < 0) { + platform_device_put(device); + return; + } + + /* Since we dont get the return value of probe + * We need to check if device probing succeeded or not */ + if (!platform_get_drvdata(device)) { + platform_device_unregister(device); + return; + } + + /* register device in global table */ + platform_devices[device_count] = device; + device_count++; +} + +static void snd_portman_detach(struct parport *p) +{ + /* nothing to do here */ +} + +static struct parport_driver portman_parport_driver = { + .name = "portman2x4", + .attach = snd_portman_attach, + .detach = snd_portman_detach +}; + +/********************************************************************* + * platform stuff + *********************************************************************/ +static void snd_portman_card_private_free(struct snd_card *card) +{ + struct portman *pm = card->private_data; + struct pardevice *pardev = pm->pardev; + + if (pardev) { + if (pm->pardev_claimed) + parport_release(pardev); + parport_unregister_device(pardev); + } + + portman_free(pm); +} + +static int __devinit snd_portman_probe(struct platform_device *pdev) +{ + struct pardevice *pardev; + struct parport *p; + int dev = pdev->id; + struct snd_card *card = NULL; + struct portman *pm = NULL; + int err; + + p = platform_get_drvdata(pdev); + platform_set_drvdata(pdev, NULL); + + if (dev >= SNDRV_CARDS) + return -ENODEV; + if (!enable[dev]) + return -ENOENT; + + if ((err = snd_portman_probe_port(p)) < 0) + return err; + + card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); + if (card == NULL) { + snd_printd("Cannot create card\n"); + return -ENOMEM; + } + strcpy(card->driver, DRIVER_NAME); + strcpy(card->shortname, CARD_NAME); + sprintf(card->longname, "%s at 0x%lx, irq %i", + card->shortname, p->base, p->irq); + + pardev = parport_register_device(p, /* port */ + DRIVER_NAME, /* name */ + NULL, /* preempt */ + NULL, /* wakeup */ + snd_portman_interrupt, /* ISR */ + PARPORT_DEV_EXCL, /* flags */ + (void *)card); /* private */ + if (pardev == NULL) { + snd_printd("Cannot register pardevice\n"); + err = -EIO; + goto __err; + } + + if ((err = portman_create(card, pardev, &pm)) < 0) { + snd_printd("Cannot create main component\n"); + parport_unregister_device(pardev); + goto __err; + } + card->private_data = pm; + card->private_free = snd_portman_card_private_free; + + if ((err = snd_portman_rawmidi_create(card)) < 0) { + snd_printd("Creating Rawmidi component failed\n"); + goto __err; + } + + /* claim parport */ + if (parport_claim(pardev)) { + snd_printd("Cannot claim parport 0x%lx\n", pardev->port->base); + err = -EIO; + goto __err; + } + pm->pardev_claimed = 1; + + /* init device */ + if ((err = portman_device_init(pm)) < 0) + goto __err; + + platform_set_drvdata(pdev, card); + + /* At this point card will be usable */ + if ((err = snd_card_register(card)) < 0) { + snd_printd("Cannot register card\n"); + goto __err; + } + + snd_printk(KERN_INFO "Portman 2x4 on 0x%lx\n", p->base); + return 0; + +__err: + snd_card_free(card); + return err; +} + +static int snd_portman_remove(struct platform_device *pdev) +{ + struct snd_card *card = platform_get_drvdata(pdev); + + if (card) + snd_card_free(card); + + return 0; +} + + +static struct platform_driver snd_portman_driver = { + .probe = snd_portman_probe, + .remove = snd_portman_remove, + .driver = { + .name = PLATFORM_DRIVER + } +}; + +/********************************************************************* + * module init stuff + *********************************************************************/ +static void snd_portman_unregister_all(void) +{ + int i; + + for (i = 0; i < SNDRV_CARDS; ++i) { + if (platform_devices[i]) { + platform_device_unregister(platform_devices[i]); + platform_devices[i] = NULL; + } + } + platform_driver_unregister(&snd_portman_driver); + parport_unregister_driver(&portman_parport_driver); +} + +static int __init snd_portman_module_init(void) +{ + int err; + + if ((err = platform_driver_register(&snd_portman_driver)) < 0) + return err; + + if (parport_register_driver(&portman_parport_driver) != 0) { + platform_driver_unregister(&snd_portman_driver); + return -EIO; + } + + if (device_count == 0) { + snd_portman_unregister_all(); + return -ENODEV; + } + + return 0; +} + +static void __exit snd_portman_module_exit(void) +{ + snd_portman_unregister_all(); +} + +module_init(snd_portman_module_init); +module_exit(snd_portman_module_exit); -- cgit v1.2.3 From cd7509a43c3047a6339484e5009c2db7ee4c7a51 Mon Sep 17 00:00:00 2001 From: Kailang Yang Date: Fri, 26 Jan 2007 18:33:17 +0100 Subject: [ALSA] hda-codec - Add HP BPC-D7000 support Add HP BPC-D7000 support. Signed-off-by: Kailang Yang Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 153 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 151 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index a2986250903..d01895515e0 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -87,6 +87,8 @@ enum { ALC262_HIPPO_1, ALC262_FUJITSU, ALC262_HP_BPC, + ALC262_HP_BPC_D7000_WL, + ALC262_HP_BPC_D7000_WF, ALC262_BENQ_ED8, ALC262_AUTO, ALC262_MODEL_LAST /* last tag */ @@ -5919,6 +5921,30 @@ static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = { { } /* end */ }; +static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT), + HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT), + { } /* end */ +}; + +static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = { + HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; + #define alc262_capture_mixer alc882_capture_mixer #define alc262_capture_alt_mixer alc882_capture_alt_mixer @@ -6448,6 +6474,100 @@ static struct hda_verb alc262_HP_BPC_init_verbs[] = { { } }; +static struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = { + /* + * Unmute ADC0-2 and set the default input to mic-in + */ + {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + * mixer widget + * Note: PASD motherboards uses the Line In 2 as the input for front + * panel mic (mic 2) + */ + /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(6)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(7)}, + /* + * Set up output mixers (0x0c - 0x0e) + */ + /* set vol=0 to output mixers */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + /* set up input amps for analog loopback */ + /* Amp Indices: DAC = 0, mixer = 1 */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP */ + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Mono */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* rear MIC */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* Line in */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Line out */ + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD in */ + + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, + + /* {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, */ + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, + {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, + {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, + + /* FIXME: use matrix-type input source selection */ + /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ + /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, /*rear MIC*/ + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /*Line in*/ + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, /*F MIC*/ + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, /*Front*/ + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, /*CD*/ + /* {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */ + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, /*HP*/ + /* Input mixer2 */ + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, + /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */ + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, + /* Input mixer3 */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, + /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, + + { } +}; + /* pcm configuration: identiacal with ALC880 */ #define alc262_pcm_analog_playback alc880_pcm_analog_playback #define alc262_pcm_analog_capture alc880_pcm_analog_capture @@ -6511,6 +6631,7 @@ static const char *alc262_models[ALC262_MODEL_LAST] = { [ALC262_HIPPO_1] = "hippo_1", [ALC262_FUJITSU] = "fujitsu", [ALC262_HP_BPC] = "hp-bpc", + [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000", [ALC262_BENQ_ED8] = "benq", [ALC262_AUTO] = "auto", }; @@ -6519,9 +6640,16 @@ static struct snd_pci_quirk alc262_cfg_tbl[] = { SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO), SND_PCI_QUIRK(0x103c, 0x12fe, "HP xw9400", ALC262_HP_BPC), SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC), - SND_PCI_QUIRK(0x103c, 0x2801, "HP q954", ALC262_HP_BPC), SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC), SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC), + SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL), + SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL), + SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL), + SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL), + SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF), + SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF), + SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF), + SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF), SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO), SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU), SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1), @@ -6586,6 +6714,27 @@ static struct alc_config_preset alc262_presets[] = { .channel_mode = alc262_modes, .input_mux = &alc262_HP_capture_source, }, + [ALC262_HP_BPC_D7000_WF] = { + .mixers = { alc262_HP_BPC_WildWest_mixer }, + .init_verbs = { alc262_HP_BPC_WildWest_init_verbs }, + .num_dacs = ARRAY_SIZE(alc262_dac_nids), + .dac_nids = alc262_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc262_modes), + .channel_mode = alc262_modes, + .input_mux = &alc262_HP_capture_source, + }, + [ALC262_HP_BPC_D7000_WL] = { + .mixers = { alc262_HP_BPC_WildWest_mixer, + alc262_HP_BPC_WildWest_option_mixer }, + .init_verbs = { alc262_HP_BPC_WildWest_init_verbs }, + .num_dacs = ARRAY_SIZE(alc262_dac_nids), + .dac_nids = alc262_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc262_modes), + .channel_mode = alc262_modes, + .input_mux = &alc262_HP_capture_source, + }, [ALC262_BENQ_ED8] = { .mixers = { alc262_base_mixer }, .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs }, @@ -6623,7 +6772,7 @@ static int patch_alc262(struct hda_codec *codec) board_config = snd_hda_check_board_config(codec, ALC262_MODEL_LAST, alc262_models, alc262_cfg_tbl); - + if (board_config < 0) { printk(KERN_INFO "hda_codec: Unknown model for ALC262, " "trying auto-probe from BIOS...\n"); -- cgit v1.2.3 From 377a4f7ea35d7d6cc05faea7030522d93435dc11 Mon Sep 17 00:00:00 2001 From: Peter Eriksen Date: Mon, 29 Jan 2007 14:45:53 +0100 Subject: [ALSA] sound/isa/gus/gus_main.c: Use abs() instead of x < 0 ? -x : x. Signed-off-by: Peter Eriksen Signed-off-by: Andrew Morton Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/isa/gus/gus_main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/isa/gus/gus_main.c b/sound/isa/gus/gus_main.c index b680fddf0d7..8ced5e81b9a 100644 --- a/sound/isa/gus/gus_main.c +++ b/sound/isa/gus/gus_main.c @@ -294,10 +294,10 @@ static int snd_gus_init_dma_irq(struct snd_gus_card * gus, int latches) gus->mix_cntrl_reg |= 4; /* enable MIC */ } dma1 = gus->gf1.dma1; - dma1 = dma1 < 0 ? -dma1 : dma1; + dma1 = abs(dma1); dma1 = dmas[dma1 & 7]; dma2 = gus->gf1.dma2; - dma2 = dma2 < 0 ? -dma2 : dma2; + dma2 = abs(dma2); dma2 = dmas[dma2 & 7]; dma1 |= gus->equal_dma ? 0x40 : (dma2 << 3); @@ -306,7 +306,7 @@ static int snd_gus_init_dma_irq(struct snd_gus_card * gus, int latches) return -EINVAL; } irq = gus->gf1.irq; - irq = irq < 0 ? -irq : irq; + irq = abs(irq); irq = irqs[irq & 0x0f]; if (irq == 0) { snd_printk(KERN_ERR "Error! IRQ isn't defined.\n"); -- cgit v1.2.3 From bcb4d788f573805c74ac4f39a622b30955b2f916 Mon Sep 17 00:00:00 2001 From: "Robert P. J. Day" Date: Mon, 29 Jan 2007 14:46:18 +0100 Subject: [ALSA] Remove useless reference to obsolete KERNELD Remove the final useless reference to the obsolete KERNELD feature. Signed-off-by: Robert P. J. Day Signed-off-by: Andrew Morton Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/core/timer.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'sound') diff --git a/sound/core/timer.c b/sound/core/timer.c index 4e79f9ce1a8..3e063835106 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -35,9 +35,6 @@ #include #include #include -#ifdef CONFIG_KERNELD -#include -#endif #if defined(CONFIG_SND_HPET) || defined(CONFIG_SND_HPET_MODULE) #define DEFAULT_TIMER_LIMIT 3 -- cgit v1.2.3 From 189bc171434e84797f586130fca8eb4df3746e3f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 29 Jan 2007 15:25:40 +0100 Subject: [ALSA] ice1712 - Reorganize existing eeprom data Reorganize EEPROM data (in C99 style). Signed-of-by: Philipp Matthias Hahn Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/ice1712/aureon.c | 112 +++++++++++++++------------------------- sound/pci/ice1712/juli.c | 26 +++++----- sound/pci/ice1712/phase.c | 52 +++++++++---------- sound/pci/ice1712/pontis.c | 26 +++++----- sound/pci/ice1712/prodigy192.c | 26 +++++----- sound/pci/ice1712/vt1720_mobo.c | 53 +++++++++---------- 6 files changed, 133 insertions(+), 162 deletions(-) (limited to 'sound') diff --git a/sound/pci/ice1712/aureon.c b/sound/pci/ice1712/aureon.c index a085618d33f..041d2f07572 100644 --- a/sound/pci/ice1712/aureon.c +++ b/sound/pci/ice1712/aureon.c @@ -2110,84 +2110,54 @@ static int __devinit aureon_init(struct snd_ice1712 *ice) */ static unsigned char aureon51_eeprom[] __devinitdata = { - 0x0a, /* SYSCONF: clock 512, spdif-in/ADC, 3DACs */ - 0x80, /* ACLINK: I2S */ - 0xfc, /* I2S: vol, 96k, 24bit, 192k */ - 0xc3, /* SPDIF: out-en, out-int, spdif-in */ - 0xff, /* GPIO_DIR */ - 0xff, /* GPIO_DIR1 */ - 0x5f, /* GPIO_DIR2 */ - 0x00, /* GPIO_MASK */ - 0x00, /* GPIO_MASK1 */ - 0x00, /* GPIO_MASK2 */ - 0x00, /* GPIO_STATE */ - 0x00, /* GPIO_STATE1 */ - 0x00, /* GPIO_STATE2 */ + [ICE_EEP2_SYSCONF] = 0x0a, /* clock 512, spdif-in/ADC, 3DACs */ + [ICE_EEP2_ACLINK] = 0x80, /* I2S */ + [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */ + [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */ + [ICE_EEP2_GPIO_DIR] = 0xff, + [ICE_EEP2_GPIO_DIR1] = 0xff, + [ICE_EEP2_GPIO_DIR2] = 0x5f, + [ICE_EEP2_GPIO_MASK] = 0x00, + [ICE_EEP2_GPIO_MASK1] = 0x00, + [ICE_EEP2_GPIO_MASK2] = 0x00, + [ICE_EEP2_GPIO_STATE] = 0x00, + [ICE_EEP2_GPIO_STATE1] = 0x00, + [ICE_EEP2_GPIO_STATE2] = 0x00, }; static unsigned char aureon71_eeprom[] __devinitdata = { - 0x0b, /* SYSCONF: clock 512, spdif-in/ADC, 4DACs */ - 0x80, /* ACLINK: I2S */ - 0xfc, /* I2S: vol, 96k, 24bit, 192k */ - 0xc3, /* SPDIF: out-en, out-int, spdif-in */ - 0xff, /* GPIO_DIR */ - 0xff, /* GPIO_DIR1 */ - 0x5f, /* GPIO_DIR2 */ - 0x00, /* GPIO_MASK */ - 0x00, /* GPIO_MASK1 */ - 0x00, /* GPIO_MASK2 */ - 0x00, /* GPIO_STATE */ - 0x00, /* GPIO_STATE1 */ - 0x00, /* GPIO_STATE2 */ -}; - -static unsigned char prodigy71_eeprom[] __devinitdata = { - 0x0b, /* SYSCONF: clock 512, spdif-in/ADC, 4DACs */ - 0x80, /* ACLINK: I2S */ - 0xfc, /* I2S: vol, 96k, 24bit, 192k */ - 0xc3, /* SPDIF: out-en, out-int, spdif-in */ - 0xff, /* GPIO_DIR */ - 0xff, /* GPIO_DIR1 */ - 0x5f, /* GPIO_DIR2 */ - 0x00, /* GPIO_MASK */ - 0x00, /* GPIO_MASK1 */ - 0x00, /* GPIO_MASK2 */ - 0x00, /* GPIO_STATE */ - 0x00, /* GPIO_STATE1 */ - 0x00, /* GPIO_STATE2 */ + [ICE_EEP2_SYSCONF] = 0x0b, /* clock 512, spdif-in/ADC, 4DACs */ + [ICE_EEP2_ACLINK] = 0x80, /* I2S */ + [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */ + [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */ + [ICE_EEP2_GPIO_DIR] = 0xff, + [ICE_EEP2_GPIO_DIR1] = 0xff, + [ICE_EEP2_GPIO_DIR2] = 0x5f, + [ICE_EEP2_GPIO_MASK] = 0x00, + [ICE_EEP2_GPIO_MASK1] = 0x00, + [ICE_EEP2_GPIO_MASK2] = 0x00, + [ICE_EEP2_GPIO_STATE] = 0x00, + [ICE_EEP2_GPIO_STATE1] = 0x00, + [ICE_EEP2_GPIO_STATE2] = 0x00, }; +#define prodigy71_eeprom aureon71_eeprom static unsigned char prodigy71lt_eeprom[] __devinitdata = { - 0x4b, /* SYSCINF: clock 512, spdif-in/ADC, 4DACs */ - 0x80, /* ACLINK: I2S */ - 0xfc, /* I2S: vol, 96k, 24bit, 192k */ - 0xc3, /* SPDIF: out-en, out-int, spdif-in */ - 0xff, /* GPIO_DIR */ - 0xff, /* GPIO_DIR1 */ - 0x5f, /* GPIO_DIR2 */ - 0x00, /* GPIO_MASK */ - 0x00, /* GPIO_MASK1 */ - 0x00, /* GPIO_MASK2 */ - 0x00, /* GPIO_STATE */ - 0x00, /* GPIO_STATE1 */ - 0x00, /* GPIO_STATE2 */ -}; - -static unsigned char prodigy71xt_eeprom[] __devinitdata = { - 0x4b, /* SYSCINF: clock 512, spdif-in/ADC, 4DACs */ - 0x80, /* ACLINK: I2S */ - 0xfc, /* I2S: vol, 96k, 24bit, 192k */ - 0xc3, /* SPDIF: out-en, out-int, spdif-in */ - 0xff, /* GPIO_DIR */ - 0xff, /* GPIO_DIR1 */ - 0x5f, /* GPIO_DIR2 */ - 0x00, /* GPIO_MASK */ - 0x00, /* GPIO_MASK1 */ - 0x00, /* GPIO_MASK2 */ - 0x00, /* GPIO_STATE */ - 0x00, /* GPIO_STATE1 */ - 0x00, /* GPIO_STATE2 */ + [ICE_EEP2_SYSCONF] = 0x4b, /* clock 384, spdif-in/ADC, 4DACs */ + [ICE_EEP2_ACLINK] = 0x80, /* I2S */ + [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */ + [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */ + [ICE_EEP2_GPIO_DIR] = 0xff, + [ICE_EEP2_GPIO_DIR1] = 0xff, + [ICE_EEP2_GPIO_DIR2] = 0x5f, + [ICE_EEP2_GPIO_MASK] = 0x00, + [ICE_EEP2_GPIO_MASK1] = 0x00, + [ICE_EEP2_GPIO_MASK2] = 0x00, + [ICE_EEP2_GPIO_STATE] = 0x00, + [ICE_EEP2_GPIO_STATE1] = 0x00, + [ICE_EEP2_GPIO_STATE2] = 0x00, }; +#define prodigy71xt_eeprom prodigy71lt_eeprom /* entry point */ struct snd_ice1712_card_info snd_vt1724_aureon_cards[] __devinitdata = { diff --git a/sound/pci/ice1712/juli.c b/sound/pci/ice1712/juli.c index 5176b41ea9d..a7e779b7142 100644 --- a/sound/pci/ice1712/juli.c +++ b/sound/pci/ice1712/juli.c @@ -207,19 +207,19 @@ static int __devinit juli_init(struct snd_ice1712 *ice) */ static unsigned char juli_eeprom[] __devinitdata = { - 0x20, /* SYSCONF: clock 512, mpu401, 1xADC, 1xDACs */ - 0x80, /* ACLINK: I2S */ - 0xf8, /* I2S: vol, 96k, 24bit, 192k */ - 0xc3, /* SPDIF: out-en, out-int, spdif-in */ - 0x9f, /* GPIO_DIR */ - 0xff, /* GPIO_DIR1 */ - 0x7f, /* GPIO_DIR2 */ - 0x9f, /* GPIO_MASK */ - 0xff, /* GPIO_MASK1 */ - 0x7f, /* GPIO_MASK2 */ - 0x16, /* GPIO_STATE: internal clock, multiple 1x, 48kHz */ - 0x80, /* GPIO_STATE1: mute */ - 0x00, /* GPIO_STATE2 */ + [ICE_EEP2_SYSCONF] = 0x20, /* clock 512, mpu401, 1xADC, 1xDACs */ + [ICE_EEP2_ACLINK] = 0x80, /* I2S */ + [ICE_EEP2_I2S] = 0xf8, /* vol, 96k, 24bit, 192k */ + [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */ + [ICE_EEP2_GPIO_DIR] = 0x9f, + [ICE_EEP2_GPIO_DIR1] = 0xff, + [ICE_EEP2_GPIO_DIR2] = 0x7f, + [ICE_EEP2_GPIO_MASK] = 0x9f, + [ICE_EEP2_GPIO_MASK1] = 0xff, + [ICE_EEP2_GPIO_MASK2] = 0x7f, + [ICE_EEP2_GPIO_STATE] = 0x16, /* internal clock, multiple 1x, 48kHz */ + [ICE_EEP2_GPIO_STATE1] = 0x80, /* mute */ + [ICE_EEP2_GPIO_STATE2] = 0x00, }; /* entry point */ diff --git a/sound/pci/ice1712/phase.c b/sound/pci/ice1712/phase.c index e08d73f4ff8..c7f6615d60d 100644 --- a/sound/pci/ice1712/phase.c +++ b/sound/pci/ice1712/phase.c @@ -153,35 +153,35 @@ static int __devinit phase22_add_controls(struct snd_ice1712 *ice) } static unsigned char phase22_eeprom[] __devinitdata = { - 0x00, /* SYSCONF: 1xADC, 1xDACs */ - 0x80, /* ACLINK: I2S */ - 0xf8, /* I2S: vol, 96k, 24bit*/ - 0xc3, /* SPDIF: out-en, out-int, spdif-in */ - 0xFF, /* GPIO_DIR */ - 0xFF, /* GPIO_DIR1 */ - 0xFF, /* GPIO_DIR2 */ - 0x00, /* GPIO_MASK */ - 0x00, /* GPIO_MASK1 */ - 0x00, /* GPIO_MASK2 */ - 0x00, /* GPIO_STATE: */ - 0x00, /* GPIO_STATE1: */ - 0x00, /* GPIO_STATE2 */ + [ICE_EEP2_SYSCONF] = 0x00, /* 1xADC, 1xDACs */ + [ICE_EEP2_ACLINK] = 0x80, /* I2S */ + [ICE_EEP2_I2S] = 0xf8, /* vol, 96k, 24bit */ + [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */ + [ICE_EEP2_GPIO_DIR] = 0xff, + [ICE_EEP2_GPIO_DIR1] = 0xff, + [ICE_EEP2_GPIO_DIR2] = 0xff, + [ICE_EEP2_GPIO_MASK] = 0x00, + [ICE_EEP2_GPIO_MASK1] = 0x00, + [ICE_EEP2_GPIO_MASK2] = 0x00, + [ICE_EEP2_GPIO_STATE] = 0x00, + [ICE_EEP2_GPIO_STATE1] = 0x00, + [ICE_EEP2_GPIO_STATE2] = 0x00, }; static unsigned char phase28_eeprom[] __devinitdata = { - 0x0b, /* SYSCONF: clock 512, spdif-in/ADC, 4DACs */ - 0x80, /* ACLINK: I2S */ - 0xfc, /* I2S: vol, 96k, 24bit, 192k */ - 0xc3, /* SPDIF: out-en, out-int, spdif-in */ - 0xff, /* GPIO_DIR */ - 0xff, /* GPIO_DIR1 */ - 0x5f, /* GPIO_DIR2 */ - 0x00, /* GPIO_MASK */ - 0x00, /* GPIO_MASK1 */ - 0x00, /* GPIO_MASK2 */ - 0x00, /* GPIO_STATE */ - 0x00, /* GPIO_STATE1 */ - 0x00, /* GPIO_STATE2 */ + [ICE_EEP2_SYSCONF] = 0x0b, /* clock 512, spdif-in/ADC, 4DACs */ + [ICE_EEP2_ACLINK] = 0x80, /* I2S */ + [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */ + [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */ + [ICE_EEP2_GPIO_DIR] = 0xff, + [ICE_EEP2_GPIO_DIR1] = 0xff, + [ICE_EEP2_GPIO_DIR2] = 0x5f, + [ICE_EEP2_GPIO_MASK] = 0x00, + [ICE_EEP2_GPIO_MASK1] = 0x00, + [ICE_EEP2_GPIO_MASK2] = 0x00, + [ICE_EEP2_GPIO_STATE] = 0x00, + [ICE_EEP2_GPIO_STATE1] = 0x00, + [ICE_EEP2_GPIO_STATE2] = 0x00, }; /* diff --git a/sound/pci/ice1712/pontis.c b/sound/pci/ice1712/pontis.c index 6c74c2d2e7f..b135c1401dc 100644 --- a/sound/pci/ice1712/pontis.c +++ b/sound/pci/ice1712/pontis.c @@ -827,19 +827,19 @@ static int __devinit pontis_init(struct snd_ice1712 *ice) */ static unsigned char pontis_eeprom[] __devinitdata = { - 0x08, /* SYSCONF: clock 256, mpu401, spdif-in/ADC, 1DAC */ - 0x80, /* ACLINK: I2S */ - 0xf8, /* I2S: vol, 96k, 24bit, 192k */ - 0xc3, /* SPDIF: out-en, out-int, spdif-in */ - 0x07, /* GPIO_DIR */ - 0x00, /* GPIO_DIR1 */ - 0x00, /* GPIO_DIR2 (ignored) */ - 0x0f, /* GPIO_MASK (4-7 reserved for CS8416) */ - 0xff, /* GPIO_MASK1 */ - 0x00, /* GPIO_MASK2 (ignored) */ - 0x06, /* GPIO_STATE (0-low, 1-high, 2-high) */ - 0x00, /* GPIO_STATE1 */ - 0x00, /* GPIO_STATE2 (ignored) */ + [ICE_EEP2_SYSCONF] = 0x08, /* clock 256, mpu401, spdif-in/ADC, 1DAC */ + [ICE_EEP2_ACLINK] = 0x80, /* I2S */ + [ICE_EEP2_I2S] = 0xf8, /* vol, 96k, 24bit, 192k */ + [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */ + [ICE_EEP2_GPIO_DIR] = 0x07, + [ICE_EEP2_GPIO_DIR1] = 0x00, + [ICE_EEP2_GPIO_DIR2] = 0x00, /* ignored */ + [ICE_EEP2_GPIO_MASK] = 0x0f, /* 4-7 reserved for CS8416 */ + [ICE_EEP2_GPIO_MASK1] = 0xff, + [ICE_EEP2_GPIO_MASK2] = 0x00, /* ignored */ + [ICE_EEP2_GPIO_STATE] = 0x06, /* 0-low, 1-high, 2-high */ + [ICE_EEP2_GPIO_STATE1] = 0x00, + [ICE_EEP2_GPIO_STATE2] = 0x00, /* ignored */ }; /* entry point */ diff --git a/sound/pci/ice1712/prodigy192.c b/sound/pci/ice1712/prodigy192.c index 41b2605daa3..b9b63179dbe 100644 --- a/sound/pci/ice1712/prodigy192.c +++ b/sound/pci/ice1712/prodigy192.c @@ -507,19 +507,19 @@ static int __devinit prodigy192_init(struct snd_ice1712 *ice) */ static unsigned char prodigy71_eeprom[] __devinitdata = { - 0x2b, /* SYSCONF: clock 512, mpu401, spdif-in/ADC, 4DACs */ - 0x80, /* ACLINK: I2S */ - 0xf8, /* I2S: vol, 96k, 24bit, 192k */ - 0xc3, /* SPDIF: out-en, out-int, spdif-in */ - 0xff, /* GPIO_DIR */ - 0xff, /* GPIO_DIR1 */ - 0xbf, /* GPIO_DIR2 */ - 0x00, /* GPIO_MASK */ - 0x00, /* GPIO_MASK1 */ - 0x00, /* GPIO_MASK2 */ - 0x00, /* GPIO_STATE */ - 0x00, /* GPIO_STATE1 */ - 0x00, /* GPIO_STATE2 */ + [ICE_EEP2_SYSCONF] = 0x2b, /* clock 512, mpu401, spdif-in/ADC, 4DACs */ + [ICE_EEP2_ACLINK] = 0x80, /* I2S */ + [ICE_EEP2_I2S] = 0xf8, /* vol, 96k, 24bit, 192k */ + [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */ + [ICE_EEP2_GPIO_DIR] = 0xff, + [ICE_EEP2_GPIO_DIR1] = 0xff, + [ICE_EEP2_GPIO_DIR2] = 0xbf, + [ICE_EEP2_GPIO_MASK] = 0x00, + [ICE_EEP2_GPIO_MASK1] = 0x00, + [ICE_EEP2_GPIO_MASK2] = 0x00, + [ICE_EEP2_GPIO_STATE] = 0x00, + [ICE_EEP2_GPIO_STATE1] = 0x00, + [ICE_EEP2_GPIO_STATE2] = 0x00, }; diff --git a/sound/pci/ice1712/vt1720_mobo.c b/sound/pci/ice1712/vt1720_mobo.c index 7ca263c1309..239524158fe 100644 --- a/sound/pci/ice1712/vt1720_mobo.c +++ b/sound/pci/ice1712/vt1720_mobo.c @@ -30,6 +30,7 @@ #include #include "ice1712.h" +#include "envy24ht.h" #include "vt1720_mobo.h" @@ -56,35 +57,35 @@ static int __devinit k8x800_add_controls(struct snd_ice1712 *ice) /* EEPROM image */ static unsigned char k8x800_eeprom[] __devinitdata = { - 0x01, /* SYSCONF: clock 256, 1ADC, 2DACs */ - 0x02, /* ACLINK: ACLINK, packed */ - 0x00, /* I2S: - */ - 0x00, /* SPDIF: - */ - 0xff, /* GPIO_DIR */ - 0xff, /* GPIO_DIR1 */ - 0x00, /* - */ - 0xff, /* GPIO_MASK */ - 0xff, /* GPIO_MASK1 */ - 0x00, /* - */ - 0x00, /* GPIO_STATE */ - 0x00, /* GPIO_STATE1 */ - 0x00, /* - */ + [ICE_EEP2_SYSCONF] = 0x01, /* clock 256, 1ADC, 2DACs */ + [ICE_EEP2_ACLINK] = 0x02, /* ACLINK, packed */ + [ICE_EEP2_I2S] = 0x00, /* - */ + [ICE_EEP2_SPDIF] = 0x00, /* - */ + [ICE_EEP2_GPIO_DIR] = 0xff, + [ICE_EEP2_GPIO_DIR1] = 0xff, + [ICE_EEP2_GPIO_DIR2] = 0x00, /* - */ + [ICE_EEP2_GPIO_MASK] = 0xff, + [ICE_EEP2_GPIO_MASK1] = 0xff, + [ICE_EEP2_GPIO_MASK2] = 0x00, /* - */ + [ICE_EEP2_GPIO_STATE] = 0x00, + [ICE_EEP2_GPIO_STATE1] = 0x00, + [ICE_EEP2_GPIO_STATE2] = 0x00, /* - */ }; static unsigned char sn25p_eeprom[] __devinitdata = { - 0x01, /* SYSCONF: clock 256, 1ADC, 2DACs */ - 0x02, /* ACLINK: ACLINK, packed */ - 0x00, /* I2S: - */ - 0x41, /* SPDIF: - */ - 0xff, /* GPIO_DIR */ - 0xff, /* GPIO_DIR1 */ - 0x00, /* - */ - 0xff, /* GPIO_MASK */ - 0xff, /* GPIO_MASK1 */ - 0x00, /* - */ - 0x00, /* GPIO_STATE */ - 0x00, /* GPIO_STATE1 */ - 0x00, /* - */ + [ICE_EEP2_SYSCONF] = 0x01, /* clock 256, 1ADC, 2DACs */ + [ICE_EEP2_ACLINK] = 0x02, /* ACLINK, packed */ + [ICE_EEP2_I2S] = 0x00, /* - */ + [ICE_EEP2_SPDIF] = 0x41, /* - */ + [ICE_EEP2_GPIO_DIR] = 0xff, + [ICE_EEP2_GPIO_DIR1] = 0xff, + [ICE_EEP2_GPIO_DIR2] = 0x00, /* - */ + [ICE_EEP2_GPIO_MASK] = 0xff, + [ICE_EEP2_GPIO_MASK1] = 0xff, + [ICE_EEP2_GPIO_MASK2] = 0x00, /* - */ + [ICE_EEP2_GPIO_STATE] = 0x00, + [ICE_EEP2_GPIO_STATE1] = 0x00, + [ICE_EEP2_GPIO_STATE2] = 0x00, /* - */ }; -- cgit v1.2.3 From 32b47da03541f97e40f1af5488ef88250459f388 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 29 Jan 2007 15:26:36 +0100 Subject: [ALSA] Add 'const' to files in pci/ice1712/ Mark a lot of data as 'const' Signed-of-by: Philipp Matthias Hahn Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/ice1712/amp.c | 4 +-- sound/pci/ice1712/amp.h | 2 +- sound/pci/ice1712/aureon.c | 42 +++++++++++------------ sound/pci/ice1712/aureon.h | 2 +- sound/pci/ice1712/delta.c | 34 +++++++++---------- sound/pci/ice1712/delta.h | 2 +- sound/pci/ice1712/ews.c | 24 ++++++------- sound/pci/ice1712/ews.h | 2 +- sound/pci/ice1712/hoontech.c | 7 ++-- sound/pci/ice1712/hoontech.h | 2 +- sound/pci/ice1712/ice1712.c | 72 +++++++++++++++++++-------------------- sound/pci/ice1712/ice1712.h | 4 +-- sound/pci/ice1712/ice1724.c | 74 ++++++++++++++++++++--------------------- sound/pci/ice1712/juli.c | 6 ++-- sound/pci/ice1712/juli.h | 2 +- sound/pci/ice1712/phase.c | 20 +++++------ sound/pci/ice1712/phase.h | 2 +- sound/pci/ice1712/pontis.c | 14 ++++---- sound/pci/ice1712/pontis.h | 2 +- sound/pci/ice1712/prodigy192.c | 10 +++--- sound/pci/ice1712/prodigy192.h | 2 +- sound/pci/ice1712/revo.c | 22 ++++++------ sound/pci/ice1712/revo.h | 2 +- sound/pci/ice1712/vt1720_mobo.c | 6 ++-- sound/pci/ice1712/vt1720_mobo.h | 2 +- sound/pci/ice1712/wtm.c | 2 +- 26 files changed, 180 insertions(+), 183 deletions(-) (limited to 'sound') diff --git a/sound/pci/ice1712/amp.c b/sound/pci/ice1712/amp.c index 59c4078ad33..6e22d326df3 100644 --- a/sound/pci/ice1712/amp.c +++ b/sound/pci/ice1712/amp.c @@ -42,7 +42,7 @@ static void wm_put(struct snd_ice1712 *ice, int reg, unsigned short val) static int __devinit snd_vt1724_amp_init(struct snd_ice1712 *ice) { - static unsigned short wm_inits[] = { + static const unsigned short wm_inits[] = { WM_ATTEN_L, 0x0000, /* 0 db */ WM_ATTEN_R, 0x0000, /* 0 db */ WM_DAC_CTRL, 0x0008, /* 24bit I2S */ @@ -75,7 +75,7 @@ static int __devinit snd_vt1724_amp_add_controls(struct snd_ice1712 *ice) /* entry point */ -struct snd_ice1712_card_info snd_vt1724_amp_cards[] __devinitdata = { +const struct snd_ice1712_card_info snd_vt1724_amp_cards[] __devinitdata = { { .subvendor = VT1724_SUBDEVICE_AV710, .name = "Chaintech AV-710", diff --git a/sound/pci/ice1712/amp.h b/sound/pci/ice1712/amp.h index a0fc89b4812..7b667bad0c6 100644 --- a/sound/pci/ice1712/amp.h +++ b/sound/pci/ice1712/amp.h @@ -42,7 +42,7 @@ #define WM_DAC_CTRL 0x02 #define WM_INT_CTRL 0x03 -extern struct snd_ice1712_card_info snd_vt1724_amp_cards[]; +extern const struct snd_ice1712_card_info snd_vt1724_amp_cards[]; #endif /* __SOUND_AMP_H */ diff --git a/sound/pci/ice1712/aureon.c b/sound/pci/ice1712/aureon.c index 041d2f07572..625a9a32b7c 100644 --- a/sound/pci/ice1712/aureon.c +++ b/sound/pci/ice1712/aureon.c @@ -294,7 +294,7 @@ static unsigned short aureon_ac97_read(struct snd_ice1712 *ice, unsigned short r static int aureon_ac97_init (struct snd_ice1712 *ice) { int i; - static unsigned short ac97_defaults[] = { + static const unsigned short ac97_defaults[] = { 0x00, 0x9640, 0x02, 0x8000, 0x04, 0x8000, @@ -674,7 +674,7 @@ static DECLARE_TLV_DB_SCALE(db_scale_ac97_gain, -3450, 150, 0); * Logarithmic volume values for WM8770 * Computed as 20 * Log10(255 / x) */ -static unsigned char wm_vol[256] = { +static const unsigned char wm_vol[256] = { 127, 48, 42, 39, 36, 34, 33, 31, 30, 29, 28, 27, 27, 26, 25, 25, 24, 24, 23, 23, 22, 22, 21, 21, 21, 20, 20, 20, 19, 19, 19, 18, 18, 18, 18, 17, 17, 17, 17, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 13, 13, 13, @@ -1067,14 +1067,14 @@ static int wm_adc_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val */ static int wm_adc_mux_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { + static const char * const texts[] = { "CD", //AIN1 "Aux", //AIN2 "Line", //AIN3 "Mic", //AIN4 "AC97" //AIN5 }; - static char *universe_texts[] = { + static const char * const universe_texts[] = { "Aux1", //AIN1 "CD", //AIN2 "Phono", //AIN3 @@ -1140,11 +1140,11 @@ static int wm_adc_mux_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val static int aureon_cs8415_mux_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); - static char *aureon_texts[] = { + static const char * const aureon_texts[] = { "CD", //RXP0 "Optical" //RXP1 }; - static char *prodigy_texts[] = { + static const char * const prodigy_texts[] = { "CD", "Coax" }; @@ -1368,7 +1368,7 @@ static int aureon_deemp_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v */ static int aureon_oversampling_info(struct snd_kcontrol *k, struct snd_ctl_elem_info *uinfo) { - static char *texts[2] = { "128x", "64x" }; + static const char * const texts[2] = { "128x", "64x" }; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; @@ -1411,7 +1411,7 @@ static int aureon_oversampling_put(struct snd_kcontrol *kcontrol, struct snd_ctl * mixers */ -static struct snd_kcontrol_new aureon_dac_controls[] __devinitdata = { +static const struct snd_kcontrol_new aureon_dac_controls[] __devinitdata = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", @@ -1526,7 +1526,7 @@ static struct snd_kcontrol_new aureon_dac_controls[] __devinitdata = { } }; -static struct snd_kcontrol_new wm_controls[] __devinitdata = { +static const struct snd_kcontrol_new wm_controls[] __devinitdata = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PCM Playback Switch", @@ -1592,7 +1592,7 @@ static struct snd_kcontrol_new wm_controls[] __devinitdata = { } }; -static struct snd_kcontrol_new ac97_controls[] __devinitdata = { +static const struct snd_kcontrol_new ac97_controls[] __devinitdata = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "AC97 Playback Switch", @@ -1697,7 +1697,7 @@ static struct snd_kcontrol_new ac97_controls[] __devinitdata = { } }; -static struct snd_kcontrol_new universe_ac97_controls[] __devinitdata = { +static const struct snd_kcontrol_new universe_ac97_controls[] __devinitdata = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "AC97 Playback Switch", @@ -1829,8 +1829,7 @@ static struct snd_kcontrol_new universe_ac97_controls[] __devinitdata = { }; - -static struct snd_kcontrol_new cs8415_controls[] __devinitdata = { +static const struct snd_kcontrol_new cs8415_controls[] __devinitdata = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), @@ -1875,7 +1874,6 @@ static struct snd_kcontrol_new cs8415_controls[] __devinitdata = { } }; - static int __devinit aureon_add_controls(struct snd_ice1712 *ice) { unsigned int i, counts; @@ -1943,7 +1941,7 @@ static int __devinit aureon_add_controls(struct snd_ice1712 *ice) */ static int __devinit aureon_init(struct snd_ice1712 *ice) { - static unsigned short wm_inits_aureon[] = { + static const unsigned short wm_inits_aureon[] = { /* These come first to reduce init pop noise */ 0x1b, 0x044, /* ADC Mux (AC'97 source) */ 0x1c, 0x00B, /* Out Mux1 (VOUT1 = DAC+AUX, VOUT2 = DAC) */ @@ -1979,7 +1977,7 @@ static int __devinit aureon_init(struct snd_ice1712 *ice) 0x1a, 0x000, /* -12dB ADC/R */ (unsigned short)-1 }; - static unsigned short wm_inits_prodigy[] = { + static const unsigned short wm_inits_prodigy[] = { /* These come first to reduce init pop noise */ 0x1b, 0x000, /* ADC Mux */ @@ -2021,7 +2019,7 @@ static int __devinit aureon_init(struct snd_ice1712 *ice) (unsigned short)-1 }; - static unsigned short cs_inits[] = { + static const unsigned short cs_inits[] = { 0x0441, /* RUN */ 0x0180, /* no mute, OMCK output on RMCK pin */ 0x0201, /* S/PDIF source on RXP1 */ @@ -2029,7 +2027,7 @@ static int __devinit aureon_init(struct snd_ice1712 *ice) (unsigned short)-1 }; unsigned int tmp; - unsigned short *p; + const unsigned short *p; int err, i; if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY) { @@ -2109,7 +2107,7 @@ static int __devinit aureon_init(struct snd_ice1712 *ice) * hence the driver needs to sets up it properly. */ -static unsigned char aureon51_eeprom[] __devinitdata = { +static const unsigned char aureon51_eeprom[] __devinitdata = { [ICE_EEP2_SYSCONF] = 0x0a, /* clock 512, spdif-in/ADC, 3DACs */ [ICE_EEP2_ACLINK] = 0x80, /* I2S */ [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */ @@ -2125,7 +2123,7 @@ static unsigned char aureon51_eeprom[] __devinitdata = { [ICE_EEP2_GPIO_STATE2] = 0x00, }; -static unsigned char aureon71_eeprom[] __devinitdata = { +static const unsigned char aureon71_eeprom[] __devinitdata = { [ICE_EEP2_SYSCONF] = 0x0b, /* clock 512, spdif-in/ADC, 4DACs */ [ICE_EEP2_ACLINK] = 0x80, /* I2S */ [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */ @@ -2142,7 +2140,7 @@ static unsigned char aureon71_eeprom[] __devinitdata = { }; #define prodigy71_eeprom aureon71_eeprom -static unsigned char prodigy71lt_eeprom[] __devinitdata = { +static const unsigned char prodigy71lt_eeprom[] __devinitdata = { [ICE_EEP2_SYSCONF] = 0x4b, /* clock 384, spdif-in/ADC, 4DACs */ [ICE_EEP2_ACLINK] = 0x80, /* I2S */ [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */ @@ -2160,7 +2158,7 @@ static unsigned char prodigy71lt_eeprom[] __devinitdata = { #define prodigy71xt_eeprom prodigy71lt_eeprom /* entry point */ -struct snd_ice1712_card_info snd_vt1724_aureon_cards[] __devinitdata = { +const struct snd_ice1712_card_info snd_vt1724_aureon_cards[] __devinitdata = { { .subvendor = VT1724_SUBDEVICE_AUREON51_SKY, .name = "Terratec Aureon 5.1-Sky", diff --git a/sound/pci/ice1712/aureon.h b/sound/pci/ice1712/aureon.h index c253b8e2c78..79e58e88ed4 100644 --- a/sound/pci/ice1712/aureon.h +++ b/sound/pci/ice1712/aureon.h @@ -38,7 +38,7 @@ #define VT1724_SUBDEVICE_PRODIGY71LT 0x32315441 /* PRODIGY 7.1 LT */ #define VT1724_SUBDEVICE_PRODIGY71XT 0x36315441 /* PRODIGY 7.1 XT*/ -extern struct snd_ice1712_card_info snd_vt1724_aureon_cards[]; +extern const struct snd_ice1712_card_info snd_vt1724_aureon_cards[]; /* GPIO bits */ #define AUREON_CS8415_CS (1 << 22) diff --git a/sound/pci/ice1712/delta.c b/sound/pci/ice1712/delta.c index af659800c9b..3eeb36c6e98 100644 --- a/sound/pci/ice1712/delta.c +++ b/sound/pci/ice1712/delta.c @@ -416,7 +416,7 @@ static int snd_ice1712_delta1010lt_wordclock_status_get(struct snd_kcontrol *kco return 0; } -static struct snd_kcontrol_new snd_ice1712_delta1010lt_wordclock_status __devinitdata = +static const struct snd_kcontrol_new snd_ice1712_delta1010lt_wordclock_status __devinitdata = { .access = (SNDRV_CTL_ELEM_ACCESS_READ), .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -429,7 +429,7 @@ static struct snd_kcontrol_new snd_ice1712_delta1010lt_wordclock_status __devini * initialize the chips on M-Audio cards */ -static struct snd_akm4xxx akm_audiophile __devinitdata = { +static const struct snd_akm4xxx akm_audiophile __devinitdata = { .type = SND_AK4528, .num_adcs = 2, .num_dacs = 2, @@ -438,7 +438,7 @@ static struct snd_akm4xxx akm_audiophile __devinitdata = { } }; -static struct snd_ak4xxx_private akm_audiophile_priv __devinitdata = { +static const struct snd_ak4xxx_private akm_audiophile_priv __devinitdata = { .caddr = 2, .cif = 0, .data_mask = ICE1712_DELTA_AP_DOUT, @@ -450,7 +450,7 @@ static struct snd_ak4xxx_private akm_audiophile_priv __devinitdata = { .mask_flags = 0, }; -static struct snd_akm4xxx akm_delta410 __devinitdata = { +static const struct snd_akm4xxx akm_delta410 __devinitdata = { .type = SND_AK4529, .num_adcs = 2, .num_dacs = 8, @@ -459,7 +459,7 @@ static struct snd_akm4xxx akm_delta410 __devinitdata = { } }; -static struct snd_ak4xxx_private akm_delta410_priv __devinitdata = { +static const struct snd_ak4xxx_private akm_delta410_priv __devinitdata = { .caddr = 0, .cif = 0, .data_mask = ICE1712_DELTA_AP_DOUT, @@ -471,7 +471,7 @@ static struct snd_ak4xxx_private akm_delta410_priv __devinitdata = { .mask_flags = 0, }; -static struct snd_akm4xxx akm_delta1010lt __devinitdata = { +static const struct snd_akm4xxx akm_delta1010lt __devinitdata = { .type = SND_AK4524, .num_adcs = 8, .num_dacs = 8, @@ -481,7 +481,7 @@ static struct snd_akm4xxx akm_delta1010lt __devinitdata = { } }; -static struct snd_ak4xxx_private akm_delta1010lt_priv __devinitdata = { +static const struct snd_ak4xxx_private akm_delta1010lt_priv __devinitdata = { .caddr = 2, .cif = 0, /* the default level of the CIF pin from AK4524 */ .data_mask = ICE1712_DELTA_1010LT_DOUT, @@ -493,7 +493,7 @@ static struct snd_ak4xxx_private akm_delta1010lt_priv __devinitdata = { .mask_flags = 0, }; -static struct snd_akm4xxx akm_delta44 __devinitdata = { +static const struct snd_akm4xxx akm_delta44 __devinitdata = { .type = SND_AK4524, .num_adcs = 4, .num_dacs = 4, @@ -503,7 +503,7 @@ static struct snd_akm4xxx akm_delta44 __devinitdata = { } }; -static struct snd_ak4xxx_private akm_delta44_priv __devinitdata = { +static const struct snd_ak4xxx_private akm_delta44_priv __devinitdata = { .caddr = 2, .cif = 0, /* the default level of the CIF pin from AK4524 */ .data_mask = ICE1712_DELTA_CODEC_SERIAL_DATA, @@ -515,7 +515,7 @@ static struct snd_ak4xxx_private akm_delta44_priv __devinitdata = { .mask_flags = 0, }; -static struct snd_akm4xxx akm_vx442 __devinitdata = { +static const struct snd_akm4xxx akm_vx442 __devinitdata = { .type = SND_AK4524, .num_adcs = 4, .num_dacs = 4, @@ -525,7 +525,7 @@ static struct snd_akm4xxx akm_vx442 __devinitdata = { } }; -static struct snd_ak4xxx_private akm_vx442_priv __devinitdata = { +static const struct snd_ak4xxx_private akm_vx442_priv __devinitdata = { .caddr = 2, .cif = 0, .data_mask = ICE1712_VX442_DOUT, @@ -650,15 +650,15 @@ static int __devinit snd_ice1712_delta_init(struct snd_ice1712 *ice) * additional controls for M-Audio cards */ -static struct snd_kcontrol_new snd_ice1712_delta1010_wordclock_select __devinitdata = +static const struct snd_kcontrol_new snd_ice1712_delta1010_wordclock_select __devinitdata = ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Word Clock Sync", 0, ICE1712_DELTA_WORD_CLOCK_SELECT, 1, 0); -static struct snd_kcontrol_new snd_ice1712_delta1010lt_wordclock_select __devinitdata = +static const struct snd_kcontrol_new snd_ice1712_delta1010lt_wordclock_select __devinitdata = ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Word Clock Sync", 0, ICE1712_DELTA_1010LT_WORDCLOCK, 0, 0); -static struct snd_kcontrol_new snd_ice1712_delta1010_wordclock_status __devinitdata = +static const struct snd_kcontrol_new snd_ice1712_delta1010_wordclock_status __devinitdata = ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Word Clock Status", 0, ICE1712_DELTA_WORD_CLOCK_STATUS, 1, SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE); -static struct snd_kcontrol_new snd_ice1712_deltadio2496_spdif_in_select __devinitdata = +static const struct snd_kcontrol_new snd_ice1712_deltadio2496_spdif_in_select __devinitdata = ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "IEC958 Input Optical", 0, ICE1712_DELTA_SPDIF_INPUT_SELECT, 0, 0); -static struct snd_kcontrol_new snd_ice1712_delta_spdif_in_status __devinitdata = +static const struct snd_kcontrol_new snd_ice1712_delta_spdif_in_status __devinitdata = ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Delta IEC958 Input Status", 0, ICE1712_DELTA_SPDIF_IN_STAT, 1, SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE); @@ -735,7 +735,7 @@ static int __devinit snd_ice1712_delta_add_controls(struct snd_ice1712 *ice) /* entry point */ -struct snd_ice1712_card_info snd_ice1712_delta_cards[] __devinitdata = { +const struct snd_ice1712_card_info snd_ice1712_delta_cards[] __devinitdata = { { .subvendor = ICE1712_SUBDEVICE_DELTA1010, .name = "M Audio Delta 1010", diff --git a/sound/pci/ice1712/delta.h b/sound/pci/ice1712/delta.h index 746ebde9452..e65d669af63 100644 --- a/sound/pci/ice1712/delta.h +++ b/sound/pci/ice1712/delta.h @@ -46,7 +46,7 @@ #define ICE1712_SUBDEVICE_MEDIASTATION 0x694c0100 /* entry point */ -extern struct snd_ice1712_card_info snd_ice1712_delta_cards[]; +extern const struct snd_ice1712_card_info snd_ice1712_delta_cards[]; /* diff --git a/sound/pci/ice1712/ews.c b/sound/pci/ice1712/ews.c index b135389fec6..9b7ff302c07 100644 --- a/sound/pci/ice1712/ews.c +++ b/sound/pci/ice1712/ews.c @@ -332,7 +332,7 @@ static void ews88_setup_spdif(struct snd_ice1712 *ice, int rate) /* */ -static struct snd_akm4xxx akm_ews88mt __devinitdata = { +static const struct snd_akm4xxx akm_ews88mt __devinitdata = { .num_adcs = 8, .num_dacs = 8, .type = SND_AK4524, @@ -342,7 +342,7 @@ static struct snd_akm4xxx akm_ews88mt __devinitdata = { } }; -static struct snd_ak4xxx_private akm_ews88mt_priv __devinitdata = { +static const struct snd_ak4xxx_private akm_ews88mt_priv __devinitdata = { .caddr = 2, .cif = 1, /* CIF high */ .data_mask = ICE1712_EWS88_SERIAL_DATA, @@ -354,7 +354,7 @@ static struct snd_ak4xxx_private akm_ews88mt_priv __devinitdata = { .mask_flags = 0, }; -static struct snd_akm4xxx akm_ewx2496 __devinitdata = { +static const struct snd_akm4xxx akm_ewx2496 __devinitdata = { .num_adcs = 2, .num_dacs = 2, .type = SND_AK4524, @@ -363,7 +363,7 @@ static struct snd_akm4xxx akm_ewx2496 __devinitdata = { } }; -static struct snd_ak4xxx_private akm_ewx2496_priv __devinitdata = { +static const struct snd_ak4xxx_private akm_ewx2496_priv __devinitdata = { .caddr = 2, .cif = 1, /* CIF high */ .data_mask = ICE1712_EWS88_SERIAL_DATA, @@ -375,7 +375,7 @@ static struct snd_ak4xxx_private akm_ewx2496_priv __devinitdata = { .mask_flags = 0, }; -static struct snd_akm4xxx akm_6fire __devinitdata = { +static const struct snd_akm4xxx akm_6fire __devinitdata = { .num_adcs = 6, .num_dacs = 6, .type = SND_AK4524, @@ -384,7 +384,7 @@ static struct snd_akm4xxx akm_6fire __devinitdata = { } }; -static struct snd_ak4xxx_private akm_6fire_priv __devinitdata = { +static const struct snd_ak4xxx_private akm_6fire_priv __devinitdata = { .caddr = 2, .cif = 1, /* CIF high */ .data_mask = ICE1712_6FIRE_SERIAL_DATA, @@ -578,7 +578,7 @@ static int snd_ice1712_ewx_io_sense_put(struct snd_kcontrol *kcontrol, struct sn return val != nval; } -static struct snd_kcontrol_new snd_ice1712_ewx2496_controls[] __devinitdata = { +static const struct snd_kcontrol_new snd_ice1712_ewx2496_controls[] __devinitdata = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Input Sensitivity Switch", @@ -678,7 +678,7 @@ static int snd_ice1712_ews88mt_input_sense_put(struct snd_kcontrol *kcontrol, st return ndata != data; } -static struct snd_kcontrol_new snd_ice1712_ews88mt_input_sense __devinitdata = { +static const struct snd_kcontrol_new snd_ice1712_ews88mt_input_sense __devinitdata = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Input Sensitivity Switch", .info = snd_ice1712_ewx_io_sense_info, @@ -687,7 +687,7 @@ static struct snd_kcontrol_new snd_ice1712_ews88mt_input_sense __devinitdata = { .count = 8, }; -static struct snd_kcontrol_new snd_ice1712_ews88mt_output_sense __devinitdata = { +static const struct snd_kcontrol_new snd_ice1712_ews88mt_output_sense __devinitdata = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Output Sensitivity Switch", .info = snd_ice1712_ewx_io_sense_info, @@ -769,7 +769,7 @@ static int snd_ice1712_ews88d_control_put(struct snd_kcontrol *kcontrol, struct .private_value = xshift | (xinvert << 8),\ } -static struct snd_kcontrol_new snd_ice1712_ews88d_controls[] __devinitdata = { +static const struct snd_kcontrol_new snd_ice1712_ews88d_controls[] __devinitdata = { EWS88D_CONTROL(SNDRV_CTL_ELEM_IFACE_MIXER, "IEC958 Input Optical", 0, 1, 0), /* inverted */ EWS88D_CONTROL(SNDRV_CTL_ELEM_IFACE_MIXER, "ADAT Output Optical", 1, 0, 0), EWS88D_CONTROL(SNDRV_CTL_ELEM_IFACE_MIXER, "ADAT External Master Clock", 2, 0, 0), @@ -909,7 +909,7 @@ static int snd_ice1712_6fire_select_input_put(struct snd_kcontrol *kcontrol, str .private_value = xshift | (xinvert << 8),\ } -static struct snd_kcontrol_new snd_ice1712_6fire_controls[] __devinitdata = { +static const struct snd_kcontrol_new snd_ice1712_6fire_controls[] __devinitdata = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Analog Input Select", @@ -989,7 +989,7 @@ static int __devinit snd_ice1712_ews_add_controls(struct snd_ice1712 *ice) /* entry point */ -struct snd_ice1712_card_info snd_ice1712_ews_cards[] __devinitdata = { +const struct snd_ice1712_card_info snd_ice1712_ews_cards[] __devinitdata = { { .subvendor = ICE1712_SUBDEVICE_EWX2496, .name = "TerraTec EWX24/96", diff --git a/sound/pci/ice1712/ews.h b/sound/pci/ice1712/ews.h index a12a0b05355..df449b4741f 100644 --- a/sound/pci/ice1712/ews.h +++ b/sound/pci/ice1712/ews.h @@ -40,7 +40,7 @@ #define ICE1712_SUBDEVICE_PHASE88 0x3b155111 /* entry point */ -extern struct snd_ice1712_card_info snd_ice1712_ews_cards[]; +extern const struct snd_ice1712_card_info snd_ice1712_ews_cards[]; /* TerraTec EWX 24/96 configuration definitions */ diff --git a/sound/pci/ice1712/hoontech.c b/sound/pci/ice1712/hoontech.c index 3f27d04e7d3..df97313aaf8 100644 --- a/sound/pci/ice1712/hoontech.c +++ b/sound/pci/ice1712/hoontech.c @@ -239,7 +239,7 @@ static void stdsp24_ak4524_lock(struct snd_akm4xxx *ak, int chip) static int __devinit snd_ice1712_value_init(struct snd_ice1712 *ice) { /* Hoontech STDSP24 with modified hardware */ - static struct snd_akm4xxx akm_stdsp24_mv __devinitdata = { + static const struct snd_akm4xxx akm_stdsp24_mv __devinitdata = { .num_adcs = 2, .num_dacs = 2, .type = SND_AK4524, @@ -248,7 +248,7 @@ static int __devinit snd_ice1712_value_init(struct snd_ice1712 *ice) } }; - static struct snd_ak4xxx_private akm_stdsp24_mv_priv __devinitdata = { + static const struct snd_ak4xxx_private akm_stdsp24_mv_priv __devinitdata = { .caddr = 2, .cif = 1, /* CIF high */ .data_mask = ICE1712_STDSP24_SERIAL_DATA, @@ -298,7 +298,7 @@ static int __devinit snd_ice1712_ez8_init(struct snd_ice1712 *ice) /* entry point */ -struct snd_ice1712_card_info snd_ice1712_hoontech_cards[] __devinitdata = { +const struct snd_ice1712_card_info snd_ice1712_hoontech_cards[] __devinitdata = { { .subvendor = ICE1712_SUBDEVICE_STDSP24, .name = "Hoontech SoundTrack Audio DSP24", @@ -325,4 +325,3 @@ struct snd_ice1712_card_info snd_ice1712_hoontech_cards[] __devinitdata = { }, { } /* terminator */ }; - diff --git a/sound/pci/ice1712/hoontech.h b/sound/pci/ice1712/hoontech.h index 1ee538b20fb..b62d6e4f6c7 100644 --- a/sound/pci/ice1712/hoontech.h +++ b/sound/pci/ice1712/hoontech.h @@ -35,7 +35,7 @@ #define ICE1712_SUBDEVICE_STDSP24_MEDIA7_1 0x16141217 /* Hoontech ST Audio DSP24 Media 7.1 */ #define ICE1712_SUBDEVICE_EVENT_EZ8 0x00010001 /* A dummy id for EZ8 */ -extern struct snd_ice1712_card_info snd_ice1712_hoontech_cards[]; +extern const struct snd_ice1712_card_info snd_ice1712_hoontech_cards[]; /* Hoontech SoundTrack Audio DSP 24 GPIO definitions */ diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c index 8ba31cfb904..b8baadba810 100644 --- a/sound/pci/ice1712/ice1712.c +++ b/sound/pci/ice1712/ice1712.c @@ -107,7 +107,7 @@ module_param_array(dxr_enable, int, NULL, 0444); MODULE_PARM_DESC(dxr_enable, "Enable DXR support for Terratec DMX6FIRE."); -static struct pci_device_id snd_ice1712_ids[] = { +static const struct pci_device_id snd_ice1712_ids[] = { { PCI_VENDOR_ID_ICE, PCI_DEVICE_ID_ICE_1712, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ICE1712 */ { 0, } }; @@ -287,7 +287,7 @@ static int snd_ice1712_digmix_route_ac97_put(struct snd_kcontrol *kcontrol, stru return val != nval; } -static struct snd_kcontrol_new snd_ice1712_mixer_digmix_route_ac97 __devinitdata = { +static const struct snd_kcontrol_new snd_ice1712_mixer_digmix_route_ac97 __devinitdata = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Digital Mixer To AC97", .info = snd_ice1712_digmix_route_ac97_info, @@ -719,7 +719,7 @@ static snd_pcm_uframes_t snd_ice1712_capture_pointer(struct snd_pcm_substream *s return bytes_to_frames(substream->runtime, ptr); } -static struct snd_pcm_hardware snd_ice1712_playback = +static const struct snd_pcm_hardware snd_ice1712_playback = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | @@ -739,7 +739,7 @@ static struct snd_pcm_hardware snd_ice1712_playback = .fifo_size = 0, }; -static struct snd_pcm_hardware snd_ice1712_playback_ds = +static const struct snd_pcm_hardware snd_ice1712_playback_ds = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | @@ -759,7 +759,7 @@ static struct snd_pcm_hardware snd_ice1712_playback_ds = .fifo_size = 0, }; -static struct snd_pcm_hardware snd_ice1712_capture = +static const struct snd_pcm_hardware snd_ice1712_capture = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | @@ -1133,7 +1133,7 @@ static snd_pcm_uframes_t snd_ice1712_capture_pro_pointer(struct snd_pcm_substrea return bytes_to_frames(substream->runtime, ptr); } -static struct snd_pcm_hardware snd_ice1712_playback_pro = +static const struct snd_pcm_hardware snd_ice1712_playback_pro = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | @@ -1153,7 +1153,7 @@ static struct snd_pcm_hardware snd_ice1712_playback_pro = .fifo_size = 0, }; -static struct snd_pcm_hardware snd_ice1712_capture_pro = +static const struct snd_pcm_hardware snd_ice1712_capture_pro = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | @@ -1380,7 +1380,7 @@ static int snd_ice1712_pro_mixer_volume_put(struct snd_kcontrol *kcontrol, struc static DECLARE_TLV_DB_SCALE(db_scale_playback, -14400, 150, 0); -static struct snd_kcontrol_new snd_ice1712_multi_playback_ctrls[] __devinitdata = { +static const struct snd_kcontrol_new snd_ice1712_multi_playback_ctrls[] __devinitdata = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Multi Playback Switch", @@ -1404,7 +1404,7 @@ static struct snd_kcontrol_new snd_ice1712_multi_playback_ctrls[] __devinitdata }, }; -static struct snd_kcontrol_new snd_ice1712_multi_capture_analog_switch __devinitdata = { +static const struct snd_kcontrol_new snd_ice1712_multi_capture_analog_switch __devinitdata = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "H/W Multi Capture Switch", .info = snd_ice1712_pro_mixer_switch_info, @@ -1413,7 +1413,7 @@ static struct snd_kcontrol_new snd_ice1712_multi_capture_analog_switch __devinit .private_value = 10, }; -static struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_switch __devinitdata = { +static const struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_switch __devinitdata = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = SNDRV_CTL_NAME_IEC958("Multi ",CAPTURE,SWITCH), .info = snd_ice1712_pro_mixer_switch_info, @@ -1423,7 +1423,7 @@ static struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_switch __devinitd .count = 2, }; -static struct snd_kcontrol_new snd_ice1712_multi_capture_analog_volume __devinitdata = { +static const struct snd_kcontrol_new snd_ice1712_multi_capture_analog_volume __devinitdata = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ), @@ -1435,7 +1435,7 @@ static struct snd_kcontrol_new snd_ice1712_multi_capture_analog_volume __devinit .tlv = { .p = db_scale_playback } }; -static struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_volume __devinitdata = { +static const struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_volume __devinitdata = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = SNDRV_CTL_NAME_IEC958("Multi ",CAPTURE,VOLUME), .info = snd_ice1712_pro_mixer_volume_info, @@ -1627,7 +1627,7 @@ static int snd_ice1712_eeprom_get(struct snd_kcontrol *kcontrol, return 0; } -static struct snd_kcontrol_new snd_ice1712_eeprom __devinitdata = { +static const struct snd_kcontrol_new snd_ice1712_eeprom __devinitdata = { .iface = SNDRV_CTL_ELEM_IFACE_CARD, .name = "ICE1712 EEPROM", .access = SNDRV_CTL_ELEM_ACCESS_READ, @@ -1663,7 +1663,7 @@ static int snd_ice1712_spdif_default_put(struct snd_kcontrol *kcontrol, return 0; } -static struct snd_kcontrol_new snd_ice1712_spdif_default __devinitdata = +static const struct snd_kcontrol_new snd_ice1712_spdif_default __devinitdata = { .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), @@ -1714,7 +1714,7 @@ static int snd_ice1712_spdif_maskp_get(struct snd_kcontrol *kcontrol, return 0; } -static struct snd_kcontrol_new snd_ice1712_spdif_maskc __devinitdata = +static const struct snd_kcontrol_new snd_ice1712_spdif_maskc __devinitdata = { .access = SNDRV_CTL_ELEM_ACCESS_READ, .iface = SNDRV_CTL_ELEM_IFACE_PCM, @@ -1723,7 +1723,7 @@ static struct snd_kcontrol_new snd_ice1712_spdif_maskc __devinitdata = .get = snd_ice1712_spdif_maskc_get, }; -static struct snd_kcontrol_new snd_ice1712_spdif_maskp __devinitdata = +static const struct snd_kcontrol_new snd_ice1712_spdif_maskp __devinitdata = { .access = SNDRV_CTL_ELEM_ACCESS_READ, .iface = SNDRV_CTL_ELEM_IFACE_PCM, @@ -1750,7 +1750,7 @@ static int snd_ice1712_spdif_stream_put(struct snd_kcontrol *kcontrol, return 0; } -static struct snd_kcontrol_new snd_ice1712_spdif_stream __devinitdata = +static const struct snd_kcontrol_new snd_ice1712_spdif_stream __devinitdata = { .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE), @@ -1811,7 +1811,7 @@ int snd_ice1712_gpio_put(struct snd_kcontrol *kcontrol, static int snd_ice1712_pro_internal_clock_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { + static const char * const texts[] = { "8000", /* 0: 6 */ "9600", /* 1: 3 */ "11025", /* 2: 10 */ @@ -1840,7 +1840,7 @@ static int snd_ice1712_pro_internal_clock_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); - static unsigned char xlate[16] = { + static const unsigned char xlate[16] = { 9, 6, 3, 1, 7, 4, 0, 12, 8, 5, 2, 11, 255, 255, 255, 10 }; unsigned char val; @@ -1864,7 +1864,7 @@ static int snd_ice1712_pro_internal_clock_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); - static unsigned int xrate[13] = { + static const unsigned int xrate[13] = { 8000, 9600, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 64000, 88200, 96000 }; @@ -1891,7 +1891,7 @@ static int snd_ice1712_pro_internal_clock_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_ice1712_pro_internal_clock __devinitdata = { +static const struct snd_kcontrol_new snd_ice1712_pro_internal_clock __devinitdata = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Multi Track Internal Clock", .info = snd_ice1712_pro_internal_clock_info, @@ -1902,7 +1902,7 @@ static struct snd_kcontrol_new snd_ice1712_pro_internal_clock __devinitdata = { static int snd_ice1712_pro_internal_clock_default_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { + static const char * const texts[] = { "8000", /* 0: 6 */ "9600", /* 1: 3 */ "11025", /* 2: 10 */ @@ -1931,7 +1931,7 @@ static int snd_ice1712_pro_internal_clock_default_get(struct snd_kcontrol *kcont struct snd_ctl_elem_value *ucontrol) { int val; - static unsigned int xrate[13] = { + static const unsigned int xrate[13] = { 8000, 9600, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 64000, 88200, 96000 }; @@ -1948,7 +1948,7 @@ static int snd_ice1712_pro_internal_clock_default_get(struct snd_kcontrol *kcont static int snd_ice1712_pro_internal_clock_default_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - static unsigned int xrate[13] = { + static const unsigned int xrate[13] = { 8000, 9600, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 64000, 88200, 96000 }; @@ -1962,7 +1962,7 @@ static int snd_ice1712_pro_internal_clock_default_put(struct snd_kcontrol *kcont return change; } -static struct snd_kcontrol_new snd_ice1712_pro_internal_clock_default __devinitdata = { +static const struct snd_kcontrol_new snd_ice1712_pro_internal_clock_default __devinitdata = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Multi Track Internal Clock Default", .info = snd_ice1712_pro_internal_clock_default_info, @@ -2001,7 +2001,7 @@ static int snd_ice1712_pro_rate_locking_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_ice1712_pro_rate_locking __devinitdata = { +static const struct snd_kcontrol_new snd_ice1712_pro_rate_locking __devinitdata = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Multi Track Rate Locking", .info = snd_ice1712_pro_rate_locking_info, @@ -2040,7 +2040,7 @@ static int snd_ice1712_pro_rate_reset_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_ice1712_pro_rate_reset __devinitdata = { +static const struct snd_kcontrol_new snd_ice1712_pro_rate_reset __devinitdata = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Multi Track Rate Reset", .info = snd_ice1712_pro_rate_reset_info, @@ -2054,7 +2054,7 @@ static struct snd_kcontrol_new snd_ice1712_pro_rate_reset __devinitdata = { static int snd_ice1712_pro_route_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { + static const char * const texts[] = { "PCM Out", /* 0 */ "H/W In 0", "H/W In 1", "H/W In 2", "H/W In 3", /* 1-4 */ "H/W In 4", "H/W In 5", "H/W In 6", "H/W In 7", /* 5-8 */ @@ -2207,7 +2207,7 @@ static int snd_ice1712_pro_route_spdif_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_ice1712_mixer_pro_analog_route __devinitdata = { +static const struct snd_kcontrol_new snd_ice1712_mixer_pro_analog_route __devinitdata = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "H/W Playback Route", .info = snd_ice1712_pro_route_info, @@ -2215,7 +2215,7 @@ static struct snd_kcontrol_new snd_ice1712_mixer_pro_analog_route __devinitdata .put = snd_ice1712_pro_route_analog_put, }; -static struct snd_kcontrol_new snd_ice1712_mixer_pro_spdif_route __devinitdata = { +static const struct snd_kcontrol_new snd_ice1712_mixer_pro_spdif_route __devinitdata = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Route", .info = snd_ice1712_pro_route_info, @@ -2257,7 +2257,7 @@ static int snd_ice1712_pro_volume_rate_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_ice1712_mixer_pro_volume_rate __devinitdata = { +static const struct snd_kcontrol_new snd_ice1712_mixer_pro_volume_rate __devinitdata = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Multi Track Volume Rate", .info = snd_ice1712_pro_volume_rate_info, @@ -2290,7 +2290,7 @@ static int snd_ice1712_pro_peak_get(struct snd_kcontrol *kcontrol, return 0; } -static struct snd_kcontrol_new snd_ice1712_mixer_pro_peak __devinitdata = { +static const struct snd_kcontrol_new snd_ice1712_mixer_pro_peak __devinitdata = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Multi Track Peak", .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, @@ -2305,7 +2305,7 @@ static struct snd_kcontrol_new snd_ice1712_mixer_pro_peak __devinitdata = { /* * list of available boards */ -static struct snd_ice1712_card_info *card_tables[] __devinitdata = { +static const struct snd_ice1712_card_info *card_tables[] __devinitdata = { snd_ice1712_hoontech_cards, snd_ice1712_delta_cards, snd_ice1712_ews_cards, @@ -2329,7 +2329,7 @@ static int __devinit snd_ice1712_read_eeprom(struct snd_ice1712 *ice, { int dev = 0xa0; /* EEPROM device address */ unsigned int i, size; - struct snd_ice1712_card_info **tbl, *c; + const struct snd_ice1712_card_info **tbl, *c; if (! modelname || ! *modelname) { ice->eeprom.subvendor = 0; @@ -2658,7 +2658,7 @@ static int __devinit snd_ice1712_create(struct snd_card *card, * */ -static struct snd_ice1712_card_info no_matched __devinitdata; +static const struct snd_ice1712_card_info no_matched __devinitdata; static int __devinit snd_ice1712_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) @@ -2667,7 +2667,7 @@ static int __devinit snd_ice1712_probe(struct pci_dev *pci, struct snd_card *card; struct snd_ice1712 *ice; int pcm_dev = 0, err; - struct snd_ice1712_card_info **tbl, *c; + const struct snd_ice1712_card_info **tbl, *c; if (dev >= SNDRV_CARDS) return -ENODEV; diff --git a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h index 064542bf3af..c3d9feaaf57 100644 --- a/sound/pci/ice1712/ice1712.h +++ b/sound/pci/ice1712/ice1712.h @@ -514,8 +514,8 @@ struct snd_ice1712_card_info { unsigned int mpu401_2_info_flags; const char *mpu401_1_name; const char *mpu401_2_name; - unsigned int eeprom_size; - unsigned char *eeprom_data; + const unsigned int eeprom_size; + const unsigned char *eeprom_data; }; diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index 4566c0f789a..1127ebdf5fe 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c @@ -87,7 +87,7 @@ MODULE_PARM_DESC(model, "Use the given board model."); /* Both VT1720 and VT1724 have the same PCI IDs */ -static struct pci_device_id snd_vt1724_ids[] = { +static const struct pci_device_id snd_vt1724_ids[] = { { PCI_VENDOR_ID_ICE, PCI_DEVICE_ID_VT1724, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { 0, } }; @@ -342,7 +342,7 @@ static int snd_vt1724_pcm_trigger(struct snd_pcm_substream *substream, int cmd) what = 0; snd_pcm_group_for_each(pos, substream) { - struct vt1724_pcm_reg *reg; + const struct vt1724_pcm_reg *reg; s = snd_pcm_group_substream_entry(pos); reg = s->runtime->private_data; what |= reg->start; @@ -606,7 +606,7 @@ static snd_pcm_uframes_t snd_vt1724_playback_pro_pointer(struct snd_pcm_substrea static int snd_vt1724_pcm_prepare(struct snd_pcm_substream *substream) { struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); - struct vt1724_pcm_reg *reg = substream->runtime->private_data; + const struct vt1724_pcm_reg *reg = substream->runtime->private_data; spin_lock_irq(&ice->reg_lock); outl(substream->runtime->dma_addr, ice->profi_port + reg->addr); @@ -621,7 +621,7 @@ static int snd_vt1724_pcm_prepare(struct snd_pcm_substream *substream) static snd_pcm_uframes_t snd_vt1724_pcm_pointer(struct snd_pcm_substream *substream) { struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); - struct vt1724_pcm_reg *reg = substream->runtime->private_data; + const struct vt1724_pcm_reg *reg = substream->runtime->private_data; size_t ptr; if (!(inl(ICEMT1724(ice, DMA_CONTROL)) & reg->start)) @@ -647,21 +647,21 @@ static snd_pcm_uframes_t snd_vt1724_pcm_pointer(struct snd_pcm_substream *substr #endif } -static struct vt1724_pcm_reg vt1724_playback_pro_reg = { +static const struct vt1724_pcm_reg vt1724_playback_pro_reg = { .addr = VT1724_MT_PLAYBACK_ADDR, .size = VT1724_MT_PLAYBACK_SIZE, .count = VT1724_MT_PLAYBACK_COUNT, .start = VT1724_PDMA0_START, }; -static struct vt1724_pcm_reg vt1724_capture_pro_reg = { +static const struct vt1724_pcm_reg vt1724_capture_pro_reg = { .addr = VT1724_MT_CAPTURE_ADDR, .size = VT1724_MT_CAPTURE_SIZE, .count = VT1724_MT_CAPTURE_COUNT, .start = VT1724_RDMA0_START, }; -static struct snd_pcm_hardware snd_vt1724_playback_pro = +static const struct snd_pcm_hardware snd_vt1724_playback_pro = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | @@ -680,7 +680,7 @@ static struct snd_pcm_hardware snd_vt1724_playback_pro = .periods_max = 1024, }; -static struct snd_pcm_hardware snd_vt1724_spdif = +static const struct snd_pcm_hardware snd_vt1724_spdif = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | @@ -702,7 +702,7 @@ static struct snd_pcm_hardware snd_vt1724_spdif = .periods_max = 1024, }; -static struct snd_pcm_hardware snd_vt1724_2ch_stereo = +static const struct snd_pcm_hardware snd_vt1724_2ch_stereo = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | @@ -774,7 +774,7 @@ static int snd_vt1724_playback_pro_open(struct snd_pcm_substream *substream) struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); int chs; - runtime->private_data = &vt1724_playback_pro_reg; + runtime->private_data = (void *)&vt1724_playback_pro_reg; ice->playback_pro_substream = substream; runtime->hw = snd_vt1724_playback_pro; snd_pcm_set_sync(substream); @@ -803,7 +803,7 @@ static int snd_vt1724_capture_pro_open(struct snd_pcm_substream *substream) struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; - runtime->private_data = &vt1724_capture_pro_reg; + runtime->private_data = (void *)&vt1724_capture_pro_reg; ice->capture_pro_substream = substream; runtime->hw = snd_vt1724_2ch_stereo; snd_pcm_set_sync(substream); @@ -889,14 +889,14 @@ static int __devinit snd_vt1724_pcm_profi(struct snd_ice1712 * ice, int device) * SPDIF PCM */ -static struct vt1724_pcm_reg vt1724_playback_spdif_reg = { +static const struct vt1724_pcm_reg vt1724_playback_spdif_reg = { .addr = VT1724_MT_PDMA4_ADDR, .size = VT1724_MT_PDMA4_SIZE, .count = VT1724_MT_PDMA4_COUNT, .start = VT1724_PDMA4_START, }; -static struct vt1724_pcm_reg vt1724_capture_spdif_reg = { +static const struct vt1724_pcm_reg vt1724_capture_spdif_reg = { .addr = VT1724_MT_RDMA1_ADDR, .size = VT1724_MT_RDMA1_SIZE, .count = VT1724_MT_RDMA1_COUNT, @@ -954,7 +954,7 @@ static int snd_vt1724_playback_spdif_open(struct snd_pcm_substream *substream) struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; - runtime->private_data = &vt1724_playback_spdif_reg; + runtime->private_data = (void *)&vt1724_playback_spdif_reg; ice->playback_con_substream = substream; if (ice->force_pdma4) { runtime->hw = snd_vt1724_2ch_stereo; @@ -986,7 +986,7 @@ static int snd_vt1724_capture_spdif_open(struct snd_pcm_substream *substream) struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; - runtime->private_data = &vt1724_capture_spdif_reg; + runtime->private_data = (void *)&vt1724_capture_spdif_reg; ice->capture_con_substream = substream; if (ice->force_rdma1) { runtime->hw = snd_vt1724_2ch_stereo; @@ -1091,7 +1091,7 @@ static int __devinit snd_vt1724_pcm_spdif(struct snd_ice1712 * ice, int device) * independent surround PCMs */ -static struct vt1724_pcm_reg vt1724_playback_dma_regs[3] = { +static const struct vt1724_pcm_reg vt1724_playback_dma_regs[3] = { { .addr = VT1724_MT_PDMA1_ADDR, .size = VT1724_MT_PDMA1_SIZE, @@ -1137,7 +1137,7 @@ static int snd_vt1724_playback_indep_open(struct snd_pcm_substream *substream) return -EBUSY; /* FIXME: should handle blocking mode properly */ } mutex_unlock(&ice->open_mutex); - runtime->private_data = &vt1724_playback_dma_regs[substream->number]; + runtime->private_data = (void *)&vt1724_playback_dma_regs[substream->number]; ice->playback_con_substream_ds[substream->number] = substream; runtime->hw = snd_vt1724_2ch_stereo; snd_pcm_set_sync(substream); @@ -1318,7 +1318,7 @@ static int snd_vt1724_eeprom_get(struct snd_kcontrol *kcontrol, return 0; } -static struct snd_kcontrol_new snd_vt1724_eeprom __devinitdata = { +static const struct snd_kcontrol_new snd_vt1724_eeprom __devinitdata = { .iface = SNDRV_CTL_ELEM_IFACE_CARD, .name = "ICE1724 EEPROM", .access = SNDRV_CTL_ELEM_ACCESS_READ, @@ -1431,7 +1431,7 @@ static int snd_vt1724_spdif_default_put(struct snd_kcontrol *kcontrol, return (val != old); } -static struct snd_kcontrol_new snd_vt1724_spdif_default __devinitdata = +static const struct snd_kcontrol_new snd_vt1724_spdif_default __devinitdata = { .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), @@ -1463,7 +1463,7 @@ static int snd_vt1724_spdif_maskp_get(struct snd_kcontrol *kcontrol, return 0; } -static struct snd_kcontrol_new snd_vt1724_spdif_maskc __devinitdata = +static const struct snd_kcontrol_new snd_vt1724_spdif_maskc __devinitdata = { .access = SNDRV_CTL_ELEM_ACCESS_READ, .iface = SNDRV_CTL_ELEM_IFACE_PCM, @@ -1472,7 +1472,7 @@ static struct snd_kcontrol_new snd_vt1724_spdif_maskc __devinitdata = .get = snd_vt1724_spdif_maskc_get, }; -static struct snd_kcontrol_new snd_vt1724_spdif_maskp __devinitdata = +static const struct snd_kcontrol_new snd_vt1724_spdif_maskp __devinitdata = { .access = SNDRV_CTL_ELEM_ACCESS_READ, .iface = SNDRV_CTL_ELEM_IFACE_PCM, @@ -1517,7 +1517,7 @@ static int snd_vt1724_spdif_sw_put(struct snd_kcontrol *kcontrol, return old != val; } -static struct snd_kcontrol_new snd_vt1724_spdif_switch __devinitdata = +static const struct snd_kcontrol_new snd_vt1724_spdif_switch __devinitdata = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* FIXME: the following conflict with IEC958 Playback Route */ @@ -1585,7 +1585,7 @@ int snd_ice1712_gpio_put(struct snd_kcontrol *kcontrol, static int snd_vt1724_pro_internal_clock_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts_1724[] = { + static const char * const texts_1724[] = { "8000", /* 0: 6 */ "9600", /* 1: 3 */ "11025", /* 2: 10 */ @@ -1603,7 +1603,7 @@ static int snd_vt1724_pro_internal_clock_info(struct snd_kcontrol *kcontrol, "192000", /* 14: 14 */ "IEC958 Input", /* 15: -- */ }; - static char *texts_1720[] = { + static const char * const texts_1720[] = { "8000", /* 0: 6 */ "9600", /* 1: 3 */ "11025", /* 2: 10 */ @@ -1636,7 +1636,7 @@ static int snd_vt1724_pro_internal_clock_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); - static unsigned char xlate[16] = { + static const unsigned char xlate[16] = { 9, 6, 3, 1, 7, 4, 0, 12, 8, 5, 2, 11, 13, 255, 14, 10 }; unsigned char val; @@ -1695,7 +1695,7 @@ static int snd_vt1724_pro_internal_clock_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_vt1724_pro_internal_clock __devinitdata = { +static const struct snd_kcontrol_new snd_vt1724_pro_internal_clock __devinitdata = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Multi Track Internal Clock", .info = snd_vt1724_pro_internal_clock_info, @@ -1734,7 +1734,7 @@ static int snd_vt1724_pro_rate_locking_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_vt1724_pro_rate_locking __devinitdata = { +static const struct snd_kcontrol_new snd_vt1724_pro_rate_locking __devinitdata = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Multi Track Rate Locking", .info = snd_vt1724_pro_rate_locking_info, @@ -1773,7 +1773,7 @@ static int snd_vt1724_pro_rate_reset_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_vt1724_pro_rate_reset __devinitdata = { +static const struct snd_kcontrol_new snd_vt1724_pro_rate_reset __devinitdata = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Multi Track Rate Reset", .info = snd_vt1724_pro_rate_reset_info, @@ -1817,7 +1817,7 @@ static int get_route_val(struct snd_ice1712 *ice, int shift) { unsigned long val; unsigned char eitem; - static unsigned char xlate[8] = { + static const unsigned char xlate[8] = { 0, 255, 1, 2, 255, 255, 3, 4, }; @@ -1836,7 +1836,7 @@ static int put_route_val(struct snd_ice1712 *ice, unsigned int val, int shift) { unsigned int old_val, nval; int change; - static unsigned char xroute[8] = { + static const unsigned char xroute[8] = { 0, /* PCM */ 2, /* PSDIN0 Left */ 3, /* PSDIN0 Right */ @@ -1892,7 +1892,7 @@ static int snd_vt1724_pro_route_spdif_put(struct snd_kcontrol *kcontrol, digital_route_shift(idx)); } -static struct snd_kcontrol_new snd_vt1724_mixer_pro_analog_route __devinitdata = { +static const struct snd_kcontrol_new snd_vt1724_mixer_pro_analog_route __devinitdata = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "H/W Playback Route", .info = snd_vt1724_pro_route_info, @@ -1900,7 +1900,7 @@ static struct snd_kcontrol_new snd_vt1724_mixer_pro_analog_route __devinitdata = .put = snd_vt1724_pro_route_analog_put, }; -static struct snd_kcontrol_new snd_vt1724_mixer_pro_spdif_route __devinitdata = { +static const struct snd_kcontrol_new snd_vt1724_mixer_pro_spdif_route __devinitdata = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Route", .info = snd_vt1724_pro_route_info, @@ -1936,7 +1936,7 @@ static int snd_vt1724_pro_peak_get(struct snd_kcontrol *kcontrol, return 0; } -static struct snd_kcontrol_new snd_vt1724_mixer_pro_peak __devinitdata = { +static const struct snd_kcontrol_new snd_vt1724_mixer_pro_peak __devinitdata = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Multi Track Peak", .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, @@ -1948,9 +1948,9 @@ static struct snd_kcontrol_new snd_vt1724_mixer_pro_peak __devinitdata = { * */ -static struct snd_ice1712_card_info no_matched __devinitdata; +static const struct snd_ice1712_card_info no_matched __devinitdata; -static struct snd_ice1712_card_info *card_tables[] __devinitdata = { +static const struct snd_ice1712_card_info *card_tables[] __devinitdata = { snd_vt1724_revo_cards, snd_vt1724_amp_cards, snd_vt1724_aureon_cards, @@ -2009,7 +2009,7 @@ static int __devinit snd_vt1724_read_eeprom(struct snd_ice1712 *ice, { const int dev = 0xa0; /* EEPROM device address */ unsigned int i, size; - struct snd_ice1712_card_info **tbl, *c; + const struct snd_ice1712_card_info **tbl, *c; if (! modelname || ! *modelname) { ice->eeprom.subvendor = 0; @@ -2308,7 +2308,7 @@ static int __devinit snd_vt1724_probe(struct pci_dev *pci, struct snd_card *card; struct snd_ice1712 *ice; int pcm_dev = 0, err; - struct snd_ice1712_card_info **tbl, *c; + const struct snd_ice1712_card_info **tbl, *c; if (dev >= SNDRV_CARDS) return -ENODEV; diff --git a/sound/pci/ice1712/juli.c b/sound/pci/ice1712/juli.c index a7e779b7142..4854eaf63a8 100644 --- a/sound/pci/ice1712/juli.c +++ b/sound/pci/ice1712/juli.c @@ -125,7 +125,7 @@ static void juli_akm_set_rate_val(struct snd_akm4xxx *ak, unsigned int rate) snd_akm4xxx_reset(ak, 0); } -static struct snd_akm4xxx akm_juli_dac __devinitdata = { +static const struct snd_akm4xxx akm_juli_dac __devinitdata = { .type = SND_AK4358, .num_dacs = 2, .ops = { @@ -206,7 +206,7 @@ static int __devinit juli_init(struct snd_ice1712 *ice) * hence the driver needs to sets up it properly. */ -static unsigned char juli_eeprom[] __devinitdata = { +static const unsigned char juli_eeprom[] __devinitdata = { [ICE_EEP2_SYSCONF] = 0x20, /* clock 512, mpu401, 1xADC, 1xDACs */ [ICE_EEP2_ACLINK] = 0x80, /* I2S */ [ICE_EEP2_I2S] = 0xf8, /* vol, 96k, 24bit, 192k */ @@ -223,7 +223,7 @@ static unsigned char juli_eeprom[] __devinitdata = { }; /* entry point */ -struct snd_ice1712_card_info snd_vt1724_juli_cards[] __devinitdata = { +const struct snd_ice1712_card_info snd_vt1724_juli_cards[] __devinitdata = { { .subvendor = VT1724_SUBDEVICE_JULI, .name = "ESI Juli@", diff --git a/sound/pci/ice1712/juli.h b/sound/pci/ice1712/juli.h index d9f8534fd92..1b9294f8bce 100644 --- a/sound/pci/ice1712/juli.h +++ b/sound/pci/ice1712/juli.h @@ -5,6 +5,6 @@ #define VT1724_SUBDEVICE_JULI 0x31305345 /* Juli@ */ -extern struct snd_ice1712_card_info snd_vt1724_juli_cards[]; +extern const struct snd_ice1712_card_info snd_vt1724_juli_cards[]; #endif /* __SOUND_JULI_H */ diff --git a/sound/pci/ice1712/phase.c b/sound/pci/ice1712/phase.c index c7f6615d60d..2d97ac8a07d 100644 --- a/sound/pci/ice1712/phase.c +++ b/sound/pci/ice1712/phase.c @@ -71,7 +71,7 @@ * Logarithmic volume values for WM8770 * Computed as 20 * Log10(255 / x) */ -static unsigned char wm_vol[256] = { +static const unsigned char wm_vol[256] = { 127, 48, 42, 39, 36, 34, 33, 31, 30, 29, 28, 27, 27, 26, 25, 25, 24, 24, 23, 23, 22, 22, 21, 21, 21, 20, 20, 20, 19, 19, 19, 18, 18, 18, 18, 17, 17, 17, 17, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 13, 13, 13, @@ -89,13 +89,13 @@ static unsigned char wm_vol[256] = { #define WM_VOL_MAX (sizeof(wm_vol) - 1) #define WM_VOL_MUTE 0x8000 -static struct snd_akm4xxx akm_phase22 __devinitdata = { +static const struct snd_akm4xxx akm_phase22 __devinitdata = { .type = SND_AK4524, .num_dacs = 2, .num_adcs = 2, }; -static struct snd_ak4xxx_private akm_phase22_priv __devinitdata = { +static const struct snd_ak4xxx_private akm_phase22_priv __devinitdata = { .caddr = 2, .cif = 1, .data_mask = 1 << 4, @@ -152,7 +152,7 @@ static int __devinit phase22_add_controls(struct snd_ice1712 *ice) return 0; } -static unsigned char phase22_eeprom[] __devinitdata = { +static const unsigned char phase22_eeprom[] __devinitdata = { [ICE_EEP2_SYSCONF] = 0x00, /* 1xADC, 1xDACs */ [ICE_EEP2_ACLINK] = 0x80, /* I2S */ [ICE_EEP2_I2S] = 0xf8, /* vol, 96k, 24bit */ @@ -168,7 +168,7 @@ static unsigned char phase22_eeprom[] __devinitdata = { [ICE_EEP2_GPIO_STATE2] = 0x00, }; -static unsigned char phase28_eeprom[] __devinitdata = { +static const unsigned char phase28_eeprom[] __devinitdata = { [ICE_EEP2_SYSCONF] = 0x0b, /* clock 512, spdif-in/ADC, 4DACs */ [ICE_EEP2_ACLINK] = 0x80, /* I2S */ [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */ @@ -343,7 +343,7 @@ static int wm_master_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_ static int __devinit phase28_init(struct snd_ice1712 *ice) { - static unsigned short wm_inits_phase28[] = { + static const unsigned short wm_inits_phase28[] = { /* These come first to reduce init pop noise */ 0x1b, 0x044, /* ADC Mux (AC'97 source) */ 0x1c, 0x00B, /* Out Mux1 (VOUT1 = DAC+AUX, VOUT2 = DAC) */ @@ -382,7 +382,7 @@ static int __devinit phase28_init(struct snd_ice1712 *ice) unsigned int tmp; struct snd_akm4xxx *ak; - unsigned short *p; + const unsigned short *p; int i; ice->num_total_dacs = 8; @@ -700,7 +700,7 @@ static int phase28_oversampling_put(struct snd_kcontrol *kcontrol, struct snd_ct static DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1); static DECLARE_TLV_DB_SCALE(db_scale_wm_pcm, -6400, 50, 1); -static struct snd_kcontrol_new phase28_dac_controls[] __devinitdata = { +static const struct snd_kcontrol_new phase28_dac_controls[] __devinitdata = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", @@ -815,7 +815,7 @@ static struct snd_kcontrol_new phase28_dac_controls[] __devinitdata = { } }; -static struct snd_kcontrol_new wm_controls[] __devinitdata = { +static const struct snd_kcontrol_new wm_controls[] __devinitdata = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PCM Playback Switch", @@ -870,7 +870,7 @@ static int __devinit phase28_add_controls(struct snd_ice1712 *ice) return 0; } -struct snd_ice1712_card_info snd_vt1724_phase_cards[] __devinitdata = { +const struct snd_ice1712_card_info snd_vt1724_phase_cards[] __devinitdata = { { .subvendor = VT1724_SUBDEVICE_PHASE22, .name = "Terratec PHASE 22", diff --git a/sound/pci/ice1712/phase.h b/sound/pci/ice1712/phase.h index 13e841b5548..ad379a99bf9 100644 --- a/sound/pci/ice1712/phase.h +++ b/sound/pci/ice1712/phase.h @@ -31,7 +31,7 @@ #define VT1724_SUBDEVICE_PHASE28 0x3b154911 /* entry point */ -extern struct snd_ice1712_card_info snd_vt1724_phase_cards[]; +extern const struct snd_ice1712_card_info snd_vt1724_phase_cards[]; /* PHASE28 GPIO bits */ #define PHASE28_SPI_MISO (1 << 21) diff --git a/sound/pci/ice1712/pontis.c b/sound/pci/ice1712/pontis.c index b135c1401dc..4c35ddecb8e 100644 --- a/sound/pci/ice1712/pontis.c +++ b/sound/pci/ice1712/pontis.c @@ -434,7 +434,7 @@ static unsigned int spi_read(struct snd_ice1712 *ice, unsigned int dev, unsigned */ static int cs_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { + static const char * const texts[] = { "Coax", /* RXP0 */ "Optical", /* RXP1 */ "CD", /* RXP2 */ @@ -571,7 +571,7 @@ static DECLARE_TLV_DB_SCALE(db_scale_volume, -6400, 50, 1); * mixers */ -static struct snd_kcontrol_new pontis_controls[] __devinitdata = { +static const struct snd_kcontrol_new pontis_controls[] __devinitdata = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | @@ -741,7 +741,7 @@ static int __devinit pontis_add_controls(struct snd_ice1712 *ice) */ static int __devinit pontis_init(struct snd_ice1712 *ice) { - static unsigned short wm_inits[] = { + static const unsigned short wm_inits[] = { /* These come first to reduce init pop noise */ WM_ADC_MUX, 0x00c0, /* ADC mute */ WM_DAC_MUTE, 0x0001, /* DAC softmute */ @@ -750,7 +750,7 @@ static int __devinit pontis_init(struct snd_ice1712 *ice) WM_POWERDOWN, 0x0008, /* All power-up except HP */ WM_RESET, 0x0000, /* reset */ }; - static unsigned short wm_inits2[] = { + static const unsigned short wm_inits2[] = { WM_MASTER_CTRL, 0x0022, /* 256fs, slave mode */ WM_DAC_INT, 0x0022, /* I2S, normal polarity, 24bit */ WM_ADC_INT, 0x0022, /* I2S, normal polarity, 24bit */ @@ -776,7 +776,7 @@ static int __devinit pontis_init(struct snd_ice1712 *ice) WM_DAC_MUTE, 0x0000, /* DAC unmute */ WM_ADC_MUX, 0x0003, /* ADC unmute, both CD/Line On */ }; - static unsigned char cs_inits[] = { + static const unsigned char cs_inits[] = { 0x04, 0x80, /* RUN, RXP0 */ 0x05, 0x05, /* slave, 24bit */ 0x01, 0x00, @@ -826,7 +826,7 @@ static int __devinit pontis_init(struct snd_ice1712 *ice) * hence the driver needs to sets up it properly. */ -static unsigned char pontis_eeprom[] __devinitdata = { +static const unsigned char pontis_eeprom[] __devinitdata = { [ICE_EEP2_SYSCONF] = 0x08, /* clock 256, mpu401, spdif-in/ADC, 1DAC */ [ICE_EEP2_ACLINK] = 0x80, /* I2S */ [ICE_EEP2_I2S] = 0xf8, /* vol, 96k, 24bit, 192k */ @@ -843,7 +843,7 @@ static unsigned char pontis_eeprom[] __devinitdata = { }; /* entry point */ -struct snd_ice1712_card_info snd_vt1720_pontis_cards[] __devinitdata = { +const struct snd_ice1712_card_info snd_vt1720_pontis_cards[] __devinitdata = { { .subvendor = VT1720_SUBDEVICE_PONTIS_MS300, .name = "Pontis MS300", diff --git a/sound/pci/ice1712/pontis.h b/sound/pci/ice1712/pontis.h index d0d1378b935..1a418255c19 100644 --- a/sound/pci/ice1712/pontis.h +++ b/sound/pci/ice1712/pontis.h @@ -28,6 +28,6 @@ #define VT1720_SUBDEVICE_PONTIS_MS300 0x00020002 /* a dummy id for MS300 */ -extern struct snd_ice1712_card_info snd_vt1720_pontis_cards[]; +extern const struct snd_ice1712_card_info snd_vt1720_pontis_cards[]; #endif /* __SOUND_PONTIS_H */ diff --git a/sound/pci/ice1712/prodigy192.c b/sound/pci/ice1712/prodigy192.c index b9b63179dbe..d551e71c67c 100644 --- a/sound/pci/ice1712/prodigy192.c +++ b/sound/pci/ice1712/prodigy192.c @@ -364,7 +364,7 @@ static DECLARE_TLV_DB_SCALE(db_scale_adc, 0, 150, 0); * mixers */ -static struct snd_kcontrol_new stac_controls[] __devinitdata = { +static const struct snd_kcontrol_new stac_controls[] __devinitdata = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", @@ -475,7 +475,7 @@ static int __devinit prodigy192_add_controls(struct snd_ice1712 *ice) */ static int __devinit prodigy192_init(struct snd_ice1712 *ice) { - static unsigned short stac_inits_prodigy[] = { + static const unsigned short stac_inits_prodigy[] = { STAC946X_RESET, 0, /* STAC946X_MASTER_VOLUME, 0, STAC946X_LF_VOLUME, 0, @@ -486,7 +486,7 @@ static int __devinit prodigy192_init(struct snd_ice1712 *ice) STAC946X_LFE_VOLUME, 0,*/ (unsigned short)-1 }; - unsigned short *p; + const unsigned short *p; /* prodigy 192 */ ice->num_total_dacs = 6; @@ -506,7 +506,7 @@ static int __devinit prodigy192_init(struct snd_ice1712 *ice) * hence the driver needs to sets up it properly. */ -static unsigned char prodigy71_eeprom[] __devinitdata = { +static const unsigned char prodigy71_eeprom[] __devinitdata = { [ICE_EEP2_SYSCONF] = 0x2b, /* clock 512, mpu401, spdif-in/ADC, 4DACs */ [ICE_EEP2_ACLINK] = 0x80, /* I2S */ [ICE_EEP2_I2S] = 0xf8, /* vol, 96k, 24bit, 192k */ @@ -524,7 +524,7 @@ static unsigned char prodigy71_eeprom[] __devinitdata = { /* entry point */ -struct snd_ice1712_card_info snd_vt1724_prodigy192_cards[] __devinitdata = { +const struct snd_ice1712_card_info snd_vt1724_prodigy192_cards[] __devinitdata = { { .subvendor = VT1724_SUBDEVICE_PRODIGY192VE, .name = "Audiotrak Prodigy 192", diff --git a/sound/pci/ice1712/prodigy192.h b/sound/pci/ice1712/prodigy192.h index 94c824e24e0..2fa2e62b9e0 100644 --- a/sound/pci/ice1712/prodigy192.h +++ b/sound/pci/ice1712/prodigy192.h @@ -6,6 +6,6 @@ #define VT1724_SUBDEVICE_PRODIGY192VE 0x34495345 /* PRODIGY 192 VE */ -extern struct snd_ice1712_card_info snd_vt1724_prodigy192_cards[]; +extern const struct snd_ice1712_card_info snd_vt1724_prodigy192_cards[]; #endif /* __SOUND_PRODIGY192_H */ diff --git a/sound/pci/ice1712/revo.c b/sound/pci/ice1712/revo.c index 0e578aa38af..7d3bccbf031 100644 --- a/sound/pci/ice1712/revo.c +++ b/sound/pci/ice1712/revo.c @@ -228,7 +228,7 @@ static struct snd_akm4xxx akm_revo_front __devinitdata = { .dac_info = revo71_front, }; -static struct snd_ak4xxx_private akm_revo_front_priv __devinitdata = { +static const struct snd_ak4xxx_private akm_revo_front_priv __devinitdata = { .caddr = 1, .cif = 0, .data_mask = VT1724_REVO_CDOUT, @@ -240,7 +240,7 @@ static struct snd_ak4xxx_private akm_revo_front_priv __devinitdata = { .mask_flags = 0, }; -static struct snd_akm4xxx akm_revo_surround __devinitdata = { +static const struct snd_akm4xxx akm_revo_surround __devinitdata = { .type = SND_AK4355, .idx_offset = 1, .num_dacs = 6, @@ -250,7 +250,7 @@ static struct snd_akm4xxx akm_revo_surround __devinitdata = { .dac_info = revo71_surround, }; -static struct snd_ak4xxx_private akm_revo_surround_priv __devinitdata = { +static const struct snd_ak4xxx_private akm_revo_surround_priv __devinitdata = { .caddr = 3, .cif = 0, .data_mask = VT1724_REVO_CDOUT, @@ -262,7 +262,7 @@ static struct snd_ak4xxx_private akm_revo_surround_priv __devinitdata = { .mask_flags = 0, }; -static struct snd_akm4xxx akm_revo51 __devinitdata = { +static const struct snd_akm4xxx akm_revo51 __devinitdata = { .type = SND_AK4358, .num_dacs = 6, .ops = { @@ -271,7 +271,7 @@ static struct snd_akm4xxx akm_revo51 __devinitdata = { .dac_info = revo51_dac, }; -static struct snd_ak4xxx_private akm_revo51_priv __devinitdata = { +static const struct snd_ak4xxx_private akm_revo51_priv __devinitdata = { .caddr = 2, .cif = 0, .data_mask = VT1724_REVO_CDOUT, @@ -283,13 +283,13 @@ static struct snd_ak4xxx_private akm_revo51_priv __devinitdata = { .mask_flags = 0, }; -static struct snd_akm4xxx akm_revo51_adc __devinitdata = { +static const struct snd_akm4xxx akm_revo51_adc __devinitdata = { .type = SND_AK5365, .num_adcs = 2, .adc_info = revo51_adc, }; -static struct snd_ak4xxx_private akm_revo51_adc_priv __devinitdata = { +static const struct snd_ak4xxx_private akm_revo51_adc_priv __devinitdata = { .caddr = 2, .cif = 0, .data_mask = VT1724_REVO_CDOUT, @@ -333,7 +333,7 @@ static struct snd_akm4xxx akm_ap192 __devinitdata = { .dac_info = ap192_dac, }; -static struct snd_ak4xxx_private akm_ap192_priv __devinitdata = { +static const struct snd_ak4xxx_private akm_ap192_priv __devinitdata = { .caddr = 2, .cif = 0, .data_mask = VT1724_REVO_CDOUT, @@ -456,7 +456,7 @@ static unsigned char ap192_ak4114_read(void *private_data, unsigned char addr) static int ap192_ak4114_init(struct snd_ice1712 *ice) { - static unsigned char ak4114_init_vals[] = { + static const unsigned char ak4114_init_vals[] = { AK4114_RST | AK4114_PWN | AK4114_OCKS0 | AK4114_OCKS1, AK4114_DIF_I24I2S, AK4114_TX1E, @@ -464,7 +464,7 @@ static int ap192_ak4114_init(struct snd_ice1712 *ice) 0, 0 }; - static unsigned char ak4114_init_txcsb[] = { + static const unsigned char ak4114_init_txcsb[] = { 0x41, 0x02, 0x2c, 0x00, 0x00 }; struct ak4114 *ak; @@ -582,7 +582,7 @@ static int __devinit revo_add_controls(struct snd_ice1712 *ice) } /* entry point */ -struct snd_ice1712_card_info snd_vt1724_revo_cards[] __devinitdata = { +const struct snd_ice1712_card_info snd_vt1724_revo_cards[] __devinitdata = { { .subvendor = VT1724_SUBDEVICE_REVOLUTION71, .name = "M Audio Revolution-7.1", diff --git a/sound/pci/ice1712/revo.h b/sound/pci/ice1712/revo.h index a3ba425911c..2a24488fad8 100644 --- a/sound/pci/ice1712/revo.h +++ b/sound/pci/ice1712/revo.h @@ -34,7 +34,7 @@ #define VT1724_SUBDEVICE_AUDIOPHILE192 0x12143236 /* entry point */ -extern struct snd_ice1712_card_info snd_vt1724_revo_cards[]; +extern const struct snd_ice1712_card_info snd_vt1724_revo_cards[]; /* diff --git a/sound/pci/ice1712/vt1720_mobo.c b/sound/pci/ice1712/vt1720_mobo.c index 239524158fe..72b060d63c2 100644 --- a/sound/pci/ice1712/vt1720_mobo.c +++ b/sound/pci/ice1712/vt1720_mobo.c @@ -56,7 +56,7 @@ static int __devinit k8x800_add_controls(struct snd_ice1712 *ice) /* EEPROM image */ -static unsigned char k8x800_eeprom[] __devinitdata = { +static const unsigned char k8x800_eeprom[] __devinitdata = { [ICE_EEP2_SYSCONF] = 0x01, /* clock 256, 1ADC, 2DACs */ [ICE_EEP2_ACLINK] = 0x02, /* ACLINK, packed */ [ICE_EEP2_I2S] = 0x00, /* - */ @@ -72,7 +72,7 @@ static unsigned char k8x800_eeprom[] __devinitdata = { [ICE_EEP2_GPIO_STATE2] = 0x00, /* - */ }; -static unsigned char sn25p_eeprom[] __devinitdata = { +static const unsigned char sn25p_eeprom[] __devinitdata = { [ICE_EEP2_SYSCONF] = 0x01, /* clock 256, 1ADC, 2DACs */ [ICE_EEP2_ACLINK] = 0x02, /* ACLINK, packed */ [ICE_EEP2_I2S] = 0x00, /* - */ @@ -90,7 +90,7 @@ static unsigned char sn25p_eeprom[] __devinitdata = { /* entry point */ -struct snd_ice1712_card_info snd_vt1720_mobo_cards[] __devinitdata = { +const struct snd_ice1712_card_info snd_vt1720_mobo_cards[] __devinitdata = { { .subvendor = VT1720_SUBDEVICE_K8X800, .name = "Albatron K8X800 Pro II", diff --git a/sound/pci/ice1712/vt1720_mobo.h b/sound/pci/ice1712/vt1720_mobo.h index 0b1b0ee1bea..70af3ad64a5 100644 --- a/sound/pci/ice1712/vt1720_mobo.h +++ b/sound/pci/ice1712/vt1720_mobo.h @@ -36,6 +36,6 @@ #define VT1720_SUBDEVICE_9CJS 0x0f272327 #define VT1720_SUBDEVICE_SN25P 0x97123650 -extern struct snd_ice1712_card_info snd_vt1720_mobo_cards[]; +extern const struct snd_ice1712_card_info snd_vt1720_mobo_cards[]; #endif /* __SOUND_VT1720_MOBO_H */ diff --git a/sound/pci/ice1712/wtm.c b/sound/pci/ice1712/wtm.c index 04e535c8542..4a706b16a0b 100644 --- a/sound/pci/ice1712/wtm.c +++ b/sound/pci/ice1712/wtm.c @@ -409,7 +409,7 @@ static int stac9460_mic_sw_put(struct snd_kcontrol *kcontrol, /* * Control tabs */ -static struct snd_kcontrol_new stac9640_controls[] __devinitdata = { +static const struct snd_kcontrol_new stac9640_controls[] __devinitdata = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", -- cgit v1.2.3 From 517400cbc75d0604bc34c1866dff7e55ca1be2b4 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 29 Jan 2007 15:27:56 +0100 Subject: [ALSA] Add some more 'const', but needs changes in i2c/other/ak4* Make data passed to ak4xxx_create 'const'. Signed-of-by: Philipp Matthias Hahn Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/i2c/other/ak4114.c | 2 +- sound/i2c/other/ak4117.c | 2 +- sound/i2c/other/ak4xxx-adda.c | 15 ++++++++------- sound/pci/ice1712/juli.c | 4 ++-- sound/pci/ice1712/revo.c | 14 +++++++------- 5 files changed, 19 insertions(+), 18 deletions(-) (limited to 'sound') diff --git a/sound/i2c/other/ak4114.c b/sound/i2c/other/ak4114.c index 69dcaf8ac79..34bbafc81cf 100644 --- a/sound/i2c/other/ak4114.c +++ b/sound/i2c/other/ak4114.c @@ -79,7 +79,7 @@ static int snd_ak4114_dev_free(struct snd_device *device) int snd_ak4114_create(struct snd_card *card, ak4114_read_t *read, ak4114_write_t *write, - unsigned char pgm[7], unsigned char txcsb[5], + const unsigned char pgm[7], const unsigned char txcsb[5], void *private_data, struct ak4114 **r_ak4114) { struct ak4114 *chip; diff --git a/sound/i2c/other/ak4117.c b/sound/i2c/other/ak4117.c index 4e45952dd95..c022f29da2f 100644 --- a/sound/i2c/other/ak4117.c +++ b/sound/i2c/other/ak4117.c @@ -74,7 +74,7 @@ static int snd_ak4117_dev_free(struct snd_device *device) } int snd_ak4117_create(struct snd_card *card, ak4117_read_t *read, ak4117_write_t *write, - unsigned char pgm[5], void *private_data, struct ak4117 **r_ak4117) + const unsigned char pgm[5], void *private_data, struct ak4117 **r_ak4117) { struct ak4117 *chip; int err = 0; diff --git a/sound/i2c/other/ak4xxx-adda.c b/sound/i2c/other/ak4xxx-adda.c index fe61b92f4e4..3d9d6c5d354 100644 --- a/sound/i2c/other/ak4xxx-adda.c +++ b/sound/i2c/other/ak4xxx-adda.c @@ -140,7 +140,7 @@ EXPORT_SYMBOL(snd_akm4xxx_reset); * Used for AK4524 input/ouput attenuation, AK4528, and * AK5365 input attenuation */ -static unsigned char vol_cvt_datt[128] = { +static const unsigned char vol_cvt_datt[128] = { 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x0a, @@ -184,7 +184,7 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak) 0x07, 0x00, /* 7: DAC right muted */ 0xff, 0xff }; - static unsigned char inits_ak4528[] = { + static const unsigned char inits_ak4528[] = { 0x00, 0x07, /* 0: all power up */ 0x01, 0x00, /* 1: ADC/DAC reset */ 0x02, 0x60, /* 2: 24bit I2S */ @@ -194,7 +194,7 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak) 0x05, 0x00, /* 5: ADC right muted */ 0xff, 0xff }; - static unsigned char inits_ak4529[] = { + static const unsigned char inits_ak4529[] = { 0x09, 0x01, /* 9: ATS=0, RSTN=1 */ 0x0a, 0x3f, /* A: all power up, no zero/overflow detection */ 0x00, 0x0c, /* 0: TDM=0, 24bit I2S, SMUTE=0 */ @@ -210,7 +210,7 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak) 0x08, 0x55, /* 8: deemphasis all off */ 0xff, 0xff }; - static unsigned char inits_ak4355[] = { + static const unsigned char inits_ak4355[] = { 0x01, 0x02, /* 1: reset and soft-mute */ 0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect, * disable DZF, sharp roll-off, RSTN#=0 */ @@ -227,7 +227,7 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak) 0x01, 0x01, /* 1: un-reset, unmute */ 0xff, 0xff }; - static unsigned char inits_ak4358[] = { + static const unsigned char inits_ak4358[] = { 0x01, 0x02, /* 1: reset and soft-mute */ 0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect, * disable DZF, sharp roll-off, RSTN#=0 */ @@ -246,7 +246,7 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak) 0x01, 0x01, /* 1: un-reset, unmute */ 0xff, 0xff }; - static unsigned char inits_ak4381[] = { + static const unsigned char inits_ak4381[] = { 0x00, 0x0c, /* 0: mode3(i2s), disable auto-clock detect */ 0x01, 0x02, /* 1: de-emphasis off, normal speed, * sharp roll-off, DZF off */ @@ -259,7 +259,8 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak) }; int chip, num_chips; - unsigned char *ptr, reg, data, *inits; + const unsigned char *ptr, *inits; + unsigned char reg, data; memset(ak->images, 0, sizeof(ak->images)); memset(ak->volumes, 0, sizeof(ak->volumes)); diff --git a/sound/pci/ice1712/juli.c b/sound/pci/ice1712/juli.c index 4854eaf63a8..d88172fa95d 100644 --- a/sound/pci/ice1712/juli.c +++ b/sound/pci/ice1712/juli.c @@ -146,7 +146,7 @@ static int __devinit juli_add_controls(struct snd_ice1712 *ice) */ static int __devinit juli_init(struct snd_ice1712 *ice) { - static unsigned char ak4114_init_vals[] = { + static const unsigned char ak4114_init_vals[] = { /* AK4117_REG_PWRDN */ AK4114_RST | AK4114_PWN | AK4114_OCKS0 | AK4114_OCKS1, /* AK4114_REQ_FORMAT */ AK4114_DIF_I24I2S, /* AK4114_REG_IO0 */ AK4114_TX1E, @@ -154,7 +154,7 @@ static int __devinit juli_init(struct snd_ice1712 *ice) /* AK4114_REG_INT0_MASK */ 0, /* AK4114_REG_INT1_MASK */ 0 }; - static unsigned char ak4114_init_txcsb[] = { + static const unsigned char ak4114_init_txcsb[] = { 0x41, 0x02, 0x2c, 0x00, 0x00 }; int err; diff --git a/sound/pci/ice1712/revo.c b/sound/pci/ice1712/revo.c index 7d3bccbf031..025a7e8497c 100644 --- a/sound/pci/ice1712/revo.c +++ b/sound/pci/ice1712/revo.c @@ -185,18 +185,18 @@ static int revo51_i2c_init(struct snd_ice1712 *ice, #define AK_DAC(xname,xch) { .name = xname, .num_channels = xch } -static struct snd_akm4xxx_dac_channel revo71_front[] = { +static const struct snd_akm4xxx_dac_channel revo71_front[] = { AK_DAC("PCM Playback Volume", 2) }; -static struct snd_akm4xxx_dac_channel revo71_surround[] = { +static const struct snd_akm4xxx_dac_channel revo71_surround[] = { AK_DAC("PCM Center Playback Volume", 1), AK_DAC("PCM LFE Playback Volume", 1), AK_DAC("PCM Side Playback Volume", 2), AK_DAC("PCM Rear Playback Volume", 2), }; -static struct snd_akm4xxx_dac_channel revo51_dac[] = { +static const struct snd_akm4xxx_dac_channel revo51_dac[] = { AK_DAC("PCM Playback Volume", 2), AK_DAC("PCM Center Playback Volume", 1), AK_DAC("PCM LFE Playback Volume", 1), @@ -210,7 +210,7 @@ static const char *revo51_adc_input_names[] = { NULL }; -static struct snd_akm4xxx_adc_channel revo51_adc[] = { +static const struct snd_akm4xxx_adc_channel revo51_adc[] = { { .name = "PCM Capture Volume", .switch_name = "PCM Capture Switch", @@ -219,7 +219,7 @@ static struct snd_akm4xxx_adc_channel revo51_adc[] = { }, }; -static struct snd_akm4xxx akm_revo_front __devinitdata = { +static const struct snd_akm4xxx akm_revo_front __devinitdata = { .type = SND_AK4381, .num_dacs = 2, .ops = { @@ -320,11 +320,11 @@ static void ap192_set_rate_val(struct snd_akm4xxx *ak, unsigned int rate) #endif } -static struct snd_akm4xxx_dac_channel ap192_dac[] = { +static const struct snd_akm4xxx_dac_channel ap192_dac[] = { AK_DAC("PCM Playback Volume", 2) }; -static struct snd_akm4xxx akm_ap192 __devinitdata = { +static const struct snd_akm4xxx akm_ap192 __devinitdata = { .type = SND_AK4358, .num_dacs = 2, .ops = { -- cgit v1.2.3 From 0cb29ea0d449d7c0ecc9649a08ab63476389701d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 29 Jan 2007 15:33:49 +0100 Subject: [ALSA] Add even more 'const' to everything related to TLV Mark TLV data as 'const' Signed-of-by: Philipp Matthias Hahn Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/drivers/dummy.c | 2 +- sound/drivers/vx/vx_mixer.c | 2 +- sound/i2c/other/ak4xxx-adda.c | 10 +++++----- sound/i2c/other/pt2258.c | 2 +- sound/isa/ad1816a/ad1816a_lib.c | 10 +++++----- sound/isa/ad1848/ad1848_lib.c | 6 +++--- sound/isa/opl3sa2.c | 4 ++-- sound/pci/ac97/ac97_codec.c | 16 ++++++++-------- sound/pci/ac97/ac97_patch.c | 6 +++--- sound/pci/ac97/ak4531_codec.c | 6 +++--- sound/pci/ca0106/ca0106_mixer.c | 4 ++-- sound/pci/cs4281.c | 2 +- sound/pci/echoaudio/echoaudio.c | 4 ++-- sound/pci/emu10k1/emufx.c | 4 ++-- sound/pci/emu10k1/emumixer.c | 2 +- sound/pci/emu10k1/p16v.c | 2 +- sound/pci/es1938.c | 2 +- sound/pci/fm801.c | 2 +- sound/pci/ice1712/aureon.c | 10 +++++----- sound/pci/ice1712/ice1712.c | 2 +- sound/pci/ice1712/phase.c | 4 ++-- sound/pci/ice1712/pontis.c | 2 +- sound/pci/ice1712/prodigy192.c | 4 ++-- sound/pci/mixart/mixart_mixer.c | 4 ++-- sound/pci/pcxhr/pcxhr_mixer.c | 6 +++--- sound/pci/trident/trident_main.c | 4 ++-- sound/pci/via82xx.c | 2 +- sound/pci/vx222/vx222.c | 4 ++-- sound/pci/vx222/vx222_ops.c | 2 +- sound/pci/ymfpci/ymfpci_main.c | 2 +- sound/pcmcia/vx/vxp_mixer.c | 2 +- sound/pcmcia/vx/vxpocket.c | 2 +- 32 files changed, 68 insertions(+), 68 deletions(-) (limited to 'sound') diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c index 42001efa9f3..8339bad969b 100644 --- a/sound/drivers/dummy.c +++ b/sound/drivers/dummy.c @@ -501,7 +501,7 @@ static int snd_dummy_volume_put(struct snd_kcontrol *kcontrol, return change; } -static DECLARE_TLV_DB_SCALE(db_scale_dummy, -4500, 30, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_dummy, -4500, 30, 0); #define DUMMY_CAPSRC(xname, xindex, addr) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ diff --git a/sound/drivers/vx/vx_mixer.c b/sound/drivers/vx/vx_mixer.c index 1613ed844ac..f63152a6a22 100644 --- a/sound/drivers/vx/vx_mixer.c +++ b/sound/drivers/vx/vx_mixer.c @@ -716,7 +716,7 @@ static int vx_monitor_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_ return 0; } -static DECLARE_TLV_DB_SCALE(db_scale_audio_gain, -10975, 25, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_audio_gain, -10975, 25, 0); static struct snd_kcontrol_new vx_control_audio_gain = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, diff --git a/sound/i2c/other/ak4xxx-adda.c b/sound/i2c/other/ak4xxx-adda.c index 3d9d6c5d354..8805110017a 100644 --- a/sound/i2c/other/ak4xxx-adda.c +++ b/sound/i2c/other/ak4xxx-adda.c @@ -162,17 +162,17 @@ static const unsigned char vol_cvt_datt[128] = { /* * dB tables */ -static DECLARE_TLV_DB_SCALE(db_scale_vol_datt, -6350, 50, 1); -static DECLARE_TLV_DB_SCALE(db_scale_8bit, -12750, 50, 1); -static DECLARE_TLV_DB_SCALE(db_scale_7bit, -6350, 50, 1); -static DECLARE_TLV_DB_LINEAR(db_scale_linear, TLV_DB_GAIN_MUTE, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_vol_datt, -6350, 50, 1); +static const DECLARE_TLV_DB_SCALE(db_scale_8bit, -12750, 50, 1); +static const DECLARE_TLV_DB_SCALE(db_scale_7bit, -6350, 50, 1); +static const DECLARE_TLV_DB_LINEAR(db_scale_linear, TLV_DB_GAIN_MUTE, 0); /* * initialize all the ak4xxx chips */ void snd_akm4xxx_init(struct snd_akm4xxx *ak) { - static unsigned char inits_ak4524[] = { + static const unsigned char inits_ak4524[] = { 0x00, 0x07, /* 0: all power up */ 0x01, 0x00, /* 1: ADC/DAC reset */ 0x02, 0x60, /* 2: 24bit I2S */ diff --git a/sound/i2c/other/pt2258.c b/sound/i2c/other/pt2258.c index 50df1df2f2b..e91cc3b44de 100644 --- a/sound/i2c/other/pt2258.c +++ b/sound/i2c/other/pt2258.c @@ -185,7 +185,7 @@ static int pt2258_switch_put(struct snd_kcontrol *kcontrol, return -EIO; } -static DECLARE_TLV_DB_SCALE(pt2258_db_scale, -7900, 100, 0); +static const DECLARE_TLV_DB_SCALE(pt2258_db_scale, -7900, 100, 0); int snd_pt2258_build_controls(struct snd_pt2258 *pt) { diff --git a/sound/isa/ad1816a/ad1816a_lib.c b/sound/isa/ad1816a/ad1816a_lib.c index b524e0d9ee4..ec9209cd517 100644 --- a/sound/isa/ad1816a/ad1816a_lib.c +++ b/sound/isa/ad1816a/ad1816a_lib.c @@ -906,11 +906,11 @@ static int snd_ad1816a_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_ return change; } -static DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0); -static DECLARE_TLV_DB_SCALE(db_scale_5bit, -4650, 150, 0); -static DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0); -static DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0); -static DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_5bit, -4650, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0); static struct snd_kcontrol_new snd_ad1816a_controls[] __devinitdata = { AD1816A_DOUBLE("Master Playback Switch", AD1816A_MASTER_ATT, 15, 7, 1, 1), diff --git a/sound/isa/ad1848/ad1848_lib.c b/sound/isa/ad1848/ad1848_lib.c index 666b3bcc19f..8094282c2ae 100644 --- a/sound/isa/ad1848/ad1848_lib.c +++ b/sound/isa/ad1848/ad1848_lib.c @@ -1223,9 +1223,9 @@ int snd_ad1848_add_ctl_elem(struct snd_ad1848 *chip, EXPORT_SYMBOL(snd_ad1848_add_ctl_elem); -static DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0); -static DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0); -static DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0); static struct ad1848_mix_elem snd_ad1848_controls[] = { AD1848_DOUBLE("PCM Playback Switch", 0, AD1848_LEFT_OUTPUT, AD1848_RIGHT_OUTPUT, 7, 7, 1, 1), diff --git a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c index 419b4ebbf00..1e30713d2ca 100644 --- a/sound/isa/opl3sa2.c +++ b/sound/isa/opl3sa2.c @@ -486,8 +486,8 @@ static int snd_opl3sa2_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_ return change; } -static DECLARE_TLV_DB_SCALE(db_scale_master, -3000, 200, 0); -static DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_master, -3000, 200, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0); static struct snd_kcontrol_new snd_opl3sa2_controls[] = { OPL3SA2_DOUBLE("Master Playback Switch", 0, 0x07, 0x08, 7, 7, 1, 1), diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index bd8cfdcfbdf..8b7853c14b5 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -1190,13 +1190,13 @@ static int snd_ac97_cmute_new_stereo(struct snd_card *card, char *name, int reg, /* * set dB information */ -static DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0); -static DECLARE_TLV_DB_SCALE(db_scale_5bit, -4650, 150, 0); -static DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0); -static DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0); -static DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_5bit, -4650, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0); -static unsigned int *find_db_scale(unsigned int maxval) +static const unsigned int *find_db_scale(unsigned int maxval) { switch (maxval) { case 0x0f: return db_scale_4bit; @@ -1206,8 +1206,8 @@ static unsigned int *find_db_scale(unsigned int maxval) return NULL; } -static void set_tlv_db_scale(struct snd_kcontrol *kctl, unsigned int *tlv) -{ +static void set_tlv_db_scale(struct snd_kcontrol *kctl, const unsigned int *tlv) +{ kctl->tlv.p = tlv; if (tlv) kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ; diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index f1950fa1f0e..641d0c8d659 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -54,7 +54,7 @@ static int patch_build_controls(struct snd_ac97 * ac97, const struct snd_kcontro /* replace with a new TLV */ static void reset_tlv(struct snd_ac97 *ac97, const char *name, - unsigned int *tlv) + const unsigned int *tlv) { struct snd_ctl_elem_id sid; struct snd_kcontrol *kctl; @@ -1569,7 +1569,7 @@ static const struct snd_kcontrol_new snd_ac97_controls_ad1885[] = { AC97_SINGLE("Line Jack Sense", AC97_AD_JACK_SPDIF, 8, 1, 1), /* inverted */ }; -static DECLARE_TLV_DB_SCALE(db_scale_6bit_6db_max, -8850, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_6bit_6db_max, -8850, 150, 0); static int patch_ad1885_specific(struct snd_ac97 * ac97) { @@ -2527,7 +2527,7 @@ static const struct snd_kcontrol_new snd_ac97_spdif_controls_alc650[] = { /* AC97_SINGLE("IEC958 Input Monitor", AC97_ALC650_MULTICH, 13, 1, 0), */ }; -static DECLARE_TLV_DB_SCALE(db_scale_5bit_3db_max, -4350, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_5bit_3db_max, -4350, 150, 0); static int patch_alc650_specific(struct snd_ac97 * ac97) { diff --git a/sound/pci/ac97/ak4531_codec.c b/sound/pci/ac97/ak4531_codec.c index c153cb79c51..dc26820a03a 100644 --- a/sound/pci/ac97/ak4531_codec.c +++ b/sound/pci/ac97/ak4531_codec.c @@ -267,9 +267,9 @@ static int snd_ak4531_put_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl return change; } -static DECLARE_TLV_DB_SCALE(db_scale_master, -6200, 200, 0); -static DECLARE_TLV_DB_SCALE(db_scale_mono, -2800, 400, 0); -static DECLARE_TLV_DB_SCALE(db_scale_input, -5000, 200, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_master, -6200, 200, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_mono, -2800, 400, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_input, -5000, 200, 0); static struct snd_kcontrol_new snd_ak4531_controls[] = { diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c index 289f78a4160..b913a1fb8c2 100644 --- a/sound/pci/ca0106/ca0106_mixer.c +++ b/sound/pci/ca0106/ca0106_mixer.c @@ -74,8 +74,8 @@ #include "ca0106.h" -static DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale1, -5175, 25, 1); -static DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale2, -10350, 50, 1); +static const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale1, -5175, 25, 1); +static const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale2, -10350, 50, 1); static int snd_ca0106_shared_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c index 8e5519de711..44cf5460764 100644 --- a/sound/pci/cs4281.c +++ b/sound/pci/cs4281.c @@ -1055,7 +1055,7 @@ static int snd_cs4281_put_volume(struct snd_kcontrol *kcontrol, return change; } -static DECLARE_TLV_DB_SCALE(db_scale_dsp, -4650, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_dsp, -4650, 150, 0); static struct snd_kcontrol_new snd_cs4281_fm_vol = { diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c index 3410bd4450a..6a428b81dba 100644 --- a/sound/pci/echoaudio/echoaudio.c +++ b/sound/pci/echoaudio/echoaudio.c @@ -34,7 +34,7 @@ module_param_array(enable, bool, NULL, 0444); MODULE_PARM_DESC(enable, "Enable " ECHOCARD_NAME " soundcard."); static unsigned int channels_list[10] = {1, 2, 4, 6, 8, 10, 12, 14, 16, 999999}; -static DECLARE_TLV_DB_SCALE(db_scale_output_gain, -12800, 100, 1); +static const DECLARE_TLV_DB_SCALE(db_scale_output_gain, -12800, 100, 1); static int get_firmware(const struct firmware **fw_entry, const struct firmware *frm, struct echoaudio *chip) @@ -1085,7 +1085,7 @@ static int snd_echo_input_gain_put(struct snd_kcontrol *kcontrol, return changed; } -static DECLARE_TLV_DB_SCALE(db_scale_input_gain, -2500, 50, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_input_gain, -2500, 50, 0); static struct snd_kcontrol_new snd_echo_line_input_gain __devinitdata = { .name = "Line Capture Volume", diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c index 7b173c49695..c02012cccd8 100644 --- a/sound/pci/emu10k1/emufx.c +++ b/sound/pci/emu10k1/emufx.c @@ -296,7 +296,7 @@ static const u32 db_table[101] = { }; /* EMU10k1/EMU10k2 DSP control db gain */ -static DECLARE_TLV_DB_SCALE(snd_emu10k1_db_scale1, -4000, 40, 1); +static const DECLARE_TLV_DB_SCALE(snd_emu10k1_db_scale1, -4000, 40, 1); static const u32 onoff_table[2] = { 0x00000000, 0x00000001 @@ -657,7 +657,7 @@ snd_emu10k1_look_for_ctl(struct snd_emu10k1 *emu, struct snd_ctl_elem_id *id) #define MAX_TLV_SIZE 256 -static unsigned int *copy_tlv(unsigned int __user *_tlv) +static unsigned int *copy_tlv(const unsigned int __user *_tlv) { unsigned int data[2]; unsigned int *tlv; diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index 0469546fc33..0981af842b7 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c @@ -42,7 +42,7 @@ #define AC97_ID_STAC9758 0x83847658 -static DECLARE_TLV_DB_SCALE(snd_audigy_db_scale2, -10350, 50, 1); /* WM8775 gain scale */ +static const DECLARE_TLV_DB_SCALE(snd_audigy_db_scale2, -10350, 50, 1); /* WM8775 gain scale */ static int snd_emu10k1_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c index 5da637c7339..465f8d50532 100644 --- a/sound/pci/emu10k1/p16v.c +++ b/sound/pci/emu10k1/p16v.c @@ -785,7 +785,7 @@ static int snd_p16v_capture_channel_put(struct snd_kcontrol *kcontrol, } return change; } -static DECLARE_TLV_DB_SCALE(snd_p16v_db_scale1, -5175, 25, 1); +static const DECLARE_TLV_DB_SCALE(snd_p16v_db_scale1, -5175, 25, 1); #define P16V_VOL(xname,xreg,xhl) { \ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c index 66ac26c5a24..fec29a10894 100644 --- a/sound/pci/es1938.c +++ b/sound/pci/es1938.c @@ -1344,7 +1344,7 @@ static unsigned int db_scale_line[] = { 8, 15, TLV_DB_SCALE_ITEM(-750, 150, 0), }; -static DECLARE_TLV_DB_SCALE(db_scale_capture, 0, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_capture, 0, 150, 0); static struct snd_kcontrol_new snd_es1938_controls[] = { ES1938_DOUBLE_TLV("Master Playback Volume", 0, 0x60, 0x62, 0, 0, 63, 0, diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index b7b361ce3a9..6dc578bbeec 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c @@ -1157,7 +1157,7 @@ static int snd_fm801_put_mux(struct snd_kcontrol *kcontrol, return snd_fm801_update_bits(chip, FM801_REC_SRC, 7, val); } -static DECLARE_TLV_DB_SCALE(db_scale_dsp, -3450, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_dsp, -3450, 150, 0); #define FM801_CONTROLS ARRAY_SIZE(snd_fm801_controls) diff --git a/sound/pci/ice1712/aureon.c b/sound/pci/ice1712/aureon.c index 625a9a32b7c..6941d85dfec 100644 --- a/sound/pci/ice1712/aureon.c +++ b/sound/pci/ice1712/aureon.c @@ -664,11 +664,11 @@ static int aureon_ac97_mmute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e return change; } -static DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1); -static DECLARE_TLV_DB_SCALE(db_scale_wm_pcm, -6400, 50, 1); -static DECLARE_TLV_DB_SCALE(db_scale_wm_adc, -1200, 100, 0); -static DECLARE_TLV_DB_SCALE(db_scale_ac97_master, -4650, 150, 0); -static DECLARE_TLV_DB_SCALE(db_scale_ac97_gain, -3450, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1); +static const DECLARE_TLV_DB_SCALE(db_scale_wm_pcm, -6400, 50, 1); +static const DECLARE_TLV_DB_SCALE(db_scale_wm_adc, -1200, 100, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_ac97_master, -4650, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_ac97_gain, -3450, 150, 0); /* * Logarithmic volume values for WM8770 diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c index b8baadba810..830a1bbd711 100644 --- a/sound/pci/ice1712/ice1712.c +++ b/sound/pci/ice1712/ice1712.c @@ -1378,7 +1378,7 @@ static int snd_ice1712_pro_mixer_volume_put(struct snd_kcontrol *kcontrol, struc return change; } -static DECLARE_TLV_DB_SCALE(db_scale_playback, -14400, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_playback, -14400, 150, 0); static const struct snd_kcontrol_new snd_ice1712_multi_playback_ctrls[] __devinitdata = { { diff --git a/sound/pci/ice1712/phase.c b/sound/pci/ice1712/phase.c index 2d97ac8a07d..0751718f4d7 100644 --- a/sound/pci/ice1712/phase.c +++ b/sound/pci/ice1712/phase.c @@ -697,8 +697,8 @@ static int phase28_oversampling_put(struct snd_kcontrol *kcontrol, struct snd_ct return 0; } -static DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1); -static DECLARE_TLV_DB_SCALE(db_scale_wm_pcm, -6400, 50, 1); +static const DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1); +static const DECLARE_TLV_DB_SCALE(db_scale_wm_pcm, -6400, 50, 1); static const struct snd_kcontrol_new phase28_dac_controls[] __devinitdata = { { diff --git a/sound/pci/ice1712/pontis.c b/sound/pci/ice1712/pontis.c index 4c35ddecb8e..9552497f076 100644 --- a/sound/pci/ice1712/pontis.c +++ b/sound/pci/ice1712/pontis.c @@ -565,7 +565,7 @@ static int pontis_gpio_data_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el return changed; } -static DECLARE_TLV_DB_SCALE(db_scale_volume, -6400, 50, 1); +static const DECLARE_TLV_DB_SCALE(db_scale_volume, -6400, 50, 1); /* * mixers diff --git a/sound/pci/ice1712/prodigy192.c b/sound/pci/ice1712/prodigy192.c index d551e71c67c..31cc66eb9f8 100644 --- a/sound/pci/ice1712/prodigy192.c +++ b/sound/pci/ice1712/prodigy192.c @@ -357,8 +357,8 @@ static int aureon_oversampling_put(struct snd_kcontrol *kcontrol, struct snd_ctl } #endif -static DECLARE_TLV_DB_SCALE(db_scale_dac, -19125, 75, 0); -static DECLARE_TLV_DB_SCALE(db_scale_adc, 0, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_dac, -19125, 75, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_adc, 0, 150, 0); /* * mixers diff --git a/sound/pci/mixart/mixart_mixer.c b/sound/pci/mixart/mixart_mixer.c index 13de0f71d4b..d7d15c036e0 100644 --- a/sound/pci/mixart/mixart_mixer.c +++ b/sound/pci/mixart/mixart_mixer.c @@ -389,7 +389,7 @@ static int mixart_analog_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e return changed; } -static DECLARE_TLV_DB_SCALE(db_scale_analog, -9600, 50, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_analog, -9600, 50, 0); static struct snd_kcontrol_new mixart_control_analog_level = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -872,7 +872,7 @@ static int mixart_pcm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem return changed; } -static DECLARE_TLV_DB_SCALE(db_scale_digital, -10950, 50, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_digital, -10950, 50, 0); static struct snd_kcontrol_new snd_mixart_pcm_vol = { diff --git a/sound/pci/pcxhr/pcxhr_mixer.c b/sound/pci/pcxhr/pcxhr_mixer.c index b133ad9e095..d9cc8d2beb6 100644 --- a/sound/pci/pcxhr/pcxhr_mixer.c +++ b/sound/pci/pcxhr/pcxhr_mixer.c @@ -44,8 +44,8 @@ #define PCXHR_ANALOG_PLAYBACK_LEVEL_MAX 128 /* 0.0 dB */ #define PCXHR_ANALOG_PLAYBACK_ZERO_LEVEL 104 /* -24.0 dB ( 0.0 dB - fix level +24.0 dB ) */ -static DECLARE_TLV_DB_SCALE(db_scale_analog_capture, -9600, 50, 0); -static DECLARE_TLV_DB_SCALE(db_scale_analog_playback, -12800, 100, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_analog_capture, -9600, 50, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_analog_playback, -12800, 100, 0); static int pcxhr_update_analog_audio_level(struct snd_pcxhr *chip, int is_capture, int channel) { @@ -195,7 +195,7 @@ static struct snd_kcontrol_new pcxhr_control_output_switch = { #define PCXHR_DIGITAL_LEVEL_MAX 0x1ff /* +18 dB */ #define PCXHR_DIGITAL_ZERO_LEVEL 0x1b7 /* 0 dB */ -static DECLARE_TLV_DB_SCALE(db_scale_digital, -10950, 50, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_digital, -10950, 50, 0); #define MORE_THAN_ONE_STREAM_LEVEL 0x000001 #define VALID_STREAM_PAN_LEVEL_MASK 0x800000 diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c index 474f2d451ae..3bff32167f6 100644 --- a/sound/pci/trident/trident_main.c +++ b/sound/pci/trident/trident_main.c @@ -2627,7 +2627,7 @@ static int snd_trident_vol_control_get(struct snd_kcontrol *kcontrol, return 0; } -static DECLARE_TLV_DB_SCALE(db_scale_gvol, -6375, 25, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_gvol, -6375, 25, 0); static int snd_trident_vol_control_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -2844,7 +2844,7 @@ static int snd_trident_pcm_rvol_control_put(struct snd_kcontrol *kcontrol, return change; } -static DECLARE_TLV_DB_SCALE(db_scale_crvol, -3175, 25, 1); +static const DECLARE_TLV_DB_SCALE(db_scale_crvol, -3175, 25, 1); static struct snd_kcontrol_new snd_trident_pcm_rvol_control __devinitdata = { diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 22caf5d7ff1..a28992269f5 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -1699,7 +1699,7 @@ static int snd_via8233_pcmdxs_volume_put(struct snd_kcontrol *kcontrol, return change; } -static DECLARE_TLV_DB_SCALE(db_scale_dxs, -9450, 150, 1); +static const DECLARE_TLV_DB_SCALE(db_scale_dxs, -9450, 150, 1); static struct snd_kcontrol_new snd_via8233_pcmdxs_volume_control __devinitdata = { .name = "PCM Playback Volume", diff --git a/sound/pci/vx222/vx222.c b/sound/pci/vx222/vx222.c index 89f58ea180b..474eac9490a 100644 --- a/sound/pci/vx222/vx222.c +++ b/sound/pci/vx222/vx222.c @@ -73,8 +73,8 @@ MODULE_DEVICE_TABLE(pci, snd_vx222_ids); /* */ -static DECLARE_TLV_DB_SCALE(db_scale_old_vol, -11350, 50, 0); -static DECLARE_TLV_DB_SCALE(db_scale_akm, -7350, 50, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_old_vol, -11350, 50, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_akm, -7350, 50, 0); static struct snd_vx_hardware vx222_old_hw = { diff --git a/sound/pci/vx222/vx222_ops.c b/sound/pci/vx222/vx222_ops.c index 5e51950e05f..55558bef716 100644 --- a/sound/pci/vx222/vx222_ops.c +++ b/sound/pci/vx222/vx222_ops.c @@ -846,7 +846,7 @@ static void vx2_set_input_level(struct snd_vx222 *chip) #define MIC_LEVEL_MAX 0xff -static DECLARE_TLV_DB_SCALE(db_scale_mic, -6450, 50, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_mic, -6450, 50, 0); /* * controls API for input levels diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c index 8b076932f4f..fd12674d039 100644 --- a/sound/pci/ymfpci/ymfpci_main.c +++ b/sound/pci/ymfpci/ymfpci_main.c @@ -1504,7 +1504,7 @@ static int snd_ymfpci_put_single(struct snd_kcontrol *kcontrol, return change; } -static DECLARE_TLV_DB_LINEAR(db_scale_native, TLV_DB_GAIN_MUTE, 0); +static const DECLARE_TLV_DB_LINEAR(db_scale_native, TLV_DB_GAIN_MUTE, 0); #define YMFPCI_DOUBLE(xname, xindex, reg) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ diff --git a/sound/pcmcia/vx/vxp_mixer.c b/sound/pcmcia/vx/vxp_mixer.c index bced7b623b1..2b1f996c898 100644 --- a/sound/pcmcia/vx/vxp_mixer.c +++ b/sound/pcmcia/vx/vxp_mixer.c @@ -64,7 +64,7 @@ static int vx_mic_level_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v return 0; } -static DECLARE_TLV_DB_SCALE(db_scale_mic, -21, 3, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_mic, -21, 3, 0); static struct snd_kcontrol_new vx_control_mic_level = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, diff --git a/sound/pcmcia/vx/vxpocket.c b/sound/pcmcia/vx/vxpocket.c index d7df59e9c64..363bcb5f08e 100644 --- a/sound/pcmcia/vx/vxpocket.c +++ b/sound/pcmcia/vx/vxpocket.c @@ -91,7 +91,7 @@ static int snd_vxpocket_dev_free(struct snd_device *device) * Only output levels can be modified */ -static DECLARE_TLV_DB_SCALE(db_scale_old_vol, -11350, 50, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_old_vol, -11350, 50, 0); static struct snd_vx_hardware vxpocket_hw = { .name = "VXPocket", -- cgit v1.2.3 From 18b9b3d99677a758e77682d6849f58fc07e30bef Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Tue, 30 Jan 2007 17:18:45 +0100 Subject: [ALSA] ASoC codec probe failure bug This patch fixes a bug whereby some resources were not being freed when codec probe() failed. Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/soc-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index cf84d825171..736949fbb4d 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1234,7 +1234,7 @@ platform_err: codec_dev->remove(pdev); cpu_dai_err: - for (i--; i > 0; i--) { + for (i--; i >= 0; i--) { struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai; if (cpu_dai->remove) cpu_dai->remove(pdev); -- cgit v1.2.3 From 877b866d86786ac69d3d939905999fe7fe1e23fd Mon Sep 17 00:00:00 2001 From: "Cory T. Tusar" Date: Tue, 30 Jan 2007 17:30:55 +0100 Subject: [ALSA] hda-codec - Dell Latitude D820 + D/Port Support port replicator headphone output on Dell Latitude D820 + D/Port. Signed-off-by: Cory T. Tusar Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_sigmatel.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 0556b7e7bb8..6f4a39273b9 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -455,6 +455,8 @@ static struct snd_pci_quirk stac9200_cfg_tbl[] = { "Dell Latitude D620", STAC_REF), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cb, "Dell Latitude 120L", STAC_REF), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cc, + "Dell Latitude D820", STAC_REF), {} /* terminator */ }; -- cgit v1.2.3 From e35115a58856ced315cb8f75df56e9b9a816e70a Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Wed, 31 Jan 2007 10:02:23 +0100 Subject: [ALSA] ASoC codec error reporting This patch improves the codec probe() error reporting by printing error messages when the card or pcms fail to register. Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/codecs/wm8731.c | 15 +++++++++++---- sound/soc/codecs/wm8750.c | 14 ++++++++++---- sound/soc/codecs/wm9712.c | 22 +++++++++++++--------- 3 files changed, 34 insertions(+), 17 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 8151b45a280..9956d654b6f 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -696,8 +696,8 @@ static int wm8731_init(struct snd_soc_device *socdev) /* register pcms */ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); if (ret < 0) { - kfree(codec->reg_cache); - return ret; + printk(KERN_ERR "wm8731: failed to create pcms\n"); + goto pcm_err; } /* power on device */ @@ -717,11 +717,18 @@ static int wm8731_init(struct snd_soc_device *socdev) wm8731_add_widgets(codec); ret = snd_soc_register_card(socdev); if (ret < 0) { - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); + printk(KERN_ERR "wm8731: failed to register card\n"); + goto card_err; } return ret; + +card_err: + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); +pcm_err: + kfree(codec->reg_cache); + return ret; } static struct snd_soc_device *wm8731_socdev; diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index e7f04b89c8a..d4a288ba644 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c @@ -1075,8 +1075,8 @@ static int wm8750_init(struct snd_soc_device *socdev) /* register pcms */ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); if (ret < 0) { - kfree(codec->reg_cache); - return ret; + printk(KERN_ERR "wm8750: failed to create pcms\n"); + goto pcm_err; } /* charge output caps */ @@ -1106,10 +1106,16 @@ static int wm8750_init(struct snd_soc_device *socdev) wm8750_add_widgets(codec); ret = snd_soc_register_card(socdev); if (ret < 0) { - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); + printk(KERN_ERR "wm8750: failed to register card\n"); + goto card_err; } + return ret; +card_err: + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); +pcm_err: + kfree(codec->reg_cache); return ret; } diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index 36c6a38a0f9..b2d2d03b954 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -692,10 +692,8 @@ static int wm9712_soc_probe(struct platform_device *pdev) codec->reg_cache = kzalloc(sizeof(u16) * ARRAY_SIZE(wm9712_reg), GFP_KERNEL); if (codec->reg_cache == NULL) { - kfree(codec->ac97); - kfree(socdev->codec); - socdev->codec = NULL; - return -ENOMEM; + ret = -ENOMEM; + goto cache_err; } memcpy(codec->reg_cache, wm9712_reg, sizeof(u16) * ARRAY_SIZE(wm9712_reg)); codec->reg_cache_size = sizeof(u16) * ARRAY_SIZE(wm9712_reg); @@ -712,8 +710,10 @@ static int wm9712_soc_probe(struct platform_device *pdev) INIT_LIST_HEAD(&codec->dapm_paths); ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0); - if (ret < 0) - goto err; + if (ret < 0) { + printk(KERN_ERR "wm9712: failed to register AC97 codec\n"); + goto codec_err; + } /* register pcms */ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); @@ -733,8 +733,10 @@ static int wm9712_soc_probe(struct platform_device *pdev) wm9712_add_controls(codec); wm9712_add_widgets(codec); ret = snd_soc_register_card(socdev); - if (ret < 0) + if (ret < 0) { + printk(KERN_ERR "wm9712: failed to register card\n"); goto reset_err; + } return 0; @@ -744,8 +746,10 @@ reset_err: pcm_err: snd_soc_free_ac97_codec(codec); -err: - kfree(socdev->codec->reg_cache); +codec_err: + kfree(codec->reg_cache); + +cache_err: kfree(socdev->codec); socdev->codec = NULL; return ret; -- cgit v1.2.3 From 298a2c753a5ae2f0e230a57e94843d248f0033e2 Mon Sep 17 00:00:00 2001 From: Frank Mandarino Date: Wed, 31 Jan 2007 10:02:56 +0100 Subject: [ALSA] ASoC WM8731 support for 32k @ 12MHz sysclk This patch adds support for 32k audio on the WM8731 when running from a 12MHz system clock. Signed-off-by: Frank Mandarino Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/codecs/wm8731.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 9956d654b6f..82f440fcf29 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -435,6 +435,7 @@ static const struct _coeff_div coeff_div[] = { /* 32k */ {12288000, 32000, 384, 0x6, 0x0, 0x0}, {18432000, 32000, 576, 0x6, 0x1, 0x0}, + {12000000, 32000, 375, 0x6, 0x0, 0x1}, /* 8k */ {12288000, 8000, 1536, 0x3, 0x0, 0x0}, -- cgit v1.2.3 From 8fa58af7db56077d6a042fd7b9dd4c9515e1c37b Mon Sep 17 00:00:00 2001 From: Karsten Wiese Date: Wed, 31 Jan 2007 10:05:30 +0100 Subject: [ALSA] snd_hwdep_release() racefix snd_card_file_remove() can free the snd_card. Touch hw->* only before calling snd_card_file_remove(). Unrelated: Allow hwdep devices not to have own ops.release(); Signed-off-by: Karsten Wiese Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/core/hwdep.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c index a6a6ad0ad3c..39c03f3dfbf 100644 --- a/sound/core/hwdep.c +++ b/sound/core/hwdep.c @@ -156,15 +156,16 @@ static int snd_hwdep_release(struct inode *inode, struct file * file) int err = -ENXIO; struct snd_hwdep *hw = file->private_data; struct module *mod = hw->card->module; + mutex_lock(&hw->open_mutex); - if (hw->ops.release) { + if (hw->ops.release) err = hw->ops.release(hw, file); - wake_up(&hw->open_wait); - } if (hw->used > 0) hw->used--; - snd_card_file_remove(hw->card, file); mutex_unlock(&hw->open_mutex); + wake_up(&hw->open_wait); + + snd_card_file_remove(hw->card, file); module_put(mod); return err; } -- cgit v1.2.3 From 4147dab62d1b4387c304888488e1f67a83ad53c8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 31 Jan 2007 10:35:19 +0100 Subject: [ALSA] hda-codec - Add model for Uniwill X40AIx Added model=uniwill-m31 for Uniwill X40AIx with ALC861 codec. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index d01895515e0..c022e8157c3 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -7758,6 +7758,7 @@ static struct snd_pci_quirk alc861_cfg_tbl[] = { SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA), SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31), + SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31), SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST), {} }; -- cgit v1.2.3 From beb60119bcc9cbd80bc5b4f7feec419e067d3e46 Mon Sep 17 00:00:00 2001 From: Gregor Jasny Date: Wed, 31 Jan 2007 12:27:39 +0100 Subject: [ALSA] usbaudio - Fix Oops with broken usb descriptors This is a patch for ALSA Bug #2724. Some webcams provide bogus settings with no valid rates. With this patch those are skipped. Signed-off-by: Gregor Jasny Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/usb/usbaudio.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'sound') diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index de680d095e9..56e42b88add 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -2463,6 +2463,7 @@ static int parse_audio_format_rates(struct snd_usb_audio *chip, struct audioform * build the rate table and bitmap flags */ int r, idx, c; + unsigned int nonzero_rates = 0; /* this table corresponds to the SNDRV_PCM_RATE_XXX bit */ static unsigned int conv_rates[] = { 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, @@ -2485,6 +2486,7 @@ static int parse_audio_format_rates(struct snd_usb_audio *chip, struct audioform fp->altsetting == 5 && fp->maxpacksize == 392) rate = 96000; fp->rate_table[r] = rate; + nonzero_rates |= rate; if (rate < fp->rate_min) fp->rate_min = rate; else if (rate > fp->rate_max) @@ -2500,6 +2502,10 @@ static int parse_audio_format_rates(struct snd_usb_audio *chip, struct audioform if (!found) fp->needs_knot = 1; } + if (!nonzero_rates) { + hwc_debug("All rates were zero. Skipping format!\n"); + return -1; + } if (fp->needs_knot) fp->rates |= SNDRV_PCM_RATE_KNOT; } else { -- cgit v1.2.3 From 965ac42ce919db225ee64678f0be02f2fdf5b5e4 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Wed, 31 Jan 2007 14:14:57 +0100 Subject: [ALSA] ASoC force running of delayed PM work at suspend() and remove() This patch fixes a bug whereby the power management delayed work would never be run at driver suspend() or module remove(). Delayed work would be created (after audio had finished) with a long delay (~5 secs) and was sometimes never queued before flush_scheduled_work() was being called at suspend or module remove. This caused the delayed work to queued after the module had been removed or after resume. This patch forces any delayed work to complete by cancelling it (timer cannot fire and add it to queue later), scheduling it for now and waiting on it's completion. This is something I probably would like to add to workqueue.c in the next merge window, however it's here atm because it can oops. Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/soc-core.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 736949fbb4d..e5aa1c20ddd 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -77,6 +77,25 @@ static int pmdown_time = 5000; module_param(pmdown_time, int, 0); MODULE_PARM_DESC(pmdown_time, "DAPM stream powerdown time (msecs)"); +/* + * This function forces any delayed work to be queued and run. + */ +static int run_delayed_work(struct delayed_work *dwork) +{ + int ret; + + /* cancel any work waiting to be queued. */ + ret = cancel_delayed_work(dwork); + + /* if there was any work waiting then we run it now and + * wait for it's completion */ + if (ret) { + schedule_delayed_work(dwork, 0); + flush_scheduled_work(); + } + return ret; +} + #ifdef CONFIG_SND_SOC_AC97_BUS /* unregister ac97 codec */ static int soc_ac97_dev_unregister(struct snd_soc_codec *codec) @@ -1101,7 +1120,7 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) } /* close any waiting streams and save state */ - flush_scheduled_work(); + run_delayed_work(&socdev->delayed_work); codec->suspend_dapm_state = codec->dapm_state; for(i = 0; i < codec->num_dai; i++) { @@ -1255,6 +1274,8 @@ static int soc_remove(struct platform_device *pdev) struct snd_soc_platform *platform = socdev->platform; struct snd_soc_codec_device *codec_dev = socdev->codec_dev; + run_delayed_work(&socdev->delayed_work); + if (platform->remove) platform->remove(pdev); -- cgit v1.2.3 From 3b6baa5a0b0a2877c18a76fa1f508cacdbc08edf Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 31 Jan 2007 14:34:38 +0100 Subject: [ALSA] Remove delayed work properly at free and suspend Remove delayed work properly at free and suspend in ac97 codec and ak4114 drivers. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/i2c/other/ak4114.c | 3 ++- sound/pci/ac97/ac97_codec.c | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/i2c/other/ak4114.c b/sound/i2c/other/ak4114.c index 34bbafc81cf..d2b17c83fd3 100644 --- a/sound/i2c/other/ak4114.c +++ b/sound/i2c/other/ak4114.c @@ -66,6 +66,7 @@ static void snd_ak4114_free(struct ak4114 *chip) { chip->init = 1; /* don't schedule new work */ mb(); + cancel_delayed_work(&chip->work); flush_scheduled_work(); kfree(chip); } @@ -97,6 +98,7 @@ int snd_ak4114_create(struct snd_card *card, chip->read = read; chip->write = write; chip->private_data = private_data; + INIT_DELAYED_WORK(&chip->work, ak4114_stats); for (reg = 0; reg < 7; reg++) chip->regmap[reg] = pgm[reg]; @@ -149,7 +151,6 @@ void snd_ak4114_reinit(struct ak4114 *chip) reg_write(chip, AK4114_REG_PWRDN, old | AK4114_RST | AK4114_PWN); /* bring up statistics / event queing */ chip->init = 0; - INIT_DELAYED_WORK(&chip->work, ak4114_stats); schedule_delayed_work(&chip->work, HZ / 10); } diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 8b7853c14b5..74ed8108147 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -990,6 +990,7 @@ static int snd_ac97_free(struct snd_ac97 *ac97) if (ac97) { #ifdef CONFIG_SND_AC97_POWER_SAVE cancel_delayed_work(&ac97->power_work); + flush_scheduled_work(); #endif snd_ac97_proc_done(ac97); if (ac97->bus) @@ -2415,6 +2416,10 @@ void snd_ac97_suspend(struct snd_ac97 *ac97) return; if (ac97->build_ops->suspend) ac97->build_ops->suspend(ac97); +#ifdef CONFIG_SND_AC97_POWER_SAVE + cancel_delayed_work(&ac97->power_work); + flush_scheduled_work(); +#endif snd_ac97_powerdown(ac97); } -- cgit v1.2.3 From 8fec560d9beb3957bf45ac93b1c0c616abd77a07 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 1 Feb 2007 11:50:56 +0100 Subject: [ALSA] usbaudio - Fix Oops with unconventional sample rates The patch fixes the memory corruption by the support of unconventional sample rates. Also, it avoids the too restrictive constraints if any of usb descriptions contain continuous rates. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/usb/usbaudio.c | 45 ++++++++++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 19 deletions(-) (limited to 'sound') diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 56e42b88add..8fd37596e3a 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -186,6 +186,7 @@ struct snd_usb_substream { u64 formats; /* format bitmasks (all or'ed) */ unsigned int num_formats; /* number of supported audio formats (list) */ struct list_head fmt_list; /* format list */ + struct snd_pcm_hw_constraint_list rate_list; /* limited rates */ spinlock_t lock; struct snd_urb_ops ops; /* callbacks (must be filled at init) */ @@ -1818,28 +1819,33 @@ static int check_hw_params_convention(struct snd_usb_substream *subs) static int snd_usb_pcm_check_knot(struct snd_pcm_runtime *runtime, struct snd_usb_substream *subs) { - struct list_head *p; - struct snd_pcm_hw_constraint_list constraints_rates; + struct audioformat *fp; + int count = 0, needs_knot = 0; int err; - list_for_each(p, &subs->fmt_list) { - struct audioformat *fp; - fp = list_entry(p, struct audioformat, list); - - if (!fp->needs_knot) - continue; - - constraints_rates.count = fp->nr_rates; - constraints_rates.list = fp->rate_table; - constraints_rates.mask = 0; - - err = snd_pcm_hw_constraint_list(runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, - &constraints_rates); - - if (err < 0) - return err; + list_for_each_entry(fp, &subs->fmt_list, list) { + if (fp->rates & SNDRV_PCM_RATE_CONTINUOUS) + return 0; + count += fp->nr_rates; + if (fp->needs_knot) + needs_knot = 1; } + if (!needs_knot) + return 0; + + subs->rate_list.count = count; + subs->rate_list.list = kmalloc(sizeof(int) * count, GFP_KERNEL); + subs->rate_list.mask = 0; + count = 0; + list_for_each_entry(fp, &subs->fmt_list, list) { + int i; + for (i = 0; i < fp->nr_rates; i++) + subs->rate_list.list[count++] = fp->rate_table[i]; + } + err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, + &subs->rate_list); + if (err < 0) + return err; return 0; } @@ -2238,6 +2244,7 @@ static void free_substream(struct snd_usb_substream *subs) kfree(fp->rate_table); kfree(fp); } + kfree(subs->rate_list.list); } -- cgit v1.2.3 From bc7320c5c8ddeb3b50c6a24013dab9ba74bce578 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Thu, 1 Feb 2007 12:26:07 +0100 Subject: [ALSA] ASoC very minor coding style fix for snd_soc_new_pcms() This very minor patch fixes the snd_soc_new_pcms() function to comply with the kernel coding style. Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/soc-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index e5aa1c20ddd..87be938622d 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1522,7 +1522,7 @@ EXPORT_SYMBOL_GPL(snd_soc_get_rate); * * Returns 0 for success, else error. */ -int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char * xid) +int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid) { struct snd_soc_codec *codec = socdev->codec; struct snd_soc_machine *machine = socdev->machine; -- cgit v1.2.3 From 0981a260a1fe4a3f22cc70ef01ce38a73f548745 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 1 Feb 2007 14:53:49 +0100 Subject: [ALSA] Fix possible invalid memory access in PCM core snd_internval_list() may access invalid memory in the case count = 0 is given. It shouldn't be passed, but it'd better to make the code a bit more robust. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/core/pcm_lib.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'sound') diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index b336797be4f..9fefcaa2c32 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -781,6 +781,11 @@ int snd_interval_list(struct snd_interval *i, unsigned int count, unsigned int * { unsigned int k; int changed = 0; + + if (!count) { + i->empty = 1; + return -EINVAL; + } for (k = 0; k < count; k++) { if (mask && !(mask & (1 << k))) continue; -- cgit v1.2.3 From 3372a153c230bd0b28d470118d5a4c5840f8f966 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 1 Feb 2007 15:46:50 +0100 Subject: [ALSA] hda-intel - Add black/whitelist for position_fix option Some devices are known to require position_fix=1 or 2 to make the driver working correctly. Otherwise the sound gets weird effects, such as stutters. Now a black/whitelist is introduced to indicate the position_fix value explicitly for such misbehaving hardwares. As a first example, Dell D820 is listed there. More will come later likely... Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/hda_intel.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 83d1ba7f33a..b9a8e238b0a 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1502,6 +1502,31 @@ static int azx_dev_free(struct snd_device *device) return azx_free(device->device_data); } +/* + * white/black-listing for position_fix + */ +static const struct snd_pci_quirk position_fix_list[] __devinitdata = { + SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_NONE), + {} +}; + +static int __devinit check_position_fix(struct azx *chip, int fix) +{ + const struct snd_pci_quirk *q; + + if (fix == POS_FIX_AUTO) { + q = snd_pci_quirk_lookup(chip->pci, position_fix_list); + if (q) { + snd_printdd(KERN_INFO + "hda_intel: position_fix set to %d " + "for device %04x:%04x\n", + q->value, q->subvendor, q->subdevice); + return q->value; + } + } + return fix; +} + /* * constructor */ @@ -1536,7 +1561,8 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, chip->driver_type = driver_type; chip->msi = enable_msi; - chip->position_fix = position_fix; + chip->position_fix = check_position_fix(chip, position_fix); + chip->single_cmd = single_cmd; #if BITS_PER_LONG != 64 -- cgit v1.2.3 From cb666e5bd865cc991c0048d6e81581019a141820 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 2 Feb 2007 17:13:49 +0100 Subject: [ALSA] soc - ASoC 0.13 core changes This patch updates the ASoC core to the new DAI matching and clocking API in version 0.13 Changes:- o Removed DAI capabilities matching code in favour of manual matching in the machine drivers. o Added DAI operations for codec and CPU interfaces. o Removed config_sysclk() function and struct snd_soc_clock_info. No longer needed as clocking is now configured manually in the machine drivers. Also removed other clocking data from structures. o Added machine driver prepare callback. Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/soc-core.c | 781 ++++++++++----------------------------------------- 1 file changed, 148 insertions(+), 633 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 87be938622d..36519aef55d 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -47,27 +47,11 @@ #else #define dbg(format, arg...) #endif -/* debug DAI capabilities matching */ -#define SOC_DEBUG_DAI 0 -#if SOC_DEBUG_DAI -#define dbgc(format, arg...) printk(format, ## arg) -#else -#define dbgc(format, arg...) -#endif - -#define CODEC_CPU(codec, cpu) ((codec << 4) | cpu) static DEFINE_MUTEX(pcm_mutex); static DEFINE_MUTEX(io_mutex); static DECLARE_WAIT_QUEUE_HEAD(soc_pm_waitq); -/* supported sample rates */ -/* ATTENTION: these values depend on the definition in pcm.h! */ -static const unsigned int rates[] = { - 5512, 8000, 11025, 16000, 22050, 32000, 44100, - 48000, 64000, 88200, 96000, 176400, 192000 -}; - /* * This is a timeout to do a DAPM powerdown after a stream is closed(). * It can be used to eliminate pops between different playback streams, e.g. @@ -142,458 +126,6 @@ static inline const char* get_dai_name(int type) return NULL; } -/* get rate format from rate */ -static inline int soc_get_rate_format(int rate) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(rates); i++) { - if (rates[i] == rate) - return 1 << i; - } - return 0; -} - -/* gets the audio system mclk/sysclk for the given parameters */ -static unsigned inline int soc_get_mclk(struct snd_soc_pcm_runtime *rtd, - struct snd_soc_clock_info *info) -{ - struct snd_soc_device *socdev = rtd->socdev; - struct snd_soc_machine *machine = socdev->machine; - int i; - - /* find the matching machine config and get it's mclk for the given - * sample rate and hardware format */ - for(i = 0; i < machine->num_links; i++) { - if (machine->dai_link[i].cpu_dai == rtd->cpu_dai && - machine->dai_link[i].config_sysclk) - return machine->dai_link[i].config_sysclk(rtd, info); - } - return 0; -} - -/* changes a bitclk multiplier mask to a divider mask */ -static u64 soc_bfs_rcw_to_div(u64 bfs, int rate, unsigned int mclk, - unsigned int pcmfmt, unsigned int chn) -{ - int i, j; - u64 bfs_ = 0; - int size = snd_pcm_format_physical_width(pcmfmt), min = 0; - - if (size <= 0) - return 0; - - /* the minimum bit clock that has enough bandwidth */ - min = size * rate * chn; - dbgc("rcw --> div min bclk %d with mclk %d\n", min, mclk); - - for (i = 0; i < 64; i++) { - if ((bfs >> i) & 0x1) { - j = min * (i + 1); - bfs_ |= SND_SOC_FSBD(mclk/j); - dbgc("rcw --> div support mult %d\n", - SND_SOC_FSBD_REAL(1<> i) & 0x1) { - j = mclk / (i + 1); - if (j >= min) { - bfs_ |= SND_SOC_FSBW(j/min); - dbgc("div --> rcw support div %d\n", - SND_SOC_FSBW_REAL(1< rcw min bclk %d with mclk %d\n", min, mclk); - - if (bfs_ < min) - return 0; - else { - bfs_ = SND_SOC_FSBW(bfs_/min); - dbgc("rate --> rcw support div %d\n", SND_SOC_FSBW_REAL(bfs_)); - return bfs_; - } -} - -/* changes a bitclk multiplier mask to a divider mask */ -static u64 soc_bfs_rate_to_div(u64 bfs, int rate, unsigned int mclk, - unsigned int pcmfmt, unsigned int chn) -{ - unsigned int bfs_ = rate * bfs; - int size = snd_pcm_format_physical_width(pcmfmt), min = 0; - - if (size <= 0) - return 0; - - /* the minimum bit clock that has enough bandwidth */ - min = size * rate * chn; - dbgc("rate --> div min bclk %d with mclk %d\n", min, mclk); - - if (bfs_ < min) - return 0; - else { - bfs_ = SND_SOC_FSBW(mclk/bfs_); - dbgc("rate --> div support div %d\n", SND_SOC_FSBD_REAL(bfs_)); - return bfs_; - } -} - -/* Matches codec DAI and SoC CPU DAI hardware parameters */ -static int soc_hw_match_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai_mode *codec_dai_mode = NULL; - struct snd_soc_dai_mode *cpu_dai_mode = NULL; - struct snd_soc_clock_info clk_info; - unsigned int fs, mclk, rate = params_rate(params), - chn, j, k, cpu_bclk, codec_bclk, pcmrate; - u16 fmt = 0; - u64 codec_bfs, cpu_bfs; - - dbg("asoc: match version %s\n", SND_SOC_VERSION); - clk_info.rate = rate; - pcmrate = soc_get_rate_format(rate); - - /* try and find a match from the codec and cpu DAI capabilities */ - for (j = 0; j < rtd->codec_dai->caps.num_modes; j++) { - for (k = 0; k < rtd->cpu_dai->caps.num_modes; k++) { - codec_dai_mode = &rtd->codec_dai->caps.mode[j]; - cpu_dai_mode = &rtd->cpu_dai->caps.mode[k]; - - if (!(codec_dai_mode->pcmrate & cpu_dai_mode->pcmrate & - pcmrate)) { - dbgc("asoc: DAI[%d:%d] failed to match rate\n", j, k); - continue; - } - - fmt = codec_dai_mode->fmt & cpu_dai_mode->fmt; - if (!(fmt & SND_SOC_DAIFMT_FORMAT_MASK)) { - dbgc("asoc: DAI[%d:%d] failed to match format\n", j, k); - continue; - } - - if (!(fmt & SND_SOC_DAIFMT_CLOCK_MASK)) { - dbgc("asoc: DAI[%d:%d] failed to match clock masters\n", - j, k); - continue; - } - - if (!(fmt & SND_SOC_DAIFMT_INV_MASK)) { - dbgc("asoc: DAI[%d:%d] failed to match invert\n", j, k); - continue; - } - - if (!(codec_dai_mode->pcmfmt & cpu_dai_mode->pcmfmt)) { - dbgc("asoc: DAI[%d:%d] failed to match pcm format\n", j, k); - continue; - } - - if (!(codec_dai_mode->pcmdir & cpu_dai_mode->pcmdir)) { - dbgc("asoc: DAI[%d:%d] failed to match direction\n", j, k); - continue; - } - - /* todo - still need to add tdm selection */ - rtd->cpu_dai->dai_runtime.fmt = - rtd->codec_dai->dai_runtime.fmt = - 1 << (ffs(fmt & SND_SOC_DAIFMT_FORMAT_MASK) -1) | - 1 << (ffs(fmt & SND_SOC_DAIFMT_CLOCK_MASK) - 1) | - 1 << (ffs(fmt & SND_SOC_DAIFMT_INV_MASK) - 1); - clk_info.bclk_master = - rtd->cpu_dai->dai_runtime.fmt & SND_SOC_DAIFMT_CLOCK_MASK; - - /* make sure the ratio between rate and master - * clock is acceptable*/ - fs = (cpu_dai_mode->fs & codec_dai_mode->fs); - if (fs == 0) { - dbgc("asoc: DAI[%d:%d] failed to match FS\n", j, k); - continue; - } - clk_info.fs = rtd->cpu_dai->dai_runtime.fs = - rtd->codec_dai->dai_runtime.fs = fs; - - /* calculate audio system clocking using slowest clocks possible*/ - mclk = soc_get_mclk(rtd, &clk_info); - if (mclk == 0) { - dbgc("asoc: DAI[%d:%d] configuration not clockable\n", j, k); - dbgc("asoc: rate %d fs %d master %x\n", rate, fs, - clk_info.bclk_master); - continue; - } - - /* calculate word size (per channel) and frame size */ - rtd->codec_dai->dai_runtime.pcmfmt = - rtd->cpu_dai->dai_runtime.pcmfmt = - 1 << params_format(params); - - chn = params_channels(params); - /* i2s always has left and right */ - if (params_channels(params) == 1 && - rtd->cpu_dai->dai_runtime.fmt & (SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_RIGHT_J | SND_SOC_DAIFMT_LEFT_J)) - chn <<= 1; - - /* Calculate bfs - the ratio between bitclock and the sample rate - * We must take into consideration the dividers and multipliers - * used in the codec and cpu DAI modes. We always choose the - * lowest possible clocks to reduce power. - */ - switch (CODEC_CPU(codec_dai_mode->flags, cpu_dai_mode->flags)) { - case CODEC_CPU(SND_SOC_DAI_BFS_DIV, SND_SOC_DAI_BFS_DIV): - /* cpu & codec bfs dividers */ - rtd->cpu_dai->dai_runtime.bfs = - rtd->codec_dai->dai_runtime.bfs = - 1 << (fls(codec_dai_mode->bfs & cpu_dai_mode->bfs) - 1); - break; - case CODEC_CPU(SND_SOC_DAI_BFS_DIV, SND_SOC_DAI_BFS_RCW): - /* normalise bfs codec divider & cpu rcw mult */ - codec_bfs = soc_bfs_div_to_rcw(codec_dai_mode->bfs, rate, - mclk, rtd->codec_dai->dai_runtime.pcmfmt, chn); - rtd->cpu_dai->dai_runtime.bfs = - 1 << (ffs(codec_bfs & cpu_dai_mode->bfs) - 1); - cpu_bfs = soc_bfs_rcw_to_div(cpu_dai_mode->bfs, rate, mclk, - rtd->codec_dai->dai_runtime.pcmfmt, chn); - rtd->codec_dai->dai_runtime.bfs = - 1 << (fls(codec_dai_mode->bfs & cpu_bfs) - 1); - break; - case CODEC_CPU(SND_SOC_DAI_BFS_RCW, SND_SOC_DAI_BFS_DIV): - /* normalise bfs codec rcw mult & cpu divider */ - codec_bfs = soc_bfs_rcw_to_div(codec_dai_mode->bfs, rate, - mclk, rtd->codec_dai->dai_runtime.pcmfmt, chn); - rtd->cpu_dai->dai_runtime.bfs = - 1 << (fls(codec_bfs & cpu_dai_mode->bfs) -1); - cpu_bfs = soc_bfs_div_to_rcw(cpu_dai_mode->bfs, rate, mclk, - rtd->codec_dai->dai_runtime.pcmfmt, chn); - rtd->codec_dai->dai_runtime.bfs = - 1 << (ffs(codec_dai_mode->bfs & cpu_bfs) -1); - break; - case CODEC_CPU(SND_SOC_DAI_BFS_RCW, SND_SOC_DAI_BFS_RCW): - /* codec & cpu bfs rate rcw multipliers */ - rtd->cpu_dai->dai_runtime.bfs = - rtd->codec_dai->dai_runtime.bfs = - 1 << (ffs(codec_dai_mode->bfs & cpu_dai_mode->bfs) -1); - break; - case CODEC_CPU(SND_SOC_DAI_BFS_DIV, SND_SOC_DAI_BFS_RATE): - /* normalise cpu bfs rate const multiplier & codec div */ - cpu_bfs = soc_bfs_rate_to_div(cpu_dai_mode->bfs, rate, - mclk, rtd->codec_dai->dai_runtime.pcmfmt, chn); - if(codec_dai_mode->bfs & cpu_bfs) { - rtd->codec_dai->dai_runtime.bfs = cpu_bfs; - rtd->cpu_dai->dai_runtime.bfs = cpu_dai_mode->bfs; - } else - rtd->cpu_dai->dai_runtime.bfs = 0; - break; - case CODEC_CPU(SND_SOC_DAI_BFS_RCW, SND_SOC_DAI_BFS_RATE): - /* normalise cpu bfs rate const multiplier & codec rcw mult */ - cpu_bfs = soc_bfs_rate_to_rcw(cpu_dai_mode->bfs, rate, - mclk, rtd->codec_dai->dai_runtime.pcmfmt, chn); - if(codec_dai_mode->bfs & cpu_bfs) { - rtd->codec_dai->dai_runtime.bfs = cpu_bfs; - rtd->cpu_dai->dai_runtime.bfs = cpu_dai_mode->bfs; - } else - rtd->cpu_dai->dai_runtime.bfs = 0; - break; - case CODEC_CPU(SND_SOC_DAI_BFS_RATE, SND_SOC_DAI_BFS_RCW): - /* normalise cpu bfs rate rcw multiplier & codec const mult */ - codec_bfs = soc_bfs_rate_to_rcw(codec_dai_mode->bfs, rate, - mclk, rtd->codec_dai->dai_runtime.pcmfmt, chn); - if(cpu_dai_mode->bfs & codec_bfs) { - rtd->cpu_dai->dai_runtime.bfs = codec_bfs; - rtd->codec_dai->dai_runtime.bfs = codec_dai_mode->bfs; - } else - rtd->cpu_dai->dai_runtime.bfs = 0; - break; - case CODEC_CPU(SND_SOC_DAI_BFS_RATE, SND_SOC_DAI_BFS_DIV): - /* normalise cpu bfs div & codec const mult */ - codec_bfs = soc_bfs_rate_to_div(codec_dai_mode->bfs, rate, - mclk, rtd->codec_dai->dai_runtime.pcmfmt, chn); - if(cpu_dai_mode->bfs & codec_bfs) { - rtd->cpu_dai->dai_runtime.bfs = codec_bfs; - rtd->codec_dai->dai_runtime.bfs = codec_dai_mode->bfs; - } else - rtd->cpu_dai->dai_runtime.bfs = 0; - break; - case CODEC_CPU(SND_SOC_DAI_BFS_RATE, SND_SOC_DAI_BFS_RATE): - /* cpu & codec constant mult */ - if(codec_dai_mode->bfs == cpu_dai_mode->bfs) - rtd->cpu_dai->dai_runtime.bfs = - rtd->codec_dai->dai_runtime.bfs = - codec_dai_mode->bfs; - else - rtd->cpu_dai->dai_runtime.bfs = - rtd->codec_dai->dai_runtime.bfs = 0; - break; - } - - /* make sure the bit clock speed is acceptable */ - if (!rtd->cpu_dai->dai_runtime.bfs || - !rtd->codec_dai->dai_runtime.bfs) { - dbgc("asoc: DAI[%d:%d] failed to match BFS\n", j, k); - dbgc("asoc: cpu_dai %llu codec %llu\n", - rtd->cpu_dai->dai_runtime.bfs, - rtd->codec_dai->dai_runtime.bfs); - dbgc("asoc: mclk %d hwfmt %x\n", mclk, fmt); - continue; - } - - goto found; - } - } - printk(KERN_ERR "asoc: no matching DAI found between codec and CPU\n"); - return -EINVAL; - -found: - /* we have matching DAI's, so complete the runtime info */ - rtd->codec_dai->dai_runtime.pcmrate = - rtd->cpu_dai->dai_runtime.pcmrate = - soc_get_rate_format(rate); - - rtd->codec_dai->dai_runtime.priv = codec_dai_mode->priv; - rtd->cpu_dai->dai_runtime.priv = cpu_dai_mode->priv; - rtd->codec_dai->dai_runtime.flags = codec_dai_mode->flags; - rtd->cpu_dai->dai_runtime.flags = cpu_dai_mode->flags; - - /* for debug atm */ - dbg("asoc: DAI[%d:%d] Match OK\n", j, k); - if (rtd->codec_dai->dai_runtime.flags == SND_SOC_DAI_BFS_DIV) { - codec_bclk = (rtd->codec_dai->dai_runtime.fs * params_rate(params)) / - SND_SOC_FSBD_REAL(rtd->codec_dai->dai_runtime.bfs); - dbg("asoc: codec fs %d mclk %d bfs div %d bclk %d\n", - rtd->codec_dai->dai_runtime.fs, mclk, - SND_SOC_FSBD_REAL(rtd->codec_dai->dai_runtime.bfs), codec_bclk); - } else if(rtd->codec_dai->dai_runtime.flags == SND_SOC_DAI_BFS_RATE) { - codec_bclk = params_rate(params) * rtd->codec_dai->dai_runtime.bfs; - dbg("asoc: codec fs %d mclk %d bfs rate mult %llu bclk %d\n", - rtd->codec_dai->dai_runtime.fs, mclk, - rtd->codec_dai->dai_runtime.bfs, codec_bclk); - } else if (rtd->cpu_dai->dai_runtime.flags == SND_SOC_DAI_BFS_RCW) { - codec_bclk = params_rate(params) * params_channels(params) * - snd_pcm_format_physical_width(rtd->codec_dai->dai_runtime.pcmfmt) * - SND_SOC_FSBW_REAL(rtd->codec_dai->dai_runtime.bfs); - dbg("asoc: codec fs %d mclk %d bfs rcw mult %d bclk %d\n", - rtd->codec_dai->dai_runtime.fs, mclk, - SND_SOC_FSBW_REAL(rtd->codec_dai->dai_runtime.bfs), codec_bclk); - } else - codec_bclk = 0; - - if (rtd->cpu_dai->dai_runtime.flags == SND_SOC_DAI_BFS_DIV) { - cpu_bclk = (rtd->cpu_dai->dai_runtime.fs * params_rate(params)) / - SND_SOC_FSBD_REAL(rtd->cpu_dai->dai_runtime.bfs); - dbg("asoc: cpu fs %d mclk %d bfs div %d bclk %d\n", - rtd->cpu_dai->dai_runtime.fs, mclk, - SND_SOC_FSBD_REAL(rtd->cpu_dai->dai_runtime.bfs), cpu_bclk); - } else if (rtd->cpu_dai->dai_runtime.flags == SND_SOC_DAI_BFS_RATE) { - cpu_bclk = params_rate(params) * rtd->cpu_dai->dai_runtime.bfs; - dbg("asoc: cpu fs %d mclk %d bfs rate mult %llu bclk %d\n", - rtd->cpu_dai->dai_runtime.fs, mclk, - rtd->cpu_dai->dai_runtime.bfs, cpu_bclk); - } else if (rtd->cpu_dai->dai_runtime.flags == SND_SOC_DAI_BFS_RCW) { - cpu_bclk = params_rate(params) * params_channels(params) * - snd_pcm_format_physical_width(rtd->cpu_dai->dai_runtime.pcmfmt) * - SND_SOC_FSBW_REAL(rtd->cpu_dai->dai_runtime.bfs); - dbg("asoc: cpu fs %d mclk %d bfs mult rcw %d bclk %d\n", - rtd->cpu_dai->dai_runtime.fs, mclk, - SND_SOC_FSBW_REAL(rtd->cpu_dai->dai_runtime.bfs), cpu_bclk); - } else - cpu_bclk = 0; - - /* - * Check we have matching bitclocks. If we don't then it means the - * sysclock returned by either the codec or cpu DAI (selected by the - * machine sysclock function) is wrong compared with the supported DAI - * modes for the codec or cpu DAI. Check your codec or CPU DAI - * config_sysclock() functions. - */ - if (cpu_bclk != codec_bclk && cpu_bclk){ - printk(KERN_ERR - "asoc: codec and cpu bitclocks differ, audio may be wrong speed\n" - ); - printk(KERN_ERR "asoc: codec %d != cpu %d\n", codec_bclk, cpu_bclk); - } - - switch(rtd->cpu_dai->dai_runtime.fmt & SND_SOC_DAIFMT_CLOCK_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - dbg("asoc: DAI codec BCLK master, LRC master\n"); - break; - case SND_SOC_DAIFMT_CBS_CFM: - dbg("asoc: DAI codec BCLK slave, LRC master\n"); - break; - case SND_SOC_DAIFMT_CBM_CFS: - dbg("asoc: DAI codec BCLK master, LRC slave\n"); - break; - case SND_SOC_DAIFMT_CBS_CFS: - dbg("asoc: DAI codec BCLK slave, LRC slave\n"); - break; - } - dbg("asoc: mode %x, invert %x\n", - rtd->cpu_dai->dai_runtime.fmt & SND_SOC_DAIFMT_FORMAT_MASK, - rtd->cpu_dai->dai_runtime.fmt & SND_SOC_DAIFMT_INV_MASK); - dbg("asoc: audio rate %d chn %d fmt %x\n", params_rate(params), - params_channels(params), params_format(params)); - - return 0; -} - -static inline u32 get_rates(struct snd_soc_dai_mode *modes, int nmodes) -{ - int i; - u32 rates = 0; - - for(i = 0; i < nmodes; i++) - rates |= modes[i].pcmrate; - - return rates; -} - -static inline u64 get_formats(struct snd_soc_dai_mode *modes, int nmodes) -{ - int i; - u64 formats = 0; - - for(i = 0; i < nmodes; i++) - formats |= modes[i].pcmfmt; - - return formats; -} - /* * Called by ALSA when a PCM substream is opened, the runtime->hw record is * then initialized and any private data can be allocated. This also calls @@ -604,20 +136,20 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_soc_machine *machine = socdev->machine; + struct snd_soc_dai_link *machine = rtd->dai; struct snd_soc_platform *platform = socdev->platform; - struct snd_soc_codec_dai *codec_dai = rtd->codec_dai; - struct snd_soc_cpu_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai; + struct snd_soc_codec_dai *codec_dai = machine->codec_dai; int ret = 0; mutex_lock(&pcm_mutex); /* startup the audio subsystem */ - if (rtd->cpu_dai->ops.startup) { - ret = rtd->cpu_dai->ops.startup(substream); + if (cpu_dai->ops.startup) { + ret = cpu_dai->ops.startup(substream); if (ret < 0) { printk(KERN_ERR "asoc: can't open interface %s\n", - rtd->cpu_dai->name); + cpu_dai->name); goto out; } } @@ -630,116 +162,101 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) } } - if (machine->ops && machine->ops->startup) { - ret = machine->ops->startup(substream); + if (codec_dai->ops.startup) { + ret = codec_dai->ops.startup(substream); if (ret < 0) { - printk(KERN_ERR "asoc: %s startup failed\n", machine->name); - goto machine_err; + printk(KERN_ERR "asoc: can't open codec %s\n", + codec_dai->name); + goto codec_dai_err; } } - if (rtd->codec_dai->ops.startup) { - ret = rtd->codec_dai->ops.startup(substream); + if (machine->ops && machine->ops->startup) { + ret = machine->ops->startup(substream); if (ret < 0) { - printk(KERN_ERR "asoc: can't open codec %s\n", - rtd->codec_dai->name); - goto codec_dai_err; + printk(KERN_ERR "asoc: %s startup failed\n", machine->name); + goto machine_err; } } - /* create runtime params from DMA, codec and cpu DAI */ - if (runtime->hw.rates) - runtime->hw.rates &= - get_rates(codec_dai->caps.mode, codec_dai->caps.num_modes) & - get_rates(cpu_dai->caps.mode, cpu_dai->caps.num_modes); - else - runtime->hw.rates = - get_rates(codec_dai->caps.mode, codec_dai->caps.num_modes) & - get_rates(cpu_dai->caps.mode, cpu_dai->caps.num_modes); - if (runtime->hw.formats) - runtime->hw.formats &= - get_formats(codec_dai->caps.mode, codec_dai->caps.num_modes) & - get_formats(cpu_dai->caps.mode, cpu_dai->caps.num_modes); - else - runtime->hw.formats = - get_formats(codec_dai->caps.mode, codec_dai->caps.num_modes) & - get_formats(cpu_dai->caps.mode, cpu_dai->caps.num_modes); - /* Check that the codec and cpu DAI's are compatible */ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { runtime->hw.rate_min = - max(rtd->codec_dai->playback.rate_min, - rtd->cpu_dai->playback.rate_min); + max(codec_dai->playback.rate_min, cpu_dai->playback.rate_min); runtime->hw.rate_max = - min(rtd->codec_dai->playback.rate_max, - rtd->cpu_dai->playback.rate_max); + min(codec_dai->playback.rate_max, cpu_dai->playback.rate_max); runtime->hw.channels_min = - max(rtd->codec_dai->playback.channels_min, - rtd->cpu_dai->playback.channels_min); + max(codec_dai->playback.channels_min, + cpu_dai->playback.channels_min); runtime->hw.channels_max = - min(rtd->codec_dai->playback.channels_max, - rtd->cpu_dai->playback.channels_max); + min(codec_dai->playback.channels_max, + cpu_dai->playback.channels_max); + runtime->hw.formats = + codec_dai->playback.formats & cpu_dai->playback.formats; + runtime->hw.rates = + codec_dai->playback.rates & cpu_dai->playback.rates; } else { runtime->hw.rate_min = - max(rtd->codec_dai->capture.rate_min, - rtd->cpu_dai->capture.rate_min); + max(codec_dai->capture.rate_min, cpu_dai->capture.rate_min); runtime->hw.rate_max = - min(rtd->codec_dai->capture.rate_max, - rtd->cpu_dai->capture.rate_max); + min(codec_dai->capture.rate_max, cpu_dai->capture.rate_max); runtime->hw.channels_min = - max(rtd->codec_dai->capture.channels_min, - rtd->cpu_dai->capture.channels_min); + max(codec_dai->capture.channels_min, + cpu_dai->capture.channels_min); runtime->hw.channels_max = - min(rtd->codec_dai->capture.channels_max, - rtd->cpu_dai->capture.channels_max); + min(codec_dai->capture.channels_max, + cpu_dai->capture.channels_max); + runtime->hw.formats = + codec_dai->capture.formats & cpu_dai->capture.formats; + runtime->hw.rates = + codec_dai->capture.rates & cpu_dai->capture.rates; } snd_pcm_limit_hw_rates(runtime); if (!runtime->hw.rates) { printk(KERN_ERR "asoc: %s <-> %s No matching rates\n", - rtd->codec_dai->name, rtd->cpu_dai->name); - goto codec_dai_err; + codec_dai->name, cpu_dai->name); + goto machine_err; } if (!runtime->hw.formats) { printk(KERN_ERR "asoc: %s <-> %s No matching formats\n", - rtd->codec_dai->name, rtd->cpu_dai->name); - goto codec_dai_err; + codec_dai->name, cpu_dai->name); + goto machine_err; } if (!runtime->hw.channels_min || !runtime->hw.channels_max) { printk(KERN_ERR "asoc: %s <-> %s No matching channels\n", - rtd->codec_dai->name, rtd->cpu_dai->name); - goto codec_dai_err; + codec_dai->name, cpu_dai->name); + goto machine_err; } - dbg("asoc: %s <-> %s info:\n", rtd->codec_dai->name, rtd->cpu_dai->name); + dbg("asoc: %s <-> %s info:\n",codec_dai->name, cpu_dai->name); dbg("asoc: rate mask 0x%x\n", runtime->hw.rates); dbg("asoc: min ch %d max ch %d\n", runtime->hw.channels_min, runtime->hw.channels_max); dbg("asoc: min rate %d max rate %d\n", runtime->hw.rate_min, runtime->hw.rate_max); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - rtd->cpu_dai->playback.active = rtd->codec_dai->playback.active = 1; + cpu_dai->playback.active = codec_dai->playback.active = 1; else - rtd->cpu_dai->capture.active = rtd->codec_dai->capture.active = 1; - rtd->cpu_dai->active = rtd->codec_dai->active = 1; - rtd->cpu_dai->runtime = runtime; + cpu_dai->capture.active = codec_dai->capture.active = 1; + cpu_dai->active = codec_dai->active = 1; + cpu_dai->runtime = runtime; socdev->codec->active++; mutex_unlock(&pcm_mutex); return 0; -codec_dai_err: +machine_err: if (machine->ops && machine->ops->shutdown) machine->ops->shutdown(substream); -machine_err: +codec_dai_err: if (platform->pcm_ops->close) platform->pcm_ops->close(substream); platform_err: - if (rtd->cpu_dai->ops.shutdown) - rtd->cpu_dai->ops.shutdown(substream); + if (cpu_dai->ops.shutdown) + cpu_dai->ops.shutdown(substream); out: mutex_unlock(&pcm_mutex); return ret; @@ -795,47 +312,49 @@ static int soc_codec_close(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; - struct snd_soc_machine *machine = socdev->machine; + struct snd_soc_dai_link *machine = rtd->dai; struct snd_soc_platform *platform = socdev->platform; + struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai; + struct snd_soc_codec_dai *codec_dai = machine->codec_dai; struct snd_soc_codec *codec = socdev->codec; mutex_lock(&pcm_mutex); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - rtd->cpu_dai->playback.active = rtd->codec_dai->playback.active = 0; + cpu_dai->playback.active = codec_dai->playback.active = 0; else - rtd->cpu_dai->capture.active = rtd->codec_dai->capture.active = 0; + cpu_dai->capture.active = codec_dai->capture.active = 0; - if (rtd->codec_dai->playback.active == 0 && - rtd->codec_dai->capture.active == 0) { - rtd->cpu_dai->active = rtd->codec_dai->active = 0; + if (codec_dai->playback.active == 0 && + codec_dai->capture.active == 0) { + cpu_dai->active = codec_dai->active = 0; } codec->active--; - if (rtd->cpu_dai->ops.shutdown) - rtd->cpu_dai->ops.shutdown(substream); + if (cpu_dai->ops.shutdown) + cpu_dai->ops.shutdown(substream); - if (rtd->codec_dai->ops.shutdown) - rtd->codec_dai->ops.shutdown(substream); + if (codec_dai->ops.shutdown) + codec_dai->ops.shutdown(substream); if (machine->ops && machine->ops->shutdown) machine->ops->shutdown(substream); if (platform->pcm_ops->close) platform->pcm_ops->close(substream); - rtd->cpu_dai->runtime = NULL; + cpu_dai->runtime = NULL; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { /* start delayed pop wq here for playback streams */ - rtd->codec_dai->pop_wait = 1; + codec_dai->pop_wait = 1; schedule_delayed_work(&socdev->delayed_work, msecs_to_jiffies(pmdown_time)); } else { /* capture streams can be powered down now */ - snd_soc_dapm_stream_event(codec, rtd->codec_dai->capture.stream_name, - SND_SOC_DAPM_STREAM_STOP); + snd_soc_dapm_stream_event(codec, + codec_dai->capture.stream_name, SND_SOC_DAPM_STREAM_STOP); - if (codec->active == 0 && rtd->codec_dai->pop_wait == 0){ + if (codec->active == 0 && codec_dai->pop_wait == 0){ if (codec->dapm_event) codec->dapm_event(codec, SNDRV_CTL_POWER_D3hot); } @@ -854,11 +373,23 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_dai_link *machine = rtd->dai; struct snd_soc_platform *platform = socdev->platform; + struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai; + struct snd_soc_codec_dai *codec_dai = machine->codec_dai; struct snd_soc_codec *codec = socdev->codec; int ret = 0; mutex_lock(&pcm_mutex); + + if (machine->ops && machine->ops->prepare) { + ret = machine->ops->prepare(substream); + if (ret < 0) { + printk(KERN_ERR "asoc: machine prepare error\n"); + goto out; + } + } + if (platform->pcm_ops->prepare) { ret = platform->pcm_ops->prepare(substream); if (ret < 0) { @@ -867,30 +398,35 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) } } - if (rtd->codec_dai->ops.prepare) { - ret = rtd->codec_dai->ops.prepare(substream); + if (codec_dai->ops.prepare) { + ret = codec_dai->ops.prepare(substream); if (ret < 0) { printk(KERN_ERR "asoc: codec DAI prepare error\n"); goto out; } } - if (rtd->cpu_dai->ops.prepare) - ret = rtd->cpu_dai->ops.prepare(substream); + if (cpu_dai->ops.prepare) { + ret = cpu_dai->ops.prepare(substream); + if (ret < 0) { + printk(KERN_ERR "asoc: cpu DAI prepare error\n"); + goto out; + } + } /* we only want to start a DAPM playback stream if we are not waiting * on an existing one stopping */ - if (rtd->codec_dai->pop_wait) { + if (codec_dai->pop_wait) { /* we are waiting for the delayed work to start */ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) - snd_soc_dapm_stream_event(codec, - rtd->codec_dai->capture.stream_name, + snd_soc_dapm_stream_event(socdev->codec, + codec_dai->capture.stream_name, SND_SOC_DAPM_STREAM_START); else { - rtd->codec_dai->pop_wait = 0; + codec_dai->pop_wait = 0; cancel_delayed_work(&socdev->delayed_work); - if (rtd->codec_dai->digital_mute) - rtd->codec_dai->digital_mute(codec, rtd->codec_dai, 0); + if (codec_dai->dai_ops.digital_mute) + codec_dai->dai_ops.digital_mute(codec_dai, 0); } } else { /* no delayed work - do we need to power up codec */ @@ -901,30 +437,30 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) snd_soc_dapm_stream_event(codec, - rtd->codec_dai->playback.stream_name, + codec_dai->playback.stream_name, SND_SOC_DAPM_STREAM_START); else snd_soc_dapm_stream_event(codec, - rtd->codec_dai->capture.stream_name, + codec_dai->capture.stream_name, SND_SOC_DAPM_STREAM_START); if (codec->dapm_event) codec->dapm_event(codec, SNDRV_CTL_POWER_D0); - if (rtd->codec_dai->digital_mute) - rtd->codec_dai->digital_mute(codec, rtd->codec_dai, 0); + if (codec_dai->dai_ops.digital_mute) + codec_dai->dai_ops.digital_mute(codec_dai, 0); } else { /* codec already powered - power on widgets */ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) snd_soc_dapm_stream_event(codec, - rtd->codec_dai->playback.stream_name, + codec_dai->playback.stream_name, SND_SOC_DAPM_STREAM_START); else snd_soc_dapm_stream_event(codec, - rtd->codec_dai->capture.stream_name, + codec_dai->capture.stream_name, SND_SOC_DAPM_STREAM_START); - if (rtd->codec_dai->digital_mute) - rtd->codec_dai->digital_mute(codec, rtd->codec_dai, 0); + if (codec_dai->dai_ops.digital_mute) + codec_dai->dai_ops.digital_mute(codec_dai, 0); } } @@ -943,39 +479,36 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_dai_link *machine = rtd->dai; struct snd_soc_platform *platform = socdev->platform; - struct snd_soc_machine *machine = socdev->machine; + struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai; + struct snd_soc_codec_dai *codec_dai = machine->codec_dai; int ret = 0; mutex_lock(&pcm_mutex); - /* we don't need to match any AC97 params */ - if (rtd->cpu_dai->type != SND_SOC_DAI_AC97) { - ret = soc_hw_match_params(substream, params); - if (ret < 0) - goto out; - } else { - struct snd_soc_clock_info clk_info; - clk_info.rate = params_rate(params); - ret = soc_get_mclk(rtd, &clk_info); - if (ret < 0) + if (machine->ops && machine->ops->hw_params) { + ret = machine->ops->hw_params(substream, params); + if (ret < 0) { + printk(KERN_ERR "asoc: machine hw_params failed\n"); goto out; + } } - if (rtd->codec_dai->ops.hw_params) { - ret = rtd->codec_dai->ops.hw_params(substream, params); + if (codec_dai->ops.hw_params) { + ret = codec_dai->ops.hw_params(substream, params); if (ret < 0) { printk(KERN_ERR "asoc: can't set codec %s hw params\n", - rtd->codec_dai->name); - goto out; + codec_dai->name); + goto codec_err; } } - if (rtd->cpu_dai->ops.hw_params) { - ret = rtd->cpu_dai->ops.hw_params(substream, params); + if (cpu_dai->ops.hw_params) { + ret = cpu_dai->ops.hw_params(substream, params); if (ret < 0) { printk(KERN_ERR "asoc: can't set interface %s hw params\n", - rtd->cpu_dai->name); + cpu_dai->name); goto interface_err; } } @@ -989,29 +522,21 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, } } - if (machine->ops && machine->ops->hw_params) { - ret = machine->ops->hw_params(substream, params); - if (ret < 0) { - printk(KERN_ERR "asoc: machine hw_params failed\n"); - goto machine_err; - } - } - out: mutex_unlock(&pcm_mutex); return ret; -machine_err: - if (platform->pcm_ops->hw_free) - platform->pcm_ops->hw_free(substream); - platform_err: - if (rtd->cpu_dai->ops.hw_free) - rtd->cpu_dai->ops.hw_free(substream); + if (cpu_dai->ops.hw_free) + cpu_dai->ops.hw_free(substream); interface_err: - if (rtd->codec_dai->ops.hw_free) - rtd->codec_dai->ops.hw_free(substream); + if (codec_dai->ops.hw_free) + codec_dai->ops.hw_free(substream); + +codec_err: + if(machine->ops && machine->ops->hw_free) + machine->ops->hw_free(substream); mutex_unlock(&pcm_mutex); return ret; @@ -1024,15 +549,17 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_dai_link *machine = rtd->dai; struct snd_soc_platform *platform = socdev->platform; + struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai; + struct snd_soc_codec_dai *codec_dai = machine->codec_dai; struct snd_soc_codec *codec = socdev->codec; - struct snd_soc_machine *machine = socdev->machine; mutex_lock(&pcm_mutex); /* apply codec digital mute */ - if (!codec->active && rtd->codec_dai->digital_mute) - rtd->codec_dai->digital_mute(codec, rtd->codec_dai, 1); + if (!codec->active && codec_dai->dai_ops.digital_mute) + codec_dai->dai_ops.digital_mute(codec_dai, 1); /* free any machine hw params */ if (machine->ops && machine->ops->hw_free) @@ -1043,11 +570,11 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) platform->pcm_ops->hw_free(substream); /* now free hw params for the DAI's */ - if (rtd->codec_dai->ops.hw_free) - rtd->codec_dai->ops.hw_free(substream); + if (codec_dai->ops.hw_free) + codec_dai->ops.hw_free(substream); - if (rtd->cpu_dai->ops.hw_free) - rtd->cpu_dai->ops.hw_free(substream); + if (cpu_dai->ops.hw_free) + cpu_dai->ops.hw_free(substream); mutex_unlock(&pcm_mutex); return 0; @@ -1057,11 +584,14 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_dai_link *machine = rtd->dai; struct snd_soc_platform *platform = socdev->platform; + struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai; + struct snd_soc_codec_dai *codec_dai = machine->codec_dai; int ret; - if (rtd->codec_dai->ops.trigger) { - ret = rtd->codec_dai->ops.trigger(substream, cmd); + if (codec_dai->ops.trigger) { + ret = codec_dai->ops.trigger(substream, cmd); if (ret < 0) return ret; } @@ -1072,8 +602,8 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) return ret; } - if (rtd->cpu_dai->ops.trigger) { - ret = rtd->cpu_dai->ops.trigger(substream, cmd); + if (cpu_dai->ops.trigger) { + ret = cpu_dai->ops.trigger(substream, cmd); if (ret < 0) return ret; } @@ -1104,8 +634,8 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) /* mute any active DAC's */ for(i = 0; i < machine->num_links; i++) { struct snd_soc_codec_dai *dai = machine->dai_link[i].codec_dai; - if (dai->digital_mute && dai->playback.active) - dai->digital_mute(codec, dai, 1); + if (dai->dai_ops.digital_mute && dai->playback.active) + dai->dai_ops.digital_mute(dai, 1); } if (machine->suspend_pre) @@ -1185,8 +715,8 @@ static int soc_resume(struct platform_device *pdev) /* unmute any active DAC's */ for(i = 0; i < machine->num_links; i++) { struct snd_soc_codec_dai *dai = machine->dai_link[i].codec_dai; - if (dai->digital_mute && dai->playback.active) - dai->digital_mute(codec, dai, 0); + if (dai->dai_ops.digital_mute && dai->playback.active) + dai->dai_ops.digital_mute(dai, 0); } for(i = 0; i < machine->num_links; i++) { @@ -1320,9 +850,10 @@ static int soc_new_pcm(struct snd_soc_device *socdev, rtd = kzalloc(sizeof(struct snd_soc_pcm_runtime), GFP_KERNEL); if (rtd == NULL) return -ENOMEM; - rtd->cpu_dai = cpu_dai; - rtd->codec_dai = codec_dai; + + rtd->dai = dai_link; rtd->socdev = socdev; + codec_dai->codec = socdev->codec; /* check client and interface hw capabilities */ sprintf(new_name, "%s %s-%s-%d",dai_link->stream_name, codec_dai->name, @@ -1498,22 +1029,6 @@ int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg, } EXPORT_SYMBOL_GPL(snd_soc_test_bits); -/** - * snd_soc_get_rate - get int sample rate - * @hwpcmrate: the hardware pcm rate - * - * Returns the audio rate integaer value, else 0. - */ -int snd_soc_get_rate(int hwpcmrate) -{ - int rate = ffs(hwpcmrate) - 1; - - if (rate > ARRAY_SIZE(rates)) - return 0; - return rates[rate]; -} -EXPORT_SYMBOL_GPL(snd_soc_get_rate); - /** * snd_soc_new_pcms - create new sound card and pcms * @socdev: the SoC audio device -- cgit v1.2.3 From 11da21a79048472a14b201120c0c50b10060220b Mon Sep 17 00:00:00 2001 From: Seth Forshee Date: Fri, 2 Feb 2007 17:14:19 +0100 Subject: [ALSA] soc - 0.13 ASoC DAPM bug fix for unnamed streams This patch fixes a bug whereby an unnamed stream would cause a NULL pointer ref in snd_soc_dapm_stream_event(). Signed-off-by: Seth Forshee Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/soc-dapm.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound') diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 5c2a34956a5..d0162a4cb7f 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1239,6 +1239,9 @@ int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, { struct snd_soc_dapm_widget *w; + if (stream == NULL) + return 0; + mutex_lock(&codec->mutex); list_for_each_entry(w, &codec->dapm_widgets, list) { -- cgit v1.2.3 From b36d61d45654104c04ff71055ef09c696fea5f89 Mon Sep 17 00:00:00 2001 From: Frank Mandarino Date: Fri, 2 Feb 2007 17:14:56 +0100 Subject: [ALSA] soc - ASoC 0.13 WM8731 codec This patch updates the WM8731 codec driver to the new API in ASoC 0.13. Changes:- o Removed DAI capabilities matching code in favour of manual matching in the machine drivers. o Added DAI operations for codec and CPU interfaces. o Removed config_sysclk() function and struct snd_soc_clock_info. No longer needed as clocking is now configured manually in the machine drivers. Also removed other clocking data from structures. Signed-off-by: Frank Mandarino Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/codecs/wm8731.c | 379 +++++++++++++++------------------------------- sound/soc/codecs/wm8731.h | 3 + 2 files changed, 127 insertions(+), 255 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 82f440fcf29..e6b990507df 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -30,7 +30,7 @@ #include "wm8731.h" #define AUDIO_NAME "wm8731" -#define WM8731_VERSION "0.12" +#define WM8731_VERSION "0.13" /* * Debug @@ -53,6 +53,11 @@ struct snd_soc_codec_device soc_codec_dev_wm8731; +/* codec private data */ +struct wm8731_priv { + unsigned int sysclk; +}; + /* * wm8731 register cache * We can't read the WM8731 register space when we are @@ -65,191 +70,6 @@ static const u16 wm8731_reg[WM8731_CACHEREGNUM] = { 0x0000, 0x0000 }; -#define WM8731_DAIFMT \ - (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_RIGHT_J | \ - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_NB_IF | SND_SOC_DAIFMT_IB_NF | \ - SND_SOC_DAIFMT_IB_IF) - -#define WM8731_DIR \ - (SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE) - -#define WM8731_RATES \ - (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \ - SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ - SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) - -#define WM8731_HIFI_BITS \ - (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ - SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) - -static struct snd_soc_dai_mode wm8731_modes[] = { - /* codec frame and clock master modes */ - /* 8k */ - { - .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8731_HIFI_BITS, - .pcmrate = SNDRV_PCM_RATE_8000, - .pcmdir = WM8731_DIR, - .flags = SND_SOC_DAI_BFS_RATE, - .fs = 1536, - .bfs = 64, - }, - { - .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8731_HIFI_BITS, - .pcmrate = SNDRV_PCM_RATE_8000, - .pcmdir = WM8731_DIR, - .flags = SND_SOC_DAI_BFS_RATE, - .fs = 2304, - .bfs = 64, - }, - { - .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8731_HIFI_BITS, - .pcmrate = SNDRV_PCM_RATE_8000, - .pcmdir = WM8731_DIR, - .flags = SND_SOC_DAI_BFS_RATE, - .fs = 1408, - .bfs = 64, - }, - { - .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8731_HIFI_BITS, - .pcmrate = SNDRV_PCM_RATE_8000, - .pcmdir = WM8731_DIR, - .flags = SND_SOC_DAI_BFS_RATE, - .fs = 2112, - .bfs = 64, - }, - - /* 32k */ - { - .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8731_HIFI_BITS, - .pcmrate = SNDRV_PCM_RATE_32000, - .pcmdir = WM8731_DIR, - .flags = SND_SOC_DAI_BFS_RATE, - .fs = 384, - .bfs = 64, - }, - { - .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8731_HIFI_BITS, - .pcmrate = SNDRV_PCM_RATE_32000, - .pcmdir = WM8731_DIR, - .flags = SND_SOC_DAI_BFS_RATE, - .fs = 576, - .bfs = 64, - }, - - /* 44.1k & 48k */ - { - .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8731_HIFI_BITS, - .pcmrate = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, - .pcmdir = WM8731_DIR, - .flags = SND_SOC_DAI_BFS_RATE, - .fs = 256, - .bfs = 64, - }, - { - .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8731_HIFI_BITS, - .pcmrate = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, - .pcmdir = WM8731_DIR, - .flags = SND_SOC_DAI_BFS_RATE, - .fs = 384, - .bfs = 64, - }, - - /* 88.2 & 96k */ - { - .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8731_HIFI_BITS, - .pcmrate = SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000, - .pcmdir = WM8731_DIR, - .flags = SND_SOC_DAI_BFS_RATE, - .fs = 128, - .bfs = 64, - }, - { - .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8731_HIFI_BITS, - .pcmrate = SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000, - .pcmdir = WM8731_DIR, - .flags = SND_SOC_DAI_BFS_RATE, - .fs = 192, - .bfs = 64, - }, - - /* USB codec frame and clock master modes */ - /* 8k */ - { - .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8731_HIFI_BITS, - .pcmrate = SNDRV_PCM_RATE_8000, - .pcmdir = WM8731_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 1500, - .bfs = SND_SOC_FSBD(1), - }, - - /* 44.1k */ - { - .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8731_HIFI_BITS, - .pcmrate = SNDRV_PCM_RATE_44100, - .pcmdir = WM8731_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 272, - .bfs = SND_SOC_FSBD(1), - }, - - /* 48k */ - { - .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8731_HIFI_BITS, - .pcmrate = SNDRV_PCM_RATE_48000, - .pcmdir = WM8731_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 250, - .bfs = SND_SOC_FSBD(1), - }, - - /* 88.2k */ - { - .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8731_HIFI_BITS, - .pcmrate = SNDRV_PCM_RATE_88200, - .pcmdir = WM8731_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 136, - .bfs = SND_SOC_FSBD(1), - }, - - /* 96k */ - { - .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8731_HIFI_BITS, - .pcmrate = SNDRV_PCM_RATE_96000, - .pcmdir = WM8731_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 125, - .bfs = SND_SOC_FSBD(1), - }, - - /* codec frame and clock slave modes */ - { - .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, - .pcmfmt = WM8731_HIFI_BITS, - .pcmrate = WM8731_RATES, - .pcmdir = WM8731_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = SND_SOC_FS_ALL, - .bfs = SND_SOC_FSB_ALL, - }, -}; - /* * read wm8731 register cache */ @@ -471,18 +291,34 @@ static inline int get_coeff(int mclk, int rate) return 0; } -/* WM8731 supports numerous clocks per sample rate */ -static unsigned int wm8731_config_sysclk(struct snd_soc_codec_dai *dai, - struct snd_soc_clock_info *info, unsigned int clk) +static int wm8731_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) { - dai->mclk = 0; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->codec; + struct wm8731_priv *wm8731 = codec->private_data; + u16 iface = wm8731_read_reg_cache(codec, WM8731_IFACE) & 0xfff3; + int i = get_coeff(wm8731->sysclk, params_rate(params)); + u16 srate = (coeff_div[i].sr << 2) | + (coeff_div[i].bosr << 1) | coeff_div[i].usb; - /* check that the calculated FS and rate actually match a clock from - * the machine driver */ - if (info->fs * info->rate == clk) - dai->mclk = clk; + wm8731_write(codec, WM8731_SRATE, srate); + + /* bit size */ + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + break; + case SNDRV_PCM_FORMAT_S20_3LE: + iface |= 0x0004; + break; + case SNDRV_PCM_FORMAT_S24_LE: + iface |= 0x0008; + break; + } - return dai->mclk; + wm8731_write(codec, WM8731_IFACE, iface); + return 0; } static int wm8731_pcm_prepare(struct snd_pcm_substream *substream) @@ -490,24 +326,76 @@ static int wm8731_pcm_prepare(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->codec; - u16 iface = 0, srate; - int i = get_coeff(rtd->codec_dai->mclk, - snd_soc_get_rate(rtd->codec_dai->dai_runtime.pcmrate)); + + /* set active */ + wm8731_write(codec, WM8731_ACTIVE, 0x0001); + + return 0; +} + +static void wm8731_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->codec; + + /* deactivate */ + if (!codec->active) { + udelay(50); + wm8731_write(codec, WM8731_ACTIVE, 0x0); + } +} + +static int wm8731_mute(struct snd_soc_codec_dai *dai, int mute) +{ + struct snd_soc_codec *codec = dai->codec; + u16 mute_reg = wm8731_read_reg_cache(codec, WM8731_APDIGI) & 0xfff7; + + if (mute) + wm8731_write(codec, WM8731_APDIGI, mute_reg | 0x8); + else + wm8731_write(codec, WM8731_APDIGI, mute_reg); + return 0; +} + +static int wm8731_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct wm8731_priv *wm8731 = codec->private_data; + + switch (freq) { + case 11289600: + case 12000000: + case 12288000: + case 16934400: + case 18432000: + wm8731->sysclk = freq; + return 0; + } + return -EINVAL; +} + + +static int wm8731_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, + unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + u16 iface = 0; /* set master/slave audio interface */ - switch (rtd->codec_dai->dai_runtime.fmt & SND_SOC_DAIFMT_CLOCK_MASK) { + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBM_CFM: iface |= 0x0040; break; case SND_SOC_DAIFMT_CBS_CFS: break; + default: + return -EINVAL; } - srate = (coeff_div[i].sr << 2) | - (coeff_div[i].bosr << 1) | coeff_div[i].usb; - wm8731_write(codec, WM8731_SRATE, srate); /* interface format */ - switch (rtd->codec_dai->dai_runtime.fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: iface |= 0x0002; break; @@ -522,25 +410,12 @@ static int wm8731_pcm_prepare(struct snd_pcm_substream *substream) case SND_SOC_DAIFMT_DSP_B: iface |= 0x0013; break; - } - - /* bit size */ - switch (rtd->codec_dai->dai_runtime.pcmfmt) { - case SNDRV_PCM_FMTBIT_S16_LE: - break; - case SNDRV_PCM_FMTBIT_S20_3LE: - iface |= 0x0004; - break; - case SNDRV_PCM_FMTBIT_S24_LE: - iface |= 0x0008; - break; - case SNDRV_PCM_FMTBIT_S32_LE: - iface |= 0x000c; - break; + default: + return -EINVAL; } /* clock inversion */ - switch (rtd->codec_dai->dai_runtime.fmt & SND_SOC_DAIFMT_INV_MASK) { + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { case SND_SOC_DAIFMT_NB_NF: break; case SND_SOC_DAIFMT_IB_IF: @@ -552,37 +427,12 @@ static int wm8731_pcm_prepare(struct snd_pcm_substream *substream) case SND_SOC_DAIFMT_NB_IF: iface |= 0x0010; break; + default: + return -EINVAL; } /* set iface */ wm8731_write(codec, WM8731_IFACE, iface); - - /* set active */ - wm8731_write(codec, WM8731_ACTIVE, 0x0001); - return 0; -} - -static void wm8731_shutdown(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_device *socdev = rtd->socdev; - struct snd_soc_codec *codec = socdev->codec; - - /* deactivate */ - if (!codec->active) { - udelay(50); - wm8731_write(codec, WM8731_ACTIVE, 0x0); - } -} - -static int wm8731_mute(struct snd_soc_codec *codec, - struct snd_soc_codec_dai *dai, int mute) -{ - u16 mute_reg = wm8731_read_reg_cache(codec, WM8731_APDIGI) & 0xfff7; - if (mute) - wm8731_write(codec, WM8731_APDIGI, mute_reg | 0x8); - else - wm8731_write(codec, WM8731_APDIGI, mute_reg); return 0; } @@ -612,28 +462,39 @@ static int wm8731_dapm_event(struct snd_soc_codec *codec, int event) return 0; } +#define WM8731_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ + SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\ + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\ + SNDRV_PCM_RATE_96000) + +#define WM8731_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ + SNDRV_PCM_FMTBIT_S24_LE) + struct snd_soc_codec_dai wm8731_dai = { .name = "WM8731", .playback = { .stream_name = "Playback", .channels_min = 1, .channels_max = 2, - }, + .rates = WM8731_RATES, + .formats = WM8731_FORMATS,}, .capture = { .stream_name = "Capture", .channels_min = 1, .channels_max = 2, - }, - .config_sysclk = wm8731_config_sysclk, - .digital_mute = wm8731_mute, + .rates = WM8731_RATES, + .formats = WM8731_FORMATS,}, .ops = { .prepare = wm8731_pcm_prepare, + .hw_params = wm8731_hw_params, .shutdown = wm8731_shutdown, }, - .caps = { - .num_modes = ARRAY_SIZE(wm8731_modes), - .mode = wm8731_modes, - }, + .dai_ops = { + .digital_mute = wm8731_mute, + .set_sysclk = wm8731_set_dai_sysclk, + .set_fmt = wm8731_set_dai_fmt, + } }; EXPORT_SYMBOL_GPL(wm8731_dai); @@ -683,7 +544,6 @@ static int wm8731_init(struct snd_soc_device *socdev) codec->dai = &wm8731_dai; codec->num_dai = 1; codec->reg_cache_size = ARRAY_SIZE(wm8731_reg); - codec->reg_cache = kzalloc(sizeof(u16) * ARRAY_SIZE(wm8731_reg), GFP_KERNEL); if (codec->reg_cache == NULL) @@ -832,6 +692,7 @@ static int wm8731_probe(struct platform_device *pdev) struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct wm8731_setup_data *setup; struct snd_soc_codec *codec; + struct wm8731_priv *wm8731; int ret = 0; info("WM8731 Audio Codec %s", WM8731_VERSION); @@ -841,6 +702,13 @@ static int wm8731_probe(struct platform_device *pdev) if (codec == NULL) return -ENOMEM; + wm8731 = kzalloc(sizeof(struct wm8731_priv), GFP_KERNEL); + if (wm8731 == NULL) { + kfree(codec); + return -ENOMEM; + } + + codec->private_data = wm8731; socdev->codec = codec; mutex_init(&codec->mutex); INIT_LIST_HEAD(&codec->dapm_widgets); @@ -875,6 +743,7 @@ static int wm8731_remove(struct platform_device *pdev) #if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE) i2c_del_driver(&wm8731_i2c_driver); #endif + kfree(codec->private_data); kfree(codec); return 0; diff --git a/sound/soc/codecs/wm8731.h b/sound/soc/codecs/wm8731.h index 8fa0f53bef1..5bcab6a7afb 100644 --- a/sound/soc/codecs/wm8731.h +++ b/sound/soc/codecs/wm8731.h @@ -31,6 +31,9 @@ #define WM8731_CACHEREGNUM 10 +#define WM8731_SYSCLK 0 +#define WM8731_DAI 0 + struct wm8731_setup_data { unsigned short i2c_address; }; -- cgit v1.2.3 From 4422b606bc04eab01dd5cb6f8e6dd0608d65bb11 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 2 Feb 2007 17:15:33 +0100 Subject: [ALSA] soc - ASoC 0.13 WM8750 codec driver This patch updates the WM8750 codec driver to the new API in ASoC 0.13. Changes:- o Removed DAI capabilities matching code in favour of manual matching in the machine drivers. o Added DAI operations for codec and CPU interfaces. o Removed config_sysclk() function and struct snd_soc_clock_info. No longer needed as clocking is now configured manually in the machine drivers. Also removed other clocking data from structures. Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/codecs/wm8750.c | 446 ++++++++++++---------------------------------- sound/soc/codecs/wm8750.h | 3 +- 2 files changed, 113 insertions(+), 336 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index d4a288ba644..c1ffb61ef7f 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c @@ -30,7 +30,7 @@ #include "wm8750.h" #define AUDIO_NAME "WM8750" -#define WM8750_VERSION "0.11" +#define WM8750_VERSION "0.12" /* * Debug @@ -51,6 +51,11 @@ #define warn(format, arg...) \ printk(KERN_WARNING AUDIO_NAME ": " format "\n" , ## arg) +/* codec private data */ +struct wm8750_priv { + unsigned int sysclk; +}; + /* * wm8750 register cache * We can't read the WM8750 register space when we @@ -70,280 +75,6 @@ static const u16 wm8750_reg[] = { 0x0079, 0x0079, 0x0079, /* 40 */ }; -#define WM8750_HIFI_DAIFMT \ - (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_RIGHT_J | \ - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_NB_IF | SND_SOC_DAIFMT_IB_NF | \ - SND_SOC_DAIFMT_IB_IF) - -#define WM8750_DIR \ - (SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE) - -#define WM8750_HIFI_FSB \ - (SND_SOC_FSBD(1) | SND_SOC_FSBD(2) | SND_SOC_FSBD(4) | \ - SND_SOC_FSBD(8) | SND_SOC_FSBD(16)) - -#define WM8750_HIFI_RATES \ - (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \ - SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ - SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) - -#define WM8750_HIFI_BITS \ - (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ - SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) - -static struct snd_soc_dai_mode wm8750_modes[] = { - /* common codec frame and clock master modes */ - /* 8k */ - { - .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8750_HIFI_BITS, - .pcmrate = SNDRV_PCM_RATE_8000, - .pcmdir = WM8750_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 1536, - .bfs = WM8750_HIFI_FSB, - }, - { - .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8750_HIFI_BITS, - .pcmrate = SNDRV_PCM_RATE_8000, - .pcmdir = WM8750_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 1408, - .bfs = WM8750_HIFI_FSB, - }, - { - .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8750_HIFI_BITS, - .pcmrate = SNDRV_PCM_RATE_8000, - .pcmdir = WM8750_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 2304, - .bfs = WM8750_HIFI_FSB, - }, - { - .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8750_HIFI_BITS, - .pcmrate = SNDRV_PCM_RATE_8000, - .pcmdir = WM8750_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 2112, - .bfs = WM8750_HIFI_FSB, - }, - { - .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8750_HIFI_BITS, - .pcmrate = SNDRV_PCM_RATE_8000, - .pcmdir = WM8750_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 1500, - .bfs = WM8750_HIFI_FSB, - }, - - /* 11.025k */ - { - .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8750_HIFI_BITS, - .pcmrate = SNDRV_PCM_RATE_11025, - .pcmdir = WM8750_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 1024, - .bfs = WM8750_HIFI_FSB, - }, - { - .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8750_HIFI_BITS, - .pcmrate = SNDRV_PCM_RATE_11025, - .pcmdir = WM8750_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 1536, - .bfs = WM8750_HIFI_FSB, - }, - { - .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8750_HIFI_BITS, - .pcmrate = SNDRV_PCM_RATE_11025, - .pcmdir = WM8750_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 1088, - .bfs = WM8750_HIFI_FSB, - }, - - /* 16k */ - { - .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8750_HIFI_BITS, - .pcmrate = SNDRV_PCM_RATE_16000, - .pcmdir = WM8750_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 768, - .bfs = WM8750_HIFI_FSB, - }, - { - .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8750_HIFI_BITS, - .pcmrate = SNDRV_PCM_RATE_16000, - .pcmdir = WM8750_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 1152, - .bfs = WM8750_HIFI_FSB - }, - { - .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8750_HIFI_BITS, - .pcmrate = SNDRV_PCM_RATE_16000, - .pcmdir = WM8750_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 750, - .bfs = WM8750_HIFI_FSB, - }, - - /* 22.05k */ - { - .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8750_HIFI_BITS, - .pcmrate = SNDRV_PCM_RATE_22050, - .pcmdir = WM8750_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 512, - .bfs = WM8750_HIFI_FSB, - }, - { - .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8750_HIFI_BITS, - .pcmrate = SNDRV_PCM_RATE_22050, - .pcmdir = WM8750_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 768, - .bfs = WM8750_HIFI_FSB, - }, - { - .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8750_HIFI_BITS, - .pcmrate = SNDRV_PCM_RATE_22050, - .pcmdir = WM8750_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 544, - .bfs = WM8750_HIFI_FSB, - }, - - /* 32k */ - { - .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8750_HIFI_BITS, - .pcmrate = SNDRV_PCM_RATE_32000, - .pcmdir = WM8750_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 384, - .bfs = WM8750_HIFI_FSB, - }, - { - .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8750_HIFI_BITS, - .pcmrate = SNDRV_PCM_RATE_32000, - .pcmdir = WM8750_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 576, - .bfs = WM8750_HIFI_FSB, - }, - { - .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8750_HIFI_BITS, - .pcmrate = SNDRV_PCM_RATE_32000, - .pcmdir = WM8750_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 375, - .bfs = WM8750_HIFI_FSB, - }, - - /* 44.1k & 48k */ - { - .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8750_HIFI_BITS, - .pcmrate = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, - .pcmdir = WM8750_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 256, - .bfs = WM8750_HIFI_FSB, - }, - { - .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8750_HIFI_BITS, - .pcmrate = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, - .pcmdir = WM8750_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 384, - .bfs = WM8750_HIFI_FSB, - }, - { - .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8750_HIFI_BITS, - .pcmrate = SNDRV_PCM_RATE_44100, - .pcmdir = WM8750_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 272, - .bfs = WM8750_HIFI_FSB, - }, - { - .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8750_HIFI_BITS, - .pcmrate = SNDRV_PCM_RATE_48000, - .pcmdir = WM8750_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 250, - .bfs = WM8750_HIFI_FSB, - }, - - /* 88.2k & 96k */ - { - .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8750_HIFI_BITS, - .pcmrate = SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000, - .pcmdir = WM8750_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 128, - .bfs = WM8750_HIFI_FSB, - }, - { - .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8750_HIFI_BITS, - .pcmrate = SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000, - .pcmdir = WM8750_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 192, - .bfs = WM8750_HIFI_FSB, - }, - { - .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8750_HIFI_BITS, - .pcmrate = SNDRV_PCM_RATE_88200, - .pcmdir = WM8750_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 136, - .bfs = WM8750_HIFI_FSB, - }, - { - .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, - .pcmfmt = WM8750_HIFI_BITS, - .pcmrate = SNDRV_PCM_RATE_96000, - .pcmdir = WM8750_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 125, - .bfs = WM8750_HIFI_FSB, - }, - - /* codec frame and clock slave modes */ - { - .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, - .pcmfmt = WM8750_HIFI_BITS, - .pcmrate = WM8750_HIFI_RATES, - .pcmdir = WM8750_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = SND_SOC_FS_ALL, - .bfs = SND_SOC_FSB_ALL, - }, -}; - /* * read wm8750 register cache */ @@ -834,40 +565,43 @@ static inline int get_coeff(int mclk, int rate) return -EINVAL; } -/* WM8750 supports numerous input clocks per sample rate */ -static unsigned int wm8750_config_sysclk(struct snd_soc_codec_dai *dai, - struct snd_soc_clock_info *info, unsigned int clk) +static int wm8750_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai, + int clk_id, unsigned int freq, int dir) { - dai->mclk = clk; - return dai->mclk; + struct snd_soc_codec *codec = codec_dai->codec; + struct wm8750_priv *wm8750 = codec->private_data; + + switch (freq) { + case 11289600: + case 12000000: + case 12288000: + case 16934400: + case 18432000: + wm8750->sysclk = freq; + return 0; + } + return -EINVAL; } -static int wm8750_pcm_prepare(struct snd_pcm_substream *substream) +static int wm8750_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, + unsigned int fmt) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_device *socdev = rtd->socdev; - struct snd_soc_codec *codec = socdev->codec; - u16 iface = 0, bfs, srate = 0; - int i = get_coeff(rtd->codec_dai->mclk, - snd_soc_get_rate(rtd->codec_dai->dai_runtime.pcmrate)); - - /* is coefficient valid ? */ - if (i < 0) - return i; - - bfs = SND_SOC_FSBD_REAL(rtd->codec_dai->dai_runtime.bfs); + struct snd_soc_codec *codec = codec_dai->codec; + u16 iface = 0; /* set master/slave audio interface */ - switch (rtd->codec_dai->dai_runtime.fmt & SND_SOC_DAIFMT_CLOCK_MASK) { + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBM_CFM: iface = 0x0040; break; case SND_SOC_DAIFMT_CBS_CFS: break; + default: + return -EINVAL; } /* interface format */ - switch (rtd->codec_dai->dai_runtime.fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: iface |= 0x0002; break; @@ -882,25 +616,12 @@ static int wm8750_pcm_prepare(struct snd_pcm_substream *substream) case SND_SOC_DAIFMT_DSP_B: iface |= 0x0013; break; - } - - /* bit size */ - switch (rtd->codec_dai->dai_runtime.pcmfmt) { - case SNDRV_PCM_FMTBIT_S16_LE: - break; - case SNDRV_PCM_FMTBIT_S20_3LE: - iface |= 0x0004; - break; - case SNDRV_PCM_FMTBIT_S24_LE: - iface |= 0x0008; - break; - case SNDRV_PCM_FMTBIT_S32_LE: - iface |= 0x000c; - break; + default: + return -EINVAL; } /* clock inversion */ - switch (rtd->codec_dai->dai_runtime.fmt & SND_SOC_DAIFMT_INV_MASK) { + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { case SND_SOC_DAIFMT_NB_NF: break; case SND_SOC_DAIFMT_IB_IF: @@ -912,35 +633,54 @@ static int wm8750_pcm_prepare(struct snd_pcm_substream *substream) case SND_SOC_DAIFMT_NB_IF: iface |= 0x0010; break; + default: + return -EINVAL; } - /* set bclk divisor rate */ - switch (bfs) { - case 1: + wm8750_write(codec, WM8750_IFACE, iface); + return 0; +} + +static int wm8750_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->codec; + struct wm8750_priv *wm8750 = codec->private_data; + u16 iface = wm8750_read_reg_cache(codec, WM8750_IFACE) & 0x1f3; + u16 srate = wm8750_read_reg_cache(codec, WM8750_SRATE) & 0x1c0; + int coeff = get_coeff(wm8750->sysclk, params_rate(params)); + + /* bit size */ + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: break; - case 4: - srate |= (0x1 << 7); + case SNDRV_PCM_FORMAT_S20_3LE: + iface |= 0x0004; break; - case 8: - srate |= (0x2 << 7); + case SNDRV_PCM_FORMAT_S24_LE: + iface |= 0x0008; break; - case 16: - srate |= (0x3 << 7); + case SNDRV_PCM_FORMAT_S32_LE: + iface |= 0x000c; break; } /* set iface & srate */ wm8750_write(codec, WM8750_IFACE, iface); - wm8750_write(codec, WM8750_SRATE, srate | - (coeff_div[i].sr << 1) | coeff_div[i].usb); + if (coeff >= 0) + wm8750_write(codec, WM8750_SRATE, srate | + (coeff_div[coeff].sr << 1) | coeff_div[coeff].usb); return 0; } -static int wm8750_mute(struct snd_soc_codec *codec, - struct snd_soc_codec_dai *dai, int mute) +static int wm8750_mute(struct snd_soc_codec_dai *dai, int mute) { + struct snd_soc_codec *codec = dai->codec; u16 mute_reg = wm8750_read_reg_cache(codec, WM8750_ADCDAC) & 0xfff7; + if (mute) wm8750_write(codec, WM8750_ADCDAC, mute_reg | 0x8); else @@ -974,26 +714,34 @@ static int wm8750_dapm_event(struct snd_soc_codec *codec, int event) return 0; } +#define WM8750_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ + SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) + +#define WM8750_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ + SNDRV_PCM_FMTBIT_S24_LE) + struct snd_soc_codec_dai wm8750_dai = { .name = "WM8750", .playback = { .stream_name = "Playback", .channels_min = 1, .channels_max = 2, - }, + .rates = WM8750_RATES, + .formats = WM8750_FORMATS,}, .capture = { .stream_name = "Capture", .channels_min = 1, .channels_max = 2, - }, - .config_sysclk = wm8750_config_sysclk, - .digital_mute = wm8750_mute, + .rates = WM8750_RATES, + .formats = WM8750_FORMATS,}, .ops = { - .prepare = wm8750_pcm_prepare, + .hw_params = wm8750_pcm_hw_params, }, - .caps = { - .num_modes = ARRAY_SIZE(wm8750_modes), - .mode = wm8750_modes, + .dai_ops = { + .digital_mute = wm8750_mute, + .set_fmt = wm8750_set_dai_fmt, + .set_sysclk = wm8750_set_dai_sysclk, }, }; EXPORT_SYMBOL_GPL(wm8750_dai); @@ -1037,8 +785,7 @@ static int wm8750_resume(struct platform_device *pdev) if (codec->suspend_dapm_state == SNDRV_CTL_POWER_D0) { wm8750_dapm_event(codec, SNDRV_CTL_POWER_D2); codec->dapm_state = SNDRV_CTL_POWER_D0; - schedule_delayed_work(&codec->delayed_work, - msecs_to_jiffies(1000)); + schedule_delayed_work(&codec->delayed_work, msecs_to_jiffies(1000)); } return 0; @@ -1218,6 +965,7 @@ static int wm8750_probe(struct platform_device *pdev) struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct wm8750_setup_data *setup = socdev->codec_data; struct snd_soc_codec *codec; + struct wm8750_priv *wm8750; int ret = 0; info("WM8750 Audio Codec %s", WM8750_VERSION); @@ -1225,12 +973,20 @@ static int wm8750_probe(struct platform_device *pdev) if (codec == NULL) return -ENOMEM; + wm8750 = kzalloc(sizeof(struct wm8750_priv), GFP_KERNEL); + if (wm8750 == NULL) { + kfree(codec); + return -ENOMEM; + } + + codec->private_data = wm8750; socdev->codec = codec; mutex_init(&codec->mutex); INIT_LIST_HEAD(&codec->dapm_widgets); INIT_LIST_HEAD(&codec->dapm_paths); wm8750_socdev = socdev; INIT_DELAYED_WORK(&codec->delayed_work, wm8750_work); + #if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE) if (setup->i2c_address) { normal_i2c[0] = setup->i2c_address; @@ -1246,6 +1002,25 @@ static int wm8750_probe(struct platform_device *pdev) return ret; } +/* + * This function forces any delayed work to be queued and run. + */ +static int run_delayed_work(struct delayed_work *dwork) +{ + int ret; + + /* cancel any work waiting to be queued. */ + ret = cancel_delayed_work(dwork); + + /* if there was any work waiting then we run it now and + * wait for it's completion */ + if (ret) { + schedule_delayed_work(dwork, 0); + flush_scheduled_work(); + } + return ret; +} + /* power down chip */ static int wm8750_remove(struct platform_device *pdev) { @@ -1254,12 +1029,13 @@ static int wm8750_remove(struct platform_device *pdev) if (codec->control_data) wm8750_dapm_event(codec, SNDRV_CTL_POWER_D3cold); - flush_scheduled_work(); + run_delayed_work(&codec->delayed_work); snd_soc_free_pcms(socdev); snd_soc_dapm_free(socdev); #if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE) i2c_del_driver(&wm8750_i2c_driver); #endif + kfree(codec->private_data); kfree(codec); return 0; diff --git a/sound/soc/codecs/wm8750.h b/sound/soc/codecs/wm8750.h index ee5eea4a2d3..a97a54a6348 100644 --- a/sound/soc/codecs/wm8750.h +++ b/sound/soc/codecs/wm8750.h @@ -55,9 +55,10 @@ #define WM8750_CACHE_REGNUM 0x2a +#define WM8750_SYSCLK 0 + struct wm8750_setup_data { unsigned short i2c_address; - unsigned int mclk; }; extern struct snd_soc_codec_dai wm8750_dai; -- cgit v1.2.3 From cbe83b1795feea33803dc89fce18b2b98abbcc9b Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 2 Feb 2007 17:16:02 +0100 Subject: [ALSA] soc - ASoC 0.13 WM9712 codec driver This patch updates the WM9712 codec driver to the new API in ASoC 0.13. Changes:- o Removed DAI capabilities matching code in favour of manual matching in the machine drivers. o Added DAI operations for codec and CPU interfaces. o Removed config_sysclk() function and struct snd_soc_clock_info. No longer needed as clocking is now configured manually in the machine drivers. Also removed other clocking data from structures. Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/codecs/wm9712.c | 44 +++++++++++++++----------------------------- 1 file changed, 15 insertions(+), 29 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index b2d2d03b954..92a64871bcd 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -34,23 +34,6 @@ static unsigned int ac97_read(struct snd_soc_codec *codec, static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int val); -#define AC97_DIR \ - (SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE) - -#define AC97_RATES \ - (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \ - SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ - SNDRV_PCM_RATE_48000) - -/* may need to expand this */ -static struct snd_soc_dai_mode ac97_modes[] = { - { - .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE, - .pcmrate = AC97_RATES, - .pcmdir = AC97_DIR, - }, -}; - /* * WM9712 register cache */ @@ -554,35 +537,38 @@ static int ac97_aux_prepare(struct snd_pcm_substream *substream) return ac97_write(codec, AC97_PCM_SURR_DAC_RATE, runtime->rate); } +#define WM9712_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ + SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) + struct snd_soc_codec_dai wm9712_dai[] = { { .name = "AC97 HiFi", .playback = { .stream_name = "HiFi Playback", .channels_min = 1, - .channels_max = 2,}, + .channels_max = 2, + .rates = WM9712_AC97_RATES, + .formats = SNDRV_PCM_FMTBIT_S16_LE,}, .capture = { .stream_name = "HiFi Capture", .channels_min = 1, - .channels_max = 2,}, + .channels_max = 2, + .rates = WM9712_AC97_RATES, + .formats = SNDRV_PCM_FMTBIT_S16_LE,}, .ops = { .prepare = ac97_prepare,}, - .caps = { - .num_modes = ARRAY_SIZE(ac97_modes), - .mode = ac97_modes,}, - }, - { +}, +{ .name = "AC97 Aux", .playback = { .stream_name = "Aux Playback", .channels_min = 1, - .channels_max = 1,}, + .channels_max = 1, + .rates = WM9712_AC97_RATES, + .formats = SNDRV_PCM_FMTBIT_S16_LE,}, .ops = { .prepare = ac97_aux_prepare,}, - .caps = { - .num_modes = ARRAY_SIZE(ac97_modes), - .mode = ac97_modes,}, - }, +} }; EXPORT_SYMBOL_GPL(wm9712_dai); -- cgit v1.2.3 From 5a8ec343c5ba1e78ba23bebd9ad4b23f39c50828 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 2 Feb 2007 17:16:41 +0100 Subject: [ALSA] soc - ASoC 0.13 generic AC97 codec This patch updates the AC97 codec driver to the new API in ASoC 0.13. Changes:- o Removed DAI capabilities matching code in favour of manual matching in the machine drivers. Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/codecs/ac97.c | 31 ++++++++++--------------------- 1 file changed, 10 insertions(+), 21 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c index dd1a9f579a6..55bc55eb6e2 100644 --- a/sound/soc/codecs/ac97.c +++ b/sound/soc/codecs/ac97.c @@ -26,22 +26,7 @@ #include #include -#define AC97_VERSION "0.5" - -#define AC97_DIR \ - (SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE) - -#define AC97_RATES \ - (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \ - SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ - SNDRV_PCM_RATE_48000) - -/* may need to expand this */ -static struct snd_soc_dai_mode soc_ac97[] = { - {0, 0, SNDRV_PCM_FMTBIT_S16_LE, AC97_RATES}, - {0, 0, SNDRV_PCM_FMTBIT_S18_3LE, AC97_RATES}, - {0, 0, SNDRV_PCM_FMTBIT_S20_3LE, AC97_RATES}, -}; +#define AC97_VERSION "0.6" static int ac97_prepare(struct snd_pcm_substream *substream) { @@ -55,21 +40,25 @@ static int ac97_prepare(struct snd_pcm_substream *substream) return snd_ac97_set_rate(codec->ac97, reg, runtime->rate); } +#define STD_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ + SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) + static struct snd_soc_codec_dai ac97_dai = { .name = "AC97 HiFi", .playback = { .stream_name = "AC97 Playback", .channels_min = 1, - .channels_max = 2,}, + .channels_max = 2, + .rates = STD_AC97_RATES, + .formats = SNDRV_PCM_FMTBIT_S16_LE,}, .capture = { .stream_name = "AC97 Capture", .channels_min = 1, - .channels_max = 2,}, + .channels_max = 2, + .rates = STD_AC97_RATES, + .formats = SNDRV_PCM_FMTBIT_S16_LE,}, .ops = { .prepare = ac97_prepare,}, - .caps = { - .num_modes = ARRAY_SIZE(soc_ac97), - .mode = soc_ac97,}, }; static unsigned int ac97_read(struct snd_soc_codec *codec, -- cgit v1.2.3 From d3d35adc79aa2e48e8177a9506e9bcb5eebba406 Mon Sep 17 00:00:00 2001 From: Frank Mandarino Date: Fri, 2 Feb 2007 17:17:39 +0100 Subject: [ALSA] soc - ASoC 0.13 AT91xxxx slave patch This patch adds support for I2S slave mode for the ETI_B1 machine from Endrelia. Signed-off-by: Frank Mandarino Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/at91/Kconfig | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/at91/Kconfig b/sound/soc/at91/Kconfig index d38ba9203bd..5bcf08b728b 100644 --- a/sound/soc/at91/Kconfig +++ b/sound/soc/at91/Kconfig @@ -13,12 +13,20 @@ config SND_AT91_SOC_I2S tristate config SND_AT91_SOC_ETI_B1_WM8731 - tristate "SoC I2S Audio support for Endrelia ETI-B1 board" - depends on SND_AT91_SOC && MACH_ETI_B1 + tristate "SoC I2S Audio support for WM8731-based Endrelia ETI-B1 boards" + depends on SND_AT91_SOC && (MACH_ETI_B1 || MACH_ETI_C1) select SND_AT91_SOC_I2S select SND_SOC_WM8731 help - Say Y if you want to add support for SoC audio on Endrelia - ETI-B1 board. + Say Y if you want to add support for SoC audio on WM8731-based + Endrelia Technologies Inc ETI-B1 or ETI-C1 boards. + +config SND_AT91_SOC_ETI_SLAVE + bool "Run codec in slave Mode on Endrelia boards" + depends on SND_AT91_SOC_ETI_B1_WM8731 + default n + help + Say Y if you want to run with the AT91 SSC generating the BCLK + and LRC signals on Endrelia boards. endmenu -- cgit v1.2.3 From 171eb8f81d7b0706c1085d272e4955251ed9f05f Mon Sep 17 00:00:00 2001 From: Frank Mandarino Date: Fri, 2 Feb 2007 17:18:38 +0100 Subject: [ALSA] soc - ASoC 0.13 AT91xxxx I2S This patch updates the AT91xxxx I2S driver to the new API in ASoC 0.13. Changes:- o Removed DAI capabilities matching code in favour of manual matching in the machine drivers. o Added DAI operations for codec and CPU interfaces. o Removed config_sysclk() function and struct snd_soc_clock_info. No longer needed as clocking is now configured manually in the machine drivers. Also removed other clocking data from structures. Signed-off-by: Frank Mandarino Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/at91/at91-i2s.c | 618 ++++++++++++++++++++++++---------------------- sound/soc/at91/at91-i2s.h | 27 ++ 2 files changed, 356 insertions(+), 289 deletions(-) create mode 100644 sound/soc/at91/at91-i2s.h (limited to 'sound') diff --git a/sound/soc/at91/at91-i2s.c b/sound/soc/at91/at91-i2s.c index 876d391c701..fcc544a96ba 100644 --- a/sound/soc/at91/at91-i2s.c +++ b/sound/soc/at91/at91-i2s.c @@ -12,8 +12,6 @@ * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * - * Revision history - * 3rd Mar 2006 Initial version. */ #include @@ -34,6 +32,7 @@ #include #include "at91-pcm.h" +#include "at91-i2s.h" #if 0 #define DBG(x...) printk(KERN_DEBUG "at91-i2s:" x) @@ -48,65 +47,6 @@ #endif -#define AT91_I2S_DAIFMT \ - (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_NB_NF) - -#define AT91_I2S_DIR \ - (SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE) - -/* priv is (SSC_CMR.DIV << 16 | SSC_TCMR.PERIOD ) */ -static struct snd_soc_dai_mode at91_i2s[] = { - - /* 8k: BCLK = (MCLK/10) = (60MHz/50) = 1.2MHz */ - { - .fmt = AT91_I2S_DAIFMT, - .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, - .pcmrate = SNDRV_PCM_RATE_8000, - .pcmdir = AT91_I2S_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 1500, - .bfs = SND_SOC_FSBD(10), - .priv = (25 << 16 | 74), - }, - - /* 16k: BCLK = (MCLK/3) ~= (60MHz/14) = 4.285714MHz */ - { - .fmt = AT91_I2S_DAIFMT, - .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, - .pcmrate = SNDRV_PCM_RATE_16000, - .pcmdir = AT91_I2S_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 750, - .bfs = SND_SOC_FSBD(3), - .priv = (7 << 16 | 133), - }, - - /* 32k: BCLK = (MCLK/3) ~= (60MHz/14) = 4.285714MHz */ - { - .fmt = AT91_I2S_DAIFMT, - .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, - .pcmrate = SNDRV_PCM_RATE_32000, - .pcmdir = AT91_I2S_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 375, - .bfs = SND_SOC_FSBD(3), - .priv = (7 << 16 | 66), - }, - - /* 48k: BCLK = (MCLK/5) ~= (60MHz/26) = 2.3076923MHz */ - { - .fmt = AT91_I2S_DAIFMT, - .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, - .pcmrate = SNDRV_PCM_RATE_48000, - .pcmdir = AT91_I2S_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 250, - .bfs = SND_SOC_FSBD(5), - .priv = (13 << 16 | 23), - }, -}; - - /* * SSC PDC registers required by the PCM DMA engine. */ @@ -184,21 +124,6 @@ static struct at91_pcm_dma_params ssc_dma_params[NUM_SSC_DEVICES][2] = { #endif }; - -/* - * A MUTEX is used to protect an SSC initialzed flag which allows - * the substream hw_params() call to initialize the SSC only if - * there are no other substreams open. If there are other - * substreams open, the hw_param() call can only check that - * it is using the same format and rate. - */ -static DECLARE_MUTEX(ssc0_mutex); -#if NUM_SSC_DEVICES == 3 -static DECLARE_MUTEX(ssc1_mutex); -static DECLARE_MUTEX(ssc2_mutex); -#endif - - struct at91_ssc_state { u32 ssc_cmr; u32 ssc_rcmr; @@ -209,16 +134,16 @@ struct at91_ssc_state { u32 ssc_imr; }; - static struct at91_ssc_info { char *name; struct at91_ssc_periph ssc; spinlock_t lock; /* lock for dir_mask */ - int dir_mask; /* 0=unused, 1=playback, 2=capture */ - struct semaphore *mutex; - int initialized; - int pcmfmt; - int rate; + unsigned short dir_mask; /* 0=unused, 1=playback, 2=capture */ + unsigned short initialized; /* 1=SSC has been initialized */ + unsigned short daifmt; + unsigned short cmr_div; + unsigned short tcmr_period; + unsigned short rcmr_period; struct at91_pcm_dma_params *dma_params[2]; struct at91_ssc_state ssc_state; @@ -227,7 +152,6 @@ static struct at91_ssc_info { .name = "ssc0", .lock = SPIN_LOCK_UNLOCKED, .dir_mask = 0, - .mutex = &ssc0_mutex, .initialized = 0, }, #if NUM_SSC_DEVICES == 3 @@ -235,20 +159,23 @@ static struct at91_ssc_info { .name = "ssc1", .lock = SPIN_LOCK_UNLOCKED, .dir_mask = 0, - .mutex = &ssc1_mutex, .initialized = 0, }, { .name = "ssc2", .lock = SPIN_LOCK_UNLOCKED, .dir_mask = 0, - .mutex = &ssc2_mutex, .initialized = 0, }, #endif }; +static unsigned int at91_i2s_sysclk; +/* + * SSC interrupt handler. Passes PDC interrupts to the DMA + * interrupt handler in the PCM driver. + */ static irqreturn_t at91_i2s_interrupt(int irq, void *dev_id) { struct at91_ssc_info *ssc_p = dev_id; @@ -278,10 +205,13 @@ static irqreturn_t at91_i2s_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } +/* + * Startup. Only that one substream allowed in each direction. + */ static int at91_i2s_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct at91_ssc_info *ssc_p = &ssc_info[rtd->cpu_dai->id]; + struct at91_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; int dir_mask; DBG("i2s_startup: SSC_SR=0x%08lx\n", @@ -296,24 +226,22 @@ static int at91_i2s_startup(struct snd_pcm_substream *substream) ssc_p->dir_mask |= dir_mask; spin_unlock_irq(&ssc_p->lock); - /* - * dma_data is not set until hw_params() is called and - * shutdown() depends on this value being NULL if hw_params() - * was not called. - */ - rtd->cpu_dai->dma_data = NULL; - return 0; } +/* + * Shutdown. Clear DMA parameters and shutdown the SSC if there + * are no other substreams open. + */ static void at91_i2s_shutdown(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct at91_ssc_info *ssc_p = &ssc_info[rtd->cpu_dai->id]; - struct at91_pcm_dma_params *dma_params = rtd->cpu_dai->dma_data; + struct at91_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; + struct at91_pcm_dma_params *dma_params; int dir, dir_mask; dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1; + dma_params = ssc_p->dma_params[dir]; if (dma_params != NULL) { at91_ssc_write(dma_params->ssc_base + AT91_SSC_CR, @@ -335,99 +263,107 @@ static void at91_i2s_shutdown(struct snd_pcm_substream *substream) DBG("Stopping pid %d clock\n", ssc_p->ssc.pid); at91_sys_write(AT91_PMC_PCDR, 1<ssc.pid); - if (ssc_p->initialized) + if (ssc_p->initialized) { free_irq(ssc_p->ssc.pid, ssc_p); + ssc_p->initialized = 0; + } /* Reset the SSC */ at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR, AT91_SSC_SWRST); - /* Force a re-init on the next hw_params() call. */ - ssc_p->initialized = 0; + /* Clear the SSC dividers */ + ssc_p->cmr_div = ssc_p->tcmr_period = ssc_p->rcmr_period = 0; } spin_unlock_irq(&ssc_p->lock); } -#ifdef CONFIG_PM -static int at91_i2s_suspend(struct platform_device *pdev, - struct snd_soc_cpu_dai *dai) +/* + * Record the SSC system clock rate. + */ +static int at91_i2s_set_dai_sysclk(struct snd_soc_cpu_dai *cpu_dai, + int clk_id, unsigned int freq, int dir) { - struct at91_ssc_info *ssc_p; - - if(!dai->active) - return 0; - - ssc_p = &ssc_info[dai->id]; - - /* Save the status register before disabling transmit and receive. */ - ssc_p->ssc_state.ssc_sr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR); - at91_ssc_write(ssc_p->ssc.base + - AT91_SSC_CR, AT91_SSC_TXDIS | AT91_SSC_RXDIS); - - /* Save the current interrupt mask, then disable unmasked interrupts. */ - ssc_p->ssc_state.ssc_imr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_IMR); - at91_ssc_write(ssc_p->ssc.base + AT91_SSC_IDR, ssc_p->ssc_state.ssc_imr); - - ssc_p->ssc_state.ssc_cmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_CMR); - ssc_p->ssc_state.ssc_rcmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_RCMR); - ssc_p->ssc_state.ssc_rfmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_RCMR); - ssc_p->ssc_state.ssc_tcmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_RCMR); - ssc_p->ssc_state.ssc_tfmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_RCMR); + /* + * The only clock supplied to the SSC is the AT91 master clock, + * which is only used if the SSC is generating BCLK and/or + * LRC clocks. + */ + switch (clk_id) { + case AT91_SYSCLK_MCK: + at91_i2s_sysclk = freq; + break; + default: + return -EINVAL; + } return 0; } -static int at91_i2s_resume(struct platform_device *pdev, - struct snd_soc_cpu_dai *dai) +/* + * Record the DAI format for use in hw_params(). + */ +static int at91_i2s_set_dai_fmt(struct snd_soc_cpu_dai *cpu_dai, + unsigned int fmt) { - struct at91_ssc_info *ssc_p; - u32 cr_mask; - - if(!dai->active) - return 0; - - ssc_p = &ssc_info[dai->id]; + struct at91_ssc_info *ssc_p = &ssc_info[cpu_dai->id]; - at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RCMR, ssc_p->ssc_state.ssc_tfmr); - at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RCMR, ssc_p->ssc_state.ssc_tcmr); - at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RCMR, ssc_p->ssc_state.ssc_rfmr); - at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RCMR, ssc_p->ssc_state.ssc_rcmr); - at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CMR, ssc_p->ssc_state.ssc_cmr); - - at91_ssc_write(ssc_p->ssc.base + AT91_SSC_IER, ssc_p->ssc_state.ssc_imr); - - at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR, - ((ssc_p->ssc_state.ssc_sr & AT91_SSC_RXENA) ? AT91_SSC_RXEN : 0) | - ((ssc_p->ssc_state.ssc_sr & AT91_SSC_TXENA) ? AT91_SSC_TXEN : 0)); + if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_I2S) + return -EINVAL; + ssc_p->daifmt = fmt; return 0; } -#else -#define at91_i2s_suspend NULL -#define at91_i2s_resume NULL -#endif - -static unsigned int at91_i2s_config_sysclk( - struct snd_soc_cpu_dai *iface, struct snd_soc_clock_info *info, - unsigned int clk) +/* + * Record SSC clock dividers for use in hw_params(). + */ +static int at91_i2s_set_dai_clkdiv(struct snd_soc_cpu_dai *cpu_dai, + int div_id, int div) { - /* Currently, there is only support for USB (12Mhz) mode */ - if (clk != 12000000) - return 0; - return 12000000; + struct at91_ssc_info *ssc_p = &ssc_info[cpu_dai->id]; + + switch (div_id) { + case AT91SSC_CMR_DIV: + /* + * The same master clock divider is used for both + * transmit and receive, so if a value has already + * been set, it must match this value. + */ + if (ssc_p->cmr_div == 0) + ssc_p->cmr_div = div; + else + if (div != ssc_p->cmr_div) + return -EBUSY; + break; + + case AT91SSC_TCMR_PERIOD: + ssc_p->tcmr_period = div; + break; + + case AT91SSC_RCMR_PERIOD: + ssc_p->rcmr_period = div; + break; + + default: + return -EINVAL; + } + + return 0; } +/* + * Configure the SSC. + */ static int at91_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - int id = rtd->cpu_dai->id; + int id = rtd->dai->cpu_dai->id; struct at91_ssc_info *ssc_p = &ssc_info[id]; struct at91_pcm_dma_params *dma_params; - unsigned int pcmfmt, rate; int dir, channels, bits; - struct clk *mck_clk; - u32 div, period, tfmr, rfmr, tcmr, rcmr; + u32 tfmr, rfmr, tcmr, rcmr; + int start_event; int ret; /* @@ -442,44 +378,134 @@ static int at91_i2s_hw_params(struct snd_pcm_substream *substream, dma_params->substream = substream; ssc_p->dma_params[dir] = dma_params; - rtd->cpu_dai->dma_data = dma_params; - rate = params_rate(params); - channels = params_channels(params); + /* + * The cpu_dai->dma_data field is only used to communicate the + * appropriate DMA parameters to the pcm driver hw_params() + * function. It should not be used for other purposes + * as it is common to all substreams. + */ + rtd->dai->cpu_dai->dma_data = dma_params; - pcmfmt = rtd->cpu_dai->dai_runtime.pcmfmt; - switch (pcmfmt) { - case SNDRV_PCM_FMTBIT_S16_LE: - /* likely this is all we'll ever support, but ... */ - bits = 16; - dma_params->pdc_xfer_size = 2; - break; - default: - printk(KERN_WARNING "at91-i2s: unsupported format %x\n", - pcmfmt); - return -EINVAL; - } + channels = params_channels(params); - /* Don't allow both SSC substreams to initialize at the same time. */ - down(ssc_p->mutex); + /* + * The SSC only supports up to 16-bit samples in I2S format, due + * to the size of the Frame Mode Register FSLEN field. Also, I2S + * implies signed data. + */ + bits = 16; + dma_params->pdc_xfer_size = 2; /* - * If this SSC is alreadly initialized, then this substream must use - * the same format and rate. + * Compute SSC register settings. */ - if (ssc_p->initialized) { - if (pcmfmt != ssc_p->pcmfmt || rate != ssc_p->rate) { - printk(KERN_WARNING "at91-i2s: " - "incompatible substream in other direction\n"); - up(ssc_p->mutex); - return -EINVAL; - } - } else { + switch (ssc_p->daifmt) { + case SND_SOC_DAIFMT_CBS_CFS: + /* + * SSC provides BCLK and LRC clocks. + * + * The SSC transmit and receive clocks are generated from the + * MCK divider, and the BCLK signal is output on the SSC TK line. + */ + rcmr = (( ssc_p->rcmr_period << 24) & AT91_SSC_PERIOD) + | (( 1 << 16) & AT91_SSC_STTDLY) + | (( AT91_SSC_START_FALLING_RF ) & AT91_SSC_START) + | (( AT91_SSC_CK_RISING ) & AT91_SSC_CKI) + | (( AT91_SSC_CKO_NONE ) & AT91_SSC_CKO) + | (( AT91_SSC_CKS_DIV ) & AT91_SSC_CKS); + + rfmr = (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE) + | (( AT91_SSC_FSOS_NEGATIVE ) & AT91_SSC_FSOS) + | (((bits - 1) << 16) & AT91_SSC_FSLEN) + | (((channels - 1) << 8) & AT91_SSC_DATNB) + | (( 1 << 7) & AT91_SSC_MSBF) + | (( 0 << 5) & AT91_SSC_LOOP) + | (((bits - 1) << 0) & AT91_SSC_DATALEN); + + tcmr = (( ssc_p->tcmr_period << 24) & AT91_SSC_PERIOD) + | (( 1 << 16) & AT91_SSC_STTDLY) + | (( AT91_SSC_START_FALLING_RF ) & AT91_SSC_START) + | (( AT91_SSC_CKI_FALLING ) & AT91_SSC_CKI) + | (( AT91_SSC_CKO_CONTINUOUS ) & AT91_SSC_CKO) + | (( AT91_SSC_CKS_DIV ) & AT91_SSC_CKS); + + tfmr = (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE) + | (( 0 << 23) & AT91_SSC_FSDEN) + | (( AT91_SSC_FSOS_NEGATIVE ) & AT91_SSC_FSOS) + | (((bits - 1) << 16) & AT91_SSC_FSLEN) + | (((channels - 1) << 8) & AT91_SSC_DATNB) + | (( 1 << 7) & AT91_SSC_MSBF) + | (( 0 << 5) & AT91_SSC_DATDEF) + | (((bits - 1) << 0) & AT91_SSC_DATALEN); + break; + + case SND_SOC_DAIFMT_CBM_CFM: + + /* + * CODEC supplies BCLK and LRC clocks. + * + * The SSC transmit clock is obtained from the BCLK signal on + * on the TK line, and the SSC receive clock is generated from the + * transmit clock. + * + * For single channel data, one sample is transferred on the falling + * edge of the LRC clock. For two channel data, one sample is + * transferred on both edges of the LRC clock. + */ + start_event = channels == 1 + ? AT91_SSC_START_FALLING_RF + : AT91_SSC_START_EDGE_RF; + + rcmr = (( 0 << 24) & AT91_SSC_PERIOD) + | (( 1 << 16) & AT91_SSC_STTDLY) + | (( start_event ) & AT91_SSC_START) + | (( AT91_SSC_CK_RISING ) & AT91_SSC_CKI) + | (( AT91_SSC_CKO_NONE ) & AT91_SSC_CKO) + | (( AT91_SSC_CKS_CLOCK ) & AT91_SSC_CKS); + + rfmr = (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE) + | (( AT91_SSC_FSOS_NONE ) & AT91_SSC_FSOS) + | (( 0 << 16) & AT91_SSC_FSLEN) + | (( 0 << 8) & AT91_SSC_DATNB) + | (( 1 << 7) & AT91_SSC_MSBF) + | (( 0 << 5) & AT91_SSC_LOOP) + | (((bits - 1) << 0) & AT91_SSC_DATALEN); + + tcmr = (( 0 << 24) & AT91_SSC_PERIOD) + | (( 1 << 16) & AT91_SSC_STTDLY) + | (( start_event ) & AT91_SSC_START) + | (( AT91_SSC_CKI_FALLING ) & AT91_SSC_CKI) + | (( AT91_SSC_CKO_NONE ) & AT91_SSC_CKO) + | (( AT91_SSC_CKS_PIN ) & AT91_SSC_CKS); + + tfmr = (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE) + | (( 0 << 23) & AT91_SSC_FSDEN) + | (( AT91_SSC_FSOS_NONE ) & AT91_SSC_FSOS) + | (( 0 << 16) & AT91_SSC_FSLEN) + | (( 0 << 8) & AT91_SSC_DATNB) + | (( 1 << 7) & AT91_SSC_MSBF) + | (( 0 << 5) & AT91_SSC_DATDEF) + | (((bits - 1) << 0) & AT91_SSC_DATALEN); + break; + + case SND_SOC_DAIFMT_CBS_CFM: + case SND_SOC_DAIFMT_CBM_CFS: + default: + printk(KERN_WARNING "at91-i2s: unsupported DAI format 0x%x.\n", + ssc_p->daifmt); + return -EINVAL; + break; + } + DBG("RCMR=%08x RFMR=%08x TCMR=%08x TFMR=%08x\n", rcmr, rfmr, tcmr, tfmr); + + if (!ssc_p->initialized) { + /* Enable PMC peripheral clock for this SSC */ DBG("Starting pid %d clock\n", ssc_p->ssc.pid); at91_sys_write(AT91_PMC_PCER, 1<ssc.pid); - /* Reset the SSC */ + /* Reset the SSC and its PDC registers */ at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR, AT91_SSC_SWRST); at91_ssc_write(ssc_p->ssc.base + AT91_PDC_RPR, 0); @@ -491,97 +517,30 @@ static int at91_i2s_hw_params(struct snd_pcm_substream *substream, at91_ssc_write(ssc_p->ssc.base + AT91_PDC_TNPR, 0); at91_ssc_write(ssc_p->ssc.base + AT91_PDC_TNCR, 0); - div = rtd->cpu_dai->dai_runtime.priv >> 16; - period = rtd->cpu_dai->dai_runtime.priv & 0xffff; - - mck_clk = clk_get(NULL, "mck"); - - DBG("mck %lu fsbd %u bfs %llu bfs_real %u bclk %lu div %u period %u\n", - clk_get_rate(mck_clk), - SND_SOC_FSBD(6), - rtd->cpu_dai->dai_runtime.bfs, - SND_SOC_FSBD_REAL(rtd->cpu_dai->dai_runtime.bfs), - clk_get_rate(mck_clk) / (2 * div), - div, - period); - - clk_put(mck_clk); - - at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CMR, div); - - /* - * Setup the TFMR and RFMR for the proper data format. - */ - tfmr = - (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE) - | (( 0 << 23) & AT91_SSC_FSDEN) - | (( AT91_SSC_FSOS_NEGATIVE ) & AT91_SSC_FSOS) - | (((bits - 1) << 16) & AT91_SSC_FSLEN) - | (((channels - 1) << 8) & AT91_SSC_DATNB) - | (( 1 << 7) & AT91_SSC_MSBF) - | (( 0 << 5) & AT91_SSC_DATDEF) - | (((bits - 1) << 0) & AT91_SSC_DATALEN); - DBG("SSC_TFMR=0x%08x\n", tfmr); - at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TFMR, tfmr); - - rfmr = - (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE) - | (( AT91_SSC_FSOS_NONE ) & AT91_SSC_FSOS) - | (( 0 << 16) & AT91_SSC_FSLEN) - | (((channels - 1) << 8) & AT91_SSC_DATNB) - | (( 1 << 7) & AT91_SSC_MSBF) - | (( 0 << 5) & AT91_SSC_LOOP) - | (((bits - 1) << 0) & AT91_SSC_DATALEN); - - DBG("SSC_RFMR=0x%08x\n", rfmr); - at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RFMR, rfmr); - - /* - * Setup the TCMR and RCMR to generate the proper BCLK - * and LRC signals. - */ - tcmr = - (( period << 24) & AT91_SSC_PERIOD) - | (( 1 << 16) & AT91_SSC_STTDLY) - | (( AT91_SSC_START_FALLING_RF ) & AT91_SSC_START) - | (( AT91_SSC_CKI_FALLING ) & AT91_SSC_CKI) - | (( AT91_SSC_CKO_CONTINUOUS ) & AT91_SSC_CKO) - | (( AT91_SSC_CKS_DIV ) & AT91_SSC_CKS); - - DBG("SSC_TCMR=0x%08x\n", tcmr); - at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TCMR, tcmr); - - rcmr = - (( 0 << 24) & AT91_SSC_PERIOD) - | (( 1 << 16) & AT91_SSC_STTDLY) - | (( AT91_SSC_START_TX_RX ) & AT91_SSC_START) - | (( AT91_SSC_CK_RISING ) & AT91_SSC_CKI) - | (( AT91_SSC_CKO_NONE ) & AT91_SSC_CKO) - | (( AT91_SSC_CKS_CLOCK ) & AT91_SSC_CKS); - - DBG("SSC_RCMR=0x%08x\n", rcmr); - at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RCMR, rcmr); - if ((ret = request_irq(ssc_p->ssc.pid, at91_i2s_interrupt, 0, ssc_p->name, ssc_p)) < 0) { printk(KERN_WARNING "at91-i2s: request_irq failure\n"); + + DBG("Stopping pid %d clock\n", ssc_p->ssc.pid); + at91_sys_write(AT91_PMC_PCER, 1<ssc.pid); return ret; } - /* - * Save the current substream parameters in order to check - * that the substream in the opposite direction uses the - * same parameters. - */ - ssc_p->pcmfmt = pcmfmt; - ssc_p->rate = rate; ssc_p->initialized = 1; - - DBG("hw_params: SSC initialized\n"); } - up(ssc_p->mutex); + /* set SSC clock mode register */ + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CMR, ssc_p->cmr_div); + + /* set receive clock mode and format */ + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RCMR, rcmr); + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RFMR, rfmr); + + /* set transmit clock mode and format */ + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TCMR, tcmr); + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TFMR, tfmr); + DBG("hw_params: SSC initialized\n"); return 0; } @@ -589,39 +548,112 @@ static int at91_i2s_hw_params(struct snd_pcm_substream *substream, static int at91_i2s_prepare(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct at91_pcm_dma_params *dma_params = rtd->cpu_dai->dma_data; + struct at91_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; + struct at91_pcm_dma_params *dma_params; + int dir; + + dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1; + dma_params = ssc_p->dma_params[dir]; at91_ssc_write(dma_params->ssc_base + AT91_SSC_CR, dma_params->mask->ssc_enable); - DBG("%s enabled SSC_SR=0x%08lx\n", - substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? "transmit" : "receive", - at91_ssc_read(ssc_info[rtd->cpu_dai->id].ssc.base + AT91_SSC_SR)); + DBG("%s enabled SSC_SR=0x%08lx\n", dir ? "receive" : "transmit", + at91_ssc_read(dma_params->ssc_base + AT91_SSC_SR)); return 0; } +#ifdef CONFIG_PM +static int at91_i2s_suspend(struct platform_device *pdev, + struct snd_soc_cpu_dai *cpu_dai) +{ + struct at91_ssc_info *ssc_p; + + if(!cpu_dai->active) + return 0; + + ssc_p = &ssc_info[cpu_dai->id]; + + /* Save the status register before disabling transmit and receive. */ + ssc_p->ssc_state.ssc_sr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR); + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR, + AT91_SSC_TXDIS | AT91_SSC_RXDIS); + + /* Save the current interrupt mask, then disable unmasked interrupts. */ + ssc_p->ssc_state.ssc_imr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_IMR); + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_IDR, ssc_p->ssc_state.ssc_imr); + + ssc_p->ssc_state.ssc_cmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_CMR); + ssc_p->ssc_state.ssc_rcmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_RCMR); + ssc_p->ssc_state.ssc_rfmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_RFMR); + ssc_p->ssc_state.ssc_tcmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_TCMR); + ssc_p->ssc_state.ssc_tfmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_TFMR); + + return 0; +} + +static int at91_i2s_resume(struct platform_device *pdev, + struct snd_soc_cpu_dai *cpu_dai) +{ + struct at91_ssc_info *ssc_p; + + if(!cpu_dai->active) + return 0; + + ssc_p = &ssc_info[cpu_dai->id]; + + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TFMR, ssc_p->ssc_state.ssc_tfmr); + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TCMR, ssc_p->ssc_state.ssc_tcmr); + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RFMR, ssc_p->ssc_state.ssc_rfmr); + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RCMR, ssc_p->ssc_state.ssc_rcmr); + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CMR, ssc_p->ssc_state.ssc_cmr); + + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_IER, ssc_p->ssc_state.ssc_imr); + + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR, + ((ssc_p->ssc_state.ssc_sr & AT91_SSC_RXENA) ? AT91_SSC_RXEN : 0) | + ((ssc_p->ssc_state.ssc_sr & AT91_SSC_TXENA) ? AT91_SSC_TXEN : 0)); + + return 0; +} + +#else +#define at91_i2s_suspend NULL +#define at91_i2s_resume NULL +#endif + +#define AT91_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ + SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\ + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\ + SNDRV_PCM_RATE_96000) + struct snd_soc_cpu_dai at91_i2s_dai[NUM_SSC_DEVICES] = { { .name = "at91_ssc0/i2s", .id = 0, .type = SND_SOC_DAI_I2S, .suspend = at91_i2s_suspend, .resume = at91_i2s_resume, - .config_sysclk = at91_i2s_config_sysclk, .playback = { .channels_min = 1, - .channels_max = 2,}, + .channels_max = 2, + .rates = AT91_I2S_RATES, + .formats = SNDRV_PCM_FMTBIT_S16_LE,}, .capture = { .channels_min = 1, - .channels_max = 2,}, + .channels_max = 2, + .rates = AT91_I2S_RATES, + .formats = SNDRV_PCM_FMTBIT_S16_LE,}, .ops = { .startup = at91_i2s_startup, .shutdown = at91_i2s_shutdown, .prepare = at91_i2s_prepare, .hw_params = at91_i2s_hw_params,}, - .caps = { - .mode = &at91_i2s[0], - .num_modes = ARRAY_SIZE(at91_i2s),}, + .dai_ops = { + .set_sysclk = at91_i2s_set_dai_sysclk, + .set_fmt = at91_i2s_set_dai_fmt, + .set_clkdiv = at91_i2s_set_dai_clkdiv,}, .private_data = &ssc_info[0].ssc, }, #if NUM_SSC_DEVICES == 3 @@ -630,21 +662,25 @@ struct snd_soc_cpu_dai at91_i2s_dai[NUM_SSC_DEVICES] = { .type = SND_SOC_DAI_I2S, .suspend = at91_i2s_suspend, .resume = at91_i2s_resume, - .config_sysclk = at91_i2s_config_sysclk, .playback = { .channels_min = 1, - .channels_max = 2,}, + .channels_max = 2, + .rates = AT91_I2S_RATES, + .formats = SNDRV_PCM_FMTBIT_S16_LE,}, .capture = { .channels_min = 1, - .channels_max = 2,}, + .channels_max = 2, + .rates = AT91_I2S_RATES, + .formats = SNDRV_PCM_FMTBIT_S16_LE,}, .ops = { .startup = at91_i2s_startup, .shutdown = at91_i2s_shutdown, .prepare = at91_i2s_prepare, .hw_params = at91_i2s_hw_params,}, - .caps = { - .mode = &at91_i2s[0], - .num_modes = ARRAY_SIZE(at91_i2s),}, + .dai_ops = { + .set_sysclk = at91_i2s_set_dai_sysclk, + .set_fmt = at91_i2s_set_dai_fmt, + .set_clkdiv = at91_i2s_set_dai_clkdiv,}, .private_data = &ssc_info[1].ssc, }, { .name = "at91_ssc2/i2s", @@ -652,21 +688,25 @@ struct snd_soc_cpu_dai at91_i2s_dai[NUM_SSC_DEVICES] = { .type = SND_SOC_DAI_I2S, .suspend = at91_i2s_suspend, .resume = at91_i2s_resume, - .config_sysclk = at91_i2s_config_sysclk, .playback = { .channels_min = 1, - .channels_max = 2,}, + .channels_max = 2, + .rates = AT91_I2S_RATES, + .formats = SNDRV_PCM_FMTBIT_S16_LE,}, .capture = { .channels_min = 1, - .channels_max = 2,}, + .channels_max = 2, + .rates = AT91_I2S_RATES, + .formats = SNDRV_PCM_FMTBIT_S16_LE,}, .ops = { .startup = at91_i2s_startup, .shutdown = at91_i2s_shutdown, .prepare = at91_i2s_prepare, .hw_params = at91_i2s_hw_params,}, - .caps = { - .mode = &at91_i2s[0], - .num_modes = ARRAY_SIZE(at91_i2s),}, + .dai_ops = { + .set_sysclk = at91_i2s_set_dai_sysclk, + .set_fmt = at91_i2s_set_dai_fmt, + .set_clkdiv = at91_i2s_set_dai_clkdiv,}, .private_data = &ssc_info[2].ssc, }, #endif diff --git a/sound/soc/at91/at91-i2s.h b/sound/soc/at91/at91-i2s.h new file mode 100644 index 00000000000..f8a875ba0cc --- /dev/null +++ b/sound/soc/at91/at91-i2s.h @@ -0,0 +1,27 @@ +/* + * at91-i2s.h - ALSA I2S interface for the Atmel AT91 SoC + * + * Author: Frank Mandarino + * Endrelia Technologies Inc. + * Created: Jan 9, 2007 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _AT91_I2S_H +#define _AT91_I2S_H + +/* I2S system clock ids */ +#define AT91_SYSCLK_MCK 0 /* SSC uses AT91 MCK as system clock */ + +/* I2S divider ids */ +#define AT91SSC_CMR_DIV 0 /* MCK divider for BCLK */ +#define AT91SSC_TCMR_PERIOD 1 /* BCLK divider for transmit FS */ +#define AT91SSC_RCMR_PERIOD 2 /* BCLK divider for receive FS */ + +extern struct snd_soc_cpu_dai at91_i2s_dai[]; + +#endif /* _AT91_I2S_H */ + -- cgit v1.2.3 From 6297027629a9349301e08442b67deb9783a5e984 Mon Sep 17 00:00:00 2001 From: Frank Mandarino Date: Fri, 2 Feb 2007 17:19:24 +0100 Subject: [ALSA] soc - ASoC 0.13 AT91xxxx DMA This patch updates the AT91xxxx audio DMA driver to the new API in ASoC 0.13. Changes:- o Updated to use new 0.13 data structures. o Suspend and Resume now conditionally compiled. o #include guard around at91-pcm.h header. Signed-off-by: Frank Mandarino Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/at91/at91-pcm.c | 7 ++++++- sound/soc/at91/at91-pcm.h | 9 +++++---- 2 files changed, 11 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/at91/at91-pcm.c b/sound/soc/at91/at91-pcm.c index fd9d7327b23..e88b12e7cc4 100644 --- a/sound/soc/at91/at91-pcm.c +++ b/sound/soc/at91/at91-pcm.c @@ -125,7 +125,7 @@ static int at91_pcm_hw_params(struct snd_pcm_substream *substream, snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); runtime->dma_bytes = params_buffer_bytes(params); - prtd->params = rtd->cpu_dai->dma_data; + prtd->params = rtd->dai->cpu_dai->dma_data; prtd->params->dma_intr_handler = at91_pcm_dma_irq; prtd->dma_buffer = runtime->dma_addr; @@ -363,6 +363,7 @@ static void at91_pcm_free_dma_buffers(struct snd_pcm *pcm) } } +#ifdef CONFIG_PM static int at91_pcm_suspend(struct platform_device *pdev, struct snd_soc_cpu_dai *dai) { @@ -410,6 +411,10 @@ static int at91_pcm_resume(struct platform_device *pdev, at91_ssc_write(params->ssc_base + AT91_PDC_PTCR, params->mask->pdc_enable); return 0; } +#else +#define at91_pcm_suspend NULL +#define at91_pcm_resume NULL +#endif struct snd_soc_platform at91_soc_platform = { .name = "at91-audio", diff --git a/sound/soc/at91/at91-pcm.h b/sound/soc/at91/at91-pcm.h index 6c3b095725c..58d0f00a07b 100644 --- a/sound/soc/at91/at91-pcm.h +++ b/sound/soc/at91/at91-pcm.h @@ -16,6 +16,9 @@ * published by the Free Software Foundation. */ +#ifndef _AT91_PCM_H +#define _AT91_PCM_H + #include struct at91_ssc_periph { @@ -23,7 +26,6 @@ struct at91_ssc_periph { u32 pid; }; - /* * Registers and status bits that are required by the PCM driver. */ @@ -44,7 +46,6 @@ struct at91_ssc_mask { u32 pdc_disable; /* PDC recv/trans disable */ }; - /* * This structure, shared between the PCM driver and the interface, * contains all information required by the PCM driver to perform the @@ -63,9 +64,9 @@ struct at91_pcm_dma_params { void (*dma_intr_handler)(u32, struct snd_pcm_substream *); }; -extern struct snd_soc_cpu_dai at91_i2s_dai[3]; extern struct snd_soc_platform at91_soc_platform; - #define at91_ssc_read(a) ((unsigned long) __raw_readl(a)) #define at91_ssc_write(a,v) __raw_writel((v),(a)) + +#endif /* _AT91_PCM_H */ -- cgit v1.2.3 From c8044274c7f1e269975b2bd55d057ceb7708e929 Mon Sep 17 00:00:00 2001 From: Frank Mandarino Date: Fri, 2 Feb 2007 17:19:58 +0100 Subject: [ALSA] soc - ASoC 0.13 AT91xxxx Eti_B1 board support This patch updates the EtI B1 machine driver to the new API in ASoC 0.13. Changes:- o Manually configure DAI hardware format. o Removed config_sysclk() function. No longer needed as clocking is now configured manually. Signed-off-by: Frank Mandarino Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/at91/eti_b1_wm8731.c | 141 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 124 insertions(+), 17 deletions(-) (limited to 'sound') diff --git a/sound/soc/at91/eti_b1_wm8731.c b/sound/soc/at91/eti_b1_wm8731.c index 089cdc9e726..8179df3bb2f 100644 --- a/sound/soc/at91/eti_b1_wm8731.c +++ b/sound/soc/at91/eti_b1_wm8731.c @@ -18,9 +18,6 @@ * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * - * Revision history - * 30th Nov 2005 Initial version. - * */ #include @@ -43,9 +40,10 @@ #include "../codecs/wm8731.h" #include "at91-pcm.h" +#include "at91-i2s.h" #if 0 -#define DBG(x...) printk(KERN_INFO "eti_b1_wm8731:" x) +#define DBG(x...) printk(KERN_INFO "eti_b1_wm8731: " x) #else #define DBG(x...) #endif @@ -57,12 +55,29 @@ #define AT91_PIO_RK1 (1 << (AT91_PIN_PB10 - PIN_BASE) % 32) #define AT91_PIO_RF1 (1 << (AT91_PIN_PB11 - PIN_BASE) % 32) - static struct clk *pck1_clk; static struct clk *pllb_clk; + static int eti_b1_startup(struct snd_pcm_substream *substream) { + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; + struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; + int ret; + + /* cpu clock is the AT91 master clock sent to the SSC */ + ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, AT91_SYSCLK_MCK, + 60000000, SND_SOC_CLOCK_IN); + if (ret < 0) + return ret; + + /* codec system clock is supplied by PCK1, set to 12MHz */ + ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8731_SYSCLK, + 12000000, SND_SOC_CLOCK_IN); + if (ret < 0) + return ret; + /* Start PCK1 clock. */ clk_enable(pck1_clk); DBG("pck1 started\n"); @@ -77,8 +92,105 @@ static void eti_b1_shutdown(struct snd_pcm_substream *substream) DBG("pck1 stopped\n"); } +static int eti_b1_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; + struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; + int ret; + +#ifdef CONFIG_SND_AT91_SOC_ETI_SLAVE + unsigned int rate; + int cmr_div, period; + + /* set codec DAI configuration */ + ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) + return ret; + + /* set cpu DAI configuration */ + ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) + return ret; + + /* + * The SSC clock dividers depend on the sample rate. The CMR.DIV + * field divides the system master clock MCK to drive the SSC TK + * signal which provides the codec BCLK. The TCMR.PERIOD and + * RCMR.PERIOD fields further divide the BCLK signal to drive + * the SSC TF and RF signals which provide the codec DACLRC and + * ADCLRC clocks. + * + * The dividers were determined through trial and error, where a + * CMR.DIV value is chosen such that the resulting BCLK value is + * divisible, or almost divisible, by (2 * sample rate), and then + * the TCMR.PERIOD or RCMR.PERIOD is BCLK / (2 * sample rate) - 1. + */ + rate = params_rate(params); + + switch (rate) { + case 8000: + cmr_div = 25; /* BCLK = 60MHz/(2*25) = 1.2MHz */ + period = 74; /* LRC = BCLK/(2*(74+1)) = 8000Hz */ + break; + case 32000: + cmr_div = 7; /* BCLK = 60MHz/(2*7) ~= 4.28571428MHz */ + period = 66; /* LRC = BCLK/(2*(66+1)) = 31982.942Hz */ + break; + case 48000: + cmr_div = 13; /* BCLK = 60MHz/(2*13) ~= 2.3076923MHz */ + period = 23; /* LRC = BCLK/(2*(23+1)) = 48076.923Hz */ + break; + default: + printk(KERN_WARNING "unsupported rate %d on ETI-B1 board\n", rate); + return -EINVAL; + } + + /* set the MCK divider for BCLK */ + ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, AT91SSC_CMR_DIV, cmr_div); + if (ret < 0) + return ret; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + /* set the BCLK divider for DACLRC */ + ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, + AT91SSC_TCMR_PERIOD, period); + } else { + /* set the BCLK divider for ADCLRC */ + ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, + AT91SSC_RCMR_PERIOD, period); + } + if (ret < 0) + return ret; + +#else /* CONFIG_SND_AT91_SOC_ETI_SLAVE */ + /* + * Codec in Master Mode. + */ + + /* set codec DAI configuration */ + ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); + if (ret < 0) + return ret; + + /* set cpu DAI configuration */ + ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); + if (ret < 0) + return ret; + +#endif /* CONFIG_SND_AT91_SOC_ETI_SLAVE */ + + return 0; +} + static struct snd_soc_ops eti_b1_ops = { .startup = eti_b1_startup, + .hw_params = eti_b1_hw_params, .shutdown = eti_b1_shutdown, }; @@ -134,29 +246,19 @@ static int eti_b1_wm8731_init(struct snd_soc_codec *codec) return 0; } -unsigned int eti_b1_config_sysclk(struct snd_soc_pcm_runtime *rtd, - struct snd_soc_clock_info *info) -{ - if(info->bclk_master & SND_SOC_DAIFMT_CBS_CFS) { - return rtd->codec_dai->config_sysclk(rtd->codec_dai, info, 12000000); - } - return 0; -} - static struct snd_soc_dai_link eti_b1_dai = { .name = "WM8731", .stream_name = "WM8731", .cpu_dai = &at91_i2s_dai[1], .codec_dai = &wm8731_dai, .init = eti_b1_wm8731_init, - .config_sysclk = eti_b1_config_sysclk, + .ops = &eti_b1_ops, }; static struct snd_soc_machine snd_soc_machine_eti_b1 = { .name = "ETI_B1", .dai_link = &eti_b1_dai, .num_links = 1, - .ops = &eti_b1_ops, }; static struct wm8731_setup_data eti_b1_wm8731_setup = { @@ -210,7 +312,7 @@ static int __init eti_b1_init(void) } ssc_pio_lines = AT91_PIO_TF1 | AT91_PIO_TK1 | AT91_PIO_TD1 - | AT91_PIO_RD1 /* | AT91_PIO_RK1 | AT91_PIO_RF1 */; + | AT91_PIO_RD1 /* | AT91_PIO_RK1 */ | AT91_PIO_RF1; /* Reset all PIO registers and assign lines to peripheral A */ at91_sys_write(AT91_PIOB + PIO_PDR, ssc_pio_lines); @@ -237,6 +339,11 @@ static int __init eti_b1_init(void) /* assign the GPIO pin to PCK1 */ at91_set_B_periph(AT91_PIN_PA24, 0); +#ifdef CONFIG_SND_AT91_SOC_ETI_SLAVE + printk(KERN_INFO "eti_b1_wm8731: Codec in Slave Mode\n"); +#else + printk(KERN_INFO "eti_b1_wm8731: Codec in Master Mode\n"); +#endif return ret; fail_io_unmap: -- cgit v1.2.3 From eaff2ae702f937020bfde96eea552caae3815784 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 2 Feb 2007 17:20:40 +0100 Subject: [ALSA] soc - ASoC 0.13 pxa2xx i2s driver This patch updates the pxa2xx I2S driver to the new API in ASoC 0.13. Changes:- o Removed DAI capabilities matching code in favour of manual matching in the machine drivers. o Added DAI operations for codec and CPU interfaces. o Removed config_sysclk() function and struct snd_soc_clock_info. No longer needed as clocking is now configured manually in the machine drivers. Also removed other clocking data from structures. o Added pxa2xx-i2s.h header Signed-off-by: Philipp Zabel Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/pxa/pxa2xx-i2s.c | 200 +++++++++++++++++++-------------------------- sound/soc/pxa/pxa2xx-i2s.h | 20 +++++ 2 files changed, 102 insertions(+), 118 deletions(-) create mode 100644 sound/soc/pxa/pxa2xx-i2s.h (limited to 'sound') diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c index 98b167fe68e..575a6137c04 100644 --- a/sound/soc/pxa/pxa2xx-i2s.c +++ b/sound/soc/pxa/pxa2xx-i2s.c @@ -29,11 +29,7 @@ #include #include "pxa2xx-pcm.h" - -/* used to disable sysclk if external crystal is used */ -static int extclk; -module_param(extclk, int, 0); -MODULE_PARM_DESC(extclk, "set to 1 to disable pxa2xx i2s sysclk"); +#include "pxa2xx-i2s.h" struct pxa_i2s_port { u32 sadiv; @@ -41,97 +37,10 @@ struct pxa_i2s_port { u32 sacr1; u32 saimr; int master; + u32 fmt; }; static struct pxa_i2s_port pxa_i2s; -#define PXA_I2S_DAIFMT \ - (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_NB_NF) - -#define PXA_I2S_DIR \ - (SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE) - -#define PXA_I2S_RATES \ - (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \ - SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ - SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) - -/* priv is divider */ -static struct snd_soc_dai_mode pxa2xx_i2s_modes[] = { - /* pxa2xx I2S frame and clock master modes */ - { - .fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, - .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, - .pcmrate = SNDRV_PCM_RATE_8000, - .pcmdir = PXA_I2S_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 256, - .bfs = SND_SOC_FSBD(4), - .priv = 0x48, - }, - { - .fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, - .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, - .pcmrate = SNDRV_PCM_RATE_11025, - .pcmdir = PXA_I2S_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 256, - .bfs = SND_SOC_FSBD(4), - .priv = 0x34, - }, - { - .fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, - .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, - .pcmrate = SNDRV_PCM_RATE_16000, - .pcmdir = PXA_I2S_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 256, - .bfs = SND_SOC_FSBD(4), - .priv = 0x24, - }, - { - .fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, - .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, - .pcmrate = SNDRV_PCM_RATE_22050, - .pcmdir = PXA_I2S_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 256, - .bfs = SND_SOC_FSBD(4), - .priv = 0x1a, - }, - { - .fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, - .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, - .pcmrate = SNDRV_PCM_RATE_44100, - .pcmdir = PXA_I2S_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 256, - .bfs = SND_SOC_FSBD(4), - .priv = 0xd, - }, - { - .fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, - .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, - .pcmrate = SNDRV_PCM_RATE_48000, - .pcmdir = PXA_I2S_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 256, - .bfs = SND_SOC_FSBD(4), - .priv = 0xc, - }, - - /* pxa2xx I2S frame master and clock slave mode */ - { - .fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBM_CFS, - .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, - .pcmrate = PXA_I2S_RATES, - .pcmdir = PXA_I2S_DIR, - .fs = SND_SOC_FS_ALL, - .flags = SND_SOC_DAI_BFS_RATE, - .bfs = 64, - .priv = 0x48, - }, -}; - static struct pxa2xx_pcm_dma_params pxa2xx_i2s_pcm_stereo_out = { .name = "I2S PCM Stereo out", .dev_addr = __PREG(SADR), @@ -171,8 +80,9 @@ static struct pxa2xx_gpio gpio_bus[] = { static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; - if (!rtd->cpu_dai->active) { + if (!cpu_dai->active) { SACR0 |= SACR0_RST; SACR0 = 0; } @@ -191,18 +101,50 @@ static int pxa_i2s_wait(void) return 0; } -static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) +static int pxa2xx_i2s_set_dai_fmt(struct snd_soc_cpu_dai *cpu_dai, + unsigned int fmt) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + /* interface format */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + pxa_i2s.fmt = 0; + break; + case SND_SOC_DAIFMT_LEFT_J: + pxa_i2s.fmt = SACR1_AMSL; + break; + } - pxa_i2s.master = 0; - if (rtd->cpu_dai->dai_runtime.fmt & SND_SOC_DAIFMT_CBS_CFS) + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: pxa_i2s.master = 1; + break; + case SND_SOC_DAIFMT_CBM_CFS: + pxa_i2s.master = 0; + break; + default: + break; + } + return 0; +} - if (pxa_i2s.master && !extclk) +static int pxa2xx_i2s_set_dai_sysclk(struct snd_soc_cpu_dai *cpu_dai, + int clk_id, unsigned int freq, int dir) +{ + if (clk_id != PXA2XX_I2S_SYSCLK) + return -ENODEV; + + if (pxa_i2s.master && dir == SND_SOC_CLOCK_OUT) pxa_gpio_mode(gpio_bus[pxa_i2s.master].sys); + return 0; +} + +static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; + pxa_gpio_mode(gpio_bus[pxa_i2s.master].rx); pxa_gpio_mode(gpio_bus[pxa_i2s.master].tx); pxa_gpio_mode(gpio_bus[pxa_i2s.master].frm); @@ -211,9 +153,9 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream, pxa_i2s_wait(); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - rtd->cpu_dai->dma_data = &pxa2xx_i2s_pcm_stereo_out; + cpu_dai->dma_data = &pxa2xx_i2s_pcm_stereo_out; else - rtd->cpu_dai->dma_data = &pxa2xx_i2s_pcm_stereo_in; + cpu_dai->dma_data = &pxa2xx_i2s_pcm_stereo_in; /* is port used by another stream */ if (!(SACR0 & SACR0_ENB)) { @@ -224,16 +166,37 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream, SACR0 |= SACR0_BCKD; SACR0 |= SACR0_RFTH(14) | SACR0_TFTH(1); - - if (rtd->cpu_dai->dai_runtime.fmt & SND_SOC_DAIFMT_LEFT_J) - SACR1 |= SACR1_AMSL; + SACR1 |= pxa_i2s.fmt; } if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) SAIMR |= SAIMR_TFS; else SAIMR |= SAIMR_RFS; - SADIV = rtd->cpu_dai->dai_runtime.priv; + switch (params_rate(params)) { + case 8000: + SADIV = 0x48; + break; + case 11025: + SADIV = 0x34; + break; + case 16000: + SADIV = 0x24; + break; + case 22050: + SADIV = 0x1a; + break; + case 44100: + SADIV = 0xd; + break; + case 48000: + SADIV = 0xc; + break; + case 96000: /* not in manual and possibly slightly inaccurate */ + SADIV = 0x6; + break; + } + return 0; } @@ -316,12 +279,9 @@ static int pxa2xx_i2s_resume(struct platform_device *pdev, #define pxa2xx_i2s_resume NULL #endif -/* pxa2xx I2S sysclock is always 256 FS */ -static unsigned int pxa_i2s_config_sysclk(struct snd_soc_cpu_dai *iface, - struct snd_soc_clock_info *info, unsigned int clk) -{ - return info->rate << 8; -} +#define PXA2XX_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ + SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000) struct snd_soc_cpu_dai pxa_i2s_dai = { .name = "pxa2xx-i2s", @@ -329,21 +289,25 @@ struct snd_soc_cpu_dai pxa_i2s_dai = { .type = SND_SOC_DAI_I2S, .suspend = pxa2xx_i2s_suspend, .resume = pxa2xx_i2s_resume, - .config_sysclk = pxa_i2s_config_sysclk, .playback = { .channels_min = 2, - .channels_max = 2,}, + .channels_max = 2, + .rates = PXA2XX_I2S_RATES, + .formats = SNDRV_PCM_FMTBIT_S16_LE,}, .capture = { .channels_min = 2, - .channels_max = 2,}, + .channels_max = 2, + .rates = PXA2XX_I2S_RATES, + .formats = SNDRV_PCM_FMTBIT_S16_LE,}, .ops = { .startup = pxa2xx_i2s_startup, .shutdown = pxa2xx_i2s_shutdown, .trigger = pxa2xx_i2s_trigger, .hw_params = pxa2xx_i2s_hw_params,}, - .caps = { - .num_modes = ARRAY_SIZE(pxa2xx_i2s_modes), - .mode = pxa2xx_i2s_modes,}, + .dai_ops = { + .set_fmt = pxa2xx_i2s_set_dai_fmt, + .set_sysclk = pxa2xx_i2s_set_dai_sysclk, + }, }; EXPORT_SYMBOL_GPL(pxa_i2s_dai); diff --git a/sound/soc/pxa/pxa2xx-i2s.h b/sound/soc/pxa/pxa2xx-i2s.h new file mode 100644 index 00000000000..a2484f0881f --- /dev/null +++ b/sound/soc/pxa/pxa2xx-i2s.h @@ -0,0 +1,20 @@ +/* + * linux/sound/arm/pxa2xx-i2s.h + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _PXA2XX_I2S_H +#define _PXA2XX_I2S_H + +/* pxa2xx DAI ID's */ +#define PXA2XX_DAI_I2S 0 + +/* I2S clock */ +#define PXA2XX_I2S_SYSCLK 0 + +extern struct snd_soc_cpu_dai pxa_i2s_dai; + +#endif -- cgit v1.2.3 From 596ce32b74dccf53ef59cc9ba2e95a2a34ba921c Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 2 Feb 2007 17:21:16 +0100 Subject: [ALSA] soc - ASoC 0.13 pxa2xx AC97 driver This patch updates the pxa2xx AC97 driver to the new API in ASoC 0.13. Changes:- o Removed DAI capabilities matching code in favour of manual matching in the machine drivers. o Added DAI operations for codec and CPU interfaces. o Added pxa2xx-ac97.h header Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/pxa/pxa2xx-ac97.c | 64 ++++++++++++++++++++------------------------- sound/soc/pxa/pxa2xx-ac97.h | 22 ++++++++++++++++ 2 files changed, 51 insertions(+), 35 deletions(-) create mode 100644 sound/soc/pxa/pxa2xx-ac97.h (limited to 'sound') diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c index 28b1985edc0..1bbbeff84ef 100644 --- a/sound/soc/pxa/pxa2xx-ac97.c +++ b/sound/soc/pxa/pxa2xx-ac97.c @@ -31,27 +31,12 @@ #include #include "pxa2xx-pcm.h" +#include "pxa2xx-ac97.h" static DEFINE_MUTEX(car_mutex); static DECLARE_WAIT_QUEUE_HEAD(gsr_wq); static volatile long gsr_bits; -#define AC97_DIR \ - (SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE) - -#define AC97_RATES \ - (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \ - SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) - -/* may need to expand this */ -static struct snd_soc_dai_mode pxa2xx_ac97_modes[] = { - { - .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, - .pcmrate = AC97_RATES, - .pcmdir = AC97_DIR, - }, -}; - /* * Beware PXA27x bugs: * @@ -334,11 +319,12 @@ static int pxa2xx_ac97_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - rtd->cpu_dai->dma_data = &pxa2xx_ac97_pcm_stereo_out; + cpu_dai->dma_data = &pxa2xx_ac97_pcm_stereo_out; else - rtd->cpu_dai->dma_data = &pxa2xx_ac97_pcm_stereo_in; + cpu_dai->dma_data = &pxa2xx_ac97_pcm_stereo_in; return 0; } @@ -347,11 +333,12 @@ static int pxa2xx_ac97_hw_aux_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - rtd->cpu_dai->dma_data = &pxa2xx_ac97_pcm_aux_mono_out; + cpu_dai->dma_data = &pxa2xx_ac97_pcm_aux_mono_out; else - rtd->cpu_dai->dma_data = &pxa2xx_ac97_pcm_aux_mono_in; + cpu_dai->dma_data = &pxa2xx_ac97_pcm_aux_mono_in; return 0; } @@ -360,15 +347,20 @@ static int pxa2xx_ac97_hw_mic_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) return -ENODEV; else - rtd->cpu_dai->dma_data = &pxa2xx_ac97_pcm_mic_mono_in; + cpu_dai->dma_data = &pxa2xx_ac97_pcm_mic_mono_in; return 0; } +#define PXA2XX_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ + SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_48000) + /* * There is only 1 physical AC97 interface for pxa2xx, but it * has extra fifo's that can be used for aux DACs and ADCs. @@ -385,16 +377,17 @@ struct snd_soc_cpu_dai pxa_ac97_dai[] = { .playback = { .stream_name = "AC97 Playback", .channels_min = 2, - .channels_max = 2,}, + .channels_max = 2, + .rates = PXA2XX_AC97_RATES, + .formats = SNDRV_PCM_FMTBIT_S16_LE,}, .capture = { .stream_name = "AC97 Capture", .channels_min = 2, - .channels_max = 2,}, + .channels_max = 2, + .rates = PXA2XX_AC97_RATES, + .formats = SNDRV_PCM_FMTBIT_S16_LE,}, .ops = { .hw_params = pxa2xx_ac97_hw_params,}, - .caps = { - .num_modes = ARRAY_SIZE(pxa2xx_ac97_modes), - .mode = pxa2xx_ac97_modes,}, }, { .name = "pxa2xx-ac97-aux", @@ -403,16 +396,17 @@ struct snd_soc_cpu_dai pxa_ac97_dai[] = { .playback = { .stream_name = "AC97 Aux Playback", .channels_min = 1, - .channels_max = 1,}, + .channels_max = 1, + .rates = PXA2XX_AC97_RATES, + .formats = SNDRV_PCM_FMTBIT_S16_LE,}, .capture = { .stream_name = "AC97 Aux Capture", .channels_min = 1, - .channels_max = 1,}, + .channels_max = 1, + .rates = PXA2XX_AC97_RATES, + .formats = SNDRV_PCM_FMTBIT_S16_LE,}, .ops = { .hw_params = pxa2xx_ac97_hw_aux_params,}, - .caps = { - .num_modes = ARRAY_SIZE(pxa2xx_ac97_modes), - .mode = pxa2xx_ac97_modes,}, }, { .name = "pxa2xx-ac97-mic", @@ -421,12 +415,12 @@ struct snd_soc_cpu_dai pxa_ac97_dai[] = { .capture = { .stream_name = "AC97 Mic Capture", .channels_min = 1, - .channels_max = 1,}, + .channels_max = 1, + .rates = PXA2XX_AC97_RATES, + .formats = SNDRV_PCM_FMTBIT_S16_LE,}, .ops = { .hw_params = pxa2xx_ac97_hw_mic_params,}, - .caps = { - .num_modes = ARRAY_SIZE(pxa2xx_ac97_modes), - .mode = pxa2xx_ac97_modes,},}, +}, }; EXPORT_SYMBOL_GPL(pxa_ac97_dai); diff --git a/sound/soc/pxa/pxa2xx-ac97.h b/sound/soc/pxa/pxa2xx-ac97.h new file mode 100644 index 00000000000..4c4b882316a --- /dev/null +++ b/sound/soc/pxa/pxa2xx-ac97.h @@ -0,0 +1,22 @@ +/* + * linux/sound/arm/pxa2xx-ac97.h + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _PXA2XX_AC97_H +#define _PXA2XX_AC97_H + +/* pxa2xx DAI ID's */ +#define PXA2XX_DAI_AC97_HIFI 0 +#define PXA2XX_DAI_AC97_AUX 1 +#define PXA2XX_DAI_AC97_MIC 2 + +extern struct snd_soc_cpu_dai pxa_ac97_dai[3]; + +/* platform data */ +extern struct snd_ac97_bus_ops pxa2xx_ac97_ops; + +#endif -- cgit v1.2.3 From a8f5d0a5d02cda0183c6e68d6a66d4c6641149a9 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 2 Feb 2007 17:21:50 +0100 Subject: [ALSA] soc - ASoC 0.13 pxa2xx DMA This patch updates the pxa2xx I2S driver to the new API in ASoC 0.13. Changes:- o Added check in hw_params to detect buffer less pcms (i.e. BT <--> codec). o Updated structures to new API o Removed DAI's and ac97 ops from PCM header. o Integer hardware constraint added for periods. Signed-off-by: Andrew Johnson Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/pxa/pxa2xx-pcm.c | 11 ++++++++++- sound/soc/pxa/pxa2xx-pcm.h | 14 -------------- 2 files changed, 10 insertions(+), 15 deletions(-) (limited to 'sound') diff --git a/sound/soc/pxa/pxa2xx-pcm.c b/sound/soc/pxa/pxa2xx-pcm.c index ff32f892287..35e8fa3a469 100644 --- a/sound/soc/pxa/pxa2xx-pcm.c +++ b/sound/soc/pxa/pxa2xx-pcm.c @@ -76,13 +76,18 @@ static int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_runtime *runtime = substream->runtime; struct pxa2xx_runtime_data *prtd = runtime->private_data; struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct pxa2xx_pcm_dma_params *dma = rtd->cpu_dai->dma_data; + struct pxa2xx_pcm_dma_params *dma = rtd->dai->cpu_dai->dma_data; size_t totsize = params_buffer_bytes(params); size_t period = params_period_bytes(params); pxa_dma_desc *dma_desc; dma_addr_t dma_buff_phys, next_desc_phys; int ret; + /* return if this is a bufferless transfer e.g. + * codec <--> BT codec or GSM modem -- lg FIXME */ + if (!dma) + return 0; + /* this may get called several times by oss emulation * with different params */ if (prtd->params == NULL) { @@ -227,6 +232,10 @@ static int pxa2xx_pcm_open(struct snd_pcm_substream *substream) if (ret) goto out; + ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + if (ret < 0) + goto out; + prtd = kzalloc(sizeof(struct pxa2xx_runtime_data), GFP_KERNEL); if (prtd == NULL) { ret = -ENOMEM; diff --git a/sound/soc/pxa/pxa2xx-pcm.h b/sound/soc/pxa/pxa2xx-pcm.h index 0b55f070da2..54c9c755e50 100644 --- a/sound/soc/pxa/pxa2xx-pcm.h +++ b/sound/soc/pxa/pxa2xx-pcm.h @@ -28,21 +28,7 @@ struct pxa2xx_gpio { u32 frm; }; -/* pxa2xx DAI ID's */ -#define PXA2XX_DAI_AC97_HIFI 0 -#define PXA2XX_DAI_AC97_AUX 1 -#define PXA2XX_DAI_AC97_MIC 2 -#define PXA2XX_DAI_I2S 0 -#define PXA2XX_DAI_SSP1 0 -#define PXA2XX_DAI_SSP2 1 -#define PXA2XX_DAI_SSP3 2 - -extern struct snd_soc_cpu_dai pxa_ac97_dai[3]; -extern struct snd_soc_cpu_dai pxa_i2s_dai; -extern struct snd_soc_cpu_dai pxa_ssp_dai[3]; - /* platform data */ extern struct snd_soc_platform pxa2xx_soc_platform; -extern struct snd_ac97_bus_ops pxa2xx_ac97_ops; #endif -- cgit v1.2.3 From d928b25a89c3154fe6d0e62a83f51c5b621aa099 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 2 Feb 2007 17:22:20 +0100 Subject: [ALSA] soc - ASoC Sharp corgi machine This patch updates the Sharp corgi machine driver to the new API in ASoC 0.13. Changes:- o Manually configure DAI hardware format. o Removed config_sysclk() function. No longer needed as clocking is now configured manually. Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/pxa/corgi.c | 84 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 53 insertions(+), 31 deletions(-) (limited to 'sound') diff --git a/sound/soc/pxa/corgi.c b/sound/soc/pxa/corgi.c index 2b1c6e94d1e..5ee51a994ac 100644 --- a/sound/soc/pxa/corgi.c +++ b/sound/soc/pxa/corgi.c @@ -37,6 +37,7 @@ #include "../codecs/wm8731.h" #include "pxa2xx-pcm.h" +#include "pxa2xx-i2s.h" #define CORGI_HP 0 #define CORGI_MIC 1 @@ -119,8 +120,59 @@ static int corgi_shutdown(struct snd_pcm_substream *substream) return 0; } +static int corgi_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; + struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; + unsigned int clk = 0; + int ret = 0; + + switch (params_rate(params)) { + case 8000: + case 16000: + case 48000: + case 96000: + clk = 12288000; + break; + case 11025: + case 22050: + case 44100: + clk = 11289600; + break; + } + + /* set codec DAI configuration */ + ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) + return ret; + + /* set cpu DAI configuration */ + ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) + return ret; + + /* set the codec system clock for DAC and ADC */ + ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8731_SYSCLK, clk, + SND_SOC_CLOCK_IN); + if (ret < 0) + return ret; + + /* set the I2S system clock as input (unused) */ + ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0, + SND_SOC_CLOCK_IN); + if (ret < 0) + return ret; + + return 0; +} + static struct snd_soc_ops corgi_ops = { .startup = corgi_startup, + .hw_params = corgi_hw_params, .shutdown = corgi_shutdown, }; @@ -264,35 +316,6 @@ static int corgi_wm8731_init(struct snd_soc_codec *codec) return 0; } -static unsigned int corgi_config_sysclk(struct snd_soc_pcm_runtime *rtd, - struct snd_soc_clock_info *info) -{ - if (info->bclk_master & SND_SOC_DAIFMT_CBS_CFS) { - /* pxa2xx is i2s master */ - switch (info->rate) { - case 44100: - case 88200: - /* configure codec digital filters for 44.1, 88.2 */ - rtd->codec_dai->config_sysclk(rtd->codec_dai, info, - 11289600); - break; - default: - /* configure codec digital filters for all other rates */ - rtd->codec_dai->config_sysclk(rtd->codec_dai, info, - CORGI_AUDIO_CLOCK); - break; - } - /* config pxa i2s as master */ - return rtd->cpu_dai->config_sysclk(rtd->cpu_dai, info, - CORGI_AUDIO_CLOCK); - } else { - /* codec is i2s master - - * only configure codec DAI clock and filters */ - return rtd->codec_dai->config_sysclk(rtd->codec_dai, info, - CORGI_AUDIO_CLOCK); - } -} - /* corgi digital audio interface glue - connects codec <--> CPU */ static struct snd_soc_dai_link corgi_dai = { .name = "WM8731", @@ -300,7 +323,7 @@ static struct snd_soc_dai_link corgi_dai = { .cpu_dai = &pxa_i2s_dai, .codec_dai = &wm8731_dai, .init = corgi_wm8731_init, - .config_sysclk = corgi_config_sysclk, + .ops = &corgi_ops, }; /* corgi audio machine driver */ @@ -308,7 +331,6 @@ static struct snd_soc_machine snd_soc_machine_corgi = { .name = "Corgi", .dai_link = &corgi_dai, .num_links = 1, - .ops = &corgi_ops, }; /* corgi audio private data */ -- cgit v1.2.3 From 97952f601e939278df1194bac56b9755338ee7c1 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 2 Feb 2007 17:22:46 +0100 Subject: [ALSA] soc - ASoC 0.13 spitz machine This patch updates the Sharp spitz machine driver to the new API in ASoC 0.13. Changes:- o Manually configure DAI hardware format. o Removed config_sysclk() function. No longer needed as clocking is now configured manually. Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/pxa/spitz.c | 86 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 53 insertions(+), 33 deletions(-) (limited to 'sound') diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c index 17c8e61efe6..80e82109fef 100644 --- a/sound/soc/pxa/spitz.c +++ b/sound/soc/pxa/spitz.c @@ -37,6 +37,7 @@ #include #include "../codecs/wm8750.h" #include "pxa2xx-pcm.h" +#include "pxa2xx-i2s.h" #define SPITZ_HP 0 #define SPITZ_MIC 1 @@ -121,8 +122,59 @@ static int spitz_startup(struct snd_pcm_substream *substream) return 0; } +static int spitz_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; + struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; + unsigned int clk = 0; + int ret = 0; + + switch (params_rate(params)) { + case 8000: + case 16000: + case 48000: + case 96000: + clk = 12288000; + break; + case 11025: + case 22050: + case 44100: + clk = 11289600; + break; + } + + /* set codec DAI configuration */ + ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) + return ret; + + /* set cpu DAI configuration */ + ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) + return ret; + + /* set the codec system clock for DAC and ADC */ + ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8750_SYSCLK, clk, + SND_SOC_CLOCK_IN); + if (ret < 0) + return ret; + + /* set the I2S system clock as input (unused) */ + ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0, + SND_SOC_CLOCK_IN); + if (ret < 0) + return ret; + + return 0; +} + static struct snd_soc_ops spitz_ops = { .startup = spitz_startup, + .hw_params = spitz_hw_params, }; static int spitz_get_jack(struct snd_kcontrol *kcontrol, @@ -276,37 +328,6 @@ static int spitz_wm8750_init(struct snd_soc_codec *codec) return 0; } -static unsigned int spitz_config_sysclk(struct snd_soc_pcm_runtime *rtd, - struct snd_soc_clock_info *info) -{ - if (info->bclk_master & SND_SOC_DAIFMT_CBS_CFS) { - /* pxa2xx is i2s master */ - switch (info->rate) { - case 11025: - case 22050: - case 44100: - case 88200: - /* configure codec digital filters - * for 11.025, 22.05, 44.1, 88.2 */ - rtd->codec_dai->config_sysclk(rtd->codec_dai, info, - 11289600); - break; - default: - /* configure codec digital filters for all other rates */ - rtd->codec_dai->config_sysclk(rtd->codec_dai, info, - SPITZ_AUDIO_CLOCK); - break; - } - /* configure pxa2xx i2s interface clocks as master */ - return rtd->cpu_dai->config_sysclk(rtd->cpu_dai, info, - SPITZ_AUDIO_CLOCK); - } else { - /* codec is i2s master - only configure codec DAI clock */ - return rtd->codec_dai->config_sysclk(rtd->codec_dai, info, - SPITZ_AUDIO_CLOCK); - } -} - /* spitz digital audio interface glue - connects codec <--> CPU */ static struct snd_soc_dai_link spitz_dai = { .name = "wm8750", @@ -314,7 +335,7 @@ static struct snd_soc_dai_link spitz_dai = { .cpu_dai = &pxa_i2s_dai, .codec_dai = &wm8750_dai, .init = spitz_wm8750_init, - .config_sysclk = spitz_config_sysclk, + .ops = &spitz_ops, }; /* spitz audio machine driver */ @@ -322,7 +343,6 @@ static struct snd_soc_machine snd_soc_machine_spitz = { .name = "Spitz", .dai_link = &spitz_dai, .num_links = 1, - .ops = &spitz_ops, }; /* spitz audio private data */ -- cgit v1.2.3 From cb4c048b9306555ccbdb97eaf7922624664b0eb1 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 2 Feb 2007 17:23:11 +0100 Subject: [ALSA] soc - ASoC 0.13 Sharp tosa machine This patch updates the Sharp tosa machine driver to the new API in ASoC 0.13. Changes:- o Update machine operations to new API. Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/pxa/tosa.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c index 8c3c6b0534d..5504e30acf1 100644 --- a/sound/soc/pxa/tosa.c +++ b/sound/soc/pxa/tosa.c @@ -40,6 +40,7 @@ #include "../codecs/wm9712.h" #include "pxa2xx-pcm.h" +#include "pxa2xx-ac97.h" static struct snd_soc_machine tosa; @@ -228,12 +229,14 @@ static struct snd_soc_dai_link tosa_dai[] = { .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI], .codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI], .init = tosa_ac97_init, + .ops = &tosa_ops, }, { .name = "AC97 Aux", .stream_name = "AC97 Aux", .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX], .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX], + .ops = &tosa_ops, }, }; @@ -241,7 +244,6 @@ static struct snd_soc_machine tosa = { .name = "Tosa", .dai_link = tosa_dai, .num_links = ARRAY_SIZE(tosa_dai), - .ops = &tosa_ops, }; static struct snd_soc_device tosa_snd_devdata = { -- cgit v1.2.3 From 73f40dc1e147b41eb74bc92ff62bb65cb3260eff Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 2 Feb 2007 17:23:42 +0100 Subject: [ALSA] soc - ASoC 0.13 Sharp poodle machine This patch updates the Sharp poodle machine driver to the new API in ASoC 0.13. Changes:- o Manually configure DAI hardware format. o Removed config_sysclk() function. No longer needed as clocking is now configured manually. Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/pxa/poodle.c | 83 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 53 insertions(+), 30 deletions(-) (limited to 'sound') diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c index ee933608682..0915cf74042 100644 --- a/sound/soc/pxa/poodle.c +++ b/sound/soc/pxa/poodle.c @@ -34,6 +34,7 @@ #include "../codecs/wm8731.h" #include "pxa2xx-pcm.h" +#include "pxa2xx-i2s.h" #define POODLE_HP 1 #define POODLE_HP_OFF 0 @@ -100,8 +101,59 @@ static int poodle_shutdown(struct snd_pcm_substream *substream) return 0; } +static int poodle_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; + struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; + unsigned int clk = 0; + int ret = 0; + + switch (params_rate(params)) { + case 8000: + case 16000: + case 48000: + case 96000: + clk = 12288000; + break; + case 11025: + case 22050: + case 44100: + clk = 11289600; + break; + } + + /* set codec DAI configuration */ + ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) + return ret; + + /* set cpu DAI configuration */ + ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) + return ret; + + /* set the codec system clock for DAC and ADC */ + ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8731_SYSCLK, clk, + SND_SOC_CLOCK_IN); + if (ret < 0) + return ret; + + /* set the I2S system clock as input (unused) */ + ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0, + SND_SOC_CLOCK_IN); + if (ret < 0) + return ret; + + return 0; +} + static struct snd_soc_ops poodle_ops = { .startup = poodle_startup, + .hw_params = poodle_hw_params, .shutdown = poodle_shutdown, }; @@ -225,34 +277,6 @@ static int poodle_wm8731_init(struct snd_soc_codec *codec) return 0; } -static unsigned int poodle_config_sysclk(struct snd_soc_pcm_runtime *rtd, - struct snd_soc_clock_info *info) -{ - if (info->bclk_master & SND_SOC_DAIFMT_CBS_CFS) { - /* pxa2xx is i2s master */ - switch (info->rate) { - case 44100: - case 88200: - /* configure codec digital filters for 44.1, 88.2 */ - rtd->codec_dai->config_sysclk(rtd->codec_dai, info, - 11289600); - break; - default: - /* configure codec digital filters for all other rates */ - rtd->codec_dai->config_sysclk(rtd->codec_dai, info, - POODLE_AUDIO_CLOCK); - break; - } - return rtd->cpu_dai->config_sysclk(rtd->cpu_dai, info, - POODLE_AUDIO_CLOCK); - } else { - /* codec is i2s master - - * only configure codec DAI clock and filters */ - return rtd->codec_dai->config_sysclk(rtd->codec_dai, info, - POODLE_AUDIO_CLOCK); - } -} - /* poodle digital audio interface glue - connects codec <--> CPU */ static struct snd_soc_dai_link poodle_dai = { .name = "WM8731", @@ -260,7 +284,7 @@ static struct snd_soc_dai_link poodle_dai = { .cpu_dai = &pxa_i2s_dai, .codec_dai = &wm8731_dai, .init = poodle_wm8731_init, - .config_sysclk = poodle_config_sysclk, + .ops = &poodle_ops, }; /* poodle audio machine driver */ @@ -268,7 +292,6 @@ static struct snd_soc_machine snd_soc_machine_poodle = { .name = "Poodle", .dai_link = &poodle_dai, .num_links = 1, - .ops = &poodle_ops, }; /* poodle audio private data */ -- cgit v1.2.3 From f32610edab47f36946d23b883aeae91e15986121 Mon Sep 17 00:00:00 2001 From: Jakub Schmidtke Date: Fri, 2 Feb 2007 18:17:27 +0100 Subject: [ALSA] hda-codec - Add ALC861VD/ALC660VD support o Added ALC861VD support to patch_realtek.c under hda-intel o Added ALC660VD as a model of 861VD o Added pci quirks for Asus G1 as well as for two devices found in Realtek's driver to point at ALC660VD model (3stack-660) o Added pci quirk for Lenovo 3000 C200 - although untested, it should work with ALC861VD 3stack model o Changed preset id = 0x10ec0660 to point at new patch_alc861vd instead of patch_861 o Organised the list of presets Signed-off-by: Jakub Schmidtke Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 708 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 702 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index c022e8157c3..583295deaec 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -108,6 +108,16 @@ enum { ALC861_MODEL_LAST, }; +/* ALC861-VD models */ +enum { + ALC660VD_3ST, + ALC861VD_3ST, + ALC861VD_3ST_DIG, + ALC861VD_6ST_DIG, + ALC861VD_AUTO, + ALC861VD_MODEL_LAST, +}; + /* ALC882 models */ enum { ALC882_3ST_DIG, @@ -7924,21 +7934,707 @@ static int patch_alc861(struct hda_codec *codec) return 0; } +/* + * ALC861-VD support + * + * Based on ALC882 + * + * In addition, an independent DAC + */ +#define ALC861VD_DIGOUT_NID 0x06 + +static hda_nid_t alc861vd_dac_nids[4] = { + /* front, surr, clfe, side surr */ + 0x02, 0x03, 0x04, 0x05 +}; + +/* dac_nids for ALC660vd are in a different order - according to + * Realtek's driver. + * This should probably tesult in a different mixer for 6stack models + * of ALC660vd codecs, but for now there is only 3stack mixer + * - and it is the same as in 861vd. + * adc_nids in ALC660vd are (is) the same as in 861vd + */ +static hda_nid_t alc660vd_dac_nids[3] = { + /* front, rear, clfe, rear_surr */ + 0x02, 0x04, 0x03 +}; + +static hda_nid_t alc861vd_adc_nids[1] = { + /* ADC0 */ + 0x09, +}; + +/* input MUX */ +/* FIXME: should be a matrix-type input source selection */ +static struct hda_input_mux alc861vd_capture_source = { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Front Mic", 0x1 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + }, +}; + +#define alc861vd_mux_enum_info alc_mux_enum_info +#define alc861vd_mux_enum_get alc_mux_enum_get + +static int alc861vd_mux_enum_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct alc_spec *spec = codec->spec; + const struct hda_input_mux *imux = spec->input_mux; + unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + static hda_nid_t capture_mixers[1] = { 0x22 }; + hda_nid_t nid = capture_mixers[adc_idx]; + unsigned int *cur_val = &spec->cur_mux[adc_idx]; + unsigned int i, idx; + + idx = ucontrol->value.enumerated.item[0]; + if (idx >= imux->num_items) + idx = imux->num_items - 1; + if (*cur_val == idx && ! codec->in_resume) + return 0; + for (i = 0; i < imux->num_items; i++) { + unsigned int v = (i == idx) ? 0x7000 : 0x7080; + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, + v | (imux->items[i].index << 8)); + } + *cur_val = idx; + return 1; +} + +/* + * 2ch mode + */ +static struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = { + { 2, NULL } +}; + +/* + * 6ch mode + */ +static struct hda_verb alc861vd_6stack_ch6_init[] = { + { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, + { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { } /* end */ +}; + +/* + * 8ch mode + */ +static struct hda_verb alc861vd_6stack_ch8_init[] = { + { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { } /* end */ +}; + +static struct hda_channel_mode alc861vd_6stack_modes[2] = { + { 6, alc861vd_6stack_ch6_init }, + { 8, alc861vd_6stack_ch8_init }, +}; + +static struct snd_kcontrol_new alc861vd_chmode_mixer[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc_ch_mode_info, + .get = alc_ch_mode_get, + .put = alc_ch_mode_put, + }, + { } /* end */ +}; + +static struct snd_kcontrol_new alc861vd_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), + + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* The multiple "Capture Source" controls confuse alsamixer + * So call somewhat different.. + *FIXME: the controls appear in the "playback" view! + */ + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 1, + .info = alc861vd_mux_enum_info, + .get = alc861vd_mux_enum_get, + .put = alc861vd_mux_enum_put, + }, + { } /* end */ +}; + +/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17 + * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b + */ +static struct snd_kcontrol_new alc861vd_6st_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + + HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, + HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, + HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + + HDA_CODEC_VOLUME("Side Playback Volume", 0x05, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), + + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + + HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + + HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + + HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), + HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), + + { } /* end */ +}; + +static struct snd_kcontrol_new alc861vd_3st_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + + HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + + HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + + HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), + HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), + + { } /* end */ +}; + +/* + * generic initialization of ADC, input mixers and output mixers + */ +static struct hda_verb alc861vd_volume_init_verbs[] = { + /* + * Unmute ADC0 and set the default input to mic-in + */ + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of + * the analog-loopback mixer widget + */ + /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + + /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(6)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(8)}, + + /* + * Set up output mixers (0x02 - 0x05) + */ + /* set vol=0 to output mixers */ + {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + /* set up input amps for analog loopback */ + /* Amp Indices: DAC = 0, mixer = 1 */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + + { } +}; + +/* + * 3-stack pin configuration: + * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b + */ +static struct hda_verb alc861vd_3stack_init_verbs[] = { + /* + * Set pin mode and muting + */ + /* set front pin widgets 0x14 for output */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* Mic (rear) pin: input vref at 80% */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Front Mic pin: input vref at 80% */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Line In pin: input */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Line-2 In: Headphone output (output 0 - 0x0c) */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* CD pin widget for input */ + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + + { } +}; + +/* + * 6-stack pin configuration: + */ +static struct hda_verb alc861vd_6stack_init_verbs[] = { + /* + * Set pin mode and muting + */ + /* set front pin widgets 0x14 for output */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* Rear Pin: output 1 (0x0d) */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, + /* CLFE Pin: output 2 (0x0e) */ + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x16, AC_VERB_SET_CONNECT_SEL, 0x02}, + /* Side Pin: output 3 (0x0f) */ + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, + + /* Mic (rear) pin: input vref at 80% */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Front Mic pin: input vref at 80% */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Line In pin: input */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Line-2 In: Headphone output (output 0 - 0x0c) */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* CD pin widget for input */ + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + + { } +}; + +/* pcm configuration: identiacal with ALC880 */ +#define alc861vd_pcm_analog_playback alc880_pcm_analog_playback +#define alc861vd_pcm_analog_capture alc880_pcm_analog_capture +#define alc861vd_pcm_digital_playback alc880_pcm_digital_playback +#define alc861vd_pcm_digital_capture alc880_pcm_digital_capture + +/* + * configuration and preset + */ +static const char *alc861vd_models[ALC861VD_MODEL_LAST] = { + [ALC660VD_3ST] = "3stack-660", + [ALC861VD_3ST] = "3stack", + [ALC861VD_3ST_DIG] = "3stack-digout", + [ALC861VD_6ST_DIG] = "6stack-digout", + [ALC861VD_AUTO] = "auto", +}; + +static struct snd_pci_quirk alc861vd_cfg_tbl[] = { + SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST), + SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST), + SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST), + + SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo 3000 C200", ALC861VD_3ST), + {} +}; + +static struct alc_config_preset alc861vd_presets[] = { + [ALC660VD_3ST] = { + .mixers = { alc861vd_3st_mixer }, + .init_verbs = { alc861vd_volume_init_verbs, + alc861vd_3stack_init_verbs }, + .num_dacs = ARRAY_SIZE(alc660vd_dac_nids), + .dac_nids = alc660vd_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids), + .adc_nids = alc861vd_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), + .channel_mode = alc861vd_3stack_2ch_modes, + .input_mux = &alc861vd_capture_source, + }, + [ALC861VD_3ST] = { + .mixers = { alc861vd_3st_mixer }, + .init_verbs = { alc861vd_volume_init_verbs, + alc861vd_3stack_init_verbs }, + .num_dacs = ARRAY_SIZE(alc861vd_dac_nids), + .dac_nids = alc861vd_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), + .channel_mode = alc861vd_3stack_2ch_modes, + .input_mux = &alc861vd_capture_source, + }, + [ALC861VD_3ST_DIG] = { + .mixers = { alc861vd_3st_mixer }, + .init_verbs = { alc861vd_volume_init_verbs, + alc861vd_3stack_init_verbs }, + .num_dacs = ARRAY_SIZE(alc861vd_dac_nids), + .dac_nids = alc861vd_dac_nids, + .dig_out_nid = ALC861VD_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), + .channel_mode = alc861vd_3stack_2ch_modes, + .input_mux = &alc861vd_capture_source, + }, + [ALC861VD_6ST_DIG] = { + .mixers = { alc861vd_6st_mixer, alc861vd_chmode_mixer }, + .init_verbs = { alc861vd_volume_init_verbs, + alc861vd_6stack_init_verbs }, + .num_dacs = ARRAY_SIZE(alc861vd_dac_nids), + .dac_nids = alc861vd_dac_nids, + .dig_out_nid = ALC861VD_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc861vd_6stack_modes), + .channel_mode = alc861vd_6stack_modes, + .input_mux = &alc861vd_capture_source, + }, +}; + +/* + * BIOS auto configuration + */ +static void alc861vd_auto_set_output_and_unmute(struct hda_codec *codec, + hda_nid_t nid, int pin_type, int dac_idx) +{ + /* set as output */ + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type); + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); +} + +static void alc861vd_auto_init_multi_out(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + int i; + + for (i = 0; i <= HDA_SIDE; i++) { + hda_nid_t nid = spec->autocfg.line_out_pins[i]; + if (nid) + alc861vd_auto_set_output_and_unmute(codec, nid, + PIN_OUT, i); + } +} + + +static void alc861vd_auto_init_hp_out(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + hda_nid_t pin; + + pin = spec->autocfg.hp_pins[0]; + if (pin) /* connect to front and use dac 0 */ + alc861vd_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); +} + +#define alc861vd_is_input_pin(nid) alc880_is_input_pin(nid) +#define ALC861VD_PIN_CD_NID ALC880_PIN_CD_NID + +static void alc861vd_auto_init_analog_input(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + int i; + + for (i = 0; i < AUTO_PIN_LAST; i++) { + hda_nid_t nid = spec->autocfg.input_pins[i]; + if (alc861vd_is_input_pin(nid)) { + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + i <= AUTO_PIN_FRONT_MIC ? + PIN_VREF80 : PIN_IN); + if (nid != ALC861VD_PIN_CD_NID) + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AMP_OUT_MUTE); + } + } +} + +#define alc861vd_idx_to_mixer_vol(nid) ((nid) + 0x02) +#define alc861vd_idx_to_mixer_switch(nid) ((nid) + 0x0c) + +/* add playback controls from the parsed DAC table */ +/* Based on ALC880 version. But ALC861VD has separate, + * different NIDs for mute/unmute switch and volume control */ +static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec, + const struct auto_pin_cfg *cfg) +{ + char name[32]; + static const char *chname[4] = {"Front", "Surround", "CLFE", "Side"}; + hda_nid_t nid_v, nid_s; + int i, err; + + for (i = 0; i < cfg->line_outs; i++) { + if (! spec->multiout.dac_nids[i]) + continue; + nid_v = alc861vd_idx_to_mixer_vol( + alc880_dac_to_idx( + spec->multiout.dac_nids[i])); + nid_s = alc861vd_idx_to_mixer_switch( + alc880_dac_to_idx( + spec->multiout.dac_nids[i])); + + if (i == 2) { + /* Center/LFE */ + if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, + "Center Playback Volume", + HDA_COMPOSE_AMP_VAL(nid_v, 1, + 0, HDA_OUTPUT))) < 0) + return err; + if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, + "LFE Playback Volume", + HDA_COMPOSE_AMP_VAL(nid_v, 2, + 0, HDA_OUTPUT))) < 0) + return err; + if ((err = add_control(spec, ALC_CTL_BIND_MUTE, + "Center Playback Switch", + HDA_COMPOSE_AMP_VAL(nid_s, 1, + 2, HDA_INPUT))) < 0) + return err; + if ((err = add_control(spec, ALC_CTL_BIND_MUTE, + "LFE Playback Switch", + HDA_COMPOSE_AMP_VAL(nid_s, 2, + 2, HDA_INPUT))) < 0) + return err; + } else { + sprintf(name, "%s Playback Volume", chname[i]); + if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, name, + HDA_COMPOSE_AMP_VAL(nid_v, 3, + 0, HDA_OUTPUT))) < 0) + return err; + sprintf(name, "%s Playback Switch", chname[i]); + if ((err = add_control(spec, ALC_CTL_BIND_MUTE, name, + HDA_COMPOSE_AMP_VAL(nid_v, 3, + 2, HDA_INPUT))) < 0) + return err; + } + } + return 0; +} + +/* add playback controls for speaker and HP outputs */ +/* Based on ALC880 version. But ALC861VD has separate, + * different NIDs for mute/unmute switch and volume control */ +static int alc861vd_auto_create_extra_out(struct alc_spec *spec, + hda_nid_t pin, const char *pfx) +{ + hda_nid_t nid_v, nid_s; + int err; + char name[32]; + + if (! pin) + return 0; + + if (alc880_is_fixed_pin(pin)) { + nid_v = alc880_idx_to_dac(alc880_fixed_pin_idx(pin)); + /* specify the DAC as the extra output */ + if (! spec->multiout.hp_nid) + spec->multiout.hp_nid = nid_v; + else + spec->multiout.extra_out_nid[0] = nid_v; + /* control HP volume/switch on the output mixer amp */ + nid_v = alc861vd_idx_to_mixer_vol( + alc880_fixed_pin_idx(pin)); + nid_s = alc861vd_idx_to_mixer_switch( + alc880_fixed_pin_idx(pin)); + + sprintf(name, "%s Playback Volume", pfx); + if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, name, + HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, + HDA_OUTPUT))) < 0) + return err; + sprintf(name, "%s Playback Switch", pfx); + if ((err = add_control(spec, ALC_CTL_BIND_MUTE, name, + HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, + HDA_INPUT))) < 0) + return err; + } else if (alc880_is_multi_pin(pin)) { + /* set manual connection */ + /* we have only a switch on HP-out PIN */ + sprintf(name, "%s Playback Switch", pfx); + if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, + HDA_COMPOSE_AMP_VAL(pin, 3, 0, + HDA_OUTPUT))) < 0) + return err; + } + return 0; +} + +/* parse the BIOS configuration and set up the alc_spec + * return 1 if successful, 0 if the proper config is not found, + * or a negative error code + * Based on ALC880 version - had to change it to override + * alc880_auto_create_extra_out and alc880_auto_create_multi_out_ctls */ +static int alc861vd_parse_auto_config(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + int err; + static hda_nid_t alc861vd_ignore[] = { 0x1d, 0 }; + + if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, + alc861vd_ignore)) < 0) + return err; + if (! spec->autocfg.line_outs) + return 0; /* can't find valid BIOS pin config */ + + if ((err = alc880_auto_fill_dac_nids(spec, &spec->autocfg)) < 0 || + (err = alc861vd_auto_create_multi_out_ctls(spec, + &spec->autocfg)) < 0 || + (err = alc861vd_auto_create_extra_out(spec, + spec->autocfg.speaker_pins[0], "Speaker")) < 0 || + (err = alc861vd_auto_create_extra_out(spec, + spec->autocfg.hp_pins[0], "Headphone")) < 0 || + (err = alc880_auto_create_analog_input_ctls(spec, + &spec->autocfg)) < 0) + return err; + + spec->multiout.max_channels = spec->multiout.num_dacs * 2; + + if (spec->autocfg.dig_out_pin) + spec->multiout.dig_out_nid = ALC861VD_DIGOUT_NID; + + if (spec->kctl_alloc) + spec->mixers[spec->num_mixers++] = spec->kctl_alloc; + + spec->init_verbs[spec->num_init_verbs++] + = alc861vd_volume_init_verbs; + + spec->num_mux_defs = 1; + spec->input_mux = &spec->private_imux; + + return 1; +} + +/* additional initialization for auto-configuration model */ +static void alc861vd_auto_init(struct hda_codec *codec) +{ + alc861vd_auto_init_multi_out(codec); + alc861vd_auto_init_hp_out(codec); + alc861vd_auto_init_analog_input(codec); +} + +static int patch_alc861vd(struct hda_codec *codec) +{ + struct alc_spec *spec; + int err, board_config; + + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; + + codec->spec = spec; + + board_config = snd_hda_check_board_config(codec, ALC861VD_MODEL_LAST, + alc861vd_models, + alc861vd_cfg_tbl); + + if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) { + printk(KERN_INFO "hda_codec: Unknown model for ALC660VD/" + "ALC861VD, trying auto-probe from BIOS...\n"); + board_config = ALC861VD_AUTO; + } + + if (board_config == ALC861VD_AUTO) { + /* automatic parse from the BIOS config */ + err = alc861vd_parse_auto_config(codec); + if (err < 0) { + alc_free(codec); + return err; + } else if (! err) { + printk(KERN_INFO + "hda_codec: Cannot set up configuration " + "from BIOS. Using base mode...\n"); + board_config = ALC861VD_3ST; + } + } + + if (board_config != ALC861VD_AUTO) + setup_preset(spec, &alc861vd_presets[board_config]); + + spec->stream_name_analog = "ALC861VD Analog"; + spec->stream_analog_playback = &alc861vd_pcm_analog_playback; + spec->stream_analog_capture = &alc861vd_pcm_analog_capture; + + spec->stream_name_digital = "ALC861VD Digital"; + spec->stream_digital_playback = &alc861vd_pcm_digital_playback; + spec->stream_digital_capture = &alc861vd_pcm_digital_capture; + + spec->adc_nids = alc861vd_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids); + + spec->mixers[spec->num_mixers] = alc861vd_capture_mixer; + spec->num_mixers++; + + codec->patch_ops = alc_patch_ops; + + if (board_config == ALC861VD_AUTO) + spec->init_hook = alc861vd_auto_init; + + return 0; +} + /* * patch entries */ struct hda_codec_preset snd_hda_preset_realtek[] = { { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 }, { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 }, - { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 }, + { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660", + .patch = patch_alc861 }, + { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd }, + { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 }, + { .id = 0x10ec0862, .name = "ALC861-VD", .patch = patch_alc861vd }, + { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 }, { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 }, { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc883 }, { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 }, { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc883 }, - { .id = 0x10ec0861, .rev = 0x100300, .name = "ALC861", - .patch = patch_alc861 }, - { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660", - .patch = patch_alc861 }, - { .id = 0x10ec0660, .name = "ALC660", .patch = patch_alc861 }, {} /* terminator */ }; -- cgit v1.2.3 From d0b0fac14edf81dc62615cd757e7c73d2059152c Mon Sep 17 00:00:00 2001 From: Bjoern Fay Date: Mon, 5 Feb 2007 12:27:21 +0100 Subject: [ALSA] usbaudio - Add support for Edirol UA-101 Added support for the Edirol UA-101 (only in high-speed mode) by taking the quirks for the UA-1000 and change them accordingly. Changes were made in 'usbaudio.c', 'usbaudio.h', and 'usbquirks.h' MIDI and recording seem to work perfectly (with JACK), but playback gives some few glitches. I think that's the mentioned synchronizing-problem in the UA-1000 quirk ('FIXME: playback must be synchronized to capture'), so I didn't change that. ToDo: Adding Mixer-Support for the built-in control-panel/patch-bay/router. Signed-off-by: Bjoern Fay Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/usb/usbaudio.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++ sound/usb/usbaudio.h | 1 + sound/usb/usbquirks.h | 32 ++++++++++++++++++++++++++++++- 3 files changed, 85 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 8fd37596e3a..4dfb91d4398 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -3077,6 +3077,58 @@ static int create_ua1000_quirk(struct snd_usb_audio *chip, return 0; } +/* + * Create a stream for an Edirol UA-101 interface. + * Copy, paste and modify from Edirol UA-1000 + */ +static int create_ua101_quirk(struct snd_usb_audio *chip, + struct usb_interface *iface, + const struct snd_usb_audio_quirk *quirk) +{ + static const struct audioformat ua101_format = { + .format = SNDRV_PCM_FORMAT_S32_LE, + .fmt_type = USB_FORMAT_TYPE_I, + .altsetting = 1, + .altset_idx = 1, + .attributes = 0, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + }; + struct usb_host_interface *alts; + struct usb_interface_descriptor *altsd; + struct audioformat *fp; + int stream, err; + + if (iface->num_altsetting != 2) + return -ENXIO; + alts = &iface->altsetting[1]; + altsd = get_iface_desc(alts); + if (alts->extralen != 18 || alts->extra[1] != USB_DT_CS_INTERFACE || + altsd->bNumEndpoints != 1) + return -ENXIO; + + fp = kmemdup(&ua101_format, sizeof(*fp), GFP_KERNEL); + if (!fp) + return -ENOMEM; + + fp->channels = alts->extra[11]; + fp->iface = altsd->bInterfaceNumber; + fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress; + fp->ep_attr = get_endpoint(alts, 0)->bmAttributes; + fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); + fp->rate_max = fp->rate_min = combine_triple(&alts->extra[15]); + + stream = (fp->endpoint & USB_DIR_IN) + ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK; + err = add_audio_endpoint(chip, stream, fp); + if (err < 0) { + kfree(fp); + return err; + } + /* FIXME: playback must be synchronized to capture */ + usb_set_interface(chip->dev, fp->iface, 0); + return 0; +} + static int snd_usb_create_quirk(struct snd_usb_audio *chip, struct usb_interface *iface, const struct snd_usb_audio_quirk *quirk); @@ -3258,6 +3310,7 @@ static int snd_usb_create_quirk(struct snd_usb_audio *chip, [QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk, [QUIRK_AUDIO_EDIROL_UA700_UA25] = create_ua700_ua25_quirk, [QUIRK_AUDIO_EDIROL_UA1000] = create_ua1000_quirk, + [QUIRK_AUDIO_EDIROL_UA101] = create_ua101_quirk, }; if (quirk->type < QUIRK_TYPE_COUNT) { diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 0f4b2b8541d..2272f45a186 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -159,6 +159,7 @@ enum quirk_type { QUIRK_AUDIO_FIXED_ENDPOINT, QUIRK_AUDIO_EDIROL_UA700_UA25, QUIRK_AUDIO_EDIROL_UA1000, + QUIRK_AUDIO_EDIROL_UA101, QUIRK_TYPE_COUNT }; diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h index a7e9563a01d..25b4ab4f61e 100644 --- a/sound/usb/usbquirks.h +++ b/sound/usb/usbquirks.h @@ -1098,7 +1098,37 @@ YAMAHA_DEVICE(0x7010, "UB99"), } } }, - /* TODO: add Edirol UA-101 support */ +/* Roland UA-101 in High-Speed Mode only */ +{ + USB_DEVICE(0x0582, 0x007d), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + .vendor_name = "Roland", + .product_name = "UA-101", + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const struct snd_usb_audio_quirk[]) { + { + .ifnum = 0, + .type = QUIRK_AUDIO_EDIROL_UA101 + }, + { + .ifnum = 1, + .type = QUIRK_AUDIO_EDIROL_UA101 + }, + { + .ifnum = 2, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = & (const struct snd_usb_midi_endpoint_info) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + }, + { + .ifnum = -1 + } + } + } +}, { /* has ID 0x0081 when not in "Advanced Driver" mode */ USB_DEVICE(0x0582, 0x0080), -- cgit v1.2.3 From 66e27788a33636cf0d9bf22eb9d56a7f4ffa3a84 Mon Sep 17 00:00:00 2001 From: Martin Langer Date: Mon, 5 Feb 2007 13:02:35 +0100 Subject: [ALSA] ac97_bus power management This patch adds CONFIG_PM to the ac97_bus driver. Signed-off-by: Martin Langer Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/ac97_bus.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sound') diff --git a/sound/ac97_bus.c b/sound/ac97_bus.c index 66de2c2f155..7fa37e15f19 100644 --- a/sound/ac97_bus.c +++ b/sound/ac97_bus.c @@ -26,6 +26,7 @@ static int ac97_bus_match(struct device *dev, struct device_driver *drv) return 1; } +#ifdef CONFIG_PM static int ac97_bus_suspend(struct device *dev, pm_message_t state) { int ret = 0; @@ -45,12 +46,15 @@ static int ac97_bus_resume(struct device *dev) return ret; } +#endif /* CONFIG_PM */ struct bus_type ac97_bus_type = { .name = "ac97", .match = ac97_bus_match, +#ifdef CONFIG_PM .suspend = ac97_bus_suspend, .resume = ac97_bus_resume, +#endif /* CONFIG_PM */ }; static int __init ac97_bus_init(void) -- cgit v1.2.3 From 1ab774e049085da6facfaf3b24d54158c3f0f5b3 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 5 Feb 2007 13:07:04 +0100 Subject: [ALSA] snd-ak4114: Fix two array overflows Fix the handling of the TXCSB registers cache. There was one array overflow in reg_write() and one in snd_ak4114_reg_write(). Thanks to David Binderman for reporting the latter. The second overflow probably doesn't matter much, given that the function snd_ak4114_reg_write() appears to be never called. I wonder why it exists and why it is exported. Signed-off-by: Jean Delvare Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/i2c/other/ak4114.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/i2c/other/ak4114.c b/sound/i2c/other/ak4114.c index d2b17c83fd3..adbfd5884d0 100644 --- a/sound/i2c/other/ak4114.c +++ b/sound/i2c/other/ak4114.c @@ -42,8 +42,8 @@ static void reg_write(struct ak4114 *ak4114, unsigned char reg, unsigned char va ak4114->write(ak4114->private_data, reg, val); if (reg <= AK4114_REG_INT1_MASK) ak4114->regmap[reg] = val; - else if (reg >= AK4114_REG_RXCSB0 && reg <= AK4114_REG_TXCSB4) - ak4114->txcsb[reg-AK4114_REG_RXCSB0] = val; + else if (reg >= AK4114_REG_TXCSB0 && reg <= AK4114_REG_TXCSB4) + ak4114->txcsb[reg-AK4114_REG_TXCSB0] = val; } static inline unsigned char reg_read(struct ak4114 *ak4114, unsigned char reg) @@ -127,7 +127,8 @@ void snd_ak4114_reg_write(struct ak4114 *chip, unsigned char reg, unsigned char if (reg <= AK4114_REG_INT1_MASK) reg_write(chip, reg, (chip->regmap[reg] & ~mask) | val); else if (reg >= AK4114_REG_TXCSB0 && reg <= AK4114_REG_TXCSB4) - reg_write(chip, reg, (chip->txcsb[reg] & ~mask) | val); + reg_write(chip, reg, + (chip->txcsb[reg-AK4114_REG_TXCSB0] & ~mask) | val); } void snd_ak4114_reinit(struct ak4114 *chip) -- cgit v1.2.3 From 88cb42901f1572c95f5933f363cfebd5044c716a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 5 Feb 2007 14:56:20 +0100 Subject: [ALSA] soc - Clean up with kmemdup() Clean up by replacing with kmemdup(). Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/codecs/wm8731.c | 11 +++-------- sound/soc/codecs/wm8750.c | 12 +++--------- sound/soc/soc-dapm.c | 10 ++-------- 3 files changed, 8 insertions(+), 25 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index e6b990507df..7ca0b526828 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -543,14 +543,10 @@ static int wm8731_init(struct snd_soc_device *socdev) codec->dapm_event = wm8731_dapm_event; codec->dai = &wm8731_dai; codec->num_dai = 1; - codec->reg_cache_size = ARRAY_SIZE(wm8731_reg); - codec->reg_cache = - kzalloc(sizeof(u16) * ARRAY_SIZE(wm8731_reg), GFP_KERNEL); + codec->reg_cache_size = sizeof(wm8731_reg); + codec->reg_cache = kmemdup(wm8731_reg, sizeof(wm8731_reg), GFP_KERNEL); if (codec->reg_cache == NULL) return -ENOMEM; - memcpy(codec->reg_cache, - wm8731_reg, sizeof(u16) * ARRAY_SIZE(wm8731_reg)); - codec->reg_cache_size = sizeof(u16) * ARRAY_SIZE(wm8731_reg); wm8731_reset(codec); @@ -627,12 +623,11 @@ static int wm8731_codec_probe(struct i2c_adapter *adap, int addr, int kind) client_template.adapter = adap; client_template.addr = addr; - i2c = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); + i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); if (i2c == NULL) { kfree(codec); return -ENOMEM; } - memcpy(i2c, &client_template, sizeof(struct i2c_client)); i2c_set_clientdata(i2c, codec); codec->control_data = i2c; diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index c1ffb61ef7f..7073e8e294f 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c @@ -807,15 +807,10 @@ static int wm8750_init(struct snd_soc_device *socdev) codec->dapm_event = wm8750_dapm_event; codec->dai = &wm8750_dai; codec->num_dai = 1; - codec->reg_cache_size = ARRAY_SIZE(wm8750_reg); - - codec->reg_cache = - kzalloc(sizeof(u16) * ARRAY_SIZE(wm8750_reg), GFP_KERNEL); + codec->reg_cache_size = sizeof(wm8750_reg); + codec->reg_cache = kmemdup(wm8750_reg, sizeof(wm8750_reg), GFP_KRENEL); if (codec->reg_cache == NULL) return -ENOMEM; - memcpy(codec->reg_cache, wm8750_reg, - sizeof(u16) * ARRAY_SIZE(wm8750_reg)); - codec->reg_cache_size = sizeof(u16) * ARRAY_SIZE(wm8750_reg); wm8750_reset(codec); @@ -900,12 +895,11 @@ static int wm8750_codec_probe(struct i2c_adapter *adap, int addr, int kind) client_template.adapter = adap; client_template.addr = addr; - i2c = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); + i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); if (i2c == NULL) { kfree(codec); return -ENOMEM; } - memcpy(i2c, &client_template, sizeof(struct i2c_client)); i2c_set_clientdata(i2c, codec); codec->control_data = i2c; diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index d0162a4cb7f..7caf8c7b0ac 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -87,16 +87,10 @@ module_param(dapm_status, int, 0); MODULE_PARM_DESC(dapm_status, "enable DPM sysfs entries"); /* create a new dapm widget */ -static struct snd_soc_dapm_widget *dapm_cnew_widget( +static inline struct snd_soc_dapm_widget *dapm_cnew_widget( const struct snd_soc_dapm_widget *_widget) { - struct snd_soc_dapm_widget* widget; - widget = kmalloc(sizeof(struct snd_soc_dapm_widget), GFP_KERNEL); - if (!widget) - return NULL; - - memcpy(widget, _widget, sizeof(struct snd_soc_dapm_widget)); - return widget; + return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL); } /* set up initial codec paths */ -- cgit v1.2.3 From 2594d960793f13582c0730a99c5396cded7cf9d9 Mon Sep 17 00:00:00 2001 From: Rolf Stefan Wilke Date: Tue, 6 Feb 2007 19:18:14 +0100 Subject: [ALSA] emu10k1 - Fix STAC9758 front channel For some time now, some users of STAC9758 (emu10k1) would have no sound on their front channels. This can be fixed (at least for me) by unmuting head phone volume and setting it to 0dB before removing the 'Front Playback' control. For details, cf. https://bugtrack.alsa-project.org/alsa-bug/view.php?id=2308 Find the appropriate patch attached. Credits to: Raymond Signed-off-by: Rolf Stefan Wilke Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/emu10k1/emumixer.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index 0981af842b7..4db6e1ca166 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c @@ -1582,6 +1582,7 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, if (emu->ac97->id == AC97_ID_STAC9758) { emu->rear_ac97 = 1; snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE|AC97SLOT_REAR_LEFT|AC97SLOT_REAR_RIGHT); + snd_ac97_write_cache(emu->ac97, AC97_HEADPHONE, 0x0202); } /* remove unused AC97 controls */ snd_ac97_write_cache(emu->ac97, AC97_SURROUND_MASTER, 0x0202); -- cgit v1.2.3 From 6116ea0741abf8f1ef9d93642d985f91c58ff6bf Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Feb 2007 14:07:08 +0100 Subject: [ALSA] Fix possible deadlocks in sequencer at removal of ports Fix possible rwsem deadlocks in sequencer code at removal of sequencer ports. The list_lock of port group can be double locked. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/core/seq/seq_ports.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c index d88153438d6..eefd1cf872b 100644 --- a/sound/core/seq/seq_ports.c +++ b/sound/core/seq/seq_ports.c @@ -245,9 +245,9 @@ static void clear_subscriber_list(struct snd_seq_client *client, list_del(&subs->dest_list); else list_del(&subs->src_list); + up_write(&agrp->list_mutex); unsubscribe_port(c, aport, agrp, &subs->info, 1); kfree(subs); - up_write(&agrp->list_mutex); snd_seq_port_unlock(aport); snd_seq_client_unlock(c); } -- cgit v1.2.3 From 288e5c35f96fefb6c5e0dc8838834c94cff616f6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 7 Feb 2007 14:07:45 +0100 Subject: [ALSA] aoa: remove suspend/resume printks This just removes two useless printks. Signed-off-by: Johannes Berg Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/aoa/fabrics/snd-aoa-fabric-layout.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'sound') diff --git a/sound/aoa/fabrics/snd-aoa-fabric-layout.c b/sound/aoa/fabrics/snd-aoa-fabric-layout.c index fa4a69fcdc2..1b94ba6dd27 100644 --- a/sound/aoa/fabrics/snd-aoa-fabric-layout.c +++ b/sound/aoa/fabrics/snd-aoa-fabric-layout.c @@ -1077,8 +1077,6 @@ static int aoa_fabric_layout_suspend(struct soundbus_dev *sdev, pm_message_t sta { struct layout_dev *ldev = sdev->ofdev.dev.driver_data; - printk("aoa_fabric_layout_suspend()\n"); - if (ldev->gpio.methods && ldev->gpio.methods->all_amps_off) ldev->gpio.methods->all_amps_off(&ldev->gpio); @@ -1089,8 +1087,6 @@ static int aoa_fabric_layout_resume(struct soundbus_dev *sdev) { struct layout_dev *ldev = sdev->ofdev.dev.driver_data; - printk("aoa_fabric_layout_resume()\n"); - if (ldev->gpio.methods && ldev->gpio.methods->all_amps_off) ldev->gpio.methods->all_amps_restore(&ldev->gpio); -- cgit v1.2.3 From 2cf9f0fc69358e15e78f936c220cfe8aa208111d Mon Sep 17 00:00:00 2001 From: Tobin Davis Date: Wed, 7 Feb 2007 16:04:25 +0100 Subject: [ALSA] hda-codec - Add support for Fujitsu PI1556 Realtek ALC880 This patch adds support for the Fujitsu PI1556 laptop. Issue: Volume knob on system maxes out lower than alsamixer (0x35 vs 0x40). Everything else works, and audio quality is good at 0x35. Signed-off-by: Tobin Davis Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 583295deaec..145682b7807 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -52,6 +52,7 @@ enum { ALC880_ASUS_DIG, ALC880_ASUS_W1V, ALC880_ASUS_DIG2, + ALC880_FUJITSU, ALC880_UNIWILL_DIG, ALC880_UNIWILL, ALC880_UNIWILL_P53, @@ -1073,6 +1074,20 @@ static struct snd_kcontrol_new alc880_uniwill_mixer[] = { { } /* end */ }; +static struct snd_kcontrol_new alc880_fujitsu_mixer[] = { + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + static struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = { HDA_CODEC_VOLUME("HPhone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("HPhone Playback Switch", 0x0c, 2, HDA_INPUT), @@ -1388,6 +1403,11 @@ static struct hda_verb alc880_uniwill_p53_init_verbs[] = { { } }; +static struct hda_verb alc880_beep_init_verbs[] = { + { 0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) }, + { } +}; + /* toggle speaker-output according to the hp-jack state */ static void alc880_uniwill_automute(struct hda_codec *codec) { @@ -2357,6 +2377,8 @@ static const char *alc880_models[ALC880_MODEL_LAST] = { [ALC880_ASUS_DIG] = "asus-dig", [ALC880_ASUS_DIG2] = "asus-dig2", [ALC880_UNIWILL_DIG] = "uniwill", + [ALC880_UNIWILL_P53] = "uniwill-p53", + [ALC880_FUJITSU] = "fujitsu", [ALC880_F1734] = "F1734", [ALC880_LG] = "lg", [ALC880_LG_LW] = "lg-lw", @@ -2427,6 +2449,7 @@ static struct snd_pci_quirk alc880_cfg_tbl[] = { SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG), SND_PCI_QUIRK(0x1734, 0x10ac, "FSC", ALC880_UNIWILL), SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734), + SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU), SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG), SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG), @@ -2635,7 +2658,21 @@ static struct alc_config_preset alc880_presets[] = { .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), .dac_nids = alc880_asus_dac_nids, .num_channel_mode = ARRAY_SIZE(alc880_w810_modes), - .channel_mode = alc880_w810_modes, + .channel_mode = alc880_threestack_modes, + .input_mux = &alc880_capture_source, + .unsol_event = alc880_uniwill_p53_unsol_event, + .init_hook = alc880_uniwill_p53_hp_automute, + }, + [ALC880_FUJITSU] = { + .mixers = { alc880_fujitsu_mixer, + alc880_pcbeep_mixer, }, + .init_verbs = { alc880_volume_init_verbs, + alc880_uniwill_p53_init_verbs, + alc880_beep_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_dac_nids), + .dac_nids = alc880_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), + .channel_mode = alc880_2_jack_modes, .input_mux = &alc880_capture_source, .unsol_event = alc880_uniwill_p53_unsol_event, .init_hook = alc880_uniwill_p53_hp_automute, -- cgit v1.2.3 From 547ac2ae3890b8e17bcfea4ba8840a10f3496da4 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 8 Feb 2007 14:25:39 +0100 Subject: [ALSA] aoa i2sbus: Stop Apple i2s DMA gracefully This fixes the problem of getting extra bytes inserted at the beginning of a recording when using the Apple i2s interface and DBDMA controller. It turns out that we can't just abort the DMA; we have to let it stop at the end of a command, and then wait for the S7 bit to be set before turning off the DBDMA controller. Doing that for playback doesn't seem to be necessary, but doesn't hurt either. We use the technique used by the Darwin driver: make each transfer command branch to a stop command if the S0 status bit is set. Thus we can ask the DMA controller to stop at the end of the current command by setting S0. The interrupt routine now looks at and clears the status word of the DBDMA command ring. This is necessary so it can know when the DBDMA controller has seen that S0 is set, and so when it should look for the DBDMA controller being stopped and S7 being set. This also ended up simplifying the calculation in i2sbus_pcm_pointer. Tested on a 15 inch albook. [Addition by Johannes] I modified this patch and added the suspend/resume bits to it to get my powermac into a decent state when playing sound across suspend to disk that has a different bitrate from what the firmware programs the hardware to. I also added the SNDRV_PCM_INFO_JOINT_DUPLEX flag because it seemed the right thing to do and I was looking at the info stuff. Signed-off-by: Paul Mackerras Signed-off-by: Johannes Berg Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/aoa/soundbus/i2sbus/i2sbus-core.c | 22 +-- sound/aoa/soundbus/i2sbus/i2sbus-pcm.c | 328 +++++++++++++++++++------------- sound/aoa/soundbus/i2sbus/i2sbus.h | 6 + 3 files changed, 210 insertions(+), 146 deletions(-) (limited to 'sound') diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-core.c b/sound/aoa/soundbus/i2sbus/i2sbus-core.c index e593a1333fe..e36f6aa448d 100644 --- a/sound/aoa/soundbus/i2sbus/i2sbus-core.c +++ b/sound/aoa/soundbus/i2sbus/i2sbus-core.c @@ -41,8 +41,8 @@ static int alloc_dbdma_descriptor_ring(struct i2sbus_dev *i2sdev, struct dbdma_command_mem *r, int numcmds) { - /* one more for rounding */ - r->size = (numcmds+1) * sizeof(struct dbdma_cmd); + /* one more for rounding, one for branch back, one for stop command */ + r->size = (numcmds + 3) * sizeof(struct dbdma_cmd); /* We use the PCI APIs for now until the generic one gets fixed * enough or until we get some macio-specific versions */ @@ -377,11 +377,8 @@ static int i2sbus_suspend(struct macio_dev* dev, pm_message_t state) if (i2sdev->sound.pcm) { /* Suspend PCM streams */ snd_pcm_suspend_all(i2sdev->sound.pcm); - /* Probably useless as we handle - * power transitions ourselves */ - snd_power_change_state(i2sdev->sound.pcm->card, - SNDRV_CTL_POWER_D3hot); } + /* Notify codecs */ list_for_each_entry(cii, &i2sdev->sound.codec_list, list) { err = 0; @@ -390,7 +387,11 @@ static int i2sbus_suspend(struct macio_dev* dev, pm_message_t state) if (err) ret = err; } + + /* wait until streams are stopped */ + i2sbus_wait_for_stop_both(i2sdev); } + return ret; } @@ -402,6 +403,9 @@ static int i2sbus_resume(struct macio_dev* dev) int err, ret = 0; list_for_each_entry(i2sdev, &control->list, item) { + /* reset i2s bus format etc. */ + i2sbus_pcm_prepare_both(i2sdev); + /* Notify codecs so they can re-initialize */ list_for_each_entry(cii, &i2sdev->sound.codec_list, list) { err = 0; @@ -410,12 +414,6 @@ static int i2sbus_resume(struct macio_dev* dev) if (err) ret = err; } - /* Notify Alsa */ - if (i2sdev->sound.pcm) { - /* Same comment as above, probably useless */ - snd_power_change_state(i2sdev->sound.pcm->card, - SNDRV_CTL_POWER_D0); - } } return ret; diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c b/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c index 7c81db7e52c..c6b42f9bdbc 100644 --- a/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c +++ b/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c @@ -125,7 +125,8 @@ static int i2sbus_pcm_open(struct i2sbus_dev *i2sdev, int in) } /* bus dependent stuff */ hw->info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_RESUME; + SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_RESUME | + SNDRV_PCM_INFO_JOINT_DUPLEX; CHECK_RATE(5512); CHECK_RATE(8000); @@ -245,18 +246,78 @@ static int i2sbus_pcm_close(struct i2sbus_dev *i2sdev, int in) return err; } +static void i2sbus_wait_for_stop(struct i2sbus_dev *i2sdev, + struct pcm_info *pi) +{ + unsigned long flags; + struct completion done; + long timeout; + + spin_lock_irqsave(&i2sdev->low_lock, flags); + if (pi->dbdma_ring.stopping) { + init_completion(&done); + pi->stop_completion = &done; + spin_unlock_irqrestore(&i2sdev->low_lock, flags); + timeout = wait_for_completion_timeout(&done, HZ); + spin_lock_irqsave(&i2sdev->low_lock, flags); + pi->stop_completion = NULL; + if (timeout == 0) { + /* timeout expired, stop dbdma forcefully */ + printk(KERN_ERR "i2sbus_wait_for_stop: timed out\n"); + /* make sure RUN, PAUSE and S0 bits are cleared */ + out_le32(&pi->dbdma->control, (RUN | PAUSE | 1) << 16); + pi->dbdma_ring.stopping = 0; + timeout = 10; + while (in_le32(&pi->dbdma->status) & ACTIVE) { + if (--timeout <= 0) + break; + udelay(1); + } + } + } + spin_unlock_irqrestore(&i2sdev->low_lock, flags); +} + +#ifdef CONFIG_PM +void i2sbus_wait_for_stop_both(struct i2sbus_dev *i2sdev) +{ + struct pcm_info *pi; + + get_pcm_info(i2sdev, 0, &pi, NULL); + i2sbus_wait_for_stop(i2sdev, pi); + get_pcm_info(i2sdev, 1, &pi, NULL); + i2sbus_wait_for_stop(i2sdev, pi); +} +#endif + static int i2sbus_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); } -static int i2sbus_hw_free(struct snd_pcm_substream *substream) +static inline int i2sbus_hw_free(struct snd_pcm_substream *substream, int in) { + struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream); + struct pcm_info *pi; + + get_pcm_info(i2sdev, in, &pi, NULL); + if (pi->dbdma_ring.stopping) + i2sbus_wait_for_stop(i2sdev, pi); snd_pcm_lib_free_pages(substream); return 0; } +static int i2sbus_playback_hw_free(struct snd_pcm_substream *substream) +{ + return i2sbus_hw_free(substream, 0); +} + +static int i2sbus_record_hw_free(struct snd_pcm_substream *substream) +{ + return i2sbus_hw_free(substream, 1); +} + static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in) { /* whee. Hard work now. The user has selected a bitrate @@ -264,7 +325,7 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in) * I2S controller appropriately. */ struct snd_pcm_runtime *runtime; struct dbdma_cmd *command; - int i, periodsize; + int i, periodsize, nperiods; dma_addr_t offset; struct bus_info bi; struct codec_info_item *cii; @@ -274,6 +335,7 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in) struct pcm_info *pi, *other; int cnt; int result = 0; + unsigned int cmd, stopaddr; mutex_lock(&i2sdev->lock); @@ -283,6 +345,13 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in) result = -EBUSY; goto out_unlock; } + if (pi->dbdma_ring.stopping) + i2sbus_wait_for_stop(i2sdev, pi); + + if (!pi->substream || !pi->substream->runtime) { + result = -EINVAL; + goto out_unlock; + } runtime = pi->substream->runtime; pi->active = 1; @@ -297,24 +366,43 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in) i2sdev->rate = runtime->rate; periodsize = snd_pcm_lib_period_bytes(pi->substream); + nperiods = pi->substream->runtime->periods; pi->current_period = 0; /* generate dbdma command ring first */ command = pi->dbdma_ring.cmds; + memset(command, 0, (nperiods + 2) * sizeof(struct dbdma_cmd)); + + /* commands to DMA to/from the ring */ + /* + * For input, we need to do a graceful stop; if we abort + * the DMA, we end up with leftover bytes that corrupt + * the next recording. To do this we set the S0 status + * bit and wait for the DMA controller to stop. Each + * command has a branch condition to + * make it branch to a stop command if S0 is set. + * On input we also need to wait for the S7 bit to be + * set before turning off the DMA controller. + * In fact we do the graceful stop for output as well. + */ offset = runtime->dma_addr; - for (i = 0; i < pi->substream->runtime->periods; - i++, command++, offset += periodsize) { - memset(command, 0, sizeof(struct dbdma_cmd)); - command->command = - cpu_to_le16((in ? INPUT_MORE : OUTPUT_MORE) | INTR_ALWAYS); + cmd = (in? INPUT_MORE: OUTPUT_MORE) | BR_IFSET | INTR_ALWAYS; + stopaddr = pi->dbdma_ring.bus_cmd_start + + (nperiods + 1) * sizeof(struct dbdma_cmd); + for (i = 0; i < nperiods; i++, command++, offset += periodsize) { + command->command = cpu_to_le16(cmd); + command->cmd_dep = cpu_to_le32(stopaddr); command->phy_addr = cpu_to_le32(offset); command->req_count = cpu_to_le16(periodsize); - command->xfer_status = cpu_to_le16(0); } - /* last one branches back to first */ - command--; - command->command |= cpu_to_le16(BR_ALWAYS); + + /* branch back to beginning of ring */ + command->command = cpu_to_le16(DBDMA_NOP | BR_ALWAYS); command->cmd_dep = cpu_to_le32(pi->dbdma_ring.bus_cmd_start); + command++; + + /* set stop command */ + command->command = cpu_to_le16(DBDMA_STOP); /* ok, let's set the serial format and stuff */ switch (runtime->format) { @@ -435,16 +523,18 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in) return result; } -static struct dbdma_cmd STOP_CMD = { - .command = __constant_cpu_to_le16(DBDMA_STOP), -}; +#ifdef CONFIG_PM +void i2sbus_pcm_prepare_both(struct i2sbus_dev *i2sdev) +{ + i2sbus_pcm_prepare(i2sdev, 0); + i2sbus_pcm_prepare(i2sdev, 1); +} +#endif static int i2sbus_pcm_trigger(struct i2sbus_dev *i2sdev, int in, int cmd) { struct codec_info_item *cii; struct pcm_info *pi; - int timeout; - struct dbdma_cmd tmp; int result = 0; unsigned long flags; @@ -464,92 +554,50 @@ static int i2sbus_pcm_trigger(struct i2sbus_dev *i2sdev, int in, int cmd) cii->codec->start(cii, pi->substream); pi->dbdma_ring.running = 1; - /* reset dma engine */ - out_le32(&pi->dbdma->control, - 0 | (RUN | PAUSE | FLUSH | WAKE) << 16); - timeout = 100; - while (in_le32(&pi->dbdma->status) & RUN && timeout--) - udelay(1); - if (timeout <= 0) { - printk(KERN_ERR - "i2sbus: error waiting for dma reset\n"); - result = -ENXIO; - goto out_unlock; + if (pi->dbdma_ring.stopping) { + /* Clear the S0 bit, then see if we stopped yet */ + out_le32(&pi->dbdma->control, 1 << 16); + if (in_le32(&pi->dbdma->status) & ACTIVE) { + /* possible race here? */ + udelay(10); + if (in_le32(&pi->dbdma->status) & ACTIVE) { + pi->dbdma_ring.stopping = 0; + goto out_unlock; /* keep running */ + } + } } + /* make sure RUN, PAUSE and S0 bits are cleared */ + out_le32(&pi->dbdma->control, (RUN | PAUSE | 1) << 16); + + /* set branch condition select register */ + out_le32(&pi->dbdma->br_sel, (1 << 16) | 1); + /* write dma command buffer address to the dbdma chip */ out_le32(&pi->dbdma->cmdptr, pi->dbdma_ring.bus_cmd_start); - /* post PCI write */ - mb(); - (void)in_le32(&pi->dbdma->status); - - /* change first command to STOP */ - tmp = *pi->dbdma_ring.cmds; - *pi->dbdma_ring.cmds = STOP_CMD; - - /* set running state, remember that the first command is STOP */ - out_le32(&pi->dbdma->control, RUN | (RUN << 16)); - timeout = 100; - /* wait for STOP to be executed */ - while (in_le32(&pi->dbdma->status) & ACTIVE && timeout--) - udelay(1); - if (timeout <= 0) { - printk(KERN_ERR "i2sbus: error waiting for dma stop\n"); - result = -ENXIO; - goto out_unlock; - } - /* again, write dma command buffer address to the dbdma chip, - * this time of the first real command */ - *pi->dbdma_ring.cmds = tmp; - out_le32(&pi->dbdma->cmdptr, pi->dbdma_ring.bus_cmd_start); - /* post write */ - mb(); - (void)in_le32(&pi->dbdma->status); - - /* reset dma engine again */ - out_le32(&pi->dbdma->control, - 0 | (RUN | PAUSE | FLUSH | WAKE) << 16); - timeout = 100; - while (in_le32(&pi->dbdma->status) & RUN && timeout--) - udelay(1); - if (timeout <= 0) { - printk(KERN_ERR - "i2sbus: error waiting for dma reset\n"); - result = -ENXIO; - goto out_unlock; - } - /* wake up the chip with the next descriptor */ - out_le32(&pi->dbdma->control, - (RUN | WAKE) | ((RUN | WAKE) << 16)); - /* get the frame count */ + /* initialize the frame count and current period */ + pi->current_period = 0; pi->frame_count = in_le32(&i2sdev->intfregs->frame_count); + /* set the DMA controller running */ + out_le32(&pi->dbdma->control, (RUN << 16) | RUN); + /* off you go! */ break; + case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: if (!pi->dbdma_ring.running) { result = -EALREADY; goto out_unlock; } + pi->dbdma_ring.running = 0; - /* turn off all relevant bits */ - out_le32(&pi->dbdma->control, - (RUN | WAKE | FLUSH | PAUSE) << 16); - { - /* FIXME: move to own function */ - int timeout = 5000; - while ((in_le32(&pi->dbdma->status) & RUN) - && --timeout > 0) - udelay(1); - if (!timeout) - printk(KERN_ERR - "i2sbus: timed out turning " - "off dbdma engine!\n"); - } + /* Set the S0 bit to make the DMA branch to the stop cmd */ + out_le32(&pi->dbdma->control, (1 << 16) | 1); + pi->dbdma_ring.stopping = 1; - pi->dbdma_ring.running = 0; list_for_each_entry(cii, &i2sdev->sound.codec_list, list) if (cii->codec->stop) cii->codec->stop(cii, pi->substream); @@ -574,70 +622,82 @@ static snd_pcm_uframes_t i2sbus_pcm_pointer(struct i2sbus_dev *i2sdev, int in) fc = in_le32(&i2sdev->intfregs->frame_count); fc = fc - pi->frame_count; - return (bytes_to_frames(pi->substream->runtime, - pi->current_period * - snd_pcm_lib_period_bytes(pi->substream)) - + fc) % pi->substream->runtime->buffer_size; + if (fc >= pi->substream->runtime->buffer_size) + fc %= pi->substream->runtime->buffer_size; + return fc; } static inline void handle_interrupt(struct i2sbus_dev *i2sdev, int in) { struct pcm_info *pi; - u32 fc; - u32 delta; + u32 fc, nframes; + u32 status; + int timeout, i; + int dma_stopped = 0; + struct snd_pcm_runtime *runtime; spin_lock(&i2sdev->low_lock); get_pcm_info(i2sdev, in, &pi, NULL); - - if (!pi->dbdma_ring.running) { - /* there was still an interrupt pending - * while we stopped. or maybe another - * processor (not the one that was stopping - * the DMA engine) was spinning above - * waiting for the lock. */ + if (!pi->dbdma_ring.running && !pi->dbdma_ring.stopping) goto out_unlock; - } - fc = in_le32(&i2sdev->intfregs->frame_count); - /* a counter overflow does not change the calculation. */ - delta = fc - pi->frame_count; - - /* update current_period */ - while (delta >= pi->substream->runtime->period_size) { - pi->current_period++; - delta = delta - pi->substream->runtime->period_size; - } - - if (unlikely(delta)) { - /* Some interrupt came late, so check the dbdma. - * This special case exists to syncronize the frame_count with - * the dbdma transfer, but is hit every once in a while. */ - int period; - - period = (in_le32(&pi->dbdma->cmdptr) - - pi->dbdma_ring.bus_cmd_start) - / sizeof(struct dbdma_cmd); - pi->current_period = pi->current_period - % pi->substream->runtime->periods; - - while (pi->current_period != period) { - pi->current_period++; - pi->current_period %= pi->substream->runtime->periods; - /* Set delta to zero, as the frame_count value is too - * high (otherwise the code path will not be executed). - * This corrects the fact that the frame_count is too - * low at the beginning due to buffering. */ - delta = 0; + i = pi->current_period; + runtime = pi->substream->runtime; + while (pi->dbdma_ring.cmds[i].xfer_status) { + if (le16_to_cpu(pi->dbdma_ring.cmds[i].xfer_status) & BT) + /* + * BT is the branch taken bit. If it took a branch + * it is because we set the S0 bit to make it + * branch to the stop command. + */ + dma_stopped = 1; + pi->dbdma_ring.cmds[i].xfer_status = 0; + + if (++i >= runtime->periods) { + i = 0; + pi->frame_count += runtime->buffer_size; } + pi->current_period = i; + + /* + * Check the frame count. The DMA tends to get a bit + * ahead of the frame counter, which confuses the core. + */ + fc = in_le32(&i2sdev->intfregs->frame_count); + nframes = i * runtime->period_size; + if (fc < pi->frame_count + nframes) + pi->frame_count = fc - nframes; } - pi->frame_count = fc - delta; - pi->current_period %= pi->substream->runtime->periods; + if (dma_stopped) { + timeout = 1000; + for (;;) { + status = in_le32(&pi->dbdma->status); + if (!(status & ACTIVE) && (!in || (status & 0x80))) + break; + if (--timeout <= 0) { + printk(KERN_ERR "i2sbus: timed out " + "waiting for DMA to stop!\n"); + break; + } + udelay(1); + } + + /* Turn off DMA controller, clear S0 bit */ + out_le32(&pi->dbdma->control, (RUN | PAUSE | 1) << 16); + pi->dbdma_ring.stopping = 0; + if (pi->stop_completion) + complete(pi->stop_completion); + } + + if (!pi->dbdma_ring.running) + goto out_unlock; spin_unlock(&i2sdev->low_lock); /* may call _trigger again, hence needs to be unlocked */ snd_pcm_period_elapsed(pi->substream); return; + out_unlock: spin_unlock(&i2sdev->low_lock); } @@ -718,7 +778,7 @@ static struct snd_pcm_ops i2sbus_playback_ops = { .close = i2sbus_playback_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = i2sbus_hw_params, - .hw_free = i2sbus_hw_free, + .hw_free = i2sbus_playback_hw_free, .prepare = i2sbus_playback_prepare, .trigger = i2sbus_playback_trigger, .pointer = i2sbus_playback_pointer, @@ -788,7 +848,7 @@ static struct snd_pcm_ops i2sbus_record_ops = { .close = i2sbus_record_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = i2sbus_hw_params, - .hw_free = i2sbus_hw_free, + .hw_free = i2sbus_record_hw_free, .prepare = i2sbus_record_prepare, .trigger = i2sbus_record_trigger, .pointer = i2sbus_record_pointer, diff --git a/sound/aoa/soundbus/i2sbus/i2sbus.h b/sound/aoa/soundbus/i2sbus/i2sbus.h index ec20ee615d7..ff29654782c 100644 --- a/sound/aoa/soundbus/i2sbus/i2sbus.h +++ b/sound/aoa/soundbus/i2sbus/i2sbus.h @@ -10,6 +10,7 @@ #include #include #include +#include #include @@ -34,6 +35,7 @@ struct dbdma_command_mem { void *space; int size; u32 running:1; + u32 stopping:1; }; struct pcm_info { @@ -45,6 +47,7 @@ struct pcm_info { u32 frame_count; struct dbdma_command_mem dbdma_ring; volatile struct dbdma_regs __iomem *dbdma; + struct completion *stop_completion; }; enum { @@ -101,6 +104,9 @@ i2sbus_tx_intr(int irq, void *devid); extern irqreturn_t i2sbus_rx_intr(int irq, void *devid); +extern void i2sbus_wait_for_stop_both(struct i2sbus_dev *i2sdev); +extern void i2sbus_pcm_prepare_both(struct i2sbus_dev *i2sdev); + /* control specific functions */ extern int i2sbus_control_init(struct macio_dev* dev, struct i2sbus_control **c); -- cgit v1.2.3 From c6d6eeeacc2ed0b736f20692ca021324f3b203b3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 8 Feb 2007 14:50:31 +0100 Subject: [ALSA] ca0106 - Add missing sysfs device assignment Added the missing device assignment before creating sysfs tree. This caused the insufficient device permissions. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/ca0106/ca0106_main.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 6f781b81187..ea6712b63c9 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -1618,6 +1618,8 @@ static int __devinit snd_ca0106_probe(struct pci_dev *pci, snd_ca0106_proc_init(chip); #endif + snd_card_set_dev(card, &pci->dev); + if ((err = snd_card_register(card)) < 0) { snd_card_free(card); return err; -- cgit v1.2.3 From c2902c8ae06762d941fab64198467f78cab6f8cd Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 9 Feb 2007 16:25:48 +0100 Subject: [PATCH] Fix breakage with CONFIG_SYSFS_DEPRECATED The fix for sysfs breakage with CONFIG_SYSFS_DEPRECATED was flown away by the conflicted merge of the ALSA git tree. The patch below fixes it again. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/core/pcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 76fcc5234d8..2743414fc8f 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -968,7 +968,7 @@ static int snd_pcm_dev_register(struct snd_device *device) * if possible */ dev = pcm->dev; if (!dev) - dev = pcm->card ? pcm->card->dev : NULL; + dev = snd_card_get_device_link(pcm->card); /* register pcm */ err = snd_register_device_for_dev(devtype, pcm->card, pcm->device, -- cgit v1.2.3