/* Set audio mode. Note that the pre-'G' models do not support BTSC+SAP,
nor do they support stereo BTSC. */ staticvoid msp3400c_set_audmode(struct i2c_client *client)
{ staticchar *strmode[] = { "mono", "stereo", "lang2", "lang1", "lang1+lang2"
}; struct msp_state *state = to_state(i2c_get_clientdata(client)); char *modestr = (state->audmode >= 0 && state->audmode < 5) ?
strmode[state->audmode] : "unknown"; int src = 0; /* channel source: FM/AM, nicam or SCART */ int audmode = state->audmode;
if (state->opmode == OPMODE_AUTOSELECT) { /* this method would break everything, let's make sure * it's never called
*/
dev_dbg_lvl(&client->dev, 1, msp_debug, "set_audmode called with mode=%d instead of set_source (ignored)\n",
state->audmode); return;
}
/* Note: for the C and D revs no NTSC stereo + SAP is possible as the hardware does not support SAP. So the rxsubchans combination
of STEREO | LANG2 does not occur. */
if (state->mode != MSP_MODE_EXTERN) { /* switch to mono if only mono is available */ if (state->rxsubchans == V4L2_TUNER_SUB_MONO)
audmode = V4L2_TUNER_MODE_MONO; /* if bilingual */ elseif (state->rxsubchans & V4L2_TUNER_SUB_LANG2) { /* and mono or stereo, then fallback to lang1 */ if (audmode == V4L2_TUNER_MODE_MONO ||
audmode == V4L2_TUNER_MODE_STEREO)
audmode = V4L2_TUNER_MODE_LANG1;
} /* if stereo, and audmode is not mono, then switch to stereo */ elseif (audmode != V4L2_TUNER_MODE_MONO)
audmode = V4L2_TUNER_MODE_STEREO;
}
/* switch demodulator */ switch (state->mode) { case MSP_MODE_FM_TERRA:
dev_dbg_lvl(&client->dev, 1, msp_debug, "FM set_audmode: %s\n", modestr); switch (audmode) { case V4L2_TUNER_MODE_STEREO:
msp_write_dsp(client, 0x000e, 0x3001); break; case V4L2_TUNER_MODE_MONO: case V4L2_TUNER_MODE_LANG1: case V4L2_TUNER_MODE_LANG2: case V4L2_TUNER_MODE_LANG1_LANG2:
msp_write_dsp(client, 0x000e, 0x3000); break;
} break; case MSP_MODE_FM_SAT:
dev_dbg_lvl(&client->dev, 1, msp_debug, "SAT set_audmode: %s\n", modestr); switch (audmode) { case V4L2_TUNER_MODE_MONO:
msp3400c_set_carrier(client, MSP_CARRIER(6.5), MSP_CARRIER(6.5)); break; case V4L2_TUNER_MODE_STEREO: case V4L2_TUNER_MODE_LANG1_LANG2:
msp3400c_set_carrier(client, MSP_CARRIER(7.2), MSP_CARRIER(7.02)); break; case V4L2_TUNER_MODE_LANG1:
msp3400c_set_carrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02)); break; case V4L2_TUNER_MODE_LANG2:
msp3400c_set_carrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02)); break;
} break; case MSP_MODE_FM_NICAM1: case MSP_MODE_FM_NICAM2: case MSP_MODE_AM_NICAM:
dev_dbg_lvl(&client->dev, 1, msp_debug, "NICAM set_audmode: %s\n", modestr); if (state->nicam_on)
src = 0x0100; /* NICAM */ break; case MSP_MODE_BTSC:
dev_dbg_lvl(&client->dev, 1, msp_debug, "BTSC set_audmode: %s\n", modestr); break; case MSP_MODE_EXTERN:
dev_dbg_lvl(&client->dev, 1, msp_debug, "extern set_audmode: %s\n", modestr);
src = 0x0200; /* SCART */ break; case MSP_MODE_FM_RADIO:
dev_dbg_lvl(&client->dev, 1, msp_debug, "FM-Radio set_audmode: %s\n", modestr); break; default:
dev_dbg_lvl(&client->dev, 1, msp_debug, "mono set_audmode\n"); return;
}
/* switch audio */
dev_dbg_lvl(&client->dev, 1, msp_debug, "set audmode %d\n", audmode); switch (audmode) { case V4L2_TUNER_MODE_STEREO: case V4L2_TUNER_MODE_LANG1_LANG2:
src |= 0x0020; break; case V4L2_TUNER_MODE_MONO: if (state->mode == MSP_MODE_AM_NICAM) {
dev_dbg_lvl(&client->dev, 1, msp_debug, "switching to AM mono\n"); /* AM mono decoding is handled by tuner, not MSP chip */ /* SCART switching control register */
msp_set_scart(client, SCART_MONO, 0);
src = 0x0200; break;
} if (state->rxsubchans & V4L2_TUNER_SUB_STEREO)
src = 0x0030; break; case V4L2_TUNER_MODE_LANG1: break; case V4L2_TUNER_MODE_LANG2:
src |= 0x0010; break;
}
dev_dbg_lvl(&client->dev, 1, msp_debug, "set_audmode final source/matrix = 0x%x\n", src);
/* * A kernel thread for msp3400 control -- we don't want to block the * in the ioctl while doing the sound carrier & stereo detect
*/ /* stereo/multilang monitoring */ staticvoid watch_stereo(struct i2c_client *client)
{ struct msp_state *state = to_state(i2c_get_clientdata(client));
if (msp_detect_stereo(client))
msp_set_audmode(client);
/* monitor tv audio mode, the first time don't wait
so long to get a quick stereo/bilingual result */
count = 3; while (state->watch_stereo) { if (msp_sleep(state, count ? 1000 : 5000)) goto restart; if (count)
count--;
watch_stereo(client);
}
}
dev_dbg_lvl(&client->dev, 1, msp_debug, "thread: exit\n"); return 0;
}
int msp3410d_thread(void *data)
{ struct i2c_client *client = data; struct msp_state *state = to_state(i2c_get_clientdata(client)); int val, i, std, count;
/* start autodetect. Note: autodetect is not supported for NTSC-M and radio, hence we force the standard in those
cases. */ if (state->radio)
std = 0x40; else
std = (state->v4l2_std & V4L2_STD_NTSC) ? 0x20 : 1;
state->watch_stereo = 0;
state->nicam_on = 0;
/* wait for tuner to settle down after a channel change */ if (msp_sleep(state, 200)) goto restart;
/* set stereo */ switch (val) { case 0x0008: /* B/G NICAM */ case 0x000a: /* I NICAM */ case 0x000b: /* D/K NICAM */ if (val == 0x000a)
state->mode = MSP_MODE_FM_NICAM2; else
state->mode = MSP_MODE_FM_NICAM1; /* just turn on stereo */
state->nicam_on = 1;
state->watch_stereo = 1; break; case 0x0009:
state->mode = MSP_MODE_AM_NICAM;
state->nicam_on = 1;
state->watch_stereo = 1; break; case 0x0020: /* BTSC */ /* The pre-'G' models only have BTSC-mono */
state->mode = MSP_MODE_BTSC; break; case 0x0040: /* FM radio */
state->mode = MSP_MODE_FM_RADIO;
state->rxsubchans = V4L2_TUNER_SUB_STEREO; /* not needed in theory if we have radio, but
short programming enables carrier mute */
msp3400c_set_mode(client, MSP_MODE_FM_RADIO);
msp3400c_set_carrier(client, MSP_CARRIER(10.7),
MSP_CARRIER(10.7)); break; case 0x0002: case 0x0003: case 0x0004: case 0x0005:
state->mode = MSP_MODE_FM_TERRA;
state->watch_stereo = 1; break;
}
/* set various prescales */
msp_write_dsp(client, 0x0d, 0x1900); /* scart */
msp_write_dsp(client, 0x0e, 0x3000); /* FM */ if (state->has_nicam)
msp_write_dsp(client, 0x10, 0x5a00); /* nicam */
if (state->has_i2s_conf)
msp_write_dem(client, 0x40, state->i2s_mode);
/* monitor tv audio mode, the first time don't wait
so long to get a quick stereo/bilingual result */
count = 3; while (state->watch_stereo) { if (msp_sleep(state, count ? 1000 : 5000)) goto restart; if (count)
count--;
watch_stereo(client);
}
}
dev_dbg_lvl(&client->dev, 1, msp_debug, "thread: exit\n"); return 0;
}
/* msp34xxG + (autoselect no-thread) * this one uses both automatic standard detection and automatic sound * select which are available in the newer G versions * struct msp: only norm, acb and source are really used in this mode
*/
if (state->radio) {
dev_dbg_lvl(&client->dev, 1, msp_debug, "selected radio modus\n"); return 0x0001;
} if (state->v4l2_std == V4L2_STD_NTSC_M_JP) {
dev_dbg_lvl(&client->dev, 1, msp_debug, "selected M (EIA-J) modus\n"); return 0x4001;
} if (state->v4l2_std == V4L2_STD_NTSC_M_KR) {
dev_dbg_lvl(&client->dev, 1, msp_debug, "selected M (A2) modus\n"); return 0x0001;
} if (state->v4l2_std == V4L2_STD_SECAM_L) {
dev_dbg_lvl(&client->dev, 1, msp_debug, "selected SECAM-L modus\n"); return 0x6001;
} if (state->v4l2_std & V4L2_STD_MN) {
dev_dbg_lvl(&client->dev, 1, msp_debug, "selected M (BTSC) modus\n"); return 0x2001;
} return 0x7001;
}
staticvoid msp34xxg_set_source(struct i2c_client *client, u16 reg, int in)
{ struct msp_state *state = to_state(i2c_get_clientdata(client)); int source, matrix;
switch (state->audmode) { case V4L2_TUNER_MODE_MONO:
source = 0; /* mono only */
matrix = 0x30; break; case V4L2_TUNER_MODE_LANG2:
source = 4; /* stereo or B */
matrix = 0x10; break; case V4L2_TUNER_MODE_LANG1_LANG2:
source = 1; /* stereo or A|B */
matrix = 0x20; break; case V4L2_TUNER_MODE_LANG1:
source = 3; /* stereo or A */
matrix = 0x00; break; case V4L2_TUNER_MODE_STEREO: default:
source = 3; /* stereo or A */
matrix = 0x20; break;
}
if (in == MSP_DSP_IN_TUNER)
source = (source << 8) | 0x20; /* the msp34x2g puts the MAIN_AVC, MAIN and AUX sources in 12, 13, 14
instead of 11, 12, 13. So we add one for that msp version. */ elseif (in >= MSP_DSP_IN_MAIN_AVC && state->has_dolby_pro_logic)
source = ((in + 1) << 8) | matrix; else
source = (in << 8) | matrix;
dev_dbg_lvl(&client->dev, 1, msp_debug, "set source to %d (0x%x) for output %02x\n", in, source, reg);
msp_write_dsp(client, reg, source);
}
msp34xxg_set_source(client, 0x0008, (in >> 4) & 0xf); /* quasi-peak detector is set to same input as the loudspeaker (MAIN) */
msp34xxg_set_source(client, 0x000c, (in >> 4) & 0xf);
msp34xxg_set_source(client, 0x0009, (in >> 8) & 0xf);
msp34xxg_set_source(client, 0x000a, (in >> 12) & 0xf); if (state->has_scart2_out)
msp34xxg_set_source(client, 0x0041, (in >> 16) & 0xf);
msp34xxg_set_source(client, 0x000b, (in >> 20) & 0xf);
}
/* (re-)initialize the msp34xxg */ staticvoid msp34xxg_reset(struct i2c_client *client)
{ struct msp_state *state = to_state(i2c_get_clientdata(client)); int tuner = (state->route_in >> 3) & 1; int modus;
/* initialize std to 1 (autodetect) to signal that no standard is
selected yet. */
state->std = 1;
msp_reset(client);
if (state->has_i2s_conf)
msp_write_dem(client, 0x40, state->i2s_mode);
/* step-by-step initialisation, as described in the manual */
modus = msp34xxg_modus(client);
modus |= tuner ? 0x100 : 0;
msp_write_dem(client, 0x30, modus);
/* write the dsps that may have an influence on
standard/audio autodetection right now */
msp34xxg_set_sources(client);
msp_write_dsp(client, 0x0d, 0x1900); /* scart */
msp_write_dsp(client, 0x0e, 0x3000); /* FM */ if (state->has_nicam)
msp_write_dsp(client, 0x10, 0x5a00); /* nicam */
/* set identification threshold. Personally, I * I set it to a higher value than the default * of 0x190 to ignore noisy stereo signals. * this needs tuning. (recommended range 0x00a0-0x03c0) * 0x7f0 = forced mono mode * * a2 threshold for stereo/bilingual. * Note: this register is part of the Manual/Compatibility mode. * It is supported by all 'G'-family chips.
*/
msp_write_dem(client, 0x22, msp_stereo_thresh);
}
int msp34xxg_thread(void *data)
{ struct i2c_client *client = data; struct msp_state *state = to_state(i2c_get_clientdata(client)); int val, i;
if (state->std == 9) { /* AM NICAM mode */
msp_write_dsp(client, 0x0e, 0x7c00);
}
/* unmute: dispatch sound to scart output, set scart volume */
msp_update_volume(state);
/* restore ACB */ if (msp_write_dsp(client, 0x13, state->acb)) return -1;
/* the periodic stereo/SAP check is only relevant for
the 0x20 standard (BTSC) */ if (state->std != 0x20) continue;
state->watch_stereo = 1;
/* monitor tv audio mode, the first time don't wait
in order to get a quick stereo/SAP update */
watch_stereo(client); while (state->watch_stereo) {
watch_stereo(client); if (msp_sleep(state, 5000)) goto restart;
}
}
dev_dbg_lvl(&client->dev, 1, msp_debug, "thread: exit\n"); return 0;
}
staticint msp34xxg_detect_stereo(struct i2c_client *client)
{ struct msp_state *state = to_state(i2c_get_clientdata(client)); int status = msp_read_dem(client, 0x0200); int is_bilingual = status & 0x100; int is_stereo = status & 0x40; int oldrx = state->rxsubchans;
switch (state->opmode) { case OPMODE_MANUAL: case OPMODE_AUTODETECT:
msp3400c_set_audmode(client); break; case OPMODE_AUTOSELECT:
msp34xxg_set_audmode(client); break;
}
}
int msp_detect_stereo(struct i2c_client *client)
{ struct msp_state *state = to_state(i2c_get_clientdata(client));
switch (state->opmode) { case OPMODE_MANUAL: case OPMODE_AUTODETECT: return msp3400c_detect_stereo(client); case OPMODE_AUTOSELECT: return msp34xxg_detect_stereo(client);
} return 0;
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.18 Sekunden
(vorverarbeitet am 2026-04-29)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.