2005-04-16 15:20:36 -07:00
/*
* ALSA driver for ICEnsemble VT1724 ( Envy24HT )
*
* Lowlevel functions for Pontis MS300
*
* Copyright ( c ) 2004 Takashi Iwai < tiwai @ suse . de >
*
* 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>
2006-01-16 16:34:20 +01:00
# include <linux/mutex.h>
2005-04-16 15:20:36 -07:00
# include <sound/core.h>
# include <sound/info.h>
2006-08-30 16:57:37 +02:00
# include <sound/tlv.h>
2005-04-16 15:20:36 -07:00
# include "ice1712.h"
# include "envy24ht.h"
# include "pontis.h"
/* I2C addresses */
# define WM_DEV 0x34
# define CS_DEV 0x20
/* WM8776 registers */
# define WM_HP_ATTEN_L 0x00 /* headphone left attenuation */
# define WM_HP_ATTEN_R 0x01 /* headphone left attenuation */
2008-09-07 12:00:02 +02:00
# define WM_HP_MASTER 0x02 /* headphone master (both channels) */
/* override LLR */
2005-04-16 15:20:36 -07:00
# define WM_DAC_ATTEN_L 0x03 /* digital left attenuation */
# define WM_DAC_ATTEN_R 0x04
# define WM_DAC_MASTER 0x05
# define WM_PHASE_SWAP 0x06 /* DAC phase swap */
# define WM_DAC_CTRL1 0x07
# define WM_DAC_MUTE 0x08
# define WM_DAC_CTRL2 0x09
# define WM_DAC_INT 0x0a
# define WM_ADC_INT 0x0b
# define WM_MASTER_CTRL 0x0c
# define WM_POWERDOWN 0x0d
# define WM_ADC_ATTEN_L 0x0e
# define WM_ADC_ATTEN_R 0x0f
# define WM_ALC_CTRL1 0x10
# define WM_ALC_CTRL2 0x11
# define WM_ALC_CTRL3 0x12
# define WM_NOISE_GATE 0x13
# define WM_LIMITER 0x14
# define WM_ADC_MUX 0x15
# define WM_OUT_MUX 0x16
# define WM_RESET 0x17
/*
* GPIO
*/
# define PONTIS_CS_CS (1<<4) /* CS */
# define PONTIS_CS_CLK (1<<5) /* CLK */
# define PONTIS_CS_RDATA (1<<6) /* CS8416 -> VT1720 */
# define PONTIS_CS_WDATA (1<<7) /* VT1720 -> CS8416 */
/*
* get the current register value of WM codec
*/
2005-11-17 15:00:18 +01:00
static unsigned short wm_get ( struct snd_ice1712 * ice , int reg )
2005-04-16 15:20:36 -07:00
{
reg < < = 1 ;
return ( ( unsigned short ) ice - > akm [ 0 ] . images [ reg ] < < 8 ) |
ice - > akm [ 0 ] . images [ reg + 1 ] ;
}
/*
* set the register value of WM codec and remember it
*/
2005-11-17 15:00:18 +01:00
static void wm_put_nocache ( struct snd_ice1712 * ice , int reg , unsigned short val )
2005-04-16 15:20:36 -07:00
{
unsigned short cval ;
cval = ( reg < < 9 ) | val ;
snd_vt1724_write_i2c ( ice , WM_DEV , cval > > 8 , cval & 0xff ) ;
}
2005-11-17 15:00:18 +01:00
static void wm_put ( struct snd_ice1712 * ice , int reg , unsigned short val )
2005-04-16 15:20:36 -07:00
{
wm_put_nocache ( ice , reg , val ) ;
reg < < = 1 ;
ice - > akm [ 0 ] . images [ reg ] = val > > 8 ;
ice - > akm [ 0 ] . images [ reg + 1 ] = val ;
}
/*
* DAC volume attenuation mixer control ( - 64 dB to 0 dB )
*/
# define DAC_0dB 0xff
# define DAC_RES 128
# define DAC_MIN (DAC_0dB - DAC_RES)
2005-11-17 15:00:18 +01:00
static int wm_dac_vol_info ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_info * uinfo )
2005-04-16 15:20:36 -07:00
{
uinfo - > type = SNDRV_CTL_ELEM_TYPE_INTEGER ;
uinfo - > count = 2 ;
uinfo - > value . integer . min = 0 ; /* mute */
uinfo - > value . integer . max = DAC_RES ; /* 0dB, 0.5dB step */
return 0 ;
}
2005-11-17 15:00:18 +01:00
static int wm_dac_vol_get ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_value * ucontrol )
2005-04-16 15:20:36 -07:00
{
2005-11-17 15:00:18 +01:00
struct snd_ice1712 * ice = snd_kcontrol_chip ( kcontrol ) ;
2005-04-16 15:20:36 -07:00
unsigned short val ;
int i ;
2006-01-16 16:34:20 +01:00
mutex_lock ( & ice - > gpio_mutex ) ;
2005-04-16 15:20:36 -07:00
for ( i = 0 ; i < 2 ; i + + ) {
val = wm_get ( ice , WM_DAC_ATTEN_L + i ) & 0xff ;
val = val > DAC_MIN ? ( val - DAC_MIN ) : 0 ;
ucontrol - > value . integer . value [ i ] = val ;
}
2006-01-16 16:34:20 +01:00
mutex_unlock ( & ice - > gpio_mutex ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
2005-11-17 15:00:18 +01:00
static int wm_dac_vol_put ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_value * ucontrol )
2005-04-16 15:20:36 -07:00
{
2005-11-17 15:00:18 +01:00
struct snd_ice1712 * ice = snd_kcontrol_chip ( kcontrol ) ;
2005-04-16 15:20:36 -07:00
unsigned short oval , nval ;
int i , idx , change = 0 ;
2006-01-16 16:34:20 +01:00
mutex_lock ( & ice - > gpio_mutex ) ;
2005-04-16 15:20:36 -07:00
for ( i = 0 ; i < 2 ; i + + ) {
nval = ucontrol - > value . integer . value [ i ] ;
nval = ( nval ? ( nval + DAC_MIN ) : 0 ) & 0xff ;
idx = WM_DAC_ATTEN_L + i ;
oval = wm_get ( ice , idx ) & 0xff ;
if ( oval ! = nval ) {
wm_put ( ice , idx , nval ) ;
wm_put_nocache ( ice , idx , nval | 0x100 ) ;
change = 1 ;
}
}
2006-01-16 16:34:20 +01:00
mutex_unlock ( & ice - > gpio_mutex ) ;
2005-04-16 15:20:36 -07:00
return change ;
}
/*
* ADC gain mixer control ( - 64 dB to 0 dB )
*/
# define ADC_0dB 0xcf
# define ADC_RES 128
# define ADC_MIN (ADC_0dB - ADC_RES)
2005-11-17 15:00:18 +01:00
static int wm_adc_vol_info ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_info * uinfo )
2005-04-16 15:20:36 -07:00
{
uinfo - > type = SNDRV_CTL_ELEM_TYPE_INTEGER ;
uinfo - > count = 2 ;
uinfo - > value . integer . min = 0 ; /* mute (-64dB) */
uinfo - > value . integer . max = ADC_RES ; /* 0dB, 0.5dB step */
return 0 ;
}
2005-11-17 15:00:18 +01:00
static int wm_adc_vol_get ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_value * ucontrol )
2005-04-16 15:20:36 -07:00
{
2005-11-17 15:00:18 +01:00
struct snd_ice1712 * ice = snd_kcontrol_chip ( kcontrol ) ;
2005-04-16 15:20:36 -07:00
unsigned short val ;
int i ;
2006-01-16 16:34:20 +01:00
mutex_lock ( & ice - > gpio_mutex ) ;
2005-04-16 15:20:36 -07:00
for ( i = 0 ; i < 2 ; i + + ) {
val = wm_get ( ice , WM_ADC_ATTEN_L + i ) & 0xff ;
val = val > ADC_MIN ? ( val - ADC_MIN ) : 0 ;
ucontrol - > value . integer . value [ i ] = val ;
}
2006-01-16 16:34:20 +01:00
mutex_unlock ( & ice - > gpio_mutex ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
2005-11-17 15:00:18 +01:00
static int wm_adc_vol_put ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_value * ucontrol )
2005-04-16 15:20:36 -07:00
{
2005-11-17 15:00:18 +01:00
struct snd_ice1712 * ice = snd_kcontrol_chip ( kcontrol ) ;
2005-04-16 15:20:36 -07:00
unsigned short ovol , nvol ;
int i , idx , change = 0 ;
2006-01-16 16:34:20 +01:00
mutex_lock ( & ice - > gpio_mutex ) ;
2005-04-16 15:20:36 -07:00
for ( i = 0 ; i < 2 ; i + + ) {
nvol = ucontrol - > value . integer . value [ i ] ;
nvol = nvol ? ( nvol + ADC_MIN ) : 0 ;
idx = WM_ADC_ATTEN_L + i ;
ovol = wm_get ( ice , idx ) & 0xff ;
if ( ovol ! = nvol ) {
wm_put ( ice , idx , nvol ) ;
change = 1 ;
}
}
2006-01-16 16:34:20 +01:00
mutex_unlock ( & ice - > gpio_mutex ) ;
2005-04-16 15:20:36 -07:00
return change ;
}
/*
* ADC input mux mixer control
*/
2007-07-23 15:42:26 +02:00
# define wm_adc_mux_info snd_ctl_boolean_mono_info
2005-04-16 15:20:36 -07:00
2005-11-17 15:00:18 +01:00
static int wm_adc_mux_get ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_value * ucontrol )
2005-04-16 15:20:36 -07:00
{
2005-11-17 15:00:18 +01:00
struct snd_ice1712 * ice = snd_kcontrol_chip ( kcontrol ) ;
2005-04-16 15:20:36 -07:00
int bit = kcontrol - > private_value ;
2006-01-16 16:34:20 +01:00
mutex_lock ( & ice - > gpio_mutex ) ;
2005-04-16 15:20:36 -07:00
ucontrol - > value . integer . value [ 0 ] = ( wm_get ( ice , WM_ADC_MUX ) & ( 1 < < bit ) ) ? 1 : 0 ;
2006-01-16 16:34:20 +01:00
mutex_unlock ( & ice - > gpio_mutex ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
2005-11-17 15:00:18 +01:00
static int wm_adc_mux_put ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_value * ucontrol )
2005-04-16 15:20:36 -07:00
{
2005-11-17 15:00:18 +01:00
struct snd_ice1712 * ice = snd_kcontrol_chip ( kcontrol ) ;
2005-04-16 15:20:36 -07:00
int bit = kcontrol - > private_value ;
unsigned short oval , nval ;
int change ;
2006-01-16 16:34:20 +01:00
mutex_lock ( & ice - > gpio_mutex ) ;
2005-04-16 15:20:36 -07:00
nval = oval = wm_get ( ice , WM_ADC_MUX ) ;
if ( ucontrol - > value . integer . value [ 0 ] )
nval | = ( 1 < < bit ) ;
else
nval & = ~ ( 1 < < bit ) ;
change = nval ! = oval ;
if ( change ) {
wm_put ( ice , WM_ADC_MUX , nval ) ;
}
2006-01-16 16:34:20 +01:00
mutex_unlock ( & ice - > gpio_mutex ) ;
2008-03-17 10:16:37 +01:00
return change ;
2005-04-16 15:20:36 -07:00
}
/*
* Analog bypass ( In - > Out )
*/
2007-07-23 15:42:26 +02:00
# define wm_bypass_info snd_ctl_boolean_mono_info
2005-04-16 15:20:36 -07:00
2005-11-17 15:00:18 +01:00
static int wm_bypass_get ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_value * ucontrol )
2005-04-16 15:20:36 -07:00
{
2005-11-17 15:00:18 +01:00
struct snd_ice1712 * ice = snd_kcontrol_chip ( kcontrol ) ;
2005-04-16 15:20:36 -07:00
2006-01-16 16:34:20 +01:00
mutex_lock ( & ice - > gpio_mutex ) ;
2005-04-16 15:20:36 -07:00
ucontrol - > value . integer . value [ 0 ] = ( wm_get ( ice , WM_OUT_MUX ) & 0x04 ) ? 1 : 0 ;
2006-01-16 16:34:20 +01:00
mutex_unlock ( & ice - > gpio_mutex ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
2005-11-17 15:00:18 +01:00
static int wm_bypass_put ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_value * ucontrol )
2005-04-16 15:20:36 -07:00
{
2005-11-17 15:00:18 +01:00
struct snd_ice1712 * ice = snd_kcontrol_chip ( kcontrol ) ;
2005-04-16 15:20:36 -07:00
unsigned short val , oval ;
int change = 0 ;
2006-01-16 16:34:20 +01:00
mutex_lock ( & ice - > gpio_mutex ) ;
2005-04-16 15:20:36 -07:00
val = oval = wm_get ( ice , WM_OUT_MUX ) ;
if ( ucontrol - > value . integer . value [ 0 ] )
val | = 0x04 ;
else
val & = ~ 0x04 ;
if ( val ! = oval ) {
wm_put ( ice , WM_OUT_MUX , val ) ;
change = 1 ;
}
2006-01-16 16:34:20 +01:00
mutex_unlock ( & ice - > gpio_mutex ) ;
2005-04-16 15:20:36 -07:00
return change ;
}
/*
* Left / Right swap
*/
2007-07-23 15:42:26 +02:00
# define wm_chswap_info snd_ctl_boolean_mono_info
2005-04-16 15:20:36 -07:00
2005-11-17 15:00:18 +01:00
static int wm_chswap_get ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_value * ucontrol )
2005-04-16 15:20:36 -07:00
{
2005-11-17 15:00:18 +01:00
struct snd_ice1712 * ice = snd_kcontrol_chip ( kcontrol ) ;
2005-04-16 15:20:36 -07:00
2006-01-16 16:34:20 +01:00
mutex_lock ( & ice - > gpio_mutex ) ;
2005-04-16 15:20:36 -07:00
ucontrol - > value . integer . value [ 0 ] = ( wm_get ( ice , WM_DAC_CTRL1 ) & 0xf0 ) ! = 0x90 ;
2006-01-16 16:34:20 +01:00
mutex_unlock ( & ice - > gpio_mutex ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
2005-11-17 15:00:18 +01:00
static int wm_chswap_put ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_value * ucontrol )
2005-04-16 15:20:36 -07:00
{
2005-11-17 15:00:18 +01:00
struct snd_ice1712 * ice = snd_kcontrol_chip ( kcontrol ) ;
2005-04-16 15:20:36 -07:00
unsigned short val , oval ;
int change = 0 ;
2006-01-16 16:34:20 +01:00
mutex_lock ( & ice - > gpio_mutex ) ;
2005-04-16 15:20:36 -07:00
oval = wm_get ( ice , WM_DAC_CTRL1 ) ;
val = oval & 0x0f ;
if ( ucontrol - > value . integer . value [ 0 ] )
val | = 0x60 ;
else
val | = 0x90 ;
if ( val ! = oval ) {
wm_put ( ice , WM_DAC_CTRL1 , val ) ;
wm_put_nocache ( ice , WM_DAC_CTRL1 , val ) ;
change = 1 ;
}
2006-01-16 16:34:20 +01:00
mutex_unlock ( & ice - > gpio_mutex ) ;
2005-04-16 15:20:36 -07:00
return change ;
}
/*
* write data in the SPI mode
*/
2005-11-17 15:00:18 +01:00
static void set_gpio_bit ( struct snd_ice1712 * ice , unsigned int bit , int val )
2005-04-16 15:20:36 -07:00
{
unsigned int tmp = snd_ice1712_gpio_read ( ice ) ;
if ( val )
tmp | = bit ;
else
tmp & = ~ bit ;
snd_ice1712_gpio_write ( ice , tmp ) ;
}
2005-11-17 15:00:18 +01:00
static void spi_send_byte ( struct snd_ice1712 * ice , unsigned char data )
2005-04-16 15:20:36 -07:00
{
int i ;
for ( i = 0 ; i < 8 ; i + + ) {
set_gpio_bit ( ice , PONTIS_CS_CLK , 0 ) ;
udelay ( 1 ) ;
set_gpio_bit ( ice , PONTIS_CS_WDATA , data & 0x80 ) ;
udelay ( 1 ) ;
set_gpio_bit ( ice , PONTIS_CS_CLK , 1 ) ;
udelay ( 1 ) ;
data < < = 1 ;
}
}
2005-11-17 15:00:18 +01:00
static unsigned int spi_read_byte ( struct snd_ice1712 * ice )
2005-04-16 15:20:36 -07:00
{
int i ;
unsigned int val = 0 ;
for ( i = 0 ; i < 8 ; i + + ) {
val < < = 1 ;
set_gpio_bit ( ice , PONTIS_CS_CLK , 0 ) ;
udelay ( 1 ) ;
if ( snd_ice1712_gpio_read ( ice ) & PONTIS_CS_RDATA )
val | = 1 ;
udelay ( 1 ) ;
set_gpio_bit ( ice , PONTIS_CS_CLK , 1 ) ;
udelay ( 1 ) ;
}
return val ;
}
2005-11-17 15:00:18 +01:00
static void spi_write ( struct snd_ice1712 * ice , unsigned int dev , unsigned int reg , unsigned int data )
2005-04-16 15:20:36 -07:00
{
snd_ice1712_gpio_set_dir ( ice , PONTIS_CS_CS | PONTIS_CS_WDATA | PONTIS_CS_CLK ) ;
snd_ice1712_gpio_set_mask ( ice , ~ ( PONTIS_CS_CS | PONTIS_CS_WDATA | PONTIS_CS_CLK ) ) ;
set_gpio_bit ( ice , PONTIS_CS_CS , 0 ) ;
spi_send_byte ( ice , dev & ~ 1 ) ; /* WRITE */
spi_send_byte ( ice , reg ) ; /* MAP */
spi_send_byte ( ice , data ) ; /* DATA */
/* trigger */
set_gpio_bit ( ice , PONTIS_CS_CS , 1 ) ;
udelay ( 1 ) ;
/* restore */
snd_ice1712_gpio_set_mask ( ice , ice - > gpio . write_mask ) ;
snd_ice1712_gpio_set_dir ( ice , ice - > gpio . direction ) ;
}
2005-11-17 15:00:18 +01:00
static unsigned int spi_read ( struct snd_ice1712 * ice , unsigned int dev , unsigned int reg )
2005-04-16 15:20:36 -07:00
{
unsigned int val ;
snd_ice1712_gpio_set_dir ( ice , PONTIS_CS_CS | PONTIS_CS_WDATA | PONTIS_CS_CLK ) ;
snd_ice1712_gpio_set_mask ( ice , ~ ( PONTIS_CS_CS | PONTIS_CS_WDATA | PONTIS_CS_CLK ) ) ;
set_gpio_bit ( ice , PONTIS_CS_CS , 0 ) ;
spi_send_byte ( ice , dev & ~ 1 ) ; /* WRITE */
spi_send_byte ( ice , reg ) ; /* MAP */
/* trigger */
set_gpio_bit ( ice , PONTIS_CS_CS , 1 ) ;
udelay ( 1 ) ;
set_gpio_bit ( ice , PONTIS_CS_CS , 0 ) ;
spi_send_byte ( ice , dev | 1 ) ; /* READ */
val = spi_read_byte ( ice ) ;
/* trigger */
set_gpio_bit ( ice , PONTIS_CS_CS , 1 ) ;
udelay ( 1 ) ;
/* restore */
snd_ice1712_gpio_set_mask ( ice , ice - > gpio . write_mask ) ;
snd_ice1712_gpio_set_dir ( ice , ice - > gpio . direction ) ;
return val ;
}
/*
* SPDIF input source
*/
2005-11-17 15:00:18 +01:00
static int cs_source_info ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_info * uinfo )
2005-04-16 15:20:36 -07:00
{
2007-01-29 15:26:36 +01:00
static const char * const texts [ ] = {
2005-04-16 15:20:36 -07:00
" Coax " , /* RXP0 */
" Optical " , /* RXP1 */
" CD " , /* RXP2 */
} ;
uinfo - > type = SNDRV_CTL_ELEM_TYPE_ENUMERATED ;
uinfo - > count = 1 ;
uinfo - > value . enumerated . items = 3 ;
if ( uinfo - > value . enumerated . item > = uinfo - > value . enumerated . items )
uinfo - > value . enumerated . item = uinfo - > value . enumerated . items - 1 ;
strcpy ( uinfo - > value . enumerated . name , texts [ uinfo - > value . enumerated . item ] ) ;
return 0 ;
}
2005-11-17 15:00:18 +01:00
static int cs_source_get ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_value * ucontrol )
2005-04-16 15:20:36 -07:00
{
2005-11-17 15:00:18 +01:00
struct snd_ice1712 * ice = snd_kcontrol_chip ( kcontrol ) ;
2005-04-16 15:20:36 -07:00
2006-01-16 16:34:20 +01:00
mutex_lock ( & ice - > gpio_mutex ) ;
2005-04-16 15:20:36 -07:00
ucontrol - > value . enumerated . item [ 0 ] = ice - > gpio . saved [ 0 ] ;
2006-01-16 16:34:20 +01:00
mutex_unlock ( & ice - > gpio_mutex ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
2005-11-17 15:00:18 +01:00
static int cs_source_put ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_value * ucontrol )
2005-04-16 15:20:36 -07:00
{
2005-11-17 15:00:18 +01:00
struct snd_ice1712 * ice = snd_kcontrol_chip ( kcontrol ) ;
2005-04-16 15:20:36 -07:00
unsigned char val ;
int change = 0 ;
2006-01-16 16:34:20 +01:00
mutex_lock ( & ice - > gpio_mutex ) ;
2005-04-16 15:20:36 -07:00
if ( ucontrol - > value . enumerated . item [ 0 ] ! = ice - > gpio . saved [ 0 ] ) {
ice - > gpio . saved [ 0 ] = ucontrol - > value . enumerated . item [ 0 ] & 3 ;
val = 0x80 | ( ice - > gpio . saved [ 0 ] < < 3 ) ;
spi_write ( ice , CS_DEV , 0x04 , val ) ;
change = 1 ;
}
2006-01-16 16:34:20 +01:00
mutex_unlock ( & ice - > gpio_mutex ) ;
2008-03-17 10:16:37 +01:00
return change ;
2005-04-16 15:20:36 -07:00
}
/*
* GPIO controls
*/
2005-11-17 15:00:18 +01:00
static int pontis_gpio_mask_info ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_info * uinfo )
2005-04-16 15:20:36 -07:00
{
uinfo - > type = SNDRV_CTL_ELEM_TYPE_INTEGER ;
uinfo - > count = 1 ;
uinfo - > value . integer . min = 0 ;
uinfo - > value . integer . max = 0xffff ; /* 16bit */
return 0 ;
}
2005-11-17 15:00:18 +01:00
static int pontis_gpio_mask_get ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_value * ucontrol )
2005-04-16 15:20:36 -07:00
{
2005-11-17 15:00:18 +01:00
struct snd_ice1712 * ice = snd_kcontrol_chip ( kcontrol ) ;
2006-01-16 16:34:20 +01:00
mutex_lock ( & ice - > gpio_mutex ) ;
2005-04-16 15:20:36 -07:00
/* 4-7 reserved */
ucontrol - > value . integer . value [ 0 ] = ( ~ ice - > gpio . write_mask & 0xffff ) | 0x00f0 ;
2006-01-16 16:34:20 +01:00
mutex_unlock ( & ice - > gpio_mutex ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
2005-11-17 15:00:18 +01:00
static int pontis_gpio_mask_put ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_value * ucontrol )
2005-04-16 15:20:36 -07:00
{
2005-11-17 15:00:18 +01:00
struct snd_ice1712 * ice = snd_kcontrol_chip ( kcontrol ) ;
2005-04-16 15:20:36 -07:00
unsigned int val ;
int changed ;
2006-01-16 16:34:20 +01:00
mutex_lock ( & ice - > gpio_mutex ) ;
2005-04-16 15:20:36 -07:00
/* 4-7 reserved */
val = ( ~ ucontrol - > value . integer . value [ 0 ] & 0xffff ) | 0x00f0 ;
changed = val ! = ice - > gpio . write_mask ;
ice - > gpio . write_mask = val ;
2006-01-16 16:34:20 +01:00
mutex_unlock ( & ice - > gpio_mutex ) ;
2005-04-16 15:20:36 -07:00
return changed ;
}
2005-11-17 15:00:18 +01:00
static int pontis_gpio_dir_get ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_value * ucontrol )
2005-04-16 15:20:36 -07:00
{
2005-11-17 15:00:18 +01:00
struct snd_ice1712 * ice = snd_kcontrol_chip ( kcontrol ) ;
2006-01-16 16:34:20 +01:00
mutex_lock ( & ice - > gpio_mutex ) ;
2005-04-16 15:20:36 -07:00
/* 4-7 reserved */
ucontrol - > value . integer . value [ 0 ] = ice - > gpio . direction & 0xff0f ;
2006-01-16 16:34:20 +01:00
mutex_unlock ( & ice - > gpio_mutex ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
2005-11-17 15:00:18 +01:00
static int pontis_gpio_dir_put ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_value * ucontrol )
2005-04-16 15:20:36 -07:00
{
2005-11-17 15:00:18 +01:00
struct snd_ice1712 * ice = snd_kcontrol_chip ( kcontrol ) ;
2005-04-16 15:20:36 -07:00
unsigned int val ;
int changed ;
2006-01-16 16:34:20 +01:00
mutex_lock ( & ice - > gpio_mutex ) ;
2005-04-16 15:20:36 -07:00
/* 4-7 reserved */
val = ucontrol - > value . integer . value [ 0 ] & 0xff0f ;
changed = ( val ! = ice - > gpio . direction ) ;
ice - > gpio . direction = val ;
2006-01-16 16:34:20 +01:00
mutex_unlock ( & ice - > gpio_mutex ) ;
2005-04-16 15:20:36 -07:00
return changed ;
}
2005-11-17 15:00:18 +01:00
static int pontis_gpio_data_get ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_value * ucontrol )
2005-04-16 15:20:36 -07:00
{
2005-11-17 15:00:18 +01:00
struct snd_ice1712 * ice = snd_kcontrol_chip ( kcontrol ) ;
2006-01-16 16:34:20 +01:00
mutex_lock ( & ice - > gpio_mutex ) ;
2005-04-16 15:20:36 -07:00
snd_ice1712_gpio_set_dir ( ice , ice - > gpio . direction ) ;
snd_ice1712_gpio_set_mask ( ice , ice - > gpio . write_mask ) ;
ucontrol - > value . integer . value [ 0 ] = snd_ice1712_gpio_read ( ice ) & 0xffff ;
2006-01-16 16:34:20 +01:00
mutex_unlock ( & ice - > gpio_mutex ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
2005-11-17 15:00:18 +01:00
static int pontis_gpio_data_put ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_value * ucontrol )
2005-04-16 15:20:36 -07:00
{
2005-11-17 15:00:18 +01:00
struct snd_ice1712 * ice = snd_kcontrol_chip ( kcontrol ) ;
2005-04-16 15:20:36 -07:00
unsigned int val , nval ;
int changed = 0 ;
2006-01-16 16:34:20 +01:00
mutex_lock ( & ice - > gpio_mutex ) ;
2005-04-16 15:20:36 -07:00
snd_ice1712_gpio_set_dir ( ice , ice - > gpio . direction ) ;
snd_ice1712_gpio_set_mask ( ice , ice - > gpio . write_mask ) ;
val = snd_ice1712_gpio_read ( ice ) & 0xffff ;
nval = ucontrol - > value . integer . value [ 0 ] & 0xffff ;
if ( val ! = nval ) {
snd_ice1712_gpio_write ( ice , nval ) ;
changed = 1 ;
}
2006-01-16 16:34:20 +01:00
mutex_unlock ( & ice - > gpio_mutex ) ;
2005-04-16 15:20:36 -07:00
return changed ;
}
2007-01-29 15:33:49 +01:00
static const DECLARE_TLV_DB_SCALE ( db_scale_volume , - 6400 , 50 , 1 ) ;
2006-08-30 16:57:37 +02:00
2005-04-16 15:20:36 -07:00
/*
* mixers
*/
2007-03-13 22:13:47 +01:00
static struct snd_kcontrol_new pontis_controls [ ] __devinitdata = {
2005-04-16 15:20:36 -07:00
{
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
2006-08-30 16:57:37 +02:00
. access = ( SNDRV_CTL_ELEM_ACCESS_READWRITE |
SNDRV_CTL_ELEM_ACCESS_TLV_READ ) ,
2005-04-16 15:20:36 -07:00
. name = " PCM Playback Volume " ,
. info = wm_dac_vol_info ,
. get = wm_dac_vol_get ,
. put = wm_dac_vol_put ,
2006-08-30 16:57:37 +02:00
. tlv = { . p = db_scale_volume } ,
2005-04-16 15:20:36 -07:00
} ,
{
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
2006-08-30 16:57:37 +02:00
. access = ( SNDRV_CTL_ELEM_ACCESS_READWRITE |
SNDRV_CTL_ELEM_ACCESS_TLV_READ ) ,
2005-04-16 15:20:36 -07:00
. name = " Capture Volume " ,
. info = wm_adc_vol_info ,
. get = wm_adc_vol_get ,
. put = wm_adc_vol_put ,
2006-08-30 16:57:37 +02:00
. tlv = { . p = db_scale_volume } ,
2005-04-16 15:20:36 -07:00
} ,
{
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " CD Capture Switch " ,
. info = wm_adc_mux_info ,
. get = wm_adc_mux_get ,
. put = wm_adc_mux_put ,
. private_value = 0 ,
} ,
{
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " Line Capture Switch " ,
. info = wm_adc_mux_info ,
. get = wm_adc_mux_get ,
. put = wm_adc_mux_put ,
. private_value = 1 ,
} ,
{
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " Analog Bypass Switch " ,
. info = wm_bypass_info ,
. get = wm_bypass_get ,
. put = wm_bypass_put ,
} ,
{
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " Swap Output Channels " ,
. info = wm_chswap_info ,
. get = wm_chswap_get ,
. put = wm_chswap_put ,
} ,
{
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " IEC958 Input Source " ,
. info = cs_source_info ,
. get = cs_source_get ,
. put = cs_source_put ,
} ,
/* FIXME: which interface? */
{
. iface = SNDRV_CTL_ELEM_IFACE_CARD ,
. name = " GPIO Mask " ,
. info = pontis_gpio_mask_info ,
. get = pontis_gpio_mask_get ,
. put = pontis_gpio_mask_put ,
} ,
{
. iface = SNDRV_CTL_ELEM_IFACE_CARD ,
. name = " GPIO Direction " ,
. info = pontis_gpio_mask_info ,
. get = pontis_gpio_dir_get ,
. put = pontis_gpio_dir_put ,
} ,
{
. iface = SNDRV_CTL_ELEM_IFACE_CARD ,
. name = " GPIO Data " ,
. info = pontis_gpio_mask_info ,
. get = pontis_gpio_data_get ,
. put = pontis_gpio_data_put ,
} ,
} ;
/*
* WM codec registers
*/
2005-11-17 15:00:18 +01:00
static void wm_proc_regs_write ( struct snd_info_entry * entry , struct snd_info_buffer * buffer )
2005-04-16 15:20:36 -07:00
{
2010-09-04 18:52:54 -07:00
struct snd_ice1712 * ice = entry - > private_data ;
2005-04-16 15:20:36 -07:00
char line [ 64 ] ;
unsigned int reg , val ;
2006-01-16 16:34:20 +01:00
mutex_lock ( & ice - > gpio_mutex ) ;
2005-04-16 15:20:36 -07:00
while ( ! snd_info_get_line ( buffer , line , sizeof ( line ) ) ) {
if ( sscanf ( line , " %x %x " , & reg , & val ) ! = 2 )
continue ;
if ( reg < = 0x17 & & val < = 0xffff )
wm_put ( ice , reg , val ) ;
}
2006-01-16 16:34:20 +01:00
mutex_unlock ( & ice - > gpio_mutex ) ;
2005-04-16 15:20:36 -07:00
}
2005-11-17 15:00:18 +01:00
static void wm_proc_regs_read ( struct snd_info_entry * entry , struct snd_info_buffer * buffer )
2005-04-16 15:20:36 -07:00
{
2010-09-04 18:52:54 -07:00
struct snd_ice1712 * ice = entry - > private_data ;
2005-04-16 15:20:36 -07:00
int reg , val ;
2006-01-16 16:34:20 +01:00
mutex_lock ( & ice - > gpio_mutex ) ;
2005-04-16 15:20:36 -07:00
for ( reg = 0 ; reg < = 0x17 ; reg + + ) {
val = wm_get ( ice , reg ) ;
snd_iprintf ( buffer , " %02x = %04x \n " , reg , val ) ;
}
2006-01-16 16:34:20 +01:00
mutex_unlock ( & ice - > gpio_mutex ) ;
2005-04-16 15:20:36 -07:00
}
2005-11-17 15:00:18 +01:00
static void wm_proc_init ( struct snd_ice1712 * ice )
2005-04-16 15:20:36 -07:00
{
2005-11-17 15:00:18 +01:00
struct snd_info_entry * entry ;
2005-04-16 15:20:36 -07:00
if ( ! snd_card_proc_new ( ice - > card , " wm_codec " , & entry ) ) {
2006-04-28 15:13:41 +02:00
snd_info_set_text_ops ( entry , ice , wm_proc_regs_read ) ;
2005-04-16 15:20:36 -07:00
entry - > mode | = S_IWUSR ;
entry - > c . text . write = wm_proc_regs_write ;
}
}
2005-11-17 15:00:18 +01:00
static void cs_proc_regs_read ( struct snd_info_entry * entry , struct snd_info_buffer * buffer )
2005-04-16 15:20:36 -07:00
{
2010-09-04 18:52:54 -07:00
struct snd_ice1712 * ice = entry - > private_data ;
2005-04-16 15:20:36 -07:00
int reg , val ;
2006-01-16 16:34:20 +01:00
mutex_lock ( & ice - > gpio_mutex ) ;
2005-04-16 15:20:36 -07:00
for ( reg = 0 ; reg < = 0x26 ; reg + + ) {
val = spi_read ( ice , CS_DEV , reg ) ;
snd_iprintf ( buffer , " %02x = %02x \n " , reg , val ) ;
}
val = spi_read ( ice , CS_DEV , 0x7f ) ;
snd_iprintf ( buffer , " %02x = %02x \n " , 0x7f , val ) ;
2006-01-16 16:34:20 +01:00
mutex_unlock ( & ice - > gpio_mutex ) ;
2005-04-16 15:20:36 -07:00
}
2005-11-17 15:00:18 +01:00
static void cs_proc_init ( struct snd_ice1712 * ice )
2005-04-16 15:20:36 -07:00
{
2005-11-17 15:00:18 +01:00
struct snd_info_entry * entry ;
2006-04-28 15:13:41 +02:00
if ( ! snd_card_proc_new ( ice - > card , " cs_codec " , & entry ) )
snd_info_set_text_ops ( entry , ice , cs_proc_regs_read ) ;
2005-04-16 15:20:36 -07:00
}
2005-11-17 15:00:18 +01:00
static int __devinit pontis_add_controls ( struct snd_ice1712 * ice )
2005-04-16 15:20:36 -07:00
{
unsigned int i ;
int err ;
for ( i = 0 ; i < ARRAY_SIZE ( pontis_controls ) ; i + + ) {
err = snd_ctl_add ( ice - > card , snd_ctl_new1 ( & pontis_controls [ i ] , ice ) ) ;
if ( err < 0 )
return err ;
}
wm_proc_init ( ice ) ;
cs_proc_init ( ice ) ;
return 0 ;
}
/*
* initialize the chip
*/
2005-11-17 15:00:18 +01:00
static int __devinit pontis_init ( struct snd_ice1712 * ice )
2005-04-16 15:20:36 -07:00
{
2007-01-29 15:26:36 +01:00
static const unsigned short wm_inits [ ] = {
2005-04-16 15:20:36 -07:00
/* These come first to reduce init pop noise */
WM_ADC_MUX , 0x00c0 , /* ADC mute */
WM_DAC_MUTE , 0x0001 , /* DAC softmute */
WM_DAC_CTRL1 , 0x0000 , /* DAC mute */
WM_POWERDOWN , 0x0008 , /* All power-up except HP */
WM_RESET , 0x0000 , /* reset */
} ;
2007-01-29 15:26:36 +01:00
static const unsigned short wm_inits2 [ ] = {
2005-04-16 15:20:36 -07:00
WM_MASTER_CTRL , 0x0022 , /* 256fs, slave mode */
WM_DAC_INT , 0x0022 , /* I2S, normal polarity, 24bit */
WM_ADC_INT , 0x0022 , /* I2S, normal polarity, 24bit */
WM_DAC_CTRL1 , 0x0090 , /* DAC L/R */
WM_OUT_MUX , 0x0001 , /* OUT DAC */
WM_HP_ATTEN_L , 0x0179 , /* HP 0dB */
WM_HP_ATTEN_R , 0x0179 , /* HP 0dB */
WM_DAC_ATTEN_L , 0x0000 , /* DAC 0dB */
WM_DAC_ATTEN_L , 0x0100 , /* DAC 0dB */
WM_DAC_ATTEN_R , 0x0000 , /* DAC 0dB */
WM_DAC_ATTEN_R , 0x0100 , /* DAC 0dB */
2008-09-07 12:00:02 +02:00
/* WM_DAC_MASTER, 0x0100, */ /* DAC master muted */
2005-04-16 15:20:36 -07:00
WM_PHASE_SWAP , 0x0000 , /* phase normal */
WM_DAC_CTRL2 , 0x0000 , /* no deemphasis, no ZFLG */
WM_ADC_ATTEN_L , 0x0000 , /* ADC muted */
WM_ADC_ATTEN_R , 0x0000 , /* ADC muted */
#if 0
WM_ALC_CTRL1 , 0x007b , /* */
WM_ALC_CTRL2 , 0x0000 , /* */
WM_ALC_CTRL3 , 0x0000 , /* */
WM_NOISE_GATE , 0x0000 , /* */
# endif
WM_DAC_MUTE , 0x0000 , /* DAC unmute */
WM_ADC_MUX , 0x0003 , /* ADC unmute, both CD/Line On */
} ;
2007-01-29 15:26:36 +01:00
static const unsigned char cs_inits [ ] = {
2005-04-16 15:20:36 -07:00
0x04 , 0x80 , /* RUN, RXP0 */
0x05 , 0x05 , /* slave, 24bit */
0x01 , 0x00 ,
0x02 , 0x00 ,
0x03 , 0x00 ,
} ;
unsigned int i ;
ice - > vt1720 = 1 ;
ice - > num_total_dacs = 2 ;
ice - > num_total_adcs = 2 ;
2011-03-30 22:57:33 -03:00
/* to remember the register values */
2005-11-17 15:00:18 +01:00
ice - > akm = kzalloc ( sizeof ( struct snd_akm4xxx ) , GFP_KERNEL ) ;
2005-04-16 15:20:36 -07:00
if ( ! ice - > akm )
return - ENOMEM ;
ice - > akm_codecs = 1 ;
/* HACK - use this as the SPDIF source.
* don ' t call snd_ice1712_gpio_get / put ( ) , otherwise it ' s overwritten
*/
ice - > gpio . saved [ 0 ] = 0 ;
/* initialize WM8776 codec */
for ( i = 0 ; i < ARRAY_SIZE ( wm_inits ) ; i + = 2 )
wm_put ( ice , wm_inits [ i ] , wm_inits [ i + 1 ] ) ;
2005-10-24 15:02:37 +02:00
schedule_timeout_uninterruptible ( 1 ) ;
2005-04-16 15:20:36 -07:00
for ( i = 0 ; i < ARRAY_SIZE ( wm_inits2 ) ; i + = 2 )
wm_put ( ice , wm_inits2 [ i ] , wm_inits2 [ i + 1 ] ) ;
/* initialize CS8416 codec */
/* assert PRST#; MT05 bit 7 */
outb ( inb ( ICEMT1724 ( ice , AC97_CMD ) ) | 0x80 , ICEMT1724 ( ice , AC97_CMD ) ) ;
mdelay ( 5 ) ;
/* deassert PRST# */
outb ( inb ( ICEMT1724 ( ice , AC97_CMD ) ) & ~ 0x80 , ICEMT1724 ( ice , AC97_CMD ) ) ;
for ( i = 0 ; i < ARRAY_SIZE ( cs_inits ) ; i + = 2 )
spi_write ( ice , CS_DEV , cs_inits [ i ] , cs_inits [ i + 1 ] ) ;
return 0 ;
}
/*
* Pontis boards don ' t provide the EEPROM data at all .
* hence the driver needs to sets up it properly .
*/
2007-03-13 22:13:47 +01:00
static unsigned char pontis_eeprom [ ] __devinitdata = {
2007-01-29 15:25:40 +01:00
[ ICE_EEP2_SYSCONF ] = 0x08 , /* clock 256, mpu401, spdif-in/ADC, 1DAC */
[ ICE_EEP2_ACLINK ] = 0x80 , /* I2S */
[ ICE_EEP2_I2S ] = 0xf8 , /* vol, 96k, 24bit, 192k */
[ ICE_EEP2_SPDIF ] = 0xc3 , /* out-en, out-int, spdif-in */
[ ICE_EEP2_GPIO_DIR ] = 0x07 ,
[ ICE_EEP2_GPIO_DIR1 ] = 0x00 ,
[ ICE_EEP2_GPIO_DIR2 ] = 0x00 , /* ignored */
[ ICE_EEP2_GPIO_MASK ] = 0x0f , /* 4-7 reserved for CS8416 */
[ ICE_EEP2_GPIO_MASK1 ] = 0xff ,
[ ICE_EEP2_GPIO_MASK2 ] = 0x00 , /* ignored */
[ ICE_EEP2_GPIO_STATE ] = 0x06 , /* 0-low, 1-high, 2-high */
[ ICE_EEP2_GPIO_STATE1 ] = 0x00 ,
[ ICE_EEP2_GPIO_STATE2 ] = 0x00 , /* ignored */
2005-04-16 15:20:36 -07:00
} ;
/* entry point */
2007-03-13 22:13:47 +01:00
struct snd_ice1712_card_info snd_vt1720_pontis_cards [ ] __devinitdata = {
2005-04-16 15:20:36 -07:00
{
. subvendor = VT1720_SUBDEVICE_PONTIS_MS300 ,
. name = " Pontis MS300 " ,
. model = " ms300 " ,
. chip_init = pontis_init ,
. build_controls = pontis_add_controls ,
. eeprom_size = sizeof ( pontis_eeprom ) ,
. eeprom_data = pontis_eeprom ,
} ,
{ } /* terminator */
} ;