2005-04-17 02:20:36 +04:00
/*
2007-10-15 11:50:19 +04:00
* Copyright ( c ) by Jaroslav Kysela < perex @ perex . cz >
2005-04-17 02:20:36 +04:00
* Universal routines for AK4531 codec
*
*
* 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 <linux/delay.h>
# include <linux/init.h>
# include <linux/slab.h>
2006-01-16 18:34:20 +03:00
# include <linux/mutex.h>
2011-07-15 20:38:28 +04:00
# include <linux/module.h>
2006-01-16 18:34:20 +03:00
2005-04-17 02:20:36 +04:00
# include <sound/core.h>
# include <sound/ak4531_codec.h>
2006-08-23 14:04:34 +04:00
# include <sound/tlv.h>
2005-04-17 02:20:36 +04:00
2008-06-16 12:39:34 +04:00
/*
2007-10-15 11:50:19 +04:00
MODULE_AUTHOR ( " Jaroslav Kysela <perex@perex.cz> " ) ;
2005-04-17 02:20:36 +04:00
MODULE_DESCRIPTION ( " Universal routines for AK4531 codec " ) ;
MODULE_LICENSE ( " GPL " ) ;
2008-06-16 12:39:34 +04:00
*/
2005-04-17 02:20:36 +04:00
2005-12-01 12:49:58 +03:00
# ifdef CONFIG_PROC_FS
2005-11-17 16:44:47 +03:00
static void snd_ak4531_proc_init ( struct snd_card * card , struct snd_ak4531 * ak4531 ) ;
2005-12-01 12:49:58 +03:00
# else
# define snd_ak4531_proc_init(card,ak)
# endif
2005-04-17 02:20:36 +04:00
/*
*
*/
#if 0
2005-11-17 16:44:47 +03:00
static void snd_ak4531_dump ( struct snd_ak4531 * ak4531 )
2005-04-17 02:20:36 +04:00
{
int idx ;
for ( idx = 0 ; idx < 0x19 ; idx + + )
2009-02-05 18:11:31 +03:00
printk ( KERN_DEBUG " ak4531 0x%x: 0x%x \n " ,
idx , ak4531 - > regs [ idx ] ) ;
2005-04-17 02:20:36 +04:00
}
# endif
/*
*
*/
# define AK4531_SINGLE(xname, xindex, reg, shift, mask, invert) \
{ . iface = SNDRV_CTL_ELEM_IFACE_MIXER , . name = xname , . index = xindex , \
. info = snd_ak4531_info_single , \
. get = snd_ak4531_get_single , . put = snd_ak4531_put_single , \
. private_value = reg | ( shift < < 16 ) | ( mask < < 24 ) | ( invert < < 22 ) }
2006-08-23 14:04:34 +04:00
# define AK4531_SINGLE_TLV(xname, xindex, reg, shift, mask, invert, xtlv) \
{ . iface = SNDRV_CTL_ELEM_IFACE_MIXER , \
. access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ , \
. name = xname , . index = xindex , \
. info = snd_ak4531_info_single , \
. get = snd_ak4531_get_single , . put = snd_ak4531_put_single , \
. private_value = reg | ( shift < < 16 ) | ( mask < < 24 ) | ( invert < < 22 ) , \
. tlv = { . p = ( xtlv ) } }
2005-04-17 02:20:36 +04:00
2005-11-17 16:44:47 +03:00
static int snd_ak4531_info_single ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_info * uinfo )
2005-04-17 02:20:36 +04:00
{
int mask = ( kcontrol - > private_value > > 24 ) & 0xff ;
uinfo - > type = mask = = 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER ;
uinfo - > count = 1 ;
uinfo - > value . integer . min = 0 ;
uinfo - > value . integer . max = mask ;
return 0 ;
}
2005-11-17 16:44:47 +03:00
static int snd_ak4531_get_single ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_value * ucontrol )
2005-04-17 02:20:36 +04:00
{
2005-11-17 16:44:47 +03:00
struct snd_ak4531 * ak4531 = snd_kcontrol_chip ( kcontrol ) ;
2005-04-17 02:20:36 +04:00
int reg = kcontrol - > private_value & 0xff ;
int shift = ( kcontrol - > private_value > > 16 ) & 0x07 ;
int mask = ( kcontrol - > private_value > > 24 ) & 0xff ;
int invert = ( kcontrol - > private_value > > 22 ) & 1 ;
int val ;
2006-01-16 18:34:20 +03:00
mutex_lock ( & ak4531 - > reg_mutex ) ;
2005-04-17 02:20:36 +04:00
val = ( ak4531 - > regs [ reg ] > > shift ) & mask ;
2006-01-16 18:34:20 +03:00
mutex_unlock ( & ak4531 - > reg_mutex ) ;
2005-04-17 02:20:36 +04:00
if ( invert ) {
val = mask - val ;
}
ucontrol - > value . integer . value [ 0 ] = val ;
return 0 ;
}
2005-11-17 16:44:47 +03:00
static int snd_ak4531_put_single ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_value * ucontrol )
2005-04-17 02:20:36 +04:00
{
2005-11-17 16:44:47 +03:00
struct snd_ak4531 * ak4531 = snd_kcontrol_chip ( kcontrol ) ;
2005-04-17 02:20:36 +04:00
int reg = kcontrol - > private_value & 0xff ;
int shift = ( kcontrol - > private_value > > 16 ) & 0x07 ;
int mask = ( kcontrol - > private_value > > 24 ) & 0xff ;
int invert = ( kcontrol - > private_value > > 22 ) & 1 ;
int change ;
int val ;
val = ucontrol - > value . integer . value [ 0 ] & mask ;
if ( invert ) {
val = mask - val ;
}
val < < = shift ;
2006-01-16 18:34:20 +03:00
mutex_lock ( & ak4531 - > reg_mutex ) ;
2005-04-17 02:20:36 +04:00
val = ( ak4531 - > regs [ reg ] & ~ ( mask < < shift ) ) | val ;
change = val ! = ak4531 - > regs [ reg ] ;
ak4531 - > write ( ak4531 , reg , ak4531 - > regs [ reg ] = val ) ;
2006-01-16 18:34:20 +03:00
mutex_unlock ( & ak4531 - > reg_mutex ) ;
2005-04-17 02:20:36 +04:00
return change ;
}
# define AK4531_DOUBLE(xname, xindex, left_reg, right_reg, left_shift, right_shift, mask, invert) \
{ . iface = SNDRV_CTL_ELEM_IFACE_MIXER , . name = xname , . index = xindex , \
. info = snd_ak4531_info_double , \
. get = snd_ak4531_get_double , . put = snd_ak4531_put_double , \
. private_value = left_reg | ( right_reg < < 8 ) | ( left_shift < < 16 ) | ( right_shift < < 19 ) | ( mask < < 24 ) | ( invert < < 22 ) }
2006-08-23 14:04:34 +04:00
# define AK4531_DOUBLE_TLV(xname, xindex, left_reg, right_reg, left_shift, right_shift, mask, invert, xtlv) \
{ . iface = SNDRV_CTL_ELEM_IFACE_MIXER , \
. access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ , \
. name = xname , . index = xindex , \
. info = snd_ak4531_info_double , \
. get = snd_ak4531_get_double , . put = snd_ak4531_put_double , \
. private_value = left_reg | ( right_reg < < 8 ) | ( left_shift < < 16 ) | ( right_shift < < 19 ) | ( mask < < 24 ) | ( invert < < 22 ) , \
. tlv = { . p = ( xtlv ) } }
2005-04-17 02:20:36 +04:00
2005-11-17 16:44:47 +03:00
static int snd_ak4531_info_double ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_info * uinfo )
2005-04-17 02:20:36 +04:00
{
int mask = ( kcontrol - > private_value > > 24 ) & 0xff ;
uinfo - > type = mask = = 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER ;
uinfo - > count = 2 ;
uinfo - > value . integer . min = 0 ;
uinfo - > value . integer . max = mask ;
return 0 ;
}
2005-11-17 16:44:47 +03:00
static int snd_ak4531_get_double ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_value * ucontrol )
2005-04-17 02:20:36 +04:00
{
2005-11-17 16:44:47 +03:00
struct snd_ak4531 * ak4531 = snd_kcontrol_chip ( kcontrol ) ;
2005-04-17 02:20:36 +04:00
int left_reg = kcontrol - > private_value & 0xff ;
int right_reg = ( kcontrol - > private_value > > 8 ) & 0xff ;
int left_shift = ( kcontrol - > private_value > > 16 ) & 0x07 ;
int right_shift = ( kcontrol - > private_value > > 19 ) & 0x07 ;
int mask = ( kcontrol - > private_value > > 24 ) & 0xff ;
int invert = ( kcontrol - > private_value > > 22 ) & 1 ;
int left , right ;
2006-01-16 18:34:20 +03:00
mutex_lock ( & ak4531 - > reg_mutex ) ;
2005-04-17 02:20:36 +04:00
left = ( ak4531 - > regs [ left_reg ] > > left_shift ) & mask ;
right = ( ak4531 - > regs [ right_reg ] > > right_shift ) & mask ;
2006-01-16 18:34:20 +03:00
mutex_unlock ( & ak4531 - > reg_mutex ) ;
2005-04-17 02:20:36 +04:00
if ( invert ) {
left = mask - left ;
right = mask - right ;
}
ucontrol - > value . integer . value [ 0 ] = left ;
ucontrol - > value . integer . value [ 1 ] = right ;
return 0 ;
}
2005-11-17 16:44:47 +03:00
static int snd_ak4531_put_double ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_value * ucontrol )
2005-04-17 02:20:36 +04:00
{
2005-11-17 16:44:47 +03:00
struct snd_ak4531 * ak4531 = snd_kcontrol_chip ( kcontrol ) ;
2005-04-17 02:20:36 +04:00
int left_reg = kcontrol - > private_value & 0xff ;
int right_reg = ( kcontrol - > private_value > > 8 ) & 0xff ;
int left_shift = ( kcontrol - > private_value > > 16 ) & 0x07 ;
int right_shift = ( kcontrol - > private_value > > 19 ) & 0x07 ;
int mask = ( kcontrol - > private_value > > 24 ) & 0xff ;
int invert = ( kcontrol - > private_value > > 22 ) & 1 ;
int change ;
int left , right ;
left = ucontrol - > value . integer . value [ 0 ] & mask ;
right = ucontrol - > value . integer . value [ 1 ] & mask ;
if ( invert ) {
left = mask - left ;
right = mask - right ;
}
left < < = left_shift ;
right < < = right_shift ;
2006-01-16 18:34:20 +03:00
mutex_lock ( & ak4531 - > reg_mutex ) ;
2005-04-17 02:20:36 +04:00
if ( left_reg = = right_reg ) {
left = ( ak4531 - > regs [ left_reg ] & ~ ( ( mask < < left_shift ) | ( mask < < right_shift ) ) ) | left | right ;
change = left ! = ak4531 - > regs [ left_reg ] ;
ak4531 - > write ( ak4531 , left_reg , ak4531 - > regs [ left_reg ] = left ) ;
} else {
left = ( ak4531 - > regs [ left_reg ] & ~ ( mask < < left_shift ) ) | left ;
right = ( ak4531 - > regs [ right_reg ] & ~ ( mask < < right_shift ) ) | right ;
change = left ! = ak4531 - > regs [ left_reg ] | | right ! = ak4531 - > regs [ right_reg ] ;
ak4531 - > write ( ak4531 , left_reg , ak4531 - > regs [ left_reg ] = left ) ;
ak4531 - > write ( ak4531 , right_reg , ak4531 - > regs [ right_reg ] = right ) ;
}
2006-01-16 18:34:20 +03:00
mutex_unlock ( & ak4531 - > reg_mutex ) ;
2005-04-17 02:20:36 +04:00
return change ;
}
# define AK4531_INPUT_SW(xname, xindex, reg1, reg2, left_shift, right_shift) \
{ . iface = SNDRV_CTL_ELEM_IFACE_MIXER , . name = xname , . index = xindex , \
. info = snd_ak4531_info_input_sw , \
. get = snd_ak4531_get_input_sw , . put = snd_ak4531_put_input_sw , \
. private_value = reg1 | ( reg2 < < 8 ) | ( left_shift < < 16 ) | ( right_shift < < 24 ) }
2005-11-17 16:44:47 +03:00
static int snd_ak4531_info_input_sw ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_info * uinfo )
2005-04-17 02:20:36 +04:00
{
uinfo - > type = SNDRV_CTL_ELEM_TYPE_BOOLEAN ;
uinfo - > count = 4 ;
uinfo - > value . integer . min = 0 ;
uinfo - > value . integer . max = 1 ;
return 0 ;
}
2005-11-17 16:44:47 +03:00
static int snd_ak4531_get_input_sw ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_value * ucontrol )
2005-04-17 02:20:36 +04:00
{
2005-11-17 16:44:47 +03:00
struct snd_ak4531 * ak4531 = snd_kcontrol_chip ( kcontrol ) ;
2005-04-17 02:20:36 +04:00
int reg1 = kcontrol - > private_value & 0xff ;
int reg2 = ( kcontrol - > private_value > > 8 ) & 0xff ;
int left_shift = ( kcontrol - > private_value > > 16 ) & 0x0f ;
int right_shift = ( kcontrol - > private_value > > 24 ) & 0x0f ;
2006-01-16 18:34:20 +03:00
mutex_lock ( & ak4531 - > reg_mutex ) ;
2005-04-17 02:20:36 +04:00
ucontrol - > value . integer . value [ 0 ] = ( ak4531 - > regs [ reg1 ] > > left_shift ) & 1 ;
ucontrol - > value . integer . value [ 1 ] = ( ak4531 - > regs [ reg2 ] > > left_shift ) & 1 ;
ucontrol - > value . integer . value [ 2 ] = ( ak4531 - > regs [ reg1 ] > > right_shift ) & 1 ;
ucontrol - > value . integer . value [ 3 ] = ( ak4531 - > regs [ reg2 ] > > right_shift ) & 1 ;
2006-01-16 18:34:20 +03:00
mutex_unlock ( & ak4531 - > reg_mutex ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2005-11-17 16:44:47 +03:00
static int snd_ak4531_put_input_sw ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_value * ucontrol )
2005-04-17 02:20:36 +04:00
{
2005-11-17 16:44:47 +03:00
struct snd_ak4531 * ak4531 = snd_kcontrol_chip ( kcontrol ) ;
2005-04-17 02:20:36 +04:00
int reg1 = kcontrol - > private_value & 0xff ;
int reg2 = ( kcontrol - > private_value > > 8 ) & 0xff ;
int left_shift = ( kcontrol - > private_value > > 16 ) & 0x0f ;
int right_shift = ( kcontrol - > private_value > > 24 ) & 0x0f ;
int change ;
int val1 , val2 ;
2006-01-16 18:34:20 +03:00
mutex_lock ( & ak4531 - > reg_mutex ) ;
2005-04-17 02:20:36 +04:00
val1 = ak4531 - > regs [ reg1 ] & ~ ( ( 1 < < left_shift ) | ( 1 < < right_shift ) ) ;
val2 = ak4531 - > regs [ reg2 ] & ~ ( ( 1 < < left_shift ) | ( 1 < < right_shift ) ) ;
val1 | = ( ucontrol - > value . integer . value [ 0 ] & 1 ) < < left_shift ;
val2 | = ( ucontrol - > value . integer . value [ 1 ] & 1 ) < < left_shift ;
val1 | = ( ucontrol - > value . integer . value [ 2 ] & 1 ) < < right_shift ;
val2 | = ( ucontrol - > value . integer . value [ 3 ] & 1 ) < < right_shift ;
change = val1 ! = ak4531 - > regs [ reg1 ] | | val2 ! = ak4531 - > regs [ reg2 ] ;
ak4531 - > write ( ak4531 , reg1 , ak4531 - > regs [ reg1 ] = val1 ) ;
ak4531 - > write ( ak4531 , reg2 , ak4531 - > regs [ reg2 ] = val2 ) ;
2006-01-16 18:34:20 +03:00
mutex_unlock ( & ak4531 - > reg_mutex ) ;
2005-04-17 02:20:36 +04:00
return change ;
}
2007-01-29 17:33:49 +03:00
static const DECLARE_TLV_DB_SCALE ( db_scale_master , - 6200 , 200 , 0 ) ;
static const DECLARE_TLV_DB_SCALE ( db_scale_mono , - 2800 , 400 , 0 ) ;
static const DECLARE_TLV_DB_SCALE ( db_scale_input , - 5000 , 200 , 0 ) ;
2006-08-23 14:04:34 +04:00
2012-12-06 21:35:10 +04:00
static struct snd_kcontrol_new snd_ak4531_controls [ ] = {
2005-04-17 02:20:36 +04:00
2006-08-23 14:04:34 +04:00
AK4531_DOUBLE_TLV ( " Master Playback Switch " , 0 ,
AK4531_LMASTER , AK4531_RMASTER , 7 , 7 , 1 , 1 ,
db_scale_master ) ,
2005-04-17 02:20:36 +04:00
AK4531_DOUBLE ( " Master Playback Volume " , 0 , AK4531_LMASTER , AK4531_RMASTER , 0 , 0 , 0x1f , 1 ) ,
2006-08-23 14:04:34 +04:00
AK4531_SINGLE_TLV ( " Master Mono Playback Switch " , 0 , AK4531_MONO_OUT , 7 , 1 , 1 ,
db_scale_mono ) ,
2005-04-17 02:20:36 +04:00
AK4531_SINGLE ( " Master Mono Playback Volume " , 0 , AK4531_MONO_OUT , 0 , 0x07 , 1 ) ,
AK4531_DOUBLE ( " PCM Switch " , 0 , AK4531_LVOICE , AK4531_RVOICE , 7 , 7 , 1 , 1 ) ,
2006-08-23 14:04:34 +04:00
AK4531_DOUBLE_TLV ( " PCM Volume " , 0 , AK4531_LVOICE , AK4531_RVOICE , 0 , 0 , 0x1f , 1 ,
db_scale_input ) ,
2005-04-17 02:20:36 +04:00
AK4531_DOUBLE ( " PCM Playback Switch " , 0 , AK4531_OUT_SW2 , AK4531_OUT_SW2 , 3 , 2 , 1 , 0 ) ,
AK4531_DOUBLE ( " PCM Capture Switch " , 0 , AK4531_LIN_SW2 , AK4531_RIN_SW2 , 2 , 2 , 1 , 0 ) ,
AK4531_DOUBLE ( " PCM Switch " , 1 , AK4531_LFM , AK4531_RFM , 7 , 7 , 1 , 1 ) ,
2006-08-23 14:04:34 +04:00
AK4531_DOUBLE_TLV ( " PCM Volume " , 1 , AK4531_LFM , AK4531_RFM , 0 , 0 , 0x1f , 1 ,
db_scale_input ) ,
2005-04-17 02:20:36 +04:00
AK4531_DOUBLE ( " PCM Playback Switch " , 1 , AK4531_OUT_SW1 , AK4531_OUT_SW1 , 6 , 5 , 1 , 0 ) ,
AK4531_INPUT_SW ( " PCM Capture Route " , 1 , AK4531_LIN_SW1 , AK4531_RIN_SW1 , 6 , 5 ) ,
AK4531_DOUBLE ( " CD Switch " , 0 , AK4531_LCD , AK4531_RCD , 7 , 7 , 1 , 1 ) ,
2006-08-23 14:04:34 +04:00
AK4531_DOUBLE_TLV ( " CD Volume " , 0 , AK4531_LCD , AK4531_RCD , 0 , 0 , 0x1f , 1 ,
db_scale_input ) ,
2005-04-17 02:20:36 +04:00
AK4531_DOUBLE ( " CD Playback Switch " , 0 , AK4531_OUT_SW1 , AK4531_OUT_SW1 , 2 , 1 , 1 , 0 ) ,
AK4531_INPUT_SW ( " CD Capture Route " , 0 , AK4531_LIN_SW1 , AK4531_RIN_SW1 , 2 , 1 ) ,
AK4531_DOUBLE ( " Line Switch " , 0 , AK4531_LLINE , AK4531_RLINE , 7 , 7 , 1 , 1 ) ,
2006-08-23 14:04:34 +04:00
AK4531_DOUBLE_TLV ( " Line Volume " , 0 , AK4531_LLINE , AK4531_RLINE , 0 , 0 , 0x1f , 1 ,
db_scale_input ) ,
2005-04-17 02:20:36 +04:00
AK4531_DOUBLE ( " Line Playback Switch " , 0 , AK4531_OUT_SW1 , AK4531_OUT_SW1 , 4 , 3 , 1 , 0 ) ,
AK4531_INPUT_SW ( " Line Capture Route " , 0 , AK4531_LIN_SW1 , AK4531_RIN_SW1 , 4 , 3 ) ,
AK4531_DOUBLE ( " Aux Switch " , 0 , AK4531_LAUXA , AK4531_RAUXA , 7 , 7 , 1 , 1 ) ,
2006-08-23 14:04:34 +04:00
AK4531_DOUBLE_TLV ( " Aux Volume " , 0 , AK4531_LAUXA , AK4531_RAUXA , 0 , 0 , 0x1f , 1 ,
db_scale_input ) ,
2005-04-17 02:20:36 +04:00
AK4531_DOUBLE ( " Aux Playback Switch " , 0 , AK4531_OUT_SW2 , AK4531_OUT_SW2 , 5 , 4 , 1 , 0 ) ,
AK4531_INPUT_SW ( " Aux Capture Route " , 0 , AK4531_LIN_SW2 , AK4531_RIN_SW2 , 4 , 3 ) ,
AK4531_SINGLE ( " Mono Switch " , 0 , AK4531_MONO1 , 7 , 1 , 1 ) ,
2006-08-23 14:04:34 +04:00
AK4531_SINGLE_TLV ( " Mono Volume " , 0 , AK4531_MONO1 , 0 , 0x1f , 1 , db_scale_input ) ,
2005-04-17 02:20:36 +04:00
AK4531_SINGLE ( " Mono Playback Switch " , 0 , AK4531_OUT_SW2 , 0 , 1 , 0 ) ,
AK4531_DOUBLE ( " Mono Capture Switch " , 0 , AK4531_LIN_SW2 , AK4531_RIN_SW2 , 0 , 0 , 1 , 0 ) ,
AK4531_SINGLE ( " Mono Switch " , 1 , AK4531_MONO2 , 7 , 1 , 1 ) ,
2006-08-23 14:04:34 +04:00
AK4531_SINGLE_TLV ( " Mono Volume " , 1 , AK4531_MONO2 , 0 , 0x1f , 1 , db_scale_input ) ,
2005-04-17 02:20:36 +04:00
AK4531_SINGLE ( " Mono Playback Switch " , 1 , AK4531_OUT_SW2 , 1 , 1 , 0 ) ,
AK4531_DOUBLE ( " Mono Capture Switch " , 1 , AK4531_LIN_SW2 , AK4531_RIN_SW2 , 1 , 1 , 1 , 0 ) ,
2006-08-23 14:04:34 +04:00
AK4531_SINGLE_TLV ( " Mic Volume " , 0 , AK4531_MIC , 0 , 0x1f , 1 , db_scale_input ) ,
2005-04-17 02:20:36 +04:00
AK4531_SINGLE ( " Mic Switch " , 0 , AK4531_MIC , 7 , 1 , 1 ) ,
AK4531_SINGLE ( " Mic Playback Switch " , 0 , AK4531_OUT_SW1 , 0 , 1 , 0 ) ,
AK4531_DOUBLE ( " Mic Capture Switch " , 0 , AK4531_LIN_SW1 , AK4531_RIN_SW1 , 0 , 0 , 1 , 0 ) ,
AK4531_DOUBLE ( " Mic Bypass Capture Switch " , 0 , AK4531_LIN_SW2 , AK4531_RIN_SW2 , 7 , 7 , 1 , 0 ) ,
AK4531_DOUBLE ( " Mono1 Bypass Capture Switch " , 0 , AK4531_LIN_SW2 , AK4531_RIN_SW2 , 6 , 6 , 1 , 0 ) ,
AK4531_DOUBLE ( " Mono2 Bypass Capture Switch " , 0 , AK4531_LIN_SW2 , AK4531_RIN_SW2 , 5 , 5 , 1 , 0 ) ,
AK4531_SINGLE ( " AD Input Select " , 0 , AK4531_AD_IN , 0 , 1 , 0 ) ,
AK4531_SINGLE ( " Mic Boost (+30dB) " , 0 , AK4531_MIC_GAIN , 0 , 1 , 0 )
} ;
2005-11-17 16:44:47 +03:00
static int snd_ak4531_free ( struct snd_ak4531 * ak4531 )
2005-04-17 02:20:36 +04:00
{
if ( ak4531 ) {
if ( ak4531 - > private_free )
ak4531 - > private_free ( ak4531 ) ;
kfree ( ak4531 ) ;
}
return 0 ;
}
2005-11-17 16:44:47 +03:00
static int snd_ak4531_dev_free ( struct snd_device * device )
2005-04-17 02:20:36 +04:00
{
2005-11-17 16:44:47 +03:00
struct snd_ak4531 * ak4531 = device - > device_data ;
2005-04-17 02:20:36 +04:00
return snd_ak4531_free ( ak4531 ) ;
}
static u8 snd_ak4531_initial_map [ 0x19 + 1 ] = {
0x9f , /* 00: Master Volume Lch */
0x9f , /* 01: Master Volume Rch */
0x9f , /* 02: Voice Volume Lch */
0x9f , /* 03: Voice Volume Rch */
0x9f , /* 04: FM Volume Lch */
0x9f , /* 05: FM Volume Rch */
0x9f , /* 06: CD Audio Volume Lch */
0x9f , /* 07: CD Audio Volume Rch */
0x9f , /* 08: Line Volume Lch */
0x9f , /* 09: Line Volume Rch */
0x9f , /* 0a: Aux Volume Lch */
0x9f , /* 0b: Aux Volume Rch */
0x9f , /* 0c: Mono1 Volume */
0x9f , /* 0d: Mono2 Volume */
0x9f , /* 0e: Mic Volume */
0x87 , /* 0f: Mono-out Volume */
0x00 , /* 10: Output Mixer SW1 */
0x00 , /* 11: Output Mixer SW2 */
0x00 , /* 12: Lch Input Mixer SW1 */
0x00 , /* 13: Rch Input Mixer SW1 */
0x00 , /* 14: Lch Input Mixer SW2 */
0x00 , /* 15: Rch Input Mixer SW2 */
0x00 , /* 16: Reset & Power Down */
0x00 , /* 17: Clock Select */
0x00 , /* 18: AD Input Select */
0x01 /* 19: Mic Amp Setup */
} ;
2012-12-06 21:35:10 +04:00
int snd_ak4531_mixer ( struct snd_card * card ,
struct snd_ak4531 * _ak4531 ,
struct snd_ak4531 * * rak4531 )
2005-04-17 02:20:36 +04:00
{
unsigned int idx ;
int err ;
2005-11-17 16:44:47 +03:00
struct snd_ak4531 * ak4531 ;
static struct snd_device_ops ops = {
2005-04-17 02:20:36 +04:00
. dev_free = snd_ak4531_dev_free ,
} ;
2008-08-08 19:12:14 +04:00
if ( snd_BUG_ON ( ! card | | ! _ak4531 ) )
return - EINVAL ;
if ( rak4531 )
* rak4531 = NULL ;
[ALSA] Replace with kzalloc() - pci stuff
AD1889 driver,ATIIXP driver,ATIIXP-modem driver,AZT3328 driver
BT87x driver,CMIPCI driver,CS4281 driver,ENS1370/1+ driver
ES1938 driver,ES1968 driver,FM801 driver,Intel8x0 driver
Intel8x0-modem driver,Maestro3 driver,SonicVibes driver,VIA82xx driver
VIA82xx-modem driver,AC97 Codec,AK4531 codec,au88x0 driver
CA0106 driver,CS46xx driver,EMU10K1/EMU10K2 driver,HDA Codec driver
HDA generic driver,HDA Intel driver,ICE1712 driver,ICE1724 driver
KORG1212 driver,MIXART driver,NM256 driver,Trident driver,YMFPCI driver
Replace kcalloc(1,..) with kzalloc().
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2005-09-09 16:21:46 +04:00
ak4531 = kzalloc ( sizeof ( * ak4531 ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ak4531 = = NULL )
return - ENOMEM ;
* ak4531 = * _ak4531 ;
2006-01-16 18:34:20 +03:00
mutex_init ( & ak4531 - > reg_mutex ) ;
2005-04-17 02:20:36 +04:00
if ( ( err = snd_component_add ( card , " AK4531 " ) ) < 0 ) {
snd_ak4531_free ( ak4531 ) ;
return err ;
}
strcpy ( card - > mixername , " Asahi Kasei AK4531 " ) ;
ak4531 - > write ( ak4531 , AK4531_RESET , 0x03 ) ; /* no RST, PD */
udelay ( 100 ) ;
ak4531 - > write ( ak4531 , AK4531_CLOCK , 0x00 ) ; /* CODEC ADC and CODEC DAC use {LR,B}CLK2 and run off LRCLK2 PLL */
2005-11-17 18:13:05 +03:00
for ( idx = 0 ; idx < = 0x19 ; idx + + ) {
2005-04-17 02:20:36 +04:00
if ( idx = = AK4531_RESET | | idx = = AK4531_CLOCK )
continue ;
ak4531 - > write ( ak4531 , idx , ak4531 - > regs [ idx ] = snd_ak4531_initial_map [ idx ] ) ; /* recording source is mixer */
}
for ( idx = 0 ; idx < ARRAY_SIZE ( snd_ak4531_controls ) ; idx + + ) {
if ( ( err = snd_ctl_add ( card , snd_ctl_new1 ( & snd_ak4531_controls [ idx ] , ak4531 ) ) ) < 0 ) {
snd_ak4531_free ( ak4531 ) ;
return err ;
}
}
snd_ak4531_proc_init ( card , ak4531 ) ;
if ( ( err = snd_device_new ( card , SNDRV_DEV_CODEC , ak4531 , & ops ) ) < 0 ) {
snd_ak4531_free ( ak4531 ) ;
return err ;
}
#if 0
snd_ak4531_dump ( ak4531 ) ;
# endif
2008-08-08 19:12:14 +04:00
if ( rak4531 )
* rak4531 = ak4531 ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2005-11-17 18:13:05 +03:00
/*
* power management
*/
# ifdef CONFIG_PM
void snd_ak4531_suspend ( struct snd_ak4531 * ak4531 )
{
/* mute */
ak4531 - > write ( ak4531 , AK4531_LMASTER , 0x9f ) ;
ak4531 - > write ( ak4531 , AK4531_RMASTER , 0x9f ) ;
/* powerdown */
ak4531 - > write ( ak4531 , AK4531_RESET , 0x01 ) ;
}
void snd_ak4531_resume ( struct snd_ak4531 * ak4531 )
{
int idx ;
/* initialize */
ak4531 - > write ( ak4531 , AK4531_RESET , 0x03 ) ;
udelay ( 100 ) ;
ak4531 - > write ( ak4531 , AK4531_CLOCK , 0x00 ) ;
/* restore mixer registers */
for ( idx = 0 ; idx < = 0x19 ; idx + + ) {
if ( idx = = AK4531_RESET | | idx = = AK4531_CLOCK )
continue ;
ak4531 - > write ( ak4531 , idx , ak4531 - > regs [ idx ] ) ;
}
}
# endif
2005-12-01 12:49:58 +03:00
# ifdef CONFIG_PROC_FS
2005-04-17 02:20:36 +04:00
/*
2005-12-01 12:49:58 +03:00
* / proc interface
2005-04-17 02:20:36 +04:00
*/
2005-11-17 16:44:47 +03:00
static void snd_ak4531_proc_read ( struct snd_info_entry * entry ,
struct snd_info_buffer * buffer )
2005-04-17 02:20:36 +04:00
{
2005-11-17 16:44:47 +03:00
struct snd_ak4531 * ak4531 = entry - > private_data ;
2005-04-17 02:20:36 +04:00
snd_iprintf ( buffer , " Asahi Kasei AK4531 \n \n " ) ;
snd_iprintf ( buffer , " Recording source : %s \n "
" MIC gain : %s \n " ,
ak4531 - > regs [ AK4531_AD_IN ] & 1 ? " external " : " mixer " ,
ak4531 - > regs [ AK4531_MIC_GAIN ] & 1 ? " +30dB " : " +0dB " ) ;
}
2012-12-06 21:35:10 +04:00
static void
2008-05-30 11:22:22 +04:00
snd_ak4531_proc_init ( struct snd_card * card , struct snd_ak4531 * ak4531 )
2005-04-17 02:20:36 +04:00
{
2005-11-17 16:44:47 +03:00
struct snd_info_entry * entry ;
2005-04-17 02:20:36 +04:00
if ( ! snd_card_proc_new ( card , " ak4531 " , & entry ) )
2006-04-28 17:13:41 +04:00
snd_info_set_text_ops ( entry , ak4531 , snd_ak4531_proc_read ) ;
2005-04-17 02:20:36 +04:00
}
2005-12-01 12:49:58 +03:00
# endif