📄 s3c24xx-uda1341.c
字号:
case CMD_RESET:
ret = snd_uda1341_update_bits(chip, data0_2, 1, 2, 1, flush); // MUTE
ret = snd_uda1341_update_bits(chip, stat0, 1, 6, 1, flush); // RESET
ret = snd_uda1341_update_bits(chip, stat0, 1, 6, 0, flush); // RESTORE
uda->cfg[CMD_RESET]=0;
break;
case CMD_FS:
ret = snd_uda1341_update_bits(chip, stat0, 3, 4, value, flush);
break;
case CMD_FORMAT:
ret = snd_uda1341_update_bits(chip, stat0, 7, 1, value, flush);
break;
case CMD_OGAIN:
ret = snd_uda1341_update_bits(chip, stat1, 1, 6, value, flush);
break;
case CMD_IGAIN:
ret = snd_uda1341_update_bits(chip, stat1, 1, 5, value, flush);
break;
case CMD_DAC:
ret = snd_uda1341_update_bits(chip, stat1, 1, 0, value, flush);
break;
case CMD_ADC:
ret = snd_uda1341_update_bits(chip, stat1, 1, 1, value, flush);
break;
case CMD_VOLUME:
ret = snd_uda1341_update_bits(chip, data0_0, 63, 0, value, flush);
break;
case CMD_BASS:
ret = snd_uda1341_update_bits(chip, data0_1, 15, 2, value, flush);
break;
case CMD_TREBBLE:
ret = snd_uda1341_update_bits(chip, data0_1, 3, 0, value, flush);
break;
case CMD_PEAK:
ret = snd_uda1341_update_bits(chip, data0_2, 1, 5, value, flush);
break;
case CMD_DEEMP:
ret = snd_uda1341_update_bits(chip, data0_2, 3, 3, value, flush);
break;
case CMD_MUTE:
ret = snd_uda1341_update_bits(chip, data0_2, 1, 2, value, flush);
break;
case CMD_FILTER:
ret = snd_uda1341_update_bits(chip, data0_2, 3, 0, value, flush);
break;
case CMD_CH1:
ret = snd_uda1341_update_bits(chip, ext0, 31, 0, value, flush);
break;
case CMD_CH2:
ret = snd_uda1341_update_bits(chip, ext1, 31, 0, value, flush);
break;
case CMD_MIC:
ret = snd_uda1341_update_bits(chip, ext2, 7, 2, value, flush);
break;
case CMD_MIXER:
ret = snd_uda1341_update_bits(chip, ext2, 3, 0, value, flush);
break;
case CMD_AGC:
ret = snd_uda1341_update_bits(chip, ext4, 1, 4, value, flush);
break;
case CMD_IG:
ret = snd_uda1341_update_bits(chip, ext4, 3, 0, value & 0x3, flush);
ret = snd_uda1341_update_bits(chip, ext5, 31, 0, value >> 2, flush);
break;
case CMD_AGC_TIME:
ret = snd_uda1341_update_bits(chip, ext6, 7, 2, value, flush);
break;
case CMD_AGC_LEVEL:
ret = snd_uda1341_update_bits(chip, ext6, 3, 0, value, flush);
break;
#ifdef CONFIG_PM
case CMD_SUSPEND:
for (reg = stat0; reg < uda1341_reg_last; reg++)
uda->suspend_regs[reg] = uda->regs[reg];
for (reg = 0; reg < CMD_LAST; reg++)
uda->suspend_cfg[reg] = uda->cfg[reg];
break;
case CMD_RESUME:
for (reg = stat0; reg < uda1341_reg_last; reg++)
snd_uda1341_codec_write(chip, reg, uda->suspend_regs[reg]);
for (reg = 0; reg < CMD_LAST; reg++)
uda->cfg[reg] = uda->suspend_cfg[reg];
break;
#endif
default:
ret = -EINVAL;
break;
}
if (!uda->active)
printk(KERN_ERR "UDA1341 codec not active!\n");
return ret;
}
/*
* Mixer Control Settings
*/
#define UDA1341_SINGLE(xname, where, reg, shift, mask, invert) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_uda1341_info_single, \
.get = snd_uda1341_get_single, .put = snd_uda1341_put_single, \
.private_value = where | (reg << 5) | (shift << 9) | (mask << 12) | (invert << 18) \
}
static int snd_uda1341_info_single(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
int mask = ( kcontrol -> private_value >> 12 ) & 63;
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;
}
static int snd_uda1341_get_single(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct s3c24xx_uda1341 *chip = snd_kcontrol_chip(kcontrol);
struct uda1341 *uda = chip -> chip_data;
int where = kcontrol -> private_value & 31;
int mask = ( kcontrol -> private_value >> 12 ) & 63;
int invert = ( kcontrol -> private_value >> 18) & 1;
ucontrol->value.integer.value[0] = uda->cfg[where];
if (invert)
ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
return 0;
}
static int snd_uda1341_put_single(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct s3c24xx_uda1341 *chip = snd_kcontrol_chip( kcontrol );
struct uda1341 *uda = chip -> chip_data;
int where = kcontrol -> private_value & 31;
int reg = ( kcontrol -> private_value >> 5 ) & 15;
int shift = ( kcontrol -> private_value >> 9 ) & 7;
int mask = ( kcontrol -> private_value >> 12 ) & 63;
int invert = ( kcontrol->private_value >> 18 ) & 1;
unsigned short val;
val = (ucontrol->value.integer.value[0] & mask);
if (invert)
val = mask - val;
uda->cfg[where] = val;
return snd_uda1341_update_bits(chip, reg, mask, shift, val, FLUSH);
}
/* }}} */
/* {{{ UDA1341 enum functions */
#define UDA1341_ENUM(xname, where, reg, shift, mask, invert) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_uda1341_info_enum, \
.get = snd_uda1341_get_enum, .put = snd_uda1341_put_enum, \
.private_value = where | (reg << 5) | (shift << 9) | (mask << 12) | (invert << 18) \
}
static int snd_uda1341_info_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
int where = kcontrol -> private_value & 31;
const char **texts;
// this register we don't handle this way
if ( !uda1341_enum_items[ where ] )
{
return -EINVAL;
}
uinfo -> type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
uinfo -> count = 1;
uinfo -> value.enumerated.items = uda1341_enum_items[ where ];
if ( uinfo -> value.enumerated.item >= uda1341_enum_items[ where ] )
{
uinfo -> value.enumerated.item = uda1341_enum_items[ where ] - 1;
}
texts = uda1341_enum_names[ where ];
strcpy( uinfo -> value.enumerated.name, texts[ uinfo -> value.enumerated.item ] );
return 0;
}
static int snd_uda1341_get_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct s3c24xx_uda1341 *chip = snd_kcontrol_chip(kcontrol);
struct uda1341 *uda = chip -> chip_data;
int where = kcontrol->private_value & 31;
ucontrol->value.enumerated.item[0] = uda->cfg[where];
return 0;
}
static int snd_uda1341_put_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct s3c24xx_uda1341 *chip = snd_kcontrol_chip(kcontrol);
struct uda1341 *uda = chip -> chip_data;
int where = kcontrol -> private_value & 31;
int reg = ( kcontrol -> private_value >> 5 ) & 15;
int shift = ( kcontrol -> private_value >> 9 ) & 7;
int mask = ( kcontrol -> private_value >> 12 ) & 63;
uda -> cfg[ where ] = ( ucontrol -> value.enumerated.item[0] & mask );
return snd_uda1341_update_bits(chip, reg, mask, shift, uda->cfg[where], FLUSH);
}
/*
* UDA1341 2regs functions
*/
#define UDA1341_2REGS(xname, where, reg_1, reg_2, shift_1, shift_2, mask_1, mask_2, invert) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), .info = snd_uda1341_info_2regs, \
.get = snd_uda1341_get_2regs, .put = snd_uda1341_put_2regs, \
.private_value = where | (reg_1 << 5) | (reg_2 << 9) | (shift_1 << 13) | (shift_2 << 16) | \
(mask_1 << 19) | (mask_2 << 25) | (invert << 31) \
}
static int snd_uda1341_info_2regs(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
int mask_1 = ( kcontrol -> private_value >> 19 ) & 63;
int mask_2 = ( kcontrol -> private_value >> 25 ) & 63;
int mask;
mask = ( mask_2 + 1 ) * ( mask_1 + 1 ) - 1;
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;
}
static int snd_uda1341_get_2regs(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct s3c24xx_uda1341 *chip = snd_kcontrol_chip(kcontrol);
struct uda1341 *uda = chip -> chip_data;
int where = kcontrol -> private_value & 31;
int mask_1 = ( kcontrol -> private_value >> 19 ) & 63;
int mask_2 = ( kcontrol -> private_value >> 25 ) & 63;
int invert = ( kcontrol -> private_value >> 31 ) & 1;
int mask;
mask = ( mask_2 + 1 ) * ( mask_1 + 1 ) - 1;
ucontrol -> value.integer.value[ 0 ] = uda->cfg[ where ];
if ( invert )
ucontrol -> value.integer.value[ 0 ] = mask - ucontrol->value.integer.value[ 0 ];
return 0;
}
static int snd_uda1341_put_2regs(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct s3c24xx_uda1341 *chip = snd_kcontrol_chip(kcontrol);
struct uda1341 *uda = chip -> chip_data;
int where = kcontrol -> private_value & 31;
int reg_1 = ( kcontrol -> private_value >> 5 ) & 15;
int reg_2 = ( kcontrol -> private_value >> 9 ) & 15;
int shift_1 = ( kcontrol -> private_value >> 13 ) & 7;
int shift_2 = ( kcontrol -> private_value >> 16 ) & 7;
int mask_1 = ( kcontrol -> private_value >> 19 ) & 63;
int mask_2 = ( kcontrol -> private_value >> 25 ) & 63;
int invert = ( kcontrol -> private_value >> 31 ) & 1;
int mask;
unsigned short val1, val2, val;
val = ucontrol->value.integer.value[0];
mask = (mask_2 + 1) * (mask_1 + 1) - 1;
val1 = val & mask_1;
val2 = (val / (mask_1 + 1)) & mask_2;
if (invert) {
val1 = mask_1 - val1;
val2 = mask_2 - val2;
}
uda->cfg[where] = invert ? mask - val : val;
//FIXME - return value
snd_uda1341_update_bits(chip, reg_1, mask_1, shift_1, val1, FLUSH);
return snd_uda1341_update_bits(chip, reg_2, mask_2, shift_2, val2, FLUSH);
}
static struct snd_kcontrol_new snd_uda1341_controls[] = {
UDA1341_SINGLE("Master Playback Switch", CMD_MUTE, data0_2, 2, 1, 1),
UDA1341_SINGLE("Master Playback Volume", CMD_VOLUME, data0_0, 0, 63, 1),
UDA1341_SINGLE("Bass Playback Volume", CMD_BASS, data0_1, 2, 15, 0),
UDA1341_SINGLE("Treble Playback Volume", CMD_TREBBLE, data0_1, 0, 3, 0),
UDA1341_SINGLE("Input Gain Switch", CMD_IGAIN, stat1, 5, 1, 0),
UDA1341_SINGLE("Output Gain Switch", CMD_OGAIN, stat1, 6, 1, 0),
UDA1341_SINGLE("Mixer Gain Channel 1 Volume", CMD_CH1, ext0, 0, 31, 1),
UDA1341_SINGLE("Mixer Gain Channel 2 Volume", CMD_CH2, ext1, 0, 31, 1),
UDA1341_SINGLE("Mic Sensitivity Volume", CMD_MIC, ext2, 2, 7, 0),
UDA1341_SINGLE("AGC Output Level", CMD_AGC_LEVEL, ext6, 0, 3, 0),
UDA1341_SINGLE("AGC Time Constant", CMD_AGC_TIME, ext6, 2, 7, 0),
UDA1341_SINGLE("AGC Time Constant Switch", CMD_AGC, ext4, 4, 1, 0),
UDA1341_SINGLE("DAC Power", CMD_DAC, stat1, 0, 1, 0),
UDA1341_SINGLE("ADC Power", CMD_ADC, stat1, 1, 1, 0),
UDA1341_ENUM("Peak detection", CMD_PEAK, data0_2, 5, 1, 0),
UDA1341_ENUM("De-emphasis", CMD_DEEMP, data0_2, 3, 3, 0),
UDA1341_ENUM("Mixer mode", CMD_MIXER, ext2, 0, 3, 0),
UDA1341_ENUM("Filter mode", CMD_FILTER, data0_2, 0, 3, 0),
UDA1341_2REGS("Gain Input Amplifier Gain (channel 2)", CMD_IG, ext4, ext5, 0, 0, 3, 31, 0),
};
int __devinit uda1341_chip_init( struct s3c24xx_uda1341 *chip )
{
struct uda1341 *uda;
uda = kzalloc( sizeof( struct uda1341 ), GFP_KERNEL );
if ( !uda )
{
return -ENOMEM;
}
uda -> regs[ stat0 ] = STAT0;
uda -> regs[ stat1 ] = STAT1;
uda -> regs[ data0_0 ] = DATA0_0;
uda -> regs[ data0_1 ] = DATA0_1;
uda -> regs[ data0_2 ] = DATA0_2;
uda -> write = snd_uda1341_codec_write;
uda -> read = snd_uda1341_codec_read;
spin_lock_init( &uda -> reg_lock );
chip -> chip_data = uda;
uda -> active = 1;
/*
* Initialize default configurations
*/
snd_uda1341_cfg_write(chip, CMD_RESET, 0, REGS_ONLY);
snd_uda1341_cfg_write(chip, CMD_MUTE, OFF, REGS_ONLY); // default value after reset
snd_uda1341_cfg_write(chip, CMD_VOLUME, 20, FLUSH); // default 0dB after reset
snd_uda1341_cfg_write(chip, CMD_BASS, 0, REGS_ONLY); // default value after reset
snd_uda1341_cfg_write(chip, CMD_TREBBLE, 0, REGS_ONLY); // default value after reset
snd_uda1341_cfg_write(chip, CMD_IGAIN, ON, FLUSH); // default off after reset
snd_uda1341_cfg_write(chip, CMD_OGAIN, ON, FLUSH); // default off after reset
snd_uda1341_cfg_write(chip, CMD_CH1, 31, FLUSH); // default value after reset
snd_uda1341_cfg_write(chip, CMD_CH2, 4, FLUSH); // default value after reset
snd_uda1341_cfg_write(chip, CMD_MIC, 4, FLUSH); // default 0dB after reset
snd_uda1341_cfg_write(chip, CMD_AGC_LEVEL, 0, FLUSH); // default value after reset
snd_uda1341_cfg_write(chip, CMD_AGC_TIME, 0, FLUSH); // default value after reset
snd_uda1341_cfg_write(chip, CMD_AGC, OFF, FLUSH); // default value after reset
snd_uda1341_cfg_write(chip, CMD_DAC, ON, FLUSH); // ??? default value after reset
snd_uda1341_cfg_write(chip, CMD_ADC, ON, FLUSH); // ??? default value after reset
snd_uda1341_cfg_write(chip, CMD_PEAK, AFTER, REGS_ONLY);// default value after reset
snd_uda1341_cfg_write(chip, CMD_DEEMP, NONE, REGS_ONLY);// default value after reset
snd_uda1341_cfg_write(chip, CMD_FILTER, MAX, FLUSH); // defaul flat after reset
snd_uda1341_cfg_write(chip, CMD_MIXER, MIXER, FLUSH); // default doub.dif.mode
return 0;
}
int __devinit snd_chip_uda1341_mixer_new( struct snd_card *card, struct s3c24xx_uda1341 *chip )
{
int idx, err;
uda1341_chip_init( chip );
for ( idx = 0; idx < ARRAY_SIZE( snd_uda1341_controls ); idx++ )
{
if ( ( err = snd_ctl_add( card, snd_ctl_new1( &snd_uda1341_controls[ idx ], chip ) ) ) < 0 )
{
s3c24xx_uda1341_free( chip );
return err;
}
}
strcpy( card -> mixername, "UDA1341TS Mixer" );
return 0;
}
#else
static int __devinit snd_chip_uda1341_mixer_new( struct snd_card *card,
struct s3c24xx_uda1341 *chip)
{
/*
* Anything more to do???
*/
strcpy( card -> mixername, "UDA1341TS Mixer" );
return 0;
}
#endif /* MIXER_EN */
/* Proc interface */
#ifdef CONFIG_PROC_FS
static const char *format_names[] = {
"I2S-bus",
"LSB 16bits",
"LSB 18bits",
"LSB 20bits",
"MSB",
"in LSB 16bits/out MSB",
"in LSB 18bits/out MSB",
"in LSB 20bits/out MSB",
};
static const char *fs_names[] = {
"512*fs",
"384*fs",
"256*fs",
"Unused - bad value!",
};
static const char* bass_values[][16] = {
{"0 dB", "0 dB", "0 dB", "0 dB", "0 dB", "0 dB", "0 dB", "0 dB", "0 dB", "0 dB", "0 dB",
"0 dB", "0 dB", "0 dB", "0 dB", "undefined", }, //flat
{"0 dB", "2 dB", "4 dB", "6 dB", "8 dB", "10 dB", "12 dB", "14 dB", "16 dB", "18 dB", "18 dB",
"18 dB", "18 dB", "18 dB", "18 dB", "undefined",}, // min
{"0 dB", "2 dB", "4 dB", "6 dB", "8 dB", "10 dB", "12 dB", "14 dB", "16 dB", "18 dB", "18 dB",
"18 dB", "18 dB", "18 dB", "18 dB", "undefined",}, // min
{"0 dB", "2 dB", "4 dB", "6 dB", "8 dB", "10 dB", "12 dB", "14 dB", "16 dB", "18 dB", "20 dB",
"22 dB", "24 dB", "24 dB", "24 dB", "undefined",}, // max
};
static const char *mic_sens_value[] = {
"-3 dB", "0 dB", "3 dB", "9 dB", "15 dB", "21 dB", "27 dB", "not used",
};
static const unsigned short AGC_atime[] = {
11, 16, 11, 16, 21, 11, 16, 21,
};
static const unsigned short AGC_dtime[] = {
100, 100, 200, 200, 200, 400, 400, 400,
};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -