2019-05-27 09:55:05 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2007-10-23 17:08:18 +04:00
/*
* ALSA driver for ICEnsemble VT1724 ( Envy24HT )
*
* Lowlevel functions for ONKYO WAVIO SE - 90 PCI and SE - 200 PCI
*
* Copyright ( c ) 2007 Shin - ya Okada sh_okada ( at ) d4 . dion . ne . jp
* ( at ) - > @
*/
# include <linux/delay.h>
# include <linux/interrupt.h>
# include <linux/init.h>
# include <linux/slab.h>
# include <sound/core.h>
# include <sound/tlv.h>
# include "ice1712.h"
# include "envy24ht.h"
# include "se.h"
2008-01-18 15:36:07 +03:00
struct se_spec {
struct {
unsigned char ch1 , ch2 ;
} vol [ 8 ] ;
} ;
2007-10-23 17:08:18 +04:00
/****************************************************************************/
/* ONKYO WAVIO SE-200PCI */
/****************************************************************************/
/*
* system configuration ICE_EEP2_SYSCONF = 0x4b
* XIN1 49.152 MHz
* not have UART
* one stereo ADC and a S / PDIF receiver connected
* four stereo DACs connected
*
* AC - Link configuration ICE_EEP2_ACLINK = 0x80
* use I2C , not use AC97
*
* I2S converters feature ICE_EEP2_I2S = 0x78
* I2S codec has no volume / mute control feature
* I2S codec supports 96 KHz and 192 KHz
* I2S codec 24 bits
*
* S / PDIF configuration ICE_EEP2_SPDIF = 0xc3
* Enable integrated S / PDIF transmitter
* internal S / PDIF out implemented
* S / PDIF is stereo
* External S / PDIF out implemented
*
*
* * * connected chips * *
*
* WM8740
* A 2 ch - DAC of main outputs .
* It setuped as I2S mode by wire , so no way to setup from software .
* The sample - rate are automatically changed .
* ML / I2S ( 28 pin ) - - - - - - - - +
* MC / DM1 ( 27 pin ) - - 5 V |
* MD / DM0 ( 26 pin ) - - GND |
* MUTEB ( 25 pin ) - - NC |
* MODE ( 24 pin ) - - GND |
* CSBIW ( 23 pin ) - - - - - - - - +
* |
* RSTB ( 22 pin ) - - R ( 1 K ) - +
* Probably it reduce the noise from the control line .
*
* WM8766
* A 6 ch - DAC for surrounds .
* It ' s control wire was connected to GPIOxx ( 3 - wire serial interface )
* ML / I2S ( 11 pin ) - - GPIO18
* MC / IWL ( 12 pin ) - - GPIO17
* MD / DM ( 13 pin ) - - GPIO16
* MUTE ( 14 pin ) - - GPIO01
*
* WM8776
* A 2 ch - ADC ( with 10 ch - selector ) plus 2 ch - DAC .
* It ' s control wire was connected to SDA / SCLK ( 2 - wire serial interface )
* MODE ( 16 pin ) - - R ( 1 K ) - - GND
* CE ( 17 pin ) - - R ( 1 K ) - - GND 2 - wire mode ( address = 0x34 )
* DI ( 18 pin ) - - SDA
* CL ( 19 pin ) - - SCLK
*
*
* * * output pins and device names * *
*
* 7.1 ch name - - output connector color - - device ( - D option )
*
* FRONT 2 ch - - green - - plughw : 0 , 0
* CENTER ( Lch ) SUBWOOFER ( Rch ) - - black - - plughw : 0 , 2 , 0
* SURROUND 2 ch - - orange - - plughw : 0 , 2 , 1
* SURROUND BACK 2 ch - - white - - plughw : 0 , 2 , 2
*
*/
/****************************************************************************/
/* WM8740 interface */
/****************************************************************************/
2012-12-06 21:35:10 +04:00
static void se200pci_WM8740_init ( struct snd_ice1712 * ice )
2007-10-23 17:08:18 +04:00
{
/* nothing to do */
}
static void se200pci_WM8740_set_pro_rate ( struct snd_ice1712 * ice ,
unsigned int rate )
{
/* nothing to do */
}
/****************************************************************************/
/* WM8766 interface */
/****************************************************************************/
static void se200pci_WM8766_write ( struct snd_ice1712 * ice ,
unsigned int addr , unsigned int data )
{
unsigned int st ;
unsigned int bits ;
int i ;
const unsigned int DATA = 0x010000 ;
const unsigned int CLOCK = 0x020000 ;
const unsigned int LOAD = 0x040000 ;
const unsigned int ALL_MASK = ( DATA | CLOCK | LOAD ) ;
snd_ice1712_save_gpio_status ( ice ) ;
st = ( ( addr & 0x7f ) < < 9 ) | ( data & 0x1ff ) ;
snd_ice1712_gpio_set_dir ( ice , ice - > gpio . direction | ALL_MASK ) ;
snd_ice1712_gpio_set_mask ( ice , ice - > gpio . write_mask & ~ ALL_MASK ) ;
bits = snd_ice1712_gpio_read ( ice ) & ~ ALL_MASK ;
snd_ice1712_gpio_write ( ice , bits ) ;
for ( i = 0 ; i < 16 ; i + + ) {
udelay ( 1 ) ;
bits & = ~ CLOCK ;
st = ( st < < 1 ) ;
if ( st & 0x10000 )
bits | = DATA ;
else
bits & = ~ DATA ;
snd_ice1712_gpio_write ( ice , bits ) ;
udelay ( 1 ) ;
bits | = CLOCK ;
snd_ice1712_gpio_write ( ice , bits ) ;
}
udelay ( 1 ) ;
bits | = LOAD ;
snd_ice1712_gpio_write ( ice , bits ) ;
udelay ( 1 ) ;
bits | = ( DATA | CLOCK ) ;
snd_ice1712_gpio_write ( ice , bits ) ;
snd_ice1712_restore_gpio_status ( ice ) ;
}
static void se200pci_WM8766_set_volume ( struct snd_ice1712 * ice , int ch ,
unsigned int vol1 , unsigned int vol2 )
{
switch ( ch ) {
case 0 :
se200pci_WM8766_write ( ice , 0x000 , vol1 ) ;
se200pci_WM8766_write ( ice , 0x001 , vol2 | 0x100 ) ;
break ;
case 1 :
se200pci_WM8766_write ( ice , 0x004 , vol1 ) ;
se200pci_WM8766_write ( ice , 0x005 , vol2 | 0x100 ) ;
break ;
case 2 :
se200pci_WM8766_write ( ice , 0x006 , vol1 ) ;
se200pci_WM8766_write ( ice , 0x007 , vol2 | 0x100 ) ;
break ;
}
}
2012-12-06 21:35:10 +04:00
static void se200pci_WM8766_init ( struct snd_ice1712 * ice )
2007-10-23 17:08:18 +04:00
{
se200pci_WM8766_write ( ice , 0x1f , 0x000 ) ; /* RESET ALL */
udelay ( 10 ) ;
se200pci_WM8766_set_volume ( ice , 0 , 0 , 0 ) ; /* volume L=0 R=0 */
se200pci_WM8766_set_volume ( ice , 1 , 0 , 0 ) ; /* volume L=0 R=0 */
se200pci_WM8766_set_volume ( ice , 2 , 0 , 0 ) ; /* volume L=0 R=0 */
se200pci_WM8766_write ( ice , 0x03 , 0x022 ) ; /* serial mode I2S-24bits */
se200pci_WM8766_write ( ice , 0x0a , 0x080 ) ; /* MCLK=256fs */
se200pci_WM8766_write ( ice , 0x12 , 0x000 ) ; /* MDP=0 */
se200pci_WM8766_write ( ice , 0x15 , 0x000 ) ; /* MDP=0 */
se200pci_WM8766_write ( ice , 0x09 , 0x000 ) ; /* demp=off mute=off */
se200pci_WM8766_write ( ice , 0x02 , 0x124 ) ; /* ch-assign L=L R=R RESET */
se200pci_WM8766_write ( ice , 0x02 , 0x120 ) ; /* ch-assign L=L R=R */
}
static void se200pci_WM8766_set_pro_rate ( struct snd_ice1712 * ice ,
unsigned int rate )
{
if ( rate > 96000 )
se200pci_WM8766_write ( ice , 0x0a , 0x000 ) ; /* MCLK=128fs */
else
se200pci_WM8766_write ( ice , 0x0a , 0x080 ) ; /* MCLK=256fs */
}
/****************************************************************************/
/* WM8776 interface */
/****************************************************************************/
static void se200pci_WM8776_write ( struct snd_ice1712 * ice ,
unsigned int addr , unsigned int data )
{
unsigned int val ;
val = ( addr < < 9 ) | data ;
snd_vt1724_write_i2c ( ice , 0x34 , val > > 8 , val & 0xff ) ;
}
static void se200pci_WM8776_set_output_volume ( struct snd_ice1712 * ice ,
unsigned int vol1 , unsigned int vol2 )
{
se200pci_WM8776_write ( ice , 0x03 , vol1 ) ;
se200pci_WM8776_write ( ice , 0x04 , vol2 | 0x100 ) ;
}
static void se200pci_WM8776_set_input_volume ( struct snd_ice1712 * ice ,
unsigned int vol1 , unsigned int vol2 )
{
se200pci_WM8776_write ( ice , 0x0e , vol1 ) ;
se200pci_WM8776_write ( ice , 0x0f , vol2 | 0x100 ) ;
}
2012-10-17 11:21:48 +04:00
static const char * const se200pci_sel [ ] = {
2007-10-23 17:08:18 +04:00
" LINE-IN " , " CD-IN " , " MIC-IN " , " ALL-MIX " , NULL
} ;
static void se200pci_WM8776_set_input_selector ( struct snd_ice1712 * ice ,
unsigned int sel )
{
2020-01-05 17:47:31 +03:00
static const unsigned char vals [ ] = {
2007-10-23 17:08:18 +04:00
/* LINE, CD, MIC, ALL, GND */
0x10 , 0x04 , 0x08 , 0x1c , 0x03
} ;
if ( sel > 4 )
sel = 4 ;
se200pci_WM8776_write ( ice , 0x15 , vals [ sel ] ) ;
}
static void se200pci_WM8776_set_afl ( struct snd_ice1712 * ice , unsigned int afl )
{
/* AFL -- After Fader Listening */
if ( afl )
se200pci_WM8776_write ( ice , 0x16 , 0x005 ) ;
else
se200pci_WM8776_write ( ice , 0x16 , 0x001 ) ;
}
2012-10-17 11:21:48 +04:00
static const char * const se200pci_agc [ ] = {
2007-10-23 17:08:18 +04:00
" Off " , " LimiterMode " , " ALCMode " , NULL
} ;
static void se200pci_WM8776_set_agc ( struct snd_ice1712 * ice , unsigned int agc )
{
/* AGC -- Auto Gain Control of the input */
switch ( agc ) {
case 0 :
se200pci_WM8776_write ( ice , 0x11 , 0x000 ) ; /* Off */
break ;
case 1 :
se200pci_WM8776_write ( ice , 0x10 , 0x07b ) ;
se200pci_WM8776_write ( ice , 0x11 , 0x100 ) ; /* LimiterMode */
break ;
case 2 :
se200pci_WM8776_write ( ice , 0x10 , 0x1fb ) ;
se200pci_WM8776_write ( ice , 0x11 , 0x100 ) ; /* ALCMode */
break ;
}
}
2012-12-06 21:35:10 +04:00
static void se200pci_WM8776_init ( struct snd_ice1712 * ice )
2007-10-23 17:08:18 +04:00
{
int i ;
2020-01-05 17:47:31 +03:00
static const unsigned short default_values [ ] = {
2007-10-23 17:08:18 +04:00
0x100 , 0x100 , 0x100 ,
0x100 , 0x100 , 0x100 ,
0x000 , 0x090 , 0x000 , 0x000 ,
0x022 , 0x022 , 0x022 ,
0x008 , 0x0cf , 0x0cf , 0x07b , 0x000 ,
0x032 , 0x000 , 0x0a6 , 0x001 , 0x001
} ;
se200pci_WM8776_write ( ice , 0x17 , 0x000 ) ; /* reset all */
/* ADC and DAC interface is I2S 24bits mode */
/* The sample-rate are automatically changed */
udelay ( 10 ) ;
/* BUT my board can not do reset all, so I load all by manually. */
for ( i = 0 ; i < ARRAY_SIZE ( default_values ) ; i + + )
se200pci_WM8776_write ( ice , i , default_values [ i ] ) ;
se200pci_WM8776_set_input_selector ( ice , 0 ) ;
se200pci_WM8776_set_afl ( ice , 0 ) ;
se200pci_WM8776_set_agc ( ice , 0 ) ;
se200pci_WM8776_set_input_volume ( ice , 0 , 0 ) ;
se200pci_WM8776_set_output_volume ( ice , 0 , 0 ) ;
/* head phone mute and power down */
se200pci_WM8776_write ( ice , 0x00 , 0 ) ;
se200pci_WM8776_write ( ice , 0x01 , 0 ) ;
se200pci_WM8776_write ( ice , 0x02 , 0x100 ) ;
se200pci_WM8776_write ( ice , 0x0d , 0x080 ) ;
}
static void se200pci_WM8776_set_pro_rate ( struct snd_ice1712 * ice ,
unsigned int rate )
{
/* nothing to do */
}
/****************************************************************************/
/* runtime interface */
/****************************************************************************/
static void se200pci_set_pro_rate ( struct snd_ice1712 * ice , unsigned int rate )
{
se200pci_WM8740_set_pro_rate ( ice , rate ) ;
se200pci_WM8766_set_pro_rate ( ice , rate ) ;
se200pci_WM8776_set_pro_rate ( ice , rate ) ;
}
struct se200pci_control {
2012-10-17 11:21:48 +04:00
const char * name ;
2007-10-23 17:08:18 +04:00
enum {
WM8766 ,
WM8776in ,
WM8776out ,
WM8776sel ,
WM8776agc ,
WM8776afl
} target ;
enum { VOLUME1 , VOLUME2 , BOOLEAN , ENUM } type ;
int ch ;
2012-10-17 11:21:48 +04:00
const char * const * member ;
2007-10-23 17:08:18 +04:00
const char * comment ;
} ;
static const struct se200pci_control se200pci_cont [ ] = {
{
. name = " Front Playback Volume " ,
. target = WM8776out ,
. type = VOLUME1 ,
. comment = " Front(green) "
} ,
{
. name = " Side Playback Volume " ,
. target = WM8766 ,
. type = VOLUME1 ,
. ch = 1 ,
. comment = " Surround(orange) "
} ,
{
. name = " Surround Playback Volume " ,
. target = WM8766 ,
. type = VOLUME1 ,
. ch = 2 ,
. comment = " SurroundBack(white) "
} ,
{
. name = " CLFE Playback Volume " ,
. target = WM8766 ,
. type = VOLUME1 ,
. ch = 0 ,
. comment = " Center(Lch)&SubWoofer(Rch)(black) "
} ,
{
. name = " Capture Volume " ,
. target = WM8776in ,
. type = VOLUME2
} ,
{
. name = " Capture Select " ,
. target = WM8776sel ,
. type = ENUM ,
. member = se200pci_sel
} ,
{
. name = " AGC Capture Mode " ,
. target = WM8776agc ,
. type = ENUM ,
. member = se200pci_agc
} ,
{
. name = " AFL Bypass Playback Switch " ,
. target = WM8776afl ,
. type = BOOLEAN
}
} ;
2007-11-15 18:05:26 +03:00
static int se200pci_get_enum_count ( int n )
2007-10-23 17:08:18 +04:00
{
2012-10-17 11:21:48 +04:00
const char * const * member ;
2007-11-15 18:05:26 +03:00
int c ;
2007-10-23 17:08:18 +04:00
2007-11-15 18:05:26 +03:00
member = se200pci_cont [ n ] . member ;
if ( ! member )
return 0 ;
for ( c = 0 ; member [ c ] ; c + + )
;
return c ;
}
2007-10-23 17:08:18 +04:00
2007-11-15 18:05:26 +03:00
static int se200pci_cont_volume_info ( struct snd_kcontrol * kc ,
struct snd_ctl_elem_info * uinfo )
{
uinfo - > type = SNDRV_CTL_ELEM_TYPE_INTEGER ;
uinfo - > count = 2 ;
uinfo - > value . integer . min = 0 ; /* mute */
uinfo - > value . integer . max = 0xff ; /* 0dB */
2007-10-23 17:08:18 +04:00
return 0 ;
}
2007-11-15 18:05:26 +03:00
# define se200pci_cont_boolean_info snd_ctl_boolean_mono_info
static int se200pci_cont_enum_info ( struct snd_kcontrol * kc ,
struct snd_ctl_elem_info * uinfo )
2007-10-23 17:08:18 +04:00
{
2007-11-15 18:05:26 +03:00
int n , c ;
2007-10-23 17:08:18 +04:00
n = kc - > private_value ;
2007-11-15 18:05:26 +03:00
c = se200pci_get_enum_count ( n ) ;
if ( ! c )
return - EINVAL ;
2014-10-20 20:18:50 +04:00
return snd_ctl_enum_info ( uinfo , 1 , c , se200pci_cont [ n ] . member ) ;
2007-10-23 17:08:18 +04:00
}
2007-11-15 18:05:26 +03:00
static int se200pci_cont_volume_get ( struct snd_kcontrol * kc ,
struct snd_ctl_elem_value * uc )
2007-10-23 17:08:18 +04:00
{
2007-11-15 18:05:26 +03:00
struct snd_ice1712 * ice = snd_kcontrol_chip ( kc ) ;
2008-01-18 15:36:07 +03:00
struct se_spec * spec = ice - > spec ;
2007-11-15 18:05:26 +03:00
int n = kc - > private_value ;
2008-01-18 15:36:07 +03:00
uc - > value . integer . value [ 0 ] = spec - > vol [ n ] . ch1 ;
uc - > value . integer . value [ 1 ] = spec - > vol [ n ] . ch2 ;
2007-11-15 18:05:26 +03:00
return 0 ;
}
2007-10-23 17:08:18 +04:00
2007-11-15 18:05:26 +03:00
static int se200pci_cont_boolean_get ( struct snd_kcontrol * kc ,
struct snd_ctl_elem_value * uc )
{
struct snd_ice1712 * ice = snd_kcontrol_chip ( kc ) ;
2008-01-18 15:36:07 +03:00
struct se_spec * spec = ice - > spec ;
2007-11-15 18:05:26 +03:00
int n = kc - > private_value ;
2008-01-18 15:36:07 +03:00
uc - > value . integer . value [ 0 ] = spec - > vol [ n ] . ch1 ;
2007-11-15 18:05:26 +03:00
return 0 ;
}
2007-10-23 17:08:18 +04:00
2007-11-15 18:05:26 +03:00
static int se200pci_cont_enum_get ( struct snd_kcontrol * kc ,
struct snd_ctl_elem_value * uc )
{
struct snd_ice1712 * ice = snd_kcontrol_chip ( kc ) ;
2008-01-18 15:36:07 +03:00
struct se_spec * spec = ice - > spec ;
2007-11-15 18:05:26 +03:00
int n = kc - > private_value ;
2008-01-18 15:36:07 +03:00
uc - > value . enumerated . item [ 0 ] = spec - > vol [ n ] . ch1 ;
2007-11-15 18:05:26 +03:00
return 0 ;
}
2007-10-23 17:08:18 +04:00
2007-11-15 18:05:26 +03:00
static void se200pci_cont_update ( struct snd_ice1712 * ice , int n )
{
2008-01-18 15:36:07 +03:00
struct se_spec * spec = ice - > spec ;
2007-10-23 17:08:18 +04:00
switch ( se200pci_cont [ n ] . target ) {
case WM8766 :
se200pci_WM8766_set_volume ( ice ,
2007-11-15 18:05:26 +03:00
se200pci_cont [ n ] . ch ,
2008-01-18 15:36:07 +03:00
spec - > vol [ n ] . ch1 ,
spec - > vol [ n ] . ch2 ) ;
2007-10-23 17:08:18 +04:00
break ;
case WM8776in :
2007-11-15 18:05:26 +03:00
se200pci_WM8776_set_input_volume ( ice ,
2008-01-18 15:36:07 +03:00
spec - > vol [ n ] . ch1 ,
spec - > vol [ n ] . ch2 ) ;
2007-10-23 17:08:18 +04:00
break ;
case WM8776out :
2007-11-15 18:05:26 +03:00
se200pci_WM8776_set_output_volume ( ice ,
2008-01-18 15:36:07 +03:00
spec - > vol [ n ] . ch1 ,
spec - > vol [ n ] . ch2 ) ;
2007-10-23 17:08:18 +04:00
break ;
case WM8776sel :
2007-11-15 18:05:26 +03:00
se200pci_WM8776_set_input_selector ( ice ,
2008-01-18 15:36:07 +03:00
spec - > vol [ n ] . ch1 ) ;
2007-10-23 17:08:18 +04:00
break ;
case WM8776agc :
2008-01-18 15:36:07 +03:00
se200pci_WM8776_set_agc ( ice , spec - > vol [ n ] . ch1 ) ;
2007-10-23 17:08:18 +04:00
break ;
case WM8776afl :
2008-01-18 15:36:07 +03:00
se200pci_WM8776_set_afl ( ice , spec - > vol [ n ] . ch1 ) ;
2007-10-23 17:08:18 +04:00
break ;
default :
break ;
}
2007-11-15 18:05:26 +03:00
}
static int se200pci_cont_volume_put ( struct snd_kcontrol * kc ,
struct snd_ctl_elem_value * uc )
{
struct snd_ice1712 * ice = snd_kcontrol_chip ( kc ) ;
2008-01-18 15:36:07 +03:00
struct se_spec * spec = ice - > spec ;
2007-11-15 18:05:26 +03:00
int n = kc - > private_value ;
unsigned int vol1 , vol2 ;
int changed ;
changed = 0 ;
vol1 = uc - > value . integer . value [ 0 ] & 0xff ;
vol2 = uc - > value . integer . value [ 1 ] & 0xff ;
2008-01-18 15:36:07 +03:00
if ( spec - > vol [ n ] . ch1 ! = vol1 ) {
spec - > vol [ n ] . ch1 = vol1 ;
2007-11-15 18:05:26 +03:00
changed = 1 ;
}
2008-01-18 15:36:07 +03:00
if ( spec - > vol [ n ] . ch2 ! = vol2 ) {
spec - > vol [ n ] . ch2 = vol2 ;
2007-11-15 18:05:26 +03:00
changed = 1 ;
}
if ( changed )
se200pci_cont_update ( ice , n ) ;
2007-10-23 17:08:18 +04:00
return changed ;
}
2007-11-15 18:05:26 +03:00
static int se200pci_cont_boolean_put ( struct snd_kcontrol * kc ,
struct snd_ctl_elem_value * uc )
{
struct snd_ice1712 * ice = snd_kcontrol_chip ( kc ) ;
2008-01-18 15:36:07 +03:00
struct se_spec * spec = ice - > spec ;
2007-11-15 18:05:26 +03:00
int n = kc - > private_value ;
unsigned int vol1 ;
vol1 = ! ! uc - > value . integer . value [ 0 ] ;
2008-01-18 15:36:07 +03:00
if ( spec - > vol [ n ] . ch1 ! = vol1 ) {
spec - > vol [ n ] . ch1 = vol1 ;
2007-11-15 18:05:26 +03:00
se200pci_cont_update ( ice , n ) ;
return 1 ;
}
return 0 ;
}
static int se200pci_cont_enum_put ( struct snd_kcontrol * kc ,
struct snd_ctl_elem_value * uc )
{
struct snd_ice1712 * ice = snd_kcontrol_chip ( kc ) ;
2008-01-18 15:36:07 +03:00
struct se_spec * spec = ice - > spec ;
2007-11-15 18:05:26 +03:00
int n = kc - > private_value ;
unsigned int vol1 ;
vol1 = uc - > value . enumerated . item [ 0 ] ;
if ( vol1 > = se200pci_get_enum_count ( n ) )
return - EINVAL ;
2008-01-18 15:36:07 +03:00
if ( spec - > vol [ n ] . ch1 ! = vol1 ) {
spec - > vol [ n ] . ch1 = vol1 ;
2007-11-15 18:05:26 +03:00
se200pci_cont_update ( ice , n ) ;
return 1 ;
}
return 0 ;
}
2007-10-23 17:08:18 +04:00
static const DECLARE_TLV_DB_SCALE ( db_scale_gain1 , - 12750 , 50 , 1 ) ;
static const DECLARE_TLV_DB_SCALE ( db_scale_gain2 , - 10350 , 50 , 1 ) ;
2012-12-06 21:35:10 +04:00
static int se200pci_add_controls ( struct snd_ice1712 * ice )
2007-10-23 17:08:18 +04:00
{
int i ;
struct snd_kcontrol_new cont ;
int err ;
memset ( & cont , 0 , sizeof ( cont ) ) ;
cont . iface = SNDRV_CTL_ELEM_IFACE_MIXER ;
for ( i = 0 ; i < ARRAY_SIZE ( se200pci_cont ) ; i + + ) {
cont . private_value = i ;
cont . name = se200pci_cont [ i ] . name ;
cont . access = SNDRV_CTL_ELEM_ACCESS_READWRITE ;
cont . tlv . p = NULL ;
2007-11-15 18:05:26 +03:00
switch ( se200pci_cont [ i ] . type ) {
case VOLUME1 :
case VOLUME2 :
cont . info = se200pci_cont_volume_info ;
cont . get = se200pci_cont_volume_get ;
cont . put = se200pci_cont_volume_put ;
2007-10-23 17:08:18 +04:00
cont . access | = SNDRV_CTL_ELEM_ACCESS_TLV_READ ;
if ( se200pci_cont [ i ] . type = = VOLUME1 )
cont . tlv . p = db_scale_gain1 ;
else
cont . tlv . p = db_scale_gain2 ;
2007-11-15 18:05:26 +03:00
break ;
case BOOLEAN :
cont . info = se200pci_cont_boolean_info ;
cont . get = se200pci_cont_boolean_get ;
cont . put = se200pci_cont_boolean_put ;
break ;
case ENUM :
cont . info = se200pci_cont_enum_info ;
cont . get = se200pci_cont_enum_get ;
cont . put = se200pci_cont_enum_put ;
break ;
default :
snd_BUG ( ) ;
return - EINVAL ;
2007-10-23 17:08:18 +04:00
}
err = snd_ctl_add ( ice - > card , snd_ctl_new1 ( & cont , ice ) ) ;
if ( err < 0 )
return err ;
}
return 0 ;
}
/****************************************************************************/
/* ONKYO WAVIO SE-90PCI */
/****************************************************************************/
/*
* system configuration ICE_EEP2_SYSCONF = 0x4b
* AC - Link configuration ICE_EEP2_ACLINK = 0x80
* I2S converters feature ICE_EEP2_I2S = 0x78
* S / PDIF configuration ICE_EEP2_SPDIF = 0xc3
*
* * * connected chip * *
*
* WM8716
* A 2 ch - DAC of main outputs .
* It setuped as I2S mode by wire , so no way to setup from software .
* ML / I2S ( 28 pin ) - - + 5 V
* MC / DM1 ( 27 pin ) - - GND
* MC / DM0 ( 26 pin ) - - GND
* MUTEB ( 25 pin ) - - open ( internal pull - up )
* MODE ( 24 pin ) - - GND
* CSBIWO ( 23 pin ) - - + 5 V
*
*/
/* Nothing to do for this chip. */
/****************************************************************************/
/* probe/initialize/setup */
/****************************************************************************/
2012-12-06 21:35:10 +04:00
static int se_init ( struct snd_ice1712 * ice )
2007-10-23 17:08:18 +04:00
{
2008-01-18 15:36:07 +03:00
struct se_spec * spec ;
spec = kzalloc ( sizeof ( * spec ) , GFP_KERNEL ) ;
if ( ! spec )
return - ENOMEM ;
ice - > spec = spec ;
2007-10-23 17:08:18 +04:00
if ( ice - > eeprom . subvendor = = VT1724_SUBDEVICE_SE90PCI ) {
ice - > num_total_dacs = 2 ;
ice - > num_total_adcs = 0 ;
ice - > vt1720 = 1 ;
return 0 ;
} else if ( ice - > eeprom . subvendor = = VT1724_SUBDEVICE_SE200PCI ) {
ice - > num_total_dacs = 8 ;
ice - > num_total_adcs = 2 ;
se200pci_WM8740_init ( ice ) ;
se200pci_WM8766_init ( ice ) ;
se200pci_WM8776_init ( ice ) ;
ice - > gpio . set_pro_rate = se200pci_set_pro_rate ;
return 0 ;
}
return - ENOENT ;
}
2012-12-06 21:35:10 +04:00
static int se_add_controls ( struct snd_ice1712 * ice )
2007-10-23 17:08:18 +04:00
{
int err ;
err = 0 ;
/* nothing to do for VT1724_SUBDEVICE_SE90PCI */
if ( ice - > eeprom . subvendor = = VT1724_SUBDEVICE_SE200PCI )
err = se200pci_add_controls ( ice ) ;
return err ;
}
/****************************************************************************/
/* entry point */
/****************************************************************************/
2020-01-05 17:47:31 +03:00
static const unsigned char se200pci_eeprom [ ] = {
2007-10-23 17:08:18 +04:00
[ ICE_EEP2_SYSCONF ] = 0x4b , /* 49.152Hz, spdif-in/ADC, 4DACs */
[ ICE_EEP2_ACLINK ] = 0x80 , /* I2S */
[ ICE_EEP2_I2S ] = 0x78 , /* 96k-ok, 24bit, 192k-ok */
[ ICE_EEP2_SPDIF ] = 0xc3 , /* out-en, out-int, spdif-in */
[ ICE_EEP2_GPIO_DIR ] = 0x02 , /* WM8766 mute 1=output */
[ ICE_EEP2_GPIO_DIR1 ] = 0x00 , /* not used */
[ ICE_EEP2_GPIO_DIR2 ] = 0x07 , /* WM8766 ML/MC/MD 1=output */
[ ICE_EEP2_GPIO_MASK ] = 0x00 , /* 0=writable */
[ ICE_EEP2_GPIO_MASK1 ] = 0x00 , /* 0=writable */
[ ICE_EEP2_GPIO_MASK2 ] = 0x00 , /* 0=writable */
[ ICE_EEP2_GPIO_STATE ] = 0x00 , /* WM8766 mute=0 */
[ ICE_EEP2_GPIO_STATE1 ] = 0x00 , /* not used */
[ ICE_EEP2_GPIO_STATE2 ] = 0x07 , /* WM8766 ML/MC/MD */
} ;
2020-01-05 17:47:31 +03:00
static const unsigned char se90pci_eeprom [ ] = {
2007-10-23 17:08:18 +04:00
[ ICE_EEP2_SYSCONF ] = 0x4b , /* 49.152Hz, spdif-in/ADC, 4DACs */
[ ICE_EEP2_ACLINK ] = 0x80 , /* I2S */
[ ICE_EEP2_I2S ] = 0x78 , /* 96k-ok, 24bit, 192k-ok */
[ ICE_EEP2_SPDIF ] = 0xc3 , /* out-en, out-int, spdif-in */
/* ALL GPIO bits are in input mode */
} ;
2012-12-06 21:35:10 +04:00
struct snd_ice1712_card_info snd_vt1724_se_cards [ ] = {
2007-10-23 17:08:18 +04:00
{
. subvendor = VT1724_SUBDEVICE_SE200PCI ,
. name = " ONKYO SE200PCI " ,
. model = " se200pci " ,
. chip_init = se_init ,
. build_controls = se_add_controls ,
. eeprom_size = sizeof ( se200pci_eeprom ) ,
. eeprom_data = se200pci_eeprom ,
} ,
{
. subvendor = VT1724_SUBDEVICE_SE90PCI ,
. name = " ONKYO SE90PCI " ,
. model = " se90pci " ,
. chip_init = se_init ,
. build_controls = se_add_controls ,
. eeprom_size = sizeof ( se90pci_eeprom ) ,
. eeprom_data = se90pci_eeprom ,
} ,
{ } /*terminator*/
} ;