2009-09-28 13:11:27 +04:00
/*
* card driver for models with PCM1796 DACs ( Xonar D2 / D2X / HDAV1 .3 / ST / STX )
*
* Copyright ( c ) Clemens Ladisch < clemens @ ladisch . de >
*
*
* This driver is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License , version 2.
*
* 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 driver ; if not , see < http : //www.gnu.org/licenses/>.
*/
/*
* Xonar D2 / D2X
* - - - - - - - - - - - -
*
* CMI8788 :
*
2010-12-02 13:42:48 +03:00
* SPI 0 - > 1 st PCM1796 ( front )
* SPI 1 - > 2 nd PCM1796 ( surround )
* SPI 2 - > 3 rd PCM1796 ( center / LFE )
* SPI 4 - > 4 th PCM1796 ( back )
2009-09-28 13:11:27 +04:00
*
2010-12-02 13:42:48 +03:00
* GPIO 2 - > M0 of CS5381
* GPIO 3 - > M1 of CS5381
* GPIO 5 < - external power present ( D2X only )
* GPIO 7 - > ALT
* GPIO 8 - > enable output to speakers
2009-09-28 13:17:36 +04:00
*
* CM9780 :
*
2010-12-02 13:42:48 +03:00
* LINE_OUT - > input of ADC
*
* AUX_IN < - aux
* VIDEO_IN < - CD
* FMIC_IN < - mic
*
* GPO 0 - > route line - in ( 0 ) or AC97 output ( 1 ) to CS5381 input
2009-09-28 13:11:27 +04:00
*/
/*
* Xonar HDAV1 .3 ( Deluxe )
* - - - - - - - - - - - - - - - - - - - - - -
*
* CMI8788 :
*
2010-12-02 13:42:48 +03:00
* I ² C < - > PCM1796 ( addr 1001100 ) ( front )
2009-09-28 13:11:27 +04:00
*
2010-12-02 13:42:48 +03:00
* GPI 0 < - external power present
2009-09-28 13:11:27 +04:00
*
2010-12-02 13:42:48 +03:00
* GPIO 0 - > enable HDMI ( 0 ) or speaker ( 1 ) output
* GPIO 2 - > M0 of CS5381
* GPIO 3 - > M1 of CS5381
* GPIO 4 < - daughterboard detection
* GPIO 5 < - daughterboard detection
* GPIO 6 - > ?
* GPIO 7 - > ?
* GPIO 8 - > route input jack to line - in ( 0 ) or mic - in ( 1 )
2009-09-28 13:11:27 +04:00
*
2010-12-02 13:42:48 +03:00
* UART < - > HDMI controller
2009-09-28 13:11:27 +04:00
*
2009-09-28 13:17:36 +04:00
* CM9780 :
*
2010-12-02 13:42:48 +03:00
* LINE_OUT - > input of ADC
*
* AUX_IN < - aux
* CD_IN < - CD
* MIC_IN < - mic
*
* GPO 0 - > route line - in ( 0 ) or AC97 output ( 1 ) to CS5381 input
2009-09-28 13:17:36 +04:00
*
2009-09-28 13:11:27 +04:00
* no daughterboard
* - - - - - - - - - - - - - - - -
*
2010-12-02 13:42:48 +03:00
* GPIO 4 < - 1
2009-09-28 13:11:27 +04:00
*
* H6 daughterboard
* - - - - - - - - - - - - - - - -
*
2010-12-02 13:42:48 +03:00
* GPIO 4 < - 0
* GPIO 5 < - 0
2009-09-28 13:11:27 +04:00
*
2010-12-02 13:42:48 +03:00
* I ² C < - > PCM1796 ( addr 1001101 ) ( surround )
* < - > PCM1796 ( addr 1001110 ) ( center / LFE )
* < - > PCM1796 ( addr 1001111 ) ( back )
2009-09-28 13:11:27 +04:00
*
* unknown daughterboard
* - - - - - - - - - - - - - - - - - - - - -
*
2010-12-02 13:42:48 +03:00
* GPIO 4 < - 0
* GPIO 5 < - 1
2009-09-28 13:11:27 +04:00
*
2010-12-02 13:42:48 +03:00
* I ² C < - > CS4362A ( addr 0011000 ) ( surround , center / LFE , back )
2009-09-28 13:11:27 +04:00
*/
/*
2014-08-04 17:17:55 +04:00
* Xonar Essence ST ( Deluxe ) / STX ( II )
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2009-09-28 13:11:27 +04:00
*
* CMI8788 :
*
2010-12-02 13:42:48 +03:00
* I ² C < - > PCM1792A ( addr 1001100 )
* < - > CS2000 ( addr 1001110 ) ( ST only )
2009-09-28 13:15:01 +04:00
*
2010-12-02 13:42:48 +03:00
* ADC1 MCLK - > REF_CLK of CS2000 ( ST only )
2009-09-28 13:11:27 +04:00
*
2010-12-02 13:42:48 +03:00
* GPI 0 < - external power present ( STX only )
2009-09-28 13:11:27 +04:00
*
2010-12-02 13:42:48 +03:00
* GPIO 0 - > enable output to speakers
* GPIO 1 - > route HP to front panel ( 0 ) or rear jack ( 1 )
* GPIO 2 - > M0 of CS5381
* GPIO 3 - > M1 of CS5381
* GPIO 4 < - daughterboard detection
* GPIO 5 < - daughterboard detection
* GPIO 6 - > ?
* GPIO 7 - > route output to speaker jacks ( 0 ) or HP ( 1 )
* GPIO 8 - > route input jack to line - in ( 0 ) or mic - in ( 1 )
2009-09-28 13:11:27 +04:00
*
* PCM1792A :
*
2010-12-02 13:42:48 +03:00
* SCK < - CLK_OUT of CS2000 ( ST only )
2009-09-28 13:17:36 +04:00
*
2010-12-02 13:42:48 +03:00
* CM9780 :
2009-09-28 13:17:36 +04:00
*
2010-12-02 13:42:48 +03:00
* LINE_OUT - > input of ADC
2009-09-28 13:17:36 +04:00
*
2010-12-02 13:42:48 +03:00
* AUX_IN < - aux
* MIC_IN < - mic
2009-09-28 13:17:36 +04:00
*
2010-12-02 13:42:48 +03:00
* GPO 0 - > route line - in ( 0 ) or AC97 output ( 1 ) to CS5381 input
2009-09-28 13:11:27 +04:00
*
* H6 daughterboard
* - - - - - - - - - - - - - - - -
*
* GPIO 4 < - 0
* GPIO 5 < - 0
*/
2010-10-04 15:22:51 +04:00
/*
2010-12-02 13:42:48 +03:00
* Xonar Xense
* - - - - - - - - - - -
2010-10-04 15:22:51 +04:00
*
* CMI8788 :
*
2010-12-02 13:42:48 +03:00
* I ² C < - > PCM1796 ( addr 1001100 ) ( front )
* < - > CS4362A ( addr 0011000 ) ( surround , center / LFE , back )
* < - > CS2000 ( addr 1001110 )
*
* ADC1 MCLK - > REF_CLK of CS2000
*
* GPI 0 < - external power present
*
* GPIO 0 - > enable output
* GPIO 1 - > route HP to front panel ( 0 ) or rear jack ( 1 )
* GPIO 2 - > M0 of CS5381
* GPIO 3 - > M1 of CS5381
* GPIO 4 - > enable output
* GPIO 5 - > enable output
* GPIO 6 - > ?
* GPIO 7 - > route output to HP ( 0 ) or speaker ( 1 )
* GPIO 8 - > route input jack to mic - in ( 0 ) or line - in ( 1 )
*
* CM9780 :
*
* LINE_OUT - > input of ADC
*
* AUX_IN < - aux
* VIDEO_IN < - ?
* FMIC_IN < - mic
2010-10-04 15:22:51 +04:00
*
2010-12-02 13:42:48 +03:00
* GPO 0 - > route line - in ( 0 ) or AC97 output ( 1 ) to CS5381 input
* GPO 1 - > route mic - in from input jack ( 0 ) or front panel header ( 1 )
2010-10-04 15:22:51 +04:00
*/
2009-09-28 13:11:27 +04:00
# include <linux/pci.h>
# include <linux/delay.h>
# include <linux/mutex.h>
# include <sound/ac97_codec.h>
# include <sound/control.h>
# include <sound/core.h>
2010-12-02 13:41:10 +03:00
# include <sound/info.h>
2009-09-28 13:11:27 +04:00
# include <sound/pcm.h>
# include <sound/pcm_params.h>
# include <sound/tlv.h>
# include "xonar.h"
# include "cm9780.h"
# include "pcm1796.h"
2009-09-28 13:15:01 +04:00
# include "cs2000.h"
2009-09-28 13:11:27 +04:00
# define GPIO_D2X_EXT_POWER 0x0020
# define GPIO_D2_ALT 0x0080
# define GPIO_D2_OUTPUT_ENABLE 0x0100
# define GPI_EXT_POWER 0x01
# define GPIO_INPUT_ROUTE 0x0100
# define GPIO_HDAV_OUTPUT_ENABLE 0x0001
2010-12-02 13:36:51 +03:00
# define GPIO_HDAV_MAGIC 0x00c0
2009-09-28 13:11:27 +04:00
# define GPIO_DB_MASK 0x0030
# define GPIO_DB_H6 0x0000
# define GPIO_ST_OUTPUT_ENABLE 0x0001
# define GPIO_ST_HP_REAR 0x0002
2010-12-02 13:36:51 +03:00
# define GPIO_ST_MAGIC 0x0040
2009-09-28 13:11:27 +04:00
# define GPIO_ST_HP 0x0080
2014-09-10 22:58:25 +04:00
# define GPIO_XENSE_OUTPUT_ENABLE (0x0001 | 0x0010 | 0x0020)
# define GPIO_XENSE_SPEAKERS 0x0080
2009-09-28 13:11:27 +04:00
# define I2C_DEVICE_PCM1796(i) (0x98 + ((i) << 1)) /* 10011, ii, /W=0 */
2009-09-28 13:15:01 +04:00
# define I2C_DEVICE_CS2000 0x9c /* 100111, 0, /W=0 */
2009-09-28 13:11:27 +04:00
2009-09-28 13:18:45 +04:00
# define PCM1796_REG_BASE 16
2009-09-28 13:11:27 +04:00
struct xonar_pcm179x {
struct xonar_generic generic ;
unsigned int dacs ;
2009-09-28 13:18:45 +04:00
u8 pcm1796_regs [ 4 ] [ 5 ] ;
2009-09-28 13:20:47 +04:00
unsigned int current_rate ;
2011-01-10 18:09:23 +03:00
bool h6 ;
2009-09-28 13:19:19 +04:00
bool hp_active ;
s8 hp_gain_offset ;
2009-09-28 13:20:47 +04:00
bool has_cs2000 ;
2010-12-02 13:41:10 +03:00
u8 cs2000_regs [ 0x1f ] ;
2011-01-10 18:05:38 +03:00
bool broken_i2c ;
2009-09-28 13:11:27 +04:00
} ;
struct xonar_hdav {
struct xonar_pcm179x pcm179x ;
struct xonar_hdmi hdmi ;
} ;
static inline void pcm1796_write_spi ( struct oxygen * chip , unsigned int codec ,
u8 reg , u8 value )
{
/* maps ALSA channel pair number to SPI output */
static const u8 codec_map [ 4 ] = {
0 , 1 , 2 , 4
} ;
oxygen_write_spi ( chip , OXYGEN_SPI_TRIGGER |
OXYGEN_SPI_DATA_LENGTH_2 |
OXYGEN_SPI_CLOCK_160 |
( codec_map [ codec ] < < OXYGEN_SPI_CODEC_SHIFT ) |
OXYGEN_SPI_CEN_LATCH_CLOCK_HI ,
( reg < < 8 ) | value ) ;
}
static inline void pcm1796_write_i2c ( struct oxygen * chip , unsigned int codec ,
u8 reg , u8 value )
{
oxygen_write_i2c ( chip , I2C_DEVICE_PCM1796 ( codec ) , reg , value ) ;
}
static void pcm1796_write ( struct oxygen * chip , unsigned int codec ,
u8 reg , u8 value )
{
2009-09-28 13:18:45 +04:00
struct xonar_pcm179x * data = chip - > model_data ;
2009-09-28 13:11:27 +04:00
if ( ( chip - > model . function_flags & OXYGEN_FUNCTION_2WIRE_SPI_MASK ) = =
OXYGEN_FUNCTION_SPI )
pcm1796_write_spi ( chip , codec , reg , value ) ;
else
pcm1796_write_i2c ( chip , codec , reg , value ) ;
2009-09-28 13:18:45 +04:00
if ( ( unsigned int ) ( reg - PCM1796_REG_BASE )
< ARRAY_SIZE ( data - > pcm1796_regs [ codec ] ) )
data - > pcm1796_regs [ codec ] [ reg - PCM1796_REG_BASE ] = value ;
2009-09-28 13:11:27 +04:00
}
2009-09-28 13:18:45 +04:00
static void pcm1796_write_cached ( struct oxygen * chip , unsigned int codec ,
u8 reg , u8 value )
2009-09-28 13:15:01 +04:00
{
2009-09-28 13:18:45 +04:00
struct xonar_pcm179x * data = chip - > model_data ;
if ( value ! = data - > pcm1796_regs [ codec ] [ reg - PCM1796_REG_BASE ] )
pcm1796_write ( chip , codec , reg , value ) ;
2009-09-28 13:15:01 +04:00
}
2009-09-28 13:18:45 +04:00
static void cs2000_write ( struct oxygen * chip , u8 reg , u8 value )
2009-09-28 13:11:27 +04:00
{
struct xonar_pcm179x * data = chip - > model_data ;
2009-09-28 13:18:45 +04:00
oxygen_write_i2c ( chip , I2C_DEVICE_CS2000 , reg , value ) ;
2010-12-02 13:41:10 +03:00
data - > cs2000_regs [ reg ] = value ;
2009-09-28 13:11:27 +04:00
}
2009-09-28 13:18:45 +04:00
static void cs2000_write_cached ( struct oxygen * chip , u8 reg , u8 value )
2009-09-28 13:11:27 +04:00
{
struct xonar_pcm179x * data = chip - > model_data ;
2010-12-02 13:41:10 +03:00
if ( value ! = data - > cs2000_regs [ reg ] )
2009-09-28 13:18:45 +04:00
cs2000_write ( chip , reg , value ) ;
2009-09-28 13:11:27 +04:00
}
2009-09-28 13:18:45 +04:00
static void pcm1796_registers_init ( struct oxygen * chip )
2009-09-28 13:11:27 +04:00
{
struct xonar_pcm179x * data = chip - > model_data ;
unsigned int i ;
2009-09-28 13:19:19 +04:00
s8 gain_offset ;
2009-09-28 13:11:27 +04:00
2011-01-10 18:02:32 +03:00
msleep ( 1 ) ;
2009-09-28 13:19:19 +04:00
gain_offset = data - > hp_active ? data - > hp_gain_offset : 0 ;
2009-09-28 13:11:27 +04:00
for ( i = 0 ; i < data - > dacs ; + + i ) {
2009-09-28 13:18:45 +04:00
/* set ATLD before ATL/ATR */
pcm1796_write ( chip , i , 18 ,
data - > pcm1796_regs [ 0 ] [ 18 - PCM1796_REG_BASE ] ) ;
2009-09-28 13:19:19 +04:00
pcm1796_write ( chip , i , 16 , chip - > dac_volume [ i * 2 ]
+ gain_offset ) ;
pcm1796_write ( chip , i , 17 , chip - > dac_volume [ i * 2 + 1 ]
+ gain_offset ) ;
2009-09-28 13:21:21 +04:00
pcm1796_write ( chip , i , 19 ,
data - > pcm1796_regs [ 0 ] [ 19 - PCM1796_REG_BASE ] ) ;
2009-09-28 13:18:45 +04:00
pcm1796_write ( chip , i , 20 ,
data - > pcm1796_regs [ 0 ] [ 20 - PCM1796_REG_BASE ] ) ;
2009-09-28 13:11:27 +04:00
pcm1796_write ( chip , i , 21 , 0 ) ;
2011-01-10 18:11:32 +03:00
gain_offset = 0 ;
2009-09-28 13:11:27 +04:00
}
2009-09-28 13:18:45 +04:00
}
static void pcm1796_init ( struct oxygen * chip )
{
struct xonar_pcm179x * data = chip - > model_data ;
2011-07-18 00:18:05 +04:00
data - > pcm1796_regs [ 0 ] [ 18 - PCM1796_REG_BASE ] =
2011-01-10 18:03:17 +03:00
PCM1796_DMF_DISABLED | PCM1796_FMT_24_I2S | PCM1796_ATLD ;
2011-07-18 00:18:05 +04:00
if ( ! data - > broken_i2c )
data - > pcm1796_regs [ 0 ] [ 18 - PCM1796_REG_BASE ] | = PCM1796_MUTE ;
2009-09-28 13:21:21 +04:00
data - > pcm1796_regs [ 0 ] [ 19 - PCM1796_REG_BASE ] =
PCM1796_FLT_SHARP | PCM1796_ATS_1 ;
2011-01-10 18:11:05 +03:00
data - > pcm1796_regs [ 0 ] [ 20 - PCM1796_REG_BASE ] =
data - > h6 ? PCM1796_OS_64 : PCM1796_OS_128 ;
2009-09-28 13:18:45 +04:00
pcm1796_registers_init ( chip ) ;
2009-09-28 13:20:47 +04:00
data - > current_rate = 48000 ;
2009-09-28 13:11:27 +04:00
}
static void xonar_d2_init ( struct oxygen * chip )
{
struct xonar_pcm179x * data = chip - > model_data ;
data - > generic . anti_pop_delay = 300 ;
data - > generic . output_enable_bit = GPIO_D2_OUTPUT_ENABLE ;
data - > dacs = 4 ;
pcm1796_init ( chip ) ;
oxygen_set_bits16 ( chip , OXYGEN_GPIO_CONTROL , GPIO_D2_ALT ) ;
oxygen_clear_bits16 ( chip , OXYGEN_GPIO_DATA , GPIO_D2_ALT ) ;
oxygen_ac97_set_bits ( chip , 0 , CM9780_JACK , CM9780_FMIC2MIC ) ;
xonar_init_cs53x1 ( chip ) ;
xonar_enable_output ( chip ) ;
snd_component_add ( chip - > card , " PCM1796 " ) ;
snd_component_add ( chip - > card , " CS5381 " ) ;
}
static void xonar_d2x_init ( struct oxygen * chip )
{
struct xonar_pcm179x * data = chip - > model_data ;
data - > generic . ext_power_reg = OXYGEN_GPIO_DATA ;
data - > generic . ext_power_int_reg = OXYGEN_GPIO_INTERRUPT_MASK ;
data - > generic . ext_power_bit = GPIO_D2X_EXT_POWER ;
oxygen_clear_bits16 ( chip , OXYGEN_GPIO_CONTROL , GPIO_D2X_EXT_POWER ) ;
xonar_init_ext_power ( chip ) ;
xonar_d2_init ( chip ) ;
}
static void xonar_hdav_init ( struct oxygen * chip )
{
struct xonar_hdav * data = chip - > model_data ;
oxygen_write16 ( chip , OXYGEN_2WIRE_BUS_STATUS ,
OXYGEN_2WIRE_LENGTH_8 |
OXYGEN_2WIRE_INTERRUPT_MASK |
2011-01-10 18:01:57 +03:00
OXYGEN_2WIRE_SPEED_STANDARD ) ;
2009-09-28 13:11:27 +04:00
data - > pcm179x . generic . anti_pop_delay = 100 ;
data - > pcm179x . generic . output_enable_bit = GPIO_HDAV_OUTPUT_ENABLE ;
data - > pcm179x . generic . ext_power_reg = OXYGEN_GPI_DATA ;
data - > pcm179x . generic . ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK ;
data - > pcm179x . generic . ext_power_bit = GPI_EXT_POWER ;
2011-01-10 18:00:34 +03:00
data - > pcm179x . dacs = chip - > model . dac_channels_mixer / 2 ;
2011-01-10 18:09:23 +03:00
data - > pcm179x . h6 = chip - > model . dac_channels_mixer > 2 ;
2009-09-28 13:11:27 +04:00
pcm1796_init ( chip ) ;
2010-12-02 13:36:51 +03:00
oxygen_set_bits16 ( chip , OXYGEN_GPIO_CONTROL ,
GPIO_HDAV_MAGIC | GPIO_INPUT_ROUTE ) ;
2009-09-28 13:11:27 +04:00
oxygen_clear_bits16 ( chip , OXYGEN_GPIO_DATA , GPIO_INPUT_ROUTE ) ;
xonar_init_cs53x1 ( chip ) ;
xonar_init_ext_power ( chip ) ;
xonar_hdmi_init ( chip , & data - > hdmi ) ;
xonar_enable_output ( chip ) ;
snd_component_add ( chip - > card , " PCM1796 " ) ;
snd_component_add ( chip - > card , " CS5381 " ) ;
}
2009-09-28 13:15:01 +04:00
static void xonar_st_init_i2c ( struct oxygen * chip )
2009-09-28 13:11:27 +04:00
{
oxygen_write16 ( chip , OXYGEN_2WIRE_BUS_STATUS ,
OXYGEN_2WIRE_LENGTH_8 |
OXYGEN_2WIRE_INTERRUPT_MASK |
2011-01-10 18:01:57 +03:00
OXYGEN_2WIRE_SPEED_STANDARD ) ;
2009-09-28 13:15:01 +04:00
}
static void xonar_st_init_common ( struct oxygen * chip )
{
struct xonar_pcm179x * data = chip - > model_data ;
2009-09-28 13:11:27 +04:00
data - > generic . output_enable_bit = GPIO_ST_OUTPUT_ENABLE ;
2011-01-10 18:00:34 +03:00
data - > dacs = chip - > model . dac_channels_mixer / 2 ;
2014-09-07 23:47:33 +04:00
data - > h6 = chip - > model . dac_channels_mixer > 2 ;
2009-09-28 13:19:19 +04:00
data - > hp_gain_offset = 2 * - 18 ;
2009-09-28 13:11:27 +04:00
pcm1796_init ( chip ) ;
oxygen_set_bits16 ( chip , OXYGEN_GPIO_CONTROL ,
2010-12-02 13:36:51 +03:00
GPIO_INPUT_ROUTE | GPIO_ST_HP_REAR |
GPIO_ST_MAGIC | GPIO_ST_HP ) ;
2009-09-28 13:11:27 +04:00
oxygen_clear_bits16 ( chip , OXYGEN_GPIO_DATA ,
GPIO_INPUT_ROUTE | GPIO_ST_HP_REAR | GPIO_ST_HP ) ;
xonar_init_cs53x1 ( chip ) ;
xonar_enable_output ( chip ) ;
snd_component_add ( chip - > card , " PCM1792A " ) ;
snd_component_add ( chip - > card , " CS5381 " ) ;
}
2009-09-28 13:15:01 +04:00
static void cs2000_registers_init ( struct oxygen * chip )
{
struct xonar_pcm179x * data = chip - > model_data ;
cs2000_write ( chip , CS2000_GLOBAL_CFG , CS2000_FREEZE ) ;
cs2000_write ( chip , CS2000_DEV_CTRL , 0 ) ;
cs2000_write ( chip , CS2000_DEV_CFG_1 ,
CS2000_R_MOD_SEL_1 |
( 0 < < CS2000_R_SEL_SHIFT ) |
CS2000_AUX_OUT_SRC_REF_CLK |
CS2000_EN_DEV_CFG_1 ) ;
cs2000_write ( chip , CS2000_DEV_CFG_2 ,
( 0 < < CS2000_LOCK_CLK_SHIFT ) |
CS2000_FRAC_N_SRC_STATIC ) ;
cs2000_write ( chip , CS2000_RATIO_0 + 0 , 0x00 ) ; /* 1.0 */
cs2000_write ( chip , CS2000_RATIO_0 + 1 , 0x10 ) ;
cs2000_write ( chip , CS2000_RATIO_0 + 2 , 0x00 ) ;
cs2000_write ( chip , CS2000_RATIO_0 + 3 , 0x00 ) ;
2010-12-02 13:41:10 +03:00
cs2000_write ( chip , CS2000_FUN_CFG_1 ,
data - > cs2000_regs [ CS2000_FUN_CFG_1 ] ) ;
2009-09-28 13:15:01 +04:00
cs2000_write ( chip , CS2000_FUN_CFG_2 , 0 ) ;
cs2000_write ( chip , CS2000_GLOBAL_CFG , CS2000_EN_DEV_CFG_2 ) ;
2011-01-10 18:02:32 +03:00
msleep ( 3 ) ; /* PLL lock delay */
2009-09-28 13:15:01 +04:00
}
static void xonar_st_init ( struct oxygen * chip )
{
struct xonar_pcm179x * data = chip - > model_data ;
2010-10-04 15:23:26 +04:00
data - > generic . anti_pop_delay = 100 ;
2011-01-10 18:09:23 +03:00
data - > h6 = chip - > model . dac_channels_mixer > 2 ;
2009-09-28 13:20:47 +04:00
data - > has_cs2000 = 1 ;
2010-12-02 13:41:10 +03:00
data - > cs2000_regs [ CS2000_FUN_CFG_1 ] = CS2000_REF_CLK_DIV_1 ;
2011-01-10 18:05:38 +03:00
data - > broken_i2c = true ;
2009-09-28 13:15:01 +04:00
oxygen_write16 ( chip , OXYGEN_I2S_A_FORMAT ,
2011-01-10 18:11:05 +03:00
OXYGEN_RATE_48000 |
OXYGEN_I2S_FORMAT_I2S |
2011-01-10 18:14:52 +03:00
OXYGEN_I2S_MCLK ( data - > h6 ? MCLK_256 : MCLK_512 ) |
2011-01-10 18:11:05 +03:00
OXYGEN_I2S_BITS_16 |
OXYGEN_I2S_MASTER |
OXYGEN_I2S_BCLK_64 ) ;
2009-09-28 13:15:01 +04:00
xonar_st_init_i2c ( chip ) ;
cs2000_registers_init ( chip ) ;
xonar_st_init_common ( chip ) ;
snd_component_add ( chip - > card , " CS2000 " ) ;
}
2009-09-28 13:11:27 +04:00
static void xonar_stx_init ( struct oxygen * chip )
{
struct xonar_pcm179x * data = chip - > model_data ;
2009-09-28 13:15:01 +04:00
xonar_st_init_i2c ( chip ) ;
2010-10-04 15:23:26 +04:00
data - > generic . anti_pop_delay = 800 ;
2009-09-28 13:11:27 +04:00
data - > generic . ext_power_reg = OXYGEN_GPI_DATA ;
data - > generic . ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK ;
data - > generic . ext_power_bit = GPI_EXT_POWER ;
xonar_init_ext_power ( chip ) ;
2009-09-28 13:15:01 +04:00
xonar_st_init_common ( chip ) ;
2009-09-28 13:11:27 +04:00
}
2014-09-10 22:58:25 +04:00
static void xonar_xense_init ( struct oxygen * chip )
{
struct xonar_pcm179x * data = chip - > model_data ;
data - > generic . ext_power_reg = OXYGEN_GPI_DATA ;
data - > generic . ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK ;
data - > generic . ext_power_bit = GPI_EXT_POWER ;
xonar_init_ext_power ( chip ) ;
data - > generic . anti_pop_delay = 100 ;
data - > has_cs2000 = 1 ;
data - > cs2000_regs [ CS2000_FUN_CFG_1 ] = CS2000_REF_CLK_DIV_1 ;
oxygen_write16 ( chip , OXYGEN_I2S_A_FORMAT ,
OXYGEN_RATE_48000 |
OXYGEN_I2S_FORMAT_I2S |
OXYGEN_I2S_MCLK ( MCLK_512 ) |
OXYGEN_I2S_BITS_16 |
OXYGEN_I2S_MASTER |
OXYGEN_I2S_BCLK_64 ) ;
xonar_st_init_i2c ( chip ) ;
cs2000_registers_init ( chip ) ;
data - > generic . output_enable_bit = GPIO_XENSE_OUTPUT_ENABLE ;
data - > dacs = 1 ;
data - > hp_gain_offset = 2 * - 18 ;
pcm1796_init ( chip ) ;
oxygen_set_bits16 ( chip , OXYGEN_GPIO_CONTROL ,
GPIO_INPUT_ROUTE | GPIO_ST_HP_REAR |
GPIO_ST_MAGIC | GPIO_XENSE_SPEAKERS ) ;
oxygen_clear_bits16 ( chip , OXYGEN_GPIO_DATA ,
GPIO_INPUT_ROUTE | GPIO_ST_HP_REAR |
GPIO_XENSE_SPEAKERS ) ;
xonar_init_cs53x1 ( chip ) ;
xonar_enable_output ( chip ) ;
snd_component_add ( chip - > card , " PCM1796 " ) ;
snd_component_add ( chip - > card , " CS5381 " ) ;
snd_component_add ( chip - > card , " CS2000 " ) ;
}
2009-09-28 13:11:27 +04:00
static void xonar_d2_cleanup ( struct oxygen * chip )
{
xonar_disable_output ( chip ) ;
}
static void xonar_hdav_cleanup ( struct oxygen * chip )
{
xonar_hdmi_cleanup ( chip ) ;
xonar_disable_output ( chip ) ;
msleep ( 2 ) ;
}
static void xonar_st_cleanup ( struct oxygen * chip )
{
xonar_disable_output ( chip ) ;
}
static void xonar_d2_suspend ( struct oxygen * chip )
{
xonar_d2_cleanup ( chip ) ;
}
static void xonar_hdav_suspend ( struct oxygen * chip )
{
xonar_hdav_cleanup ( chip ) ;
}
static void xonar_st_suspend ( struct oxygen * chip )
{
xonar_st_cleanup ( chip ) ;
}
static void xonar_d2_resume ( struct oxygen * chip )
{
2009-09-28 13:18:45 +04:00
pcm1796_registers_init ( chip ) ;
2009-09-28 13:11:27 +04:00
xonar_enable_output ( chip ) ;
}
static void xonar_hdav_resume ( struct oxygen * chip )
{
struct xonar_hdav * data = chip - > model_data ;
2009-09-28 13:18:45 +04:00
pcm1796_registers_init ( chip ) ;
2009-09-28 13:11:27 +04:00
xonar_hdmi_resume ( chip , & data - > hdmi ) ;
xonar_enable_output ( chip ) ;
}
2009-09-28 13:15:01 +04:00
static void xonar_stx_resume ( struct oxygen * chip )
2009-09-28 13:11:27 +04:00
{
2009-09-28 13:18:45 +04:00
pcm1796_registers_init ( chip ) ;
2009-09-28 13:11:27 +04:00
xonar_enable_output ( chip ) ;
}
2009-09-28 13:15:01 +04:00
static void xonar_st_resume ( struct oxygen * chip )
{
cs2000_registers_init ( chip ) ;
xonar_stx_resume ( chip ) ;
}
2009-09-28 13:20:47 +04:00
static void update_pcm1796_oversampling ( struct oxygen * chip )
2009-09-28 13:11:27 +04:00
{
struct xonar_pcm179x * data = chip - > model_data ;
unsigned int i ;
2009-09-28 13:18:45 +04:00
u8 reg ;
2011-01-10 18:11:05 +03:00
if ( data - > current_rate < = 48000 & & ! data - > h6 )
2009-09-28 13:20:47 +04:00
reg = PCM1796_OS_128 ;
else
2011-01-10 18:11:05 +03:00
reg = PCM1796_OS_64 ;
2009-09-28 13:18:45 +04:00
for ( i = 0 ; i < data - > dacs ; + + i )
pcm1796_write_cached ( chip , i , 20 , reg ) ;
}
2009-09-28 13:20:47 +04:00
static void set_pcm1796_params ( struct oxygen * chip ,
struct snd_pcm_hw_params * params )
{
struct xonar_pcm179x * data = chip - > model_data ;
2011-01-10 18:02:32 +03:00
msleep ( 1 ) ;
2009-09-28 13:20:47 +04:00
data - > current_rate = params_rate ( params ) ;
update_pcm1796_oversampling ( chip ) ;
}
2009-09-28 13:18:45 +04:00
static void update_pcm1796_volume ( struct oxygen * chip )
{
struct xonar_pcm179x * data = chip - > model_data ;
unsigned int i ;
2009-09-28 13:19:19 +04:00
s8 gain_offset ;
2009-09-28 13:18:45 +04:00
2009-09-28 13:19:19 +04:00
gain_offset = data - > hp_active ? data - > hp_gain_offset : 0 ;
2009-09-28 13:18:45 +04:00
for ( i = 0 ; i < data - > dacs ; + + i ) {
2009-09-28 13:19:19 +04:00
pcm1796_write_cached ( chip , i , 16 , chip - > dac_volume [ i * 2 ]
+ gain_offset ) ;
pcm1796_write_cached ( chip , i , 17 , chip - > dac_volume [ i * 2 + 1 ]
+ gain_offset ) ;
2011-01-10 18:11:32 +03:00
gain_offset = 0 ;
2009-09-28 13:18:45 +04:00
}
}
static void update_pcm1796_mute ( struct oxygen * chip )
{
struct xonar_pcm179x * data = chip - > model_data ;
unsigned int i ;
u8 value ;
2009-09-28 13:11:27 +04:00
2011-01-10 18:03:17 +03:00
value = PCM1796_DMF_DISABLED | PCM1796_FMT_24_I2S | PCM1796_ATLD ;
2009-09-28 13:18:45 +04:00
if ( chip - > dac_mute )
value | = PCM1796_MUTE ;
2009-09-28 13:11:27 +04:00
for ( i = 0 ; i < data - > dacs ; + + i )
2009-09-28 13:18:45 +04:00
pcm1796_write_cached ( chip , i , 18 , value ) ;
2009-09-28 13:11:27 +04:00
}
2009-09-28 13:20:47 +04:00
static void update_cs2000_rate ( struct oxygen * chip , unsigned int rate )
2009-09-28 13:15:01 +04:00
{
2009-09-28 13:20:47 +04:00
struct xonar_pcm179x * data = chip - > model_data ;
2009-09-28 13:18:45 +04:00
u8 rate_mclk , reg ;
2009-09-28 13:15:01 +04:00
2009-09-28 13:20:47 +04:00
switch ( rate ) {
case 32000 :
case 64000 :
2011-01-10 18:14:52 +03:00
rate_mclk = OXYGEN_RATE_32000 ;
2009-09-28 13:20:47 +04:00
break ;
2011-01-10 18:14:52 +03:00
case 44100 :
2009-09-28 13:20:47 +04:00
case 88200 :
case 176400 :
2011-01-10 18:14:52 +03:00
rate_mclk = OXYGEN_RATE_44100 ;
2009-09-28 13:20:47 +04:00
break ;
2011-01-10 18:14:52 +03:00
default :
case 48000 :
case 96000 :
2009-09-28 13:20:47 +04:00
case 192000 :
2011-01-10 18:14:52 +03:00
rate_mclk = OXYGEN_RATE_48000 ;
2009-09-28 13:20:47 +04:00
break ;
}
2011-01-10 18:14:52 +03:00
if ( rate < = 96000 & & ( rate > 48000 | | data - > h6 ) ) {
rate_mclk | = OXYGEN_I2S_MCLK ( MCLK_256 ) ;
2009-09-28 13:18:45 +04:00
reg = CS2000_REF_CLK_DIV_1 ;
2011-01-10 18:14:52 +03:00
} else {
rate_mclk | = OXYGEN_I2S_MCLK ( MCLK_512 ) ;
2009-09-28 13:18:45 +04:00
reg = CS2000_REF_CLK_DIV_2 ;
2011-01-10 18:14:52 +03:00
}
oxygen_write16_masked ( chip , OXYGEN_I2S_A_FORMAT , rate_mclk ,
OXYGEN_I2S_RATE_MASK | OXYGEN_I2S_MCLK_MASK ) ;
2009-09-28 13:18:45 +04:00
cs2000_write_cached ( chip , CS2000_FUN_CFG_1 , reg ) ;
2011-01-10 18:02:32 +03:00
msleep ( 3 ) ; /* PLL lock delay */
2009-09-28 13:15:01 +04:00
}
static void set_st_params ( struct oxygen * chip ,
struct snd_pcm_hw_params * params )
{
2009-09-28 13:20:47 +04:00
update_cs2000_rate ( chip , params_rate ( params ) ) ;
2009-09-28 13:15:01 +04:00
set_pcm1796_params ( chip , params ) ;
}
2009-09-28 13:11:27 +04:00
static void set_hdav_params ( struct oxygen * chip ,
struct snd_pcm_hw_params * params )
{
struct xonar_hdav * data = chip - > model_data ;
set_pcm1796_params ( chip , params ) ;
xonar_set_hdmi_params ( chip , & data - > hdmi , params ) ;
}
static const struct snd_kcontrol_new alt_switch = {
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " Analog Loopback Switch " ,
. info = snd_ctl_boolean_mono_info ,
. get = xonar_gpio_bit_switch_get ,
. put = xonar_gpio_bit_switch_put ,
. private_value = GPIO_D2_ALT ,
} ;
2009-09-28 13:21:21 +04:00
static int rolloff_info ( struct snd_kcontrol * ctl ,
struct snd_ctl_elem_info * info )
{
static const char * const names [ 2 ] = {
" Sharp Roll-off " , " Slow Roll-off "
} ;
2011-01-10 18:25:44 +03:00
return snd_ctl_enum_info ( info , 1 , 2 , names ) ;
2009-09-28 13:21:21 +04:00
}
static int rolloff_get ( struct snd_kcontrol * ctl ,
struct snd_ctl_elem_value * value )
{
struct oxygen * chip = ctl - > private_data ;
struct xonar_pcm179x * data = chip - > model_data ;
value - > value . enumerated . item [ 0 ] =
( data - > pcm1796_regs [ 0 ] [ 19 - PCM1796_REG_BASE ] &
PCM1796_FLT_MASK ) ! = PCM1796_FLT_SHARP ;
return 0 ;
}
static int rolloff_put ( struct snd_kcontrol * ctl ,
struct snd_ctl_elem_value * value )
{
struct oxygen * chip = ctl - > private_data ;
struct xonar_pcm179x * data = chip - > model_data ;
unsigned int i ;
int changed ;
u8 reg ;
mutex_lock ( & chip - > mutex ) ;
reg = data - > pcm1796_regs [ 0 ] [ 19 - PCM1796_REG_BASE ] ;
reg & = ~ PCM1796_FLT_MASK ;
if ( ! value - > value . enumerated . item [ 0 ] )
reg | = PCM1796_FLT_SHARP ;
else
reg | = PCM1796_FLT_SLOW ;
changed = reg ! = data - > pcm1796_regs [ 0 ] [ 19 - PCM1796_REG_BASE ] ;
if ( changed ) {
for ( i = 0 ; i < data - > dacs ; + + i )
pcm1796_write ( chip , i , 19 , reg ) ;
}
mutex_unlock ( & chip - > mutex ) ;
return changed ;
}
static const struct snd_kcontrol_new rolloff_control = {
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " DAC Filter Playback Enum " ,
. info = rolloff_info ,
. get = rolloff_get ,
. put = rolloff_put ,
} ;
2010-12-02 13:38:06 +03:00
static const struct snd_kcontrol_new hdav_hdmi_control = {
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " HDMI Playback Switch " ,
. info = snd_ctl_boolean_mono_info ,
. get = xonar_gpio_bit_switch_get ,
. put = xonar_gpio_bit_switch_put ,
. private_value = GPIO_HDAV_OUTPUT_ENABLE | XONAR_GPIO_BIT_INVERT ,
} ;
2009-09-28 13:11:27 +04:00
static int st_output_switch_info ( struct snd_kcontrol * ctl ,
struct snd_ctl_elem_info * info )
{
static const char * const names [ 3 ] = {
" Speakers " , " Headphones " , " FP Headphones "
} ;
2011-01-10 18:25:44 +03:00
return snd_ctl_enum_info ( info , 1 , 3 , names ) ;
2009-09-28 13:11:27 +04:00
}
static int st_output_switch_get ( struct snd_kcontrol * ctl ,
struct snd_ctl_elem_value * value )
{
struct oxygen * chip = ctl - > private_data ;
u16 gpio ;
gpio = oxygen_read16 ( chip , OXYGEN_GPIO_DATA ) ;
if ( ! ( gpio & GPIO_ST_HP ) )
value - > value . enumerated . item [ 0 ] = 0 ;
else if ( gpio & GPIO_ST_HP_REAR )
value - > value . enumerated . item [ 0 ] = 1 ;
else
value - > value . enumerated . item [ 0 ] = 2 ;
return 0 ;
}
static int st_output_switch_put ( struct snd_kcontrol * ctl ,
struct snd_ctl_elem_value * value )
{
struct oxygen * chip = ctl - > private_data ;
2009-09-28 13:19:19 +04:00
struct xonar_pcm179x * data = chip - > model_data ;
2009-09-28 13:11:27 +04:00
u16 gpio_old , gpio ;
mutex_lock ( & chip - > mutex ) ;
gpio_old = oxygen_read16 ( chip , OXYGEN_GPIO_DATA ) ;
gpio = gpio_old ;
switch ( value - > value . enumerated . item [ 0 ] ) {
case 0 :
gpio & = ~ ( GPIO_ST_HP | GPIO_ST_HP_REAR ) ;
break ;
case 1 :
gpio | = GPIO_ST_HP | GPIO_ST_HP_REAR ;
break ;
case 2 :
gpio = ( gpio | GPIO_ST_HP ) & ~ GPIO_ST_HP_REAR ;
break ;
}
oxygen_write16 ( chip , OXYGEN_GPIO_DATA , gpio ) ;
2009-09-28 13:19:19 +04:00
data - > hp_active = gpio & GPIO_ST_HP ;
update_pcm1796_volume ( chip ) ;
2009-09-28 13:11:27 +04:00
mutex_unlock ( & chip - > mutex ) ;
return gpio ! = gpio_old ;
}
2009-09-28 13:19:19 +04:00
static int st_hp_volume_offset_info ( struct snd_kcontrol * ctl ,
struct snd_ctl_elem_info * info )
{
2014-09-07 23:45:59 +04:00
static const char * const names [ 4 ] = {
" < 32 ohms " , " 32-64 ohms " , " 64-300 ohms " , " 300-600 ohms "
2009-09-28 13:19:19 +04:00
} ;
2014-09-07 23:45:59 +04:00
return snd_ctl_enum_info ( info , 1 , 4 , names ) ;
2009-09-28 13:19:19 +04:00
}
static int st_hp_volume_offset_get ( struct snd_kcontrol * ctl ,
struct snd_ctl_elem_value * value )
{
struct oxygen * chip = ctl - > private_data ;
struct xonar_pcm179x * data = chip - > model_data ;
mutex_lock ( & chip - > mutex ) ;
2014-09-07 23:45:59 +04:00
if ( data - > hp_gain_offset < 2 * - 12 )
2009-09-28 13:19:19 +04:00
value - > value . enumerated . item [ 0 ] = 0 ;
2014-09-07 23:45:59 +04:00
else if ( data - > hp_gain_offset < 2 * - 6 )
2009-09-28 13:19:19 +04:00
value - > value . enumerated . item [ 0 ] = 1 ;
2014-09-07 23:45:59 +04:00
else if ( data - > hp_gain_offset < 0 )
2009-09-28 13:19:19 +04:00
value - > value . enumerated . item [ 0 ] = 2 ;
2014-09-07 23:45:59 +04:00
else
value - > value . enumerated . item [ 0 ] = 3 ;
2009-09-28 13:19:19 +04:00
mutex_unlock ( & chip - > mutex ) ;
return 0 ;
}
static int st_hp_volume_offset_put ( struct snd_kcontrol * ctl ,
struct snd_ctl_elem_value * value )
{
2014-09-07 23:45:59 +04:00
static const s8 offsets [ ] = { 2 * - 18 , 2 * - 12 , 2 * - 6 , 0 } ;
2009-09-28 13:19:19 +04:00
struct oxygen * chip = ctl - > private_data ;
struct xonar_pcm179x * data = chip - > model_data ;
s8 offset ;
int changed ;
2014-09-07 23:45:59 +04:00
if ( value - > value . enumerated . item [ 0 ] > 3 )
2009-09-28 13:19:19 +04:00
return - EINVAL ;
offset = offsets [ value - > value . enumerated . item [ 0 ] ] ;
mutex_lock ( & chip - > mutex ) ;
changed = offset ! = data - > hp_gain_offset ;
if ( changed ) {
data - > hp_gain_offset = offset ;
update_pcm1796_volume ( chip ) ;
}
mutex_unlock ( & chip - > mutex ) ;
return changed ;
}
static const struct snd_kcontrol_new st_controls [ ] = {
{
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " Analog Output " ,
. info = st_output_switch_info ,
. get = st_output_switch_get ,
. put = st_output_switch_put ,
} ,
{
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " Headphones Impedance Playback Enum " ,
. info = st_hp_volume_offset_info ,
. get = st_hp_volume_offset_get ,
. put = st_hp_volume_offset_put ,
} ,
2009-09-28 13:11:27 +04:00
} ;
2014-09-10 22:58:25 +04:00
static int xense_output_switch_get ( struct snd_kcontrol * ctl ,
struct snd_ctl_elem_value * value )
{
struct oxygen * chip = ctl - > private_data ;
u16 gpio ;
gpio = oxygen_read16 ( chip , OXYGEN_GPIO_DATA ) ;
if ( gpio & GPIO_XENSE_SPEAKERS )
value - > value . enumerated . item [ 0 ] = 0 ;
else if ( ! ( gpio & GPIO_XENSE_SPEAKERS ) & & ( gpio & GPIO_ST_HP_REAR ) )
value - > value . enumerated . item [ 0 ] = 1 ;
else
value - > value . enumerated . item [ 0 ] = 2 ;
return 0 ;
}
static int xense_output_switch_put ( struct snd_kcontrol * ctl ,
struct snd_ctl_elem_value * value )
{
struct oxygen * chip = ctl - > private_data ;
struct xonar_pcm179x * data = chip - > model_data ;
u16 gpio_old , gpio ;
mutex_lock ( & chip - > mutex ) ;
gpio_old = oxygen_read16 ( chip , OXYGEN_GPIO_DATA ) ;
gpio = gpio_old ;
switch ( value - > value . enumerated . item [ 0 ] ) {
case 0 :
gpio | = GPIO_XENSE_SPEAKERS | GPIO_ST_HP_REAR ;
break ;
case 1 :
gpio = ( gpio | GPIO_ST_HP_REAR ) & ~ GPIO_XENSE_SPEAKERS ;
break ;
case 2 :
gpio & = ~ ( GPIO_XENSE_SPEAKERS | GPIO_ST_HP_REAR ) ;
break ;
}
oxygen_write16 ( chip , OXYGEN_GPIO_DATA , gpio ) ;
data - > hp_active = ! ( gpio & GPIO_XENSE_SPEAKERS ) ;
update_pcm1796_volume ( chip ) ;
mutex_unlock ( & chip - > mutex ) ;
return gpio ! = gpio_old ;
}
static const struct snd_kcontrol_new xense_controls [ ] = {
{
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " Analog Output " ,
. info = st_output_switch_info ,
. get = xense_output_switch_get ,
. put = xense_output_switch_put ,
} ,
{
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " Headphones Impedance Playback Enum " ,
. info = st_hp_volume_offset_info ,
. get = st_hp_volume_offset_get ,
. put = st_hp_volume_offset_put ,
} ,
} ;
2009-09-28 13:11:27 +04:00
static void xonar_line_mic_ac97_switch ( struct oxygen * chip ,
unsigned int reg , unsigned int mute )
{
if ( reg = = AC97_LINE ) {
spin_lock_irq ( & chip - > reg_lock ) ;
oxygen_write16_masked ( chip , OXYGEN_GPIO_DATA ,
mute ? GPIO_INPUT_ROUTE : 0 ,
GPIO_INPUT_ROUTE ) ;
spin_unlock_irq ( & chip - > reg_lock ) ;
}
}
static const DECLARE_TLV_DB_SCALE ( pcm1796_db_scale , - 6000 , 50 , 0 ) ;
static int xonar_d2_control_filter ( struct snd_kcontrol_new * template )
{
if ( ! strncmp ( template - > name , " CD Capture " , 11 ) )
/* CD in is actually connected to the video in pin */
template - > private_value ^ = AC97_CD ^ AC97_VIDEO ;
return 0 ;
}
2011-01-10 18:05:38 +03:00
static int xonar_st_h6_control_filter ( struct snd_kcontrol_new * template )
{
if ( ! strncmp ( template - > name , " Master Playback " , 16 ) )
/* no volume/mute, as I²C to the third DAC does not work */
return 1 ;
return 0 ;
}
2009-09-28 13:21:21 +04:00
static int add_pcm1796_controls ( struct oxygen * chip )
{
2011-01-10 18:05:38 +03:00
struct xonar_pcm179x * data = chip - > model_data ;
2009-09-28 13:21:21 +04:00
int err ;
2011-01-10 18:05:38 +03:00
if ( ! data - > broken_i2c ) {
err = snd_ctl_add ( chip - > card ,
snd_ctl_new1 ( & rolloff_control , chip ) ) ;
if ( err < 0 )
return err ;
}
2009-09-28 13:21:21 +04:00
return 0 ;
}
2009-09-28 13:11:27 +04:00
static int xonar_d2_mixer_init ( struct oxygen * chip )
{
2009-09-28 13:20:47 +04:00
int err ;
err = snd_ctl_add ( chip - > card , snd_ctl_new1 ( & alt_switch , chip ) ) ;
if ( err < 0 )
return err ;
2009-09-28 13:21:21 +04:00
err = add_pcm1796_controls ( chip ) ;
2009-09-28 13:20:47 +04:00
if ( err < 0 )
return err ;
return 0 ;
}
static int xonar_hdav_mixer_init ( struct oxygen * chip )
{
2010-12-02 13:38:06 +03:00
int err ;
err = snd_ctl_add ( chip - > card , snd_ctl_new1 ( & hdav_hdmi_control , chip ) ) ;
if ( err < 0 )
return err ;
err = add_pcm1796_controls ( chip ) ;
if ( err < 0 )
return err ;
return 0 ;
2009-09-28 13:11:27 +04:00
}
static int xonar_st_mixer_init ( struct oxygen * chip )
{
2009-09-28 13:19:19 +04:00
unsigned int i ;
int err ;
for ( i = 0 ; i < ARRAY_SIZE ( st_controls ) ; + + i ) {
err = snd_ctl_add ( chip - > card ,
snd_ctl_new1 ( & st_controls [ i ] , chip ) ) ;
if ( err < 0 )
return err ;
}
2009-09-28 13:21:21 +04:00
err = add_pcm1796_controls ( chip ) ;
2009-09-28 13:20:47 +04:00
if ( err < 0 )
return err ;
2009-09-28 13:19:19 +04:00
return 0 ;
2009-09-28 13:11:27 +04:00
}
2014-09-10 22:58:25 +04:00
static int xonar_xense_mixer_init ( struct oxygen * chip )
{
unsigned int i ;
int err ;
for ( i = 0 ; i < ARRAY_SIZE ( xense_controls ) ; + + i ) {
err = snd_ctl_add ( chip - > card ,
snd_ctl_new1 ( & xense_controls [ i ] , chip ) ) ;
if ( err < 0 )
return err ;
}
err = add_pcm1796_controls ( chip ) ;
if ( err < 0 )
return err ;
return 0 ;
}
2010-12-02 13:41:10 +03:00
static void dump_pcm1796_registers ( struct oxygen * chip ,
struct snd_info_buffer * buffer )
{
struct xonar_pcm179x * data = chip - > model_data ;
unsigned int dac , i ;
for ( dac = 0 ; dac < data - > dacs ; + + dac ) {
snd_iprintf ( buffer , " \n PCM1796 %u: " , dac + 1 ) ;
for ( i = 0 ; i < 5 ; + + i )
snd_iprintf ( buffer , " %02x " ,
data - > pcm1796_regs [ dac ] [ i ] ) ;
}
snd_iprintf ( buffer , " \n " ) ;
}
static void dump_cs2000_registers ( struct oxygen * chip ,
struct snd_info_buffer * buffer )
{
struct xonar_pcm179x * data = chip - > model_data ;
unsigned int i ;
if ( data - > has_cs2000 ) {
snd_iprintf ( buffer , " \n CS2000: \n 00: " ) ;
for ( i = 1 ; i < 0x10 ; + + i )
snd_iprintf ( buffer , " %02x " , data - > cs2000_regs [ i ] ) ;
snd_iprintf ( buffer , " \n 10: " ) ;
for ( i = 0x10 ; i < 0x1f ; + + i )
snd_iprintf ( buffer , " %02x " , data - > cs2000_regs [ i ] ) ;
snd_iprintf ( buffer , " \n " ) ;
}
}
static void dump_st_registers ( struct oxygen * chip ,
struct snd_info_buffer * buffer )
{
dump_pcm1796_registers ( chip , buffer ) ;
dump_cs2000_registers ( chip , buffer ) ;
}
2009-09-28 13:11:27 +04:00
static const struct oxygen_model model_xonar_d2 = {
. longname = " Asus Virtuoso 200 " ,
. chip = " AV200 " ,
. init = xonar_d2_init ,
. control_filter = xonar_d2_control_filter ,
. mixer_init = xonar_d2_mixer_init ,
. cleanup = xonar_d2_cleanup ,
. suspend = xonar_d2_suspend ,
. resume = xonar_d2_resume ,
. set_dac_params = set_pcm1796_params ,
. set_adc_params = xonar_set_cs53x1_params ,
. update_dac_volume = update_pcm1796_volume ,
. update_dac_mute = update_pcm1796_mute ,
2010-12-02 13:41:10 +03:00
. dump_registers = dump_pcm1796_registers ,
2009-09-28 13:11:27 +04:00
. dac_tlv = pcm1796_db_scale ,
. model_data_size = sizeof ( struct xonar_pcm179x ) ,
. device_config = PLAYBACK_0_TO_I2S |
PLAYBACK_1_TO_SPDIF |
CAPTURE_0_FROM_I2S_2 |
CAPTURE_1_FROM_SPDIF |
MIDI_OUTPUT |
2010-10-04 15:21:52 +04:00
MIDI_INPUT |
AC97_CD_INPUT ,
2011-01-10 17:59:38 +03:00
. dac_channels_pcm = 8 ,
. dac_channels_mixer = 8 ,
2009-09-28 13:11:27 +04:00
. dac_volume_min = 255 - 2 * 60 ,
. dac_volume_max = 255 ,
. misc_flags = OXYGEN_MISC_MIDI ,
. function_flags = OXYGEN_FUNCTION_SPI |
OXYGEN_FUNCTION_ENABLE_SPI_4_5 ,
2011-01-10 18:14:52 +03:00
. dac_mclks = OXYGEN_MCLKS ( 512 , 128 , 128 ) ,
2011-01-10 18:16:08 +03:00
. adc_mclks = OXYGEN_MCLKS ( 256 , 128 , 128 ) ,
2011-01-10 18:03:17 +03:00
. dac_i2s_format = OXYGEN_I2S_FORMAT_I2S ,
2009-09-28 13:11:27 +04:00
. adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST ,
} ;
static const struct oxygen_model model_xonar_hdav = {
. longname = " Asus Virtuoso 200 " ,
. chip = " AV200 " ,
. init = xonar_hdav_init ,
2009-09-28 13:20:47 +04:00
. mixer_init = xonar_hdav_mixer_init ,
2009-09-28 13:11:27 +04:00
. cleanup = xonar_hdav_cleanup ,
. suspend = xonar_hdav_suspend ,
. resume = xonar_hdav_resume ,
. pcm_hardware_filter = xonar_hdmi_pcm_hardware_filter ,
. set_dac_params = set_hdav_params ,
. set_adc_params = xonar_set_cs53x1_params ,
. update_dac_volume = update_pcm1796_volume ,
. update_dac_mute = update_pcm1796_mute ,
. uart_input = xonar_hdmi_uart_input ,
. ac97_switch = xonar_line_mic_ac97_switch ,
2010-12-02 13:41:10 +03:00
. dump_registers = dump_pcm1796_registers ,
2009-09-28 13:11:27 +04:00
. dac_tlv = pcm1796_db_scale ,
. model_data_size = sizeof ( struct xonar_hdav ) ,
. device_config = PLAYBACK_0_TO_I2S |
PLAYBACK_1_TO_SPDIF |
CAPTURE_0_FROM_I2S_2 |
CAPTURE_1_FROM_SPDIF ,
2011-01-10 17:59:38 +03:00
. dac_channels_pcm = 8 ,
. dac_channels_mixer = 2 ,
2009-09-28 13:11:27 +04:00
. dac_volume_min = 255 - 2 * 60 ,
. dac_volume_max = 255 ,
. misc_flags = OXYGEN_MISC_MIDI ,
. function_flags = OXYGEN_FUNCTION_2WIRE ,
2011-01-10 18:14:52 +03:00
. dac_mclks = OXYGEN_MCLKS ( 512 , 128 , 128 ) ,
2011-01-10 18:16:08 +03:00
. adc_mclks = OXYGEN_MCLKS ( 256 , 128 , 128 ) ,
2011-01-10 18:03:17 +03:00
. dac_i2s_format = OXYGEN_I2S_FORMAT_I2S ,
2009-09-28 13:11:27 +04:00
. adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST ,
} ;
static const struct oxygen_model model_xonar_st = {
. longname = " Asus Virtuoso 100 " ,
. chip = " AV200 " ,
. init = xonar_st_init ,
. mixer_init = xonar_st_mixer_init ,
. cleanup = xonar_st_cleanup ,
. suspend = xonar_st_suspend ,
. resume = xonar_st_resume ,
2009-09-28 13:15:01 +04:00
. set_dac_params = set_st_params ,
2009-09-28 13:11:27 +04:00
. set_adc_params = xonar_set_cs53x1_params ,
. update_dac_volume = update_pcm1796_volume ,
. update_dac_mute = update_pcm1796_mute ,
. ac97_switch = xonar_line_mic_ac97_switch ,
2010-12-02 13:41:10 +03:00
. dump_registers = dump_st_registers ,
2009-09-28 13:11:27 +04:00
. dac_tlv = pcm1796_db_scale ,
. model_data_size = sizeof ( struct xonar_pcm179x ) ,
. device_config = PLAYBACK_0_TO_I2S |
PLAYBACK_1_TO_SPDIF |
2010-12-02 13:39:34 +03:00
CAPTURE_0_FROM_I2S_2 |
2011-06-19 01:05:00 +04:00
CAPTURE_1_FROM_SPDIF |
2010-12-02 13:39:34 +03:00
AC97_FMIC_SWITCH ,
2011-01-10 17:59:38 +03:00
. dac_channels_pcm = 2 ,
. dac_channels_mixer = 2 ,
2009-09-28 13:11:27 +04:00
. dac_volume_min = 255 - 2 * 60 ,
. dac_volume_max = 255 ,
. function_flags = OXYGEN_FUNCTION_2WIRE ,
2011-01-10 18:14:52 +03:00
. dac_mclks = OXYGEN_MCLKS ( 512 , 128 , 128 ) ,
2011-01-10 18:16:08 +03:00
. adc_mclks = OXYGEN_MCLKS ( 256 , 128 , 128 ) ,
2011-01-10 18:03:17 +03:00
. dac_i2s_format = OXYGEN_I2S_FORMAT_I2S ,
2009-09-28 13:11:27 +04:00
. adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST ,
} ;
2012-12-06 21:35:20 +04:00
int get_xonar_pcm179x_model ( struct oxygen * chip ,
const struct pci_device_id * id )
2009-09-28 13:11:27 +04:00
{
switch ( id - > subdevice ) {
case 0x8269 :
chip - > model = model_xonar_d2 ;
chip - > model . shortname = " Xonar D2 " ;
break ;
case 0x82b7 :
chip - > model = model_xonar_d2 ;
chip - > model . shortname = " Xonar D2X " ;
chip - > model . init = xonar_d2x_init ;
break ;
case 0x8314 :
chip - > model = model_xonar_hdav ;
oxygen_clear_bits16 ( chip , OXYGEN_GPIO_CONTROL , GPIO_DB_MASK ) ;
switch ( oxygen_read16 ( chip , OXYGEN_GPIO_DATA ) & GPIO_DB_MASK ) {
default :
chip - > model . shortname = " Xonar HDAV1.3 " ;
break ;
case GPIO_DB_H6 :
chip - > model . shortname = " Xonar HDAV1.3+H6 " ;
2011-01-10 17:59:38 +03:00
chip - > model . dac_channels_mixer = 8 ;
2011-01-10 18:14:52 +03:00
chip - > model . dac_mclks = OXYGEN_MCLKS ( 256 , 128 , 128 ) ;
2009-09-28 13:11:27 +04:00
break ;
}
break ;
case 0x835d :
chip - > model = model_xonar_st ;
oxygen_clear_bits16 ( chip , OXYGEN_GPIO_CONTROL , GPIO_DB_MASK ) ;
switch ( oxygen_read16 ( chip , OXYGEN_GPIO_DATA ) & GPIO_DB_MASK ) {
default :
chip - > model . shortname = " Xonar ST " ;
break ;
case GPIO_DB_H6 :
chip - > model . shortname = " Xonar ST+H6 " ;
2011-01-10 18:05:38 +03:00
chip - > model . control_filter = xonar_st_h6_control_filter ;
2011-01-10 17:59:38 +03:00
chip - > model . dac_channels_pcm = 8 ;
chip - > model . dac_channels_mixer = 8 ;
2011-07-18 00:18:05 +04:00
chip - > model . dac_volume_min = 255 ;
2011-01-10 18:14:52 +03:00
chip - > model . dac_mclks = OXYGEN_MCLKS ( 256 , 128 , 128 ) ;
2009-09-28 13:11:27 +04:00
break ;
}
break ;
case 0x835c :
chip - > model = model_xonar_st ;
chip - > model . shortname = " Xonar STX " ;
chip - > model . init = xonar_stx_init ;
2009-09-28 13:15:01 +04:00
chip - > model . resume = xonar_stx_resume ;
chip - > model . set_dac_params = set_pcm1796_params ;
2009-09-28 13:11:27 +04:00
break ;
2014-08-04 17:17:55 +04:00
case 0x85f4 :
chip - > model = model_xonar_st ;
2014-09-07 23:47:33 +04:00
oxygen_clear_bits16 ( chip , OXYGEN_GPIO_CONTROL , GPIO_DB_MASK ) ;
switch ( oxygen_read16 ( chip , OXYGEN_GPIO_DATA ) & GPIO_DB_MASK ) {
default :
chip - > model . shortname = " Xonar STX II " ;
break ;
case GPIO_DB_H6 :
chip - > model . shortname = " Xonar STX II+H6 " ;
chip - > model . dac_channels_pcm = 8 ;
chip - > model . dac_channels_mixer = 8 ;
chip - > model . dac_mclks = OXYGEN_MCLKS ( 256 , 128 , 128 ) ;
break ;
}
2014-08-04 17:17:55 +04:00
chip - > model . init = xonar_stx_init ;
chip - > model . resume = xonar_stx_resume ;
chip - > model . set_dac_params = set_pcm1796_params ;
break ;
2014-09-10 22:58:25 +04:00
case 0x8428 :
chip - > model = model_xonar_st ;
chip - > model . shortname = " Xonar Xense " ;
chip - > model . chip = " AV100 " ;
chip - > model . init = xonar_xense_init ;
chip - > model . mixer_init = xonar_xense_mixer_init ;
break ;
2009-09-28 13:11:27 +04:00
default :
return - EINVAL ;
}
return 0 ;
}