📄 tvaudio.c
字号:
mode = VIDEO_SOUND_MONO;
if(-1 == (dsr = chip_read2(chip,TDA9874A_DSR)))
return mode;
if(-1 == (nsr = chip_read2(chip,TDA9874A_NSR)))
return mode;
if(-1 == (necr = chip_read2(chip,TDA9874A_NECR)))
return mode;
/* need to store dsr/nsr somewhere */
chip->shadow.bytes[MAXREGS-2] = dsr;
chip->shadow.bytes[MAXREGS-1] = nsr;
if(tda9874a_mode) {
/* Note: DSR.RSSF and DSR.AMSTAT bits are also checked.
* If NICAM auto-muting is enabled, DSR.AMSTAT=1 indicates
* that sound has (temporarily) switched from NICAM to
* mono FM (or AM) on 1st sound carrier due to high NICAM bit
* error count. So in fact there is no stereo in this case :-(
* But changing the mode to VIDEO_SOUND_MONO would switch
* external 4052 multiplexer in audio_hook().
*/
#if 0
if((nsr & 0x02) && !(dsr & 0x10)) /* NSR.S/MB=1 and DSR.AMSTAT=0 */
mode |= VIDEO_SOUND_STEREO;
#else
if(nsr & 0x02) /* NSR.S/MB=1 */
mode |= VIDEO_SOUND_STEREO;
#endif
if(nsr & 0x01) /* NSR.D/SB=1 */
mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
} else {
if(dsr & 0x02) /* DSR.IDSTE=1 */
mode |= VIDEO_SOUND_STEREO;
if(dsr & 0x04) /* DSR.IDDUA=1 */
mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
}
dprintk("tda9874a_getmode(): DSR=0x%X, NSR=0x%X, NECR=0x%X, return: %d.\n",
dsr, nsr, necr, mode);
return mode;
}
static void tda9874a_setmode(struct CHIPSTATE *chip, int mode)
{
/* Disable/enable NICAM auto-muting (based on DSR.RSSF status bit). */
/* If auto-muting is disabled, we can hear a signal of degrading quality. */
if(tda9874a_mode) {
if(chip->shadow.bytes[MAXREGS-2] & 0x20) /* DSR.RSSF=1 */
tda9874a_NCONR &= 0xfe; /* enable */
else
tda9874a_NCONR |= 0x01; /* disable */
chip_write(chip, TDA9874A_NCONR, tda9874a_NCONR);
}
/* Note: TDA9874A supports automatic FM dematrixing (FMMR register)
* and has auto-select function for audio output (AOSR register).
* Old TDA9874H doesn't support these features.
* TDA9874A also has additional mono output pin (OUTM), which
* on same (all?) tv-cards is not used, anyway (as well as MONOIN).
*/
if(tda9874a_dic == 0x11) {
int aosr = 0x80;
int mdacosr = (tda9874a_mode) ? 0x82:0x80;
switch(mode) {
case VIDEO_SOUND_MONO:
case VIDEO_SOUND_STEREO:
break;
case VIDEO_SOUND_LANG1:
aosr = 0x80; /* auto-select, dual A/A */
mdacosr = (tda9874a_mode) ? 0x82:0x80;
break;
case VIDEO_SOUND_LANG2:
aosr = 0xa0; /* auto-select, dual B/B */
mdacosr = (tda9874a_mode) ? 0x83:0x81;
break;
default:
chip->mode = 0;
return;
}
chip_write(chip, TDA9874A_AOSR, aosr);
chip_write(chip, TDA9874A_MDACOSR, mdacosr);
dprintk("tda9874a_setmode(): req. mode %d; AOSR=0x%X, MDACOSR=0x%X.\n",
mode, aosr, mdacosr);
} else { /* dic == 0x07 */
int fmmr,aosr;
switch(mode) {
case VIDEO_SOUND_MONO:
fmmr = 0x00; /* mono */
aosr = 0x10; /* A/A */
break;
case VIDEO_SOUND_STEREO:
if(tda9874a_mode) {
fmmr = 0x00;
aosr = 0x00; /* handled by NICAM auto-mute */
} else {
fmmr = (tda9874a_ESP == 1) ? 0x05 : 0x04; /* stereo */
aosr = 0x00;
}
break;
case VIDEO_SOUND_LANG1:
fmmr = 0x02; /* dual */
aosr = 0x10; /* dual A/A */
break;
case VIDEO_SOUND_LANG2:
fmmr = 0x02; /* dual */
aosr = 0x20; /* dual B/B */
break;
default:
chip->mode = 0;
return;
}
chip_write(chip, TDA9874A_FMMR, fmmr);
chip_write(chip, TDA9874A_AOSR, aosr);
dprintk("tda9874a_setmode(): req. mode %d; FMMR=0x%X, AOSR=0x%X.\n",
mode, fmmr, aosr);
}
}
static int tda9874a_checkit(struct CHIPSTATE *chip)
{
int dic,sic; /* device id. and software id. codes */
if(-1 == (dic = chip_read2(chip,TDA9874A_DIC)))
return 0;
if(-1 == (sic = chip_read2(chip,TDA9874A_SIC)))
return 0;
dprintk("tda9874a_checkit(): DIC=0x%X, SIC=0x%X.\n", dic, sic);
if((dic == 0x11)||(dic == 0x07)) {
printk("tvaudio: found tda9874%s.\n", (dic == 0x11) ? "a":"h");
tda9874a_dic = dic; /* remember device id. */
return 1;
}
return 0; /* not found */
}
static int tda9874a_initialize(struct CHIPSTATE *chip)
{
if (tda9874a_SIF > 2)
tda9874a_SIF = 1;
if (tda9874a_STD >= 8)
tda9874a_STD = 0;
if(tda9874a_AMSEL > 1)
tda9874a_AMSEL = 0;
if(tda9874a_SIF == 1)
tda9874a_GCONR = 0xc0; /* sound IF input 1 */
else
tda9874a_GCONR = 0xc1; /* sound IF input 2 */
tda9874a_ESP = tda9874a_STD;
tda9874a_mode = (tda9874a_STD < 5) ? 0 : 1;
if(tda9874a_AMSEL == 0)
tda9874a_NCONR = 0x01; /* auto-mute: analog mono input */
else
tda9874a_NCONR = 0x05; /* auto-mute: 1st carrier FM or AM */
tda9874a_setup(chip);
return 0;
}
/* ---------------------------------------------------------------------- */
/* audio chip descriptions - defines+functions for tea6420 */
#define TEA6300_VL 0x00 /* volume left */
#define TEA6300_VR 0x01 /* volume right */
#define TEA6300_BA 0x02 /* bass */
#define TEA6300_TR 0x03 /* treble */
#define TEA6300_FA 0x04 /* fader control */
#define TEA6300_S 0x05 /* switch register */
/* values for those registers: */
#define TEA6300_S_SA 0x01 /* stereo A input */
#define TEA6300_S_SB 0x02 /* stereo B */
#define TEA6300_S_SC 0x04 /* stereo C */
#define TEA6300_S_GMU 0x80 /* general mute */
#define TEA6420_S_SA 0x00 /* stereo A input */
#define TEA6420_S_SB 0x01 /* stereo B */
#define TEA6420_S_SC 0x02 /* stereo C */
#define TEA6420_S_SD 0x03 /* stereo D */
#define TEA6420_S_SE 0x04 /* stereo E */
#define TEA6420_S_GMU 0x05 /* general mute */
static int tea6300_shift10(int val) { return val >> 10; }
static int tea6300_shift12(int val) { return val >> 12; }
/* ---------------------------------------------------------------------- */
/* audio chip descriptions - defines+functions for tda8425 */
#define TDA8425_VL 0x00 /* volume left */
#define TDA8425_VR 0x01 /* volume right */
#define TDA8425_BA 0x02 /* bass */
#define TDA8425_TR 0x03 /* treble */
#define TDA8425_S1 0x08 /* switch functions */
/* values for those registers: */
#define TDA8425_S1_OFF 0xEE /* audio off (mute on) */
#define TDA8425_S1_CH1 0xCE /* audio channel 1 (mute off) - "linear stereo" mode */
#define TDA8425_S1_CH2 0xCF /* audio channel 2 (mute off) - "linear stereo" mode */
#define TDA8425_S1_MU 0x20 /* mute bit */
#define TDA8425_S1_STEREO 0x18 /* stereo bits */
#define TDA8425_S1_STEREO_SPATIAL 0x18 /* spatial stereo */
#define TDA8425_S1_STEREO_LINEAR 0x08 /* linear stereo */
#define TDA8425_S1_STEREO_PSEUDO 0x10 /* pseudo stereo */
#define TDA8425_S1_STEREO_MONO 0x00 /* forced mono */
#define TDA8425_S1_ML 0x06 /* language selector */
#define TDA8425_S1_ML_SOUND_A 0x02 /* sound a */
#define TDA8425_S1_ML_SOUND_B 0x04 /* sound b */
#define TDA8425_S1_ML_STEREO 0x06 /* stereo */
#define TDA8425_S1_IS 0x01 /* channel selector */
static int tda8425_shift10(int val) { return (val >> 10) | 0xc0; }
static int tda8425_shift12(int val) { return (val >> 12) | 0xf0; }
static int tda8425_initialize(struct CHIPSTATE *chip)
{
struct CHIPDESC *desc = chiplist + chip->type;
int inputmap[8] = { /* tuner */ TDA8425_S1_CH2, /* radio */ TDA8425_S1_CH1,
/* extern */ TDA8425_S1_CH1, /* intern */ TDA8425_S1_OFF,
/* off */ TDA8425_S1_OFF, /* on */ TDA8425_S1_CH2};
if (chip->c.adapter->id == (I2C_ALGO_BIT | I2C_HW_B_RIVA)) {
memcpy (desc->inputmap, inputmap, sizeof (inputmap));
}
return 0;
}
static void tda8425_setmode(struct CHIPSTATE *chip, int mode)
{
int s1 = chip->shadow.bytes[TDA8425_S1+1] & 0xe1;
if (mode & VIDEO_SOUND_LANG1) {
s1 |= TDA8425_S1_ML_SOUND_A;
s1 |= TDA8425_S1_STEREO_PSEUDO;
} else if (mode & VIDEO_SOUND_LANG2) {
s1 |= TDA8425_S1_ML_SOUND_B;
s1 |= TDA8425_S1_STEREO_PSEUDO;
} else {
s1 |= TDA8425_S1_ML_STEREO;
if (mode & VIDEO_SOUND_MONO)
s1 |= TDA8425_S1_STEREO_MONO;
if (mode & VIDEO_SOUND_STEREO)
s1 |= TDA8425_S1_STEREO_SPATIAL;
}
chip_write(chip,TDA8425_S1,s1);
}
/* ---------------------------------------------------------------------- */
/* audio chip descriptions - defines+functions for pic16c54 (PV951) */
/* the registers of 16C54, I2C sub address. */
#define PIC16C54_REG_KEY_CODE 0x01 /* Not use. */
#define PIC16C54_REG_MISC 0x02
/* bit definition of the RESET register, I2C data. */
#define PIC16C54_MISC_RESET_REMOTE_CTL 0x01 /* bit 0, Reset to receive the key */
/* code of remote controller */
#define PIC16C54_MISC_MTS_MAIN 0x02 /* bit 1 */
#define PIC16C54_MISC_MTS_SAP 0x04 /* bit 2 */
#define PIC16C54_MISC_MTS_BOTH 0x08 /* bit 3 */
#define PIC16C54_MISC_SND_MUTE 0x10 /* bit 4, Mute Audio(Line-in and Tuner) */
#define PIC16C54_MISC_SND_NOTMUTE 0x20 /* bit 5 */
#define PIC16C54_MISC_SWITCH_TUNER 0x40 /* bit 6 , Switch to Line-in */
#define PIC16C54_MISC_SWITCH_LINE 0x80 /* bit 7 , Switch to Tuner */
/* ---------------------------------------------------------------------- */
/* audio chip descriptions - defines+functions for TA8874Z */
// write 1st byte
#define TA8874Z_LED_STE 0x80
#define TA8874Z_LED_BIL 0x40
#define TA8874Z_LED_EXT 0x20
#define TA8874Z_MONO_SET 0x10
#define TA8874Z_MUTE 0x08
#define TA8874Z_F_MONO 0x04
#define TA8874Z_MODE_SUB 0x02
#define TA8874Z_MODE_MAIN 0x01
// write 2nd byte
//#define TA8874Z_TI 0x80 // test mode
#define TA8874Z_SEPARATION 0x3f
#define TA8874Z_SEPARATION_DEFAULT 0x10
// read
#define TA8874Z_B1 0x80
#define TA8874Z_B0 0x40
#define TA8874Z_CHAG_FLAG 0x20
// B1 B0
// mono L H
// stereo L L
// BIL H L
static int ta8874z_getmode(struct CHIPSTATE *chip)
{
int val, mode;
val = chip_read(chip);
mode = VIDEO_SOUND_MONO;
if (val & TA8874Z_B1){
mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
}else if (!(val & TA8874Z_B0)){
mode |= VIDEO_SOUND_STEREO;
}
//dprintk ("ta8874z_getmode(): raw chip read: 0x%02x, return: 0x%02x\n", val, mode);
return mode;
}
static audiocmd ta8874z_stereo = { 2, {0, TA8874Z_SEPARATION_DEFAULT}};
static audiocmd ta8874z_mono = {2, { TA8874Z_MONO_SET, TA8874Z_SEPARATION_DEFAULT}};
static audiocmd ta8874z_main = {2, { 0, TA8874Z_SEPARATION_DEFAULT}};
static audiocmd ta8874z_sub = {2, { TA8874Z_MODE_SUB, TA8874Z_SEPARATION_DEFAULT}};
static void ta8874z_setmode(struct CHIPSTATE *chip, int mode)
{
int update = 1;
audiocmd *t = NULL;
dprintk("ta8874z_setmode(): mode: 0x%02x\n", mode);
switch(mode){
case VIDEO_SOUND_MONO:
t = &ta8874z_mono;
break;
case VIDEO_SOUND_STEREO:
t = &ta8874z_stereo;
break;
case VIDEO_SOUND_LANG1:
t = &ta8874z_main;
break;
case VIDEO_SOUND_LANG2:
t = &ta8874z_sub;
break;
default:
update = 0;
}
if(update)
chip_cmd(chip, "TA8874Z", t);
}
static int ta8874z_checkit(struct CHIPSTATE *chip)
{
int rc;
rc = chip_read(chip);
return ((rc & 0x1f) == 0x1f) ? 1 : 0;
}
/* ---------------------------------------------------------------------- */
/* audio chip descriptions - struct CHIPDESC */
/* insmod options to enable/disable individual audio chips */
int tda8425 = 1;
int tda9840 = 1;
int tda9850 = 1;
int tda9855 = 1;
int tda9873 = 1;
int tda9874a = 1;
int tea6300 = 0; // address clash with msp34xx
int tea6420 = 1;
int pic16c54 = 1;
int ta8874z = 0; // address clash with tda9840
MODULE_PARM(tda8425,"i");
MODULE_PARM(tda9840,"i");
MODULE_PARM(tda9850,"i");
MODULE_PARM(tda9855,"i");
MODULE_PARM(tda9873,"i");
MODULE_PARM(tda9874a,"i");
MODULE_PARM(tea6300,"i");
MODULE_PARM(tea6420,"i");
MODULE_PARM(pic16c54,"i");
MODULE_PARM(ta8874z,"i");
static struct CHIPDESC chiplist[] = {
{
.name = "tda9840",
.id = I2C_DRIVERID_TDA9840,
.insmodopt = &tda9840,
.addr_lo = I2C_TDA9840 >> 1,
.addr_hi = I2C_TDA9840 >> 1,
.registers = 5,
.getmode = tda9840_getmode,
.setmode = tda9840_setmode,
.checkmode = generic_checkmode,
.init = { 2, { TDA9840_TEST, TDA9840_TEST_INT1SN
/* ,TDA9840_SW, TDA9840_MONO */} }
},
{
.name = "tda9873h",
.id = I2C_DRIVERID_TDA9873,
.checkit = tda9873_checkit,
.insmodopt = &tda9873,
.addr_lo = I2C_TDA985x_L >> 1,
.addr_hi = I2C_TDA985x_H >> 1,
.registers = 3,
.flags = CHIP_HAS_INPUTSEL,
.getmode = tda9873_getmode,
.setmode = tda9873_setmode,
.checkmode = generic_checkmode,
.init = { 4, { TDA9873_SW, 0xa4, 0x06, 0x03 } },
.inputreg = TDA9873_SW,
.inputmute = TDA9873_MUTE | TDA9873_AUTOMUTE,
.inputmap = {0xa0, 0xa2, 0xa0, 0xa0, 0xc0},
.inputmask = TDA9873_INP_MASK|TDA9873_MUTE|TDA9873_AUTOMUTE,
},
{
.name = "tda9874h/a",
.id = I2C_DRIVERID_TDA9874,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -