2005-04-17 02:20:36 +04:00
/*
* ALSA driver for ICEnsemble VT1724 ( Envy24HT )
*
* Lowlevel functions for AudioTrak Prodigy 192 cards
2007-04-10 13:39:58 +04:00
* Supported IEC958 input from optional MI / ODI / O add - on card .
*
* Specifics ( SW , HW ) :
* - - - - - - - - - - - - - - - - - - -
* * 49.5 MHz crystal
* * SPDIF - OUT on the card :
* - coax ( through isolation transformer ) / toslink supplied by
* 74 HC04 gates - 3 in parallel
* - output switched between on - board CD drive dig - out connector
* and ice1724 SPDTX pin , using 74 HC02 NOR gates , controlled
* by GPIO20 ( 0 = CD dig - out , 1 = SPDTX )
* * SPDTX goes straight to MI / ODI / O card ' s SPDIF - OUT coax
*
* * MI / ODI / O card : AK4114 based , used for iec958 input only
* - toslink input - > RX0
* - coax input - > RX1
* - 4 wire protocol :
* AK4114 ICE1724
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* CDTO ( pin 32 ) - - GPIO11 pin 86
* CDTI ( pin 33 ) - - GPIO10 pin 77
* CCLK ( pin 34 ) - - GPIO9 pin 76
* CSN ( pin 35 ) - - GPIO8 pin 75
* - output data Mode 7 ( 24 bit , I2S , slave )
2007-04-24 14:27:36 +04:00
* - both MCKO1 and MCKO2 of ak4114 are fed to FPGA , which
* outputs master clock to SPMCLKIN of ice1724 .
* Experimentally I found out that only a combination of
* OCKS0 = 1 , OCKS1 = 1 ( 128f s , 64f s output ) and ice1724 -
* VT1724_MT_I2S_MCLK_128X = 0 ( 256f s input ) yields correct
* sampling rate . That means the the FPGA doubles the
* MCK01 rate .
2005-04-17 02:20:36 +04:00
*
* Copyright ( c ) 2003 Takashi Iwai < tiwai @ suse . de >
* Copyright ( c ) 2003 Dimitromanolakis Apostolos < apostol @ cs . utoronto . ca >
* Copyright ( c ) 2004 Kouichi ONO < co2b @ ceres . dti . ne . jp >
*
* 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 <asm/io.h>
# include <linux/delay.h>
# include <linux/interrupt.h>
# include <linux/init.h>
# include <linux/slab.h>
# include <sound/core.h>
# include "ice1712.h"
# include "envy24ht.h"
# include "prodigy192.h"
# include "stac946x.h"
2006-08-30 18:57:37 +04:00
# include <sound/tlv.h>
2005-04-17 02:20:36 +04:00
2005-11-17 17:00:18 +03:00
static inline void stac9460_put ( struct snd_ice1712 * ice , int reg , unsigned char val )
2005-04-17 02:20:36 +04:00
{
snd_vt1724_write_i2c ( ice , PRODIGY192_STAC9460_ADDR , reg , val ) ;
}
2005-11-17 17:00:18 +03:00
static inline unsigned char stac9460_get ( struct snd_ice1712 * ice , int reg )
2005-04-17 02:20:36 +04:00
{
return snd_vt1724_read_i2c ( ice , PRODIGY192_STAC9460_ADDR , reg ) ;
}
/*
* DAC mute control
*/
2007-12-03 14:44:28 +03:00
/*
* idx = STAC9460 volume register number , mute : 0 = mute , 1 = unmute
*/
static int stac9460_dac_mute ( struct snd_ice1712 * ice , int idx ,
unsigned char mute )
{
unsigned char new , old ;
int change ;
old = stac9460_get ( ice , idx ) ;
new = ( ~ mute < < 7 & 0x80 ) | ( old & ~ 0x80 ) ;
change = ( new ! = old ) ;
if ( change )
/*printk ("Volume register 0x%02x: 0x%02x\n", idx, new);*/
stac9460_put ( ice , idx , new ) ;
return change ;
}
2007-07-23 17:42:26 +04:00
# define stac9460_dac_mute_info snd_ctl_boolean_mono_info
2005-04-17 02:20:36 +04:00
2005-11-17 17:00:18 +03:00
static int stac9460_dac_mute_get ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_value * ucontrol )
2005-04-17 02:20:36 +04:00
{
2005-11-17 17:00:18 +03:00
struct snd_ice1712 * ice = snd_kcontrol_chip ( kcontrol ) ;
2005-04-17 02:20:36 +04:00
unsigned char val ;
int idx ;
if ( kcontrol - > private_value )
idx = STAC946X_MASTER_VOLUME ;
else
idx = snd_ctl_get_ioffidx ( kcontrol , & ucontrol - > id ) + STAC946X_LF_VOLUME ;
val = stac9460_get ( ice , idx ) ;
ucontrol - > value . integer . value [ 0 ] = ( ~ val > > 7 ) & 0x1 ;
return 0 ;
}
2005-11-17 17:00:18 +03:00
static int stac9460_dac_mute_put ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_value * ucontrol )
2005-04-17 02:20:36 +04:00
{
2005-11-17 17:00:18 +03:00
struct snd_ice1712 * ice = snd_kcontrol_chip ( kcontrol ) ;
2007-12-03 14:44:28 +03:00
int idx , change ;
2005-04-17 02:20:36 +04:00
if ( kcontrol - > private_value )
idx = STAC946X_MASTER_VOLUME ;
else
idx = snd_ctl_get_ioffidx ( kcontrol , & ucontrol - > id ) + STAC946X_LF_VOLUME ;
2007-12-03 14:44:28 +03:00
/* due to possible conflicts with stac9460_set_rate_val, mutexing */
mutex_lock ( & ice - > spec . prodigy192 . mute_mutex ) ;
/*printk("Mute put: reg 0x%02x, ctrl value: 0x%02x\n", idx,
ucontrol - > value . integer . value [ 0 ] ) ; */
change = stac9460_dac_mute ( ice , idx , ucontrol - > value . integer . value [ 0 ] ) ;
mutex_unlock ( & ice - > spec . prodigy192 . mute_mutex ) ;
2005-04-17 02:20:36 +04:00
return change ;
}
/*
* DAC volume attenuation mixer control
*/
2005-11-17 17:00:18 +03:00
static int stac9460_dac_vol_info ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_info * uinfo )
2005-04-17 02:20:36 +04:00
{
uinfo - > type = SNDRV_CTL_ELEM_TYPE_INTEGER ;
uinfo - > count = 1 ;
uinfo - > value . integer . min = 0 ; /* mute */
uinfo - > value . integer . max = 0x7f ; /* 0dB */
return 0 ;
}
2005-11-17 17:00:18 +03:00
static int stac9460_dac_vol_get ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_value * ucontrol )
2005-04-17 02:20:36 +04:00
{
2005-11-17 17:00:18 +03:00
struct snd_ice1712 * ice = snd_kcontrol_chip ( kcontrol ) ;
2005-04-17 02:20:36 +04:00
int idx ;
unsigned char vol ;
if ( kcontrol - > private_value )
idx = STAC946X_MASTER_VOLUME ;
else
idx = snd_ctl_get_ioffidx ( kcontrol , & ucontrol - > id ) + STAC946X_LF_VOLUME ;
vol = stac9460_get ( ice , idx ) & 0x7f ;
ucontrol - > value . integer . value [ 0 ] = 0x7f - vol ;
return 0 ;
}
2005-11-17 17:00:18 +03:00
static int stac9460_dac_vol_put ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_value * ucontrol )
2005-04-17 02:20:36 +04:00
{
2005-11-17 17:00:18 +03:00
struct snd_ice1712 * ice = snd_kcontrol_chip ( kcontrol ) ;
2005-04-17 02:20:36 +04:00
int idx ;
unsigned char tmp , ovol , nvol ;
int change ;
if ( kcontrol - > private_value )
idx = STAC946X_MASTER_VOLUME ;
else
idx = snd_ctl_get_ioffidx ( kcontrol , & ucontrol - > id ) + STAC946X_LF_VOLUME ;
nvol = ucontrol - > value . integer . value [ 0 ] ;
tmp = stac9460_get ( ice , idx ) ;
ovol = 0x7f - ( tmp & 0x7f ) ;
change = ( ovol ! = nvol ) ;
if ( change ) {
2007-12-03 14:44:28 +03:00
ovol = ( 0x7f - nvol ) | ( tmp & 0x80 ) ;
/*printk("DAC Volume: reg 0x%02x: 0x%02x\n", idx, ovol);*/
2005-04-17 02:20:36 +04:00
stac9460_put ( ice , idx , ( 0x7f - nvol ) | ( tmp & 0x80 ) ) ;
}
return change ;
}
/*
* ADC mute control
*/
2007-07-23 17:42:26 +04:00
# define stac9460_adc_mute_info snd_ctl_boolean_stereo_info
2005-04-17 02:20:36 +04:00
2005-11-17 17:00:18 +03:00
static int stac9460_adc_mute_get ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_value * ucontrol )
2005-04-17 02:20:36 +04:00
{
2005-11-17 17:00:18 +03:00
struct snd_ice1712 * ice = snd_kcontrol_chip ( kcontrol ) ;
2005-04-17 02:20:36 +04:00
unsigned char val ;
int i ;
for ( i = 0 ; i < 2 ; + + i ) {
val = stac9460_get ( ice , STAC946X_MIC_L_VOLUME + i ) ;
ucontrol - > value . integer . value [ i ] = ~ val > > 7 & 0x1 ;
}
return 0 ;
}
2005-11-17 17:00:18 +03:00
static int stac9460_adc_mute_put ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_value * ucontrol )
2005-04-17 02:20:36 +04:00
{
2005-11-17 17:00:18 +03:00
struct snd_ice1712 * ice = snd_kcontrol_chip ( kcontrol ) ;
2005-04-17 02:20:36 +04:00
unsigned char new , old ;
int i , reg ;
int change ;
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 ) ;
}
return change ;
}
/*
* ADC gain mixer control
*/
2005-11-17 17:00:18 +03:00
static int stac9460_adc_vol_info ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_info * uinfo )
2005-04-17 02:20:36 +04:00
{
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 ;
}
2005-11-17 17:00:18 +03:00
static int stac9460_adc_vol_get ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_value * ucontrol )
2005-04-17 02:20:36 +04:00
{
2005-11-17 17:00:18 +03:00
struct snd_ice1712 * ice = snd_kcontrol_chip ( kcontrol ) ;
2005-04-17 02:20:36 +04:00
int i , reg ;
unsigned char vol ;
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 ;
}
return 0 ;
}
2005-11-17 17:00:18 +03:00
static int stac9460_adc_vol_put ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_value * ucontrol )
2005-04-17 02:20:36 +04:00
{
2005-11-17 17:00:18 +03:00
struct snd_ice1712 * ice = snd_kcontrol_chip ( kcontrol ) ;
2005-04-17 02:20:36 +04:00
int i , reg ;
unsigned char ovol , nvol ;
int change ;
for ( i = 0 ; i < 2 ; + + i ) {
reg = STAC946X_MIC_L_VOLUME + i ;
2007-11-15 17:56:07 +03:00
nvol = ucontrol - > value . integer . value [ i ] & 0x0f ;
2005-04-17 02:20:36 +04:00
ovol = 0x0f - stac9460_get ( ice , reg ) ;
change = ( ( ovol & 0x0f ) ! = nvol ) ;
if ( change )
stac9460_put ( ice , reg , ( 0x0f - nvol ) | ( ovol & ~ 0x0f ) ) ;
}
return change ;
}
2007-04-10 13:39:58 +04:00
static int stac9460_mic_sw_info ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_info * uinfo )
{
static char * texts [ 2 ] = { " Line In " , " Mic " } ;
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 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 ;
val = stac9460_get ( ice , STAC946X_GENERAL_PURPOSE ) ;
ucontrol - > value . enumerated . item [ 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 ;
old = stac9460_get ( ice , STAC946X_GENERAL_PURPOSE ) ;
new = ( ucontrol - > value . enumerated . item [ 0 ] < < 7 & 0x80 ) | ( old & ~ 0x80 ) ;
change = ( new ! = old ) ;
if ( change )
stac9460_put ( ice , STAC946X_GENERAL_PURPOSE , new ) ;
return change ;
}
2007-12-03 14:44:28 +03:00
/*
* Handler for setting correct codec rate - called when rate change is detected
*/
static void stac9460_set_rate_val ( struct snd_akm4xxx * ak , unsigned int rate )
{
unsigned char old , new ;
int idx ;
unsigned char changed [ 7 ] ;
struct snd_ice1712 * ice = ak - > private_data [ 0 ] ;
if ( rate = = 0 ) /* no hint - S/PDIF input is master, simply return */
return ;
else if ( rate < = 48000 )
new = 0x08 ; /* 256x, base rate mode */
else if ( rate < = 96000 )
new = 0x11 ; /* 256x, mid rate mode */
else
new = 0x12 ; /* 128x, high rate mode */
old = stac9460_get ( ice , STAC946X_MASTER_CLOCKING ) ;
if ( old = = new )
return ;
/* change detected, setting master clock, muting first */
/* due to possible conflicts with mute controls - mutexing */
mutex_lock ( & ice - > spec . prodigy192 . mute_mutex ) ;
/* we have to remember current mute status for each DAC */
for ( idx = 0 ; idx < 7 ; + + idx )
changed [ idx ] = stac9460_dac_mute ( ice ,
STAC946X_MASTER_VOLUME + idx , 0 ) ;
/*printk("Rate change: %d, new MC: 0x%02x\n", rate, new);*/
stac9460_put ( ice , STAC946X_MASTER_CLOCKING , new ) ;
udelay ( 10 ) ;
/* unmuting - only originally unmuted dacs -
* i . e . those changed when muting */
for ( idx = 0 ; idx < 7 ; + + idx ) {
if ( changed [ idx ] )
stac9460_dac_mute ( ice , STAC946X_MASTER_VOLUME + idx , 1 ) ;
}
mutex_unlock ( & ice - > spec . prodigy192 . mute_mutex ) ;
}
/* using akm infrastructure for setting rate of the codec */
static struct snd_akm4xxx akmlike_stac9460 __devinitdata = {
. type = NON_AKM , /* special value */
. num_adcs = 6 , /* not used in any way, just for completeness */
. num_dacs = 2 ,
. ops = {
. set_rate_val = stac9460_set_rate_val
}
} ;
2005-04-17 02:20:36 +04:00
2007-01-29 17:33:49 +03:00
static const DECLARE_TLV_DB_SCALE ( db_scale_dac , - 19125 , 75 , 0 ) ;
static const DECLARE_TLV_DB_SCALE ( db_scale_adc , 0 , 150 , 0 ) ;
2006-08-30 18:57:37 +04:00
2005-04-17 02:20:36 +04:00
/*
* mixers
*/
2007-03-14 00:13:47 +03:00
static struct snd_kcontrol_new stac_controls [ ] __devinitdata = {
2005-04-17 02:20:36 +04:00
{
. 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 ,
2006-08-30 18:57:37 +04:00
. tlv = { . p = db_scale_dac }
2005-04-17 02:20:36 +04:00
} ,
{
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
2006-08-30 18:57:37 +04:00
. access = ( SNDRV_CTL_ELEM_ACCESS_READWRITE |
SNDRV_CTL_ELEM_ACCESS_TLV_READ ) ,
2005-04-17 02:20:36 +04:00
. name = " Master Playback Volume " ,
. info = stac9460_dac_vol_info ,
. get = stac9460_dac_vol_get ,
. put = stac9460_dac_vol_put ,
. private_value = 1 ,
2006-08-30 18:57:37 +04:00
. tlv = { . p = db_scale_dac }
2005-04-17 02:20:36 +04:00
} ,
{
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " DAC Switch " ,
. count = 6 ,
. info = stac9460_dac_mute_info ,
. get = stac9460_dac_mute_get ,
. put = stac9460_dac_mute_put ,
} ,
{
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
2006-08-30 18:57:37 +04:00
. access = ( SNDRV_CTL_ELEM_ACCESS_READWRITE |
SNDRV_CTL_ELEM_ACCESS_TLV_READ ) ,
2005-04-17 02:20:36 +04:00
. name = " DAC Volume " ,
. count = 6 ,
. info = stac9460_dac_vol_info ,
. get = stac9460_dac_vol_get ,
. put = stac9460_dac_vol_put ,
2006-08-30 18:57:37 +04:00
. tlv = { . p = db_scale_dac }
2005-04-17 02:20:36 +04:00
} ,
{
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
2007-04-10 13:39:58 +04:00
. name = " ADC Capture Switch " ,
2005-04-17 02:20:36 +04:00
. count = 1 ,
. info = stac9460_adc_mute_info ,
. get = stac9460_adc_mute_get ,
. put = stac9460_adc_mute_put ,
} ,
{
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
2006-08-30 18:57:37 +04:00
. access = ( SNDRV_CTL_ELEM_ACCESS_READWRITE |
SNDRV_CTL_ELEM_ACCESS_TLV_READ ) ,
2007-04-10 13:39:58 +04:00
. name = " ADC Capture Volume " ,
2005-04-17 02:20:36 +04:00
. count = 1 ,
. info = stac9460_adc_vol_info ,
. get = stac9460_adc_vol_get ,
. put = stac9460_adc_vol_put ,
2006-08-30 18:57:37 +04:00
. tlv = { . p = db_scale_adc }
2005-04-17 02:20:36 +04:00
} ,
2007-04-10 13:39:58 +04:00
{
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " Analog Capture Input " ,
. info = stac9460_mic_sw_info ,
. get = stac9460_mic_sw_get ,
. put = stac9460_mic_sw_put ,
} ,
2005-04-17 02:20:36 +04:00
} ;
2007-04-10 13:39:58 +04:00
/* AK4114 - ICE1724 connections on Prodigy192 + MI/ODI/O */
/* CDTO (pin 32) -- GPIO11 pin 86
* CDTI ( pin 33 ) - - GPIO10 pin 77
* CCLK ( pin 34 ) - - GPIO9 pin 76
* CSN ( pin 35 ) - - GPIO8 pin 75
*/
# define AK4114_ADDR 0x00 / * C1-C0: Chip Address
* ( According to datasheet fixed to “ 00 ” )
*/
/*
* 4 wire ak4114 protocol - writing data
*/
static void write_data ( struct snd_ice1712 * ice , unsigned int gpio ,
unsigned int data , int idx )
{
for ( ; idx > = 0 ; idx - - ) {
/* drop clock */
gpio & = ~ VT1724_PRODIGY192_CCLK ;
snd_ice1712_gpio_write ( ice , gpio ) ;
udelay ( 1 ) ;
/* set data */
if ( data & ( 1 < < idx ) )
gpio | = VT1724_PRODIGY192_CDOUT ;
else
gpio & = ~ VT1724_PRODIGY192_CDOUT ;
snd_ice1712_gpio_write ( ice , gpio ) ;
udelay ( 1 ) ;
/* raise clock */
gpio | = VT1724_PRODIGY192_CCLK ;
snd_ice1712_gpio_write ( ice , gpio ) ;
udelay ( 1 ) ;
}
}
/*
* 4 wire ak4114 protocol - reading data
*/
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_PRODIGY192_CCLK ;
snd_ice1712_gpio_write ( ice , gpio ) ;
udelay ( 1 ) ;
/* read data */
if ( snd_ice1712_gpio_read ( ice ) & VT1724_PRODIGY192_CDIN )
data | = ( 1 < < idx ) ;
udelay ( 1 ) ;
/* raise clock */
gpio | = VT1724_PRODIGY192_CCLK ;
snd_ice1712_gpio_write ( ice , gpio ) ;
udelay ( 1 ) ;
}
return data ;
}
/*
* 4 wire ak4114 protocol - starting sequence
*/
static unsigned int prodigy192_4wire_start ( struct snd_ice1712 * ice )
{
unsigned int tmp ;
snd_ice1712_save_gpio_status ( ice ) ;
tmp = snd_ice1712_gpio_read ( ice ) ;
tmp | = VT1724_PRODIGY192_CCLK ; /* high at init */
tmp & = ~ VT1724_PRODIGY192_CS ; /* drop chip select */
snd_ice1712_gpio_write ( ice , tmp ) ;
udelay ( 1 ) ;
return tmp ;
}
/*
* 4 wire ak4114 protocol - final sequence
*/
static void prodigy192_4wire_finish ( struct snd_ice1712 * ice , unsigned int tmp )
{
tmp | = VT1724_PRODIGY192_CS ; /* raise chip select */
snd_ice1712_gpio_write ( ice , tmp ) ;
udelay ( 1 ) ;
snd_ice1712_restore_gpio_status ( ice ) ;
}
/*
* Write data to addr register of ak4114
*/
static void prodigy192_ak4114_write ( void * private_data , unsigned char addr ,
unsigned char data )
{
struct snd_ice1712 * ice = private_data ;
unsigned int tmp , addrdata ;
tmp = prodigy192_4wire_start ( ice ) ;
addrdata = ( AK4114_ADDR < < 6 ) | 0x20 | ( addr & 0x1f ) ;
addrdata = ( addrdata < < 8 ) | data ;
write_data ( ice , tmp , addrdata , 15 ) ;
prodigy192_4wire_finish ( ice , tmp ) ;
}
/*
* Read data from addr register of ak4114
*/
static unsigned char prodigy192_ak4114_read ( void * private_data ,
unsigned char addr )
{
struct snd_ice1712 * ice = private_data ;
unsigned int tmp ;
unsigned char data ;
tmp = prodigy192_4wire_start ( ice ) ;
write_data ( ice , tmp , ( AK4114_ADDR < < 6 ) | ( addr & 0x1f ) , 7 ) ;
data = read_data ( ice , tmp , 7 ) ;
prodigy192_4wire_finish ( ice , tmp ) ;
return data ;
}
static int ak4114_input_sw_info ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_info * uinfo )
{
static char * texts [ 2 ] = { " Toslink " , " Coax " } ;
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 ak4114_input_sw_get ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol )
{
struct snd_ice1712 * ice = snd_kcontrol_chip ( kcontrol ) ;
unsigned char val ;
val = prodigy192_ak4114_read ( ice , AK4114_REG_IO1 ) ;
/* AK4114_IPS0 bit = 0 -> RX0 = Toslink
* AK4114_IPS0 bit = 1 - > RX1 = Coax
*/
ucontrol - > value . enumerated . item [ 0 ] = ( val & AK4114_IPS0 ) ? 1 : 0 ;
return 0 ;
}
static int ak4114_input_sw_put ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol )
{
struct snd_ice1712 * ice = snd_kcontrol_chip ( kcontrol ) ;
unsigned char new , old , itemvalue ;
int change ;
old = prodigy192_ak4114_read ( ice , AK4114_REG_IO1 ) ;
/* AK4114_IPS0 could be any bit */
itemvalue = ( ucontrol - > value . enumerated . item [ 0 ] ) ? 0xff : 0x00 ;
new = ( itemvalue & AK4114_IPS0 ) | ( old & ~ AK4114_IPS0 ) ;
change = ( new ! = old ) ;
if ( change )
prodigy192_ak4114_write ( ice , AK4114_REG_IO1 , new ) ;
return change ;
}
2007-06-28 01:09:57 +04:00
static struct snd_kcontrol_new ak4114_controls [ ] __devinitdata = {
2007-04-10 13:39:58 +04:00
{
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " MIODIO IEC958 Capture Input " ,
. info = ak4114_input_sw_info ,
. get = ak4114_input_sw_get ,
. put = ak4114_input_sw_put ,
}
} ;
static int prodigy192_ak4114_init ( struct snd_ice1712 * ice )
{
static const unsigned char ak4114_init_vals [ ] = {
AK4114_RST | AK4114_PWN | AK4114_OCKS0 | AK4114_OCKS1 ,
2007-04-24 14:27:36 +04:00
/* ice1724 expects I2S and provides clock,
* DEM0 disables the deemphasis filter
*/
AK4114_DIF_I24I2S | AK4114_DEM0 ,
2007-04-10 13:39:58 +04:00
AK4114_TX1E ,
AK4114_EFH_1024 | AK4114_DIT , /* default input RX0 */
0 ,
0
} ;
static const unsigned char ak4114_init_txcsb [ ] = {
0x41 , 0x02 , 0x2c , 0x00 , 0x00
} ;
return snd_ak4114_create ( ice - > card ,
prodigy192_ak4114_read ,
prodigy192_ak4114_write ,
ak4114_init_vals , ak4114_init_txcsb ,
ice , & ice - > spec . prodigy192 . ak4114 ) ;
}
2007-12-03 14:44:28 +03:00
static void stac9460_proc_regs_read ( struct snd_info_entry * entry ,
struct snd_info_buffer * buffer )
{
struct snd_ice1712 * ice = ( struct snd_ice1712 * ) entry - > private_data ;
int reg , val ;
/* registers 0x0 - 0x14 */
for ( reg = 0 ; reg < = 0x15 ; reg + + ) {
val = stac9460_get ( ice , reg ) ;
snd_iprintf ( buffer , " 0x%02x = 0x%02x \n " , reg , val ) ;
}
}
static void stac9460_proc_init ( struct snd_ice1712 * ice )
{
struct snd_info_entry * entry ;
if ( ! snd_card_proc_new ( ice - > card , " stac9460_codec " , & entry ) )
snd_info_set_text_ops ( entry , ice , stac9460_proc_regs_read ) ;
}
2005-11-17 17:00:18 +03:00
static int __devinit prodigy192_add_controls ( struct snd_ice1712 * ice )
2005-04-17 02:20:36 +04:00
{
unsigned int i ;
int err ;
for ( i = 0 ; i < ARRAY_SIZE ( stac_controls ) ; i + + ) {
2007-04-10 13:39:58 +04:00
err = snd_ctl_add ( ice - > card ,
snd_ctl_new1 ( & stac_controls [ i ] , ice ) ) ;
if ( err < 0 )
return err ;
}
if ( ice - > spec . prodigy192 . ak4114 ) {
/* ak4114 is connected */
for ( i = 0 ; i < ARRAY_SIZE ( ak4114_controls ) ; i + + ) {
err = snd_ctl_add ( ice - > card ,
snd_ctl_new1 ( & ak4114_controls [ i ] ,
ice ) ) ;
if ( err < 0 )
return err ;
}
err = snd_ak4114_build ( ice - > spec . prodigy192 . ak4114 ,
NULL , /* ak4114 in MIO/DI/O handles no IEC958 output */
ice - > pcm - > streams [ SNDRV_PCM_STREAM_CAPTURE ] . substream ) ;
2005-04-17 02:20:36 +04:00
if ( err < 0 )
return err ;
}
2007-12-03 14:44:28 +03:00
stac9460_proc_init ( ice ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2007-04-10 13:39:58 +04:00
/*
* check for presence of MI / ODI / O add - on card with digital inputs
*/
static int prodigy192_miodio_exists ( struct snd_ice1712 * ice )
{
unsigned char orig_value ;
const unsigned char test_data = 0xd1 ; /* random value */
unsigned char addr = AK4114_REG_INT0_MASK ; /* random SAFE address */
int exists = 0 ;
orig_value = prodigy192_ak4114_read ( ice , addr ) ;
prodigy192_ak4114_write ( ice , addr , test_data ) ;
if ( prodigy192_ak4114_read ( ice , addr ) = = test_data ) {
/* ak4114 seems to communicate, apparently exists */
/* writing back original value */
prodigy192_ak4114_write ( ice , addr , orig_value ) ;
exists = 1 ;
}
return exists ;
}
2005-04-17 02:20:36 +04:00
/*
* initialize the chip
*/
2005-11-17 17:00:18 +03:00
static int __devinit prodigy192_init ( struct snd_ice1712 * ice )
2005-04-17 02:20:36 +04:00
{
2007-01-29 17:26:36 +03:00
static const unsigned short stac_inits_prodigy [ ] = {
2005-04-17 02:20:36 +04:00
STAC946X_RESET , 0 ,
2007-12-03 14:44:28 +03:00
STAC946X_MASTER_CLOCKING , 0x11 ,
2005-04-17 02:20:36 +04:00
/* STAC946X_MASTER_VOLUME, 0,
STAC946X_LF_VOLUME , 0 ,
STAC946X_RF_VOLUME , 0 ,
STAC946X_LR_VOLUME , 0 ,
STAC946X_RR_VOLUME , 0 ,
STAC946X_CENTER_VOLUME , 0 ,
STAC946X_LFE_VOLUME , 0 , */
( unsigned short ) - 1
} ;
2007-01-29 17:26:36 +03:00
const unsigned short * p ;
2007-04-10 13:39:58 +04:00
int err = 0 ;
2007-12-03 14:44:28 +03:00
struct snd_akm4xxx * ak ;
2005-04-17 02:20:36 +04:00
/* prodigy 192 */
ice - > num_total_dacs = 6 ;
ice - > num_total_adcs = 2 ;
2007-04-10 13:39:58 +04:00
ice - > vt1720 = 0 ; /* ice1724, e.g. 23 GPIOs */
2005-04-17 02:20:36 +04:00
/* initialize codec */
p = stac_inits_prodigy ;
for ( ; * p ! = ( unsigned short ) - 1 ; p + = 2 )
stac9460_put ( ice , p [ 0 ] , p [ 1 ] ) ;
2007-12-03 14:44:28 +03:00
/* reusing the akm codecs infrastructure,
* for setting rate on stac9460 */
ak = ice - > akm = kmalloc ( sizeof ( struct snd_akm4xxx ) , GFP_KERNEL ) ;
if ( ! ak )
return - ENOMEM ;
ice - > akm_codecs = 1 ;
err = snd_ice1712_akm4xxx_init ( ak , & akmlike_stac9460 , NULL , ice ) ;
if ( err < 0 )
return err ;
2005-04-17 02:20:36 +04:00
2007-04-10 13:39:58 +04:00
/* MI/ODI/O add on card with AK4114 */
if ( prodigy192_miodio_exists ( ice ) ) {
err = prodigy192_ak4114_init ( ice ) ;
/* from this moment if err = 0 then
* ice - > spec . prodigy192 . ak4114 should not be null
*/
snd_printdd ( " AK4114 initialized with status %d \n " , err ) ;
} else
snd_printdd ( " AK4114 not found \n " ) ;
if ( err < 0 )
return err ;
2007-12-03 14:44:28 +03:00
mutex_init ( & ice - > spec . prodigy192 . mute_mutex ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
/*
* Aureon boards don ' t provide the EEPROM data except for the vendor IDs .
* hence the driver needs to sets up it properly .
*/
2007-03-14 00:13:47 +03:00
static unsigned char prodigy71_eeprom [ ] __devinitdata = {
2007-04-10 13:39:58 +04:00
[ ICE_EEP2_SYSCONF ] = 0x6a , /* 49MHz crystal, mpu401,
* spdif - in + 1 stereo ADC ,
* 3 stereo DACs
*/
2007-01-29 17:25:40 +03:00
[ 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 ,
2007-04-10 13:39:58 +04:00
[ ICE_EEP2_GPIO_DIR1 ] = ~ ( VT1724_PRODIGY192_CDIN > > 8 ) ,
2007-01-29 17:25:40 +03:00
[ 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 ,
2007-04-10 13:39:58 +04:00
[ ICE_EEP2_GPIO_STATE2 ] = 0x10 , /* GPIO20: 0 = CD drive dig. input
* passthrough ,
* 1 = SPDIF - OUT from ice1724
*/
2005-04-17 02:20:36 +04:00
} ;
/* entry point */
2007-03-14 00:13:47 +03:00
struct snd_ice1712_card_info snd_vt1724_prodigy192_cards [ ] __devinitdata = {
2005-04-17 02:20:36 +04:00
{
. subvendor = VT1724_SUBDEVICE_PRODIGY192VE ,
. name = " Audiotrak Prodigy 192 " ,
. model = " prodigy192 " ,
. chip_init = prodigy192_init ,
. build_controls = prodigy192_add_controls ,
. eeprom_size = sizeof ( prodigy71_eeprom ) ,
. eeprom_data = prodigy71_eeprom ,
2007-12-03 14:44:28 +03:00
/* the current MPU401 code loops infinitely
* when opening midi device
*/
. no_mpu401 = 1 ,
2005-04-17 02:20:36 +04:00
} ,
{ } /* terminator */
} ;