Commit 7560d7a4 authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab

V4L/DVB (3317): msp3400: use v4l2_std_id and determine chip capabilities.

- Replace old norm by the v4l2_std_id values.
- Add code to correctly detect the various capabilities of the
various msp chips. It's not yet used, that's going to be the next step.
Signed-off-by: default avatarHans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@brturbo.com.br>
parent 3d7d027a
...@@ -312,10 +312,16 @@ void msp_set_audio(struct i2c_client *client) ...@@ -312,10 +312,16 @@ void msp_set_audio(struct i2c_client *client)
msp_write_dsp(client, 0x0003, treble); /* loudspeaker */ msp_write_dsp(client, 0x0003, treble); /* loudspeaker */
} }
int msp_modus(struct i2c_client *client, int norm) int msp_modus(struct i2c_client *client)
{ {
switch (norm) { struct msp_state *state = i2c_get_clientdata(client);
case VIDEO_MODE_PAL:
if (state->radio) {
v4l_dbg(1, client, "video mode selected to Radio\n");
return 0x0003;
}
if (state->std & V4L2_STD_PAL) {
v4l_dbg(1, client, "video mode selected to PAL\n"); v4l_dbg(1, client, "video mode selected to PAL\n");
#if 1 #if 1
...@@ -325,37 +331,16 @@ int msp_modus(struct i2c_client *client, int norm) ...@@ -325,37 +331,16 @@ int msp_modus(struct i2c_client *client, int norm)
/* previous value, try this if it breaks ... */ /* previous value, try this if it breaks ... */
return 0x1003; return 0x1003;
#endif #endif
case VIDEO_MODE_NTSC: /* BTSC */ }
if (state->std & V4L2_STD_NTSC) {
v4l_dbg(1, client, "video mode selected to NTSC\n"); v4l_dbg(1, client, "video mode selected to NTSC\n");
return 0x2003; return 0x2003;
case VIDEO_MODE_SECAM: }
if (state->std & V4L2_STD_SECAM) {
v4l_dbg(1, client, "video mode selected to SECAM\n"); v4l_dbg(1, client, "video mode selected to SECAM\n");
return 0x0003; return 0x0003;
case VIDEO_MODE_RADIO:
v4l_dbg(1, client, "video mode selected to Radio\n");
return 0x0003;
case VIDEO_MODE_AUTO:
v4l_dbg(1, client, "video mode selected to Auto\n");
return 0x2003;
default:
return 0x0003;
}
}
int msp_standard(int norm)
{
switch (norm) {
case VIDEO_MODE_PAL:
return 1;
case VIDEO_MODE_NTSC: /* BTSC */
return 0x0020;
case VIDEO_MODE_SECAM:
return 1;
case VIDEO_MODE_RADIO:
return 0x0040;
default:
return 1;
} }
return 0x0003;
} }
/* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */
...@@ -617,7 +602,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) ...@@ -617,7 +602,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
break; break;
case AUDC_SET_RADIO: case AUDC_SET_RADIO:
state->norm = VIDEO_MODE_RADIO; state->radio = 1;
v4l_dbg(1, client, "switching to radio mode\n"); v4l_dbg(1, client, "switching to radio mode\n");
state->watch_stereo = 0; state->watch_stereo = 0;
switch (state->opmode) { switch (state->opmode) {
...@@ -673,7 +658,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) ...@@ -673,7 +658,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
state->treble = va->treble; state->treble = va->treble;
msp_set_audio(client); msp_set_audio(client);
if (va->mode != 0 && state->norm != VIDEO_MODE_RADIO) if (va->mode != 0 && state->radio == 0)
msp_any_set_audmode(client, msp_mode_v4l1_to_v4l2(va->mode)); msp_any_set_audmode(client, msp_mode_v4l1_to_v4l2(va->mode));
break; break;
} }
...@@ -682,7 +667,13 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) ...@@ -682,7 +667,13 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
{ {
struct video_channel *vc = arg; struct video_channel *vc = arg;
state->norm = vc->norm; state->radio = 0;
if (vc->norm == VIDEO_MODE_PAL)
state->std = V4L2_STD_PAL;
else if (vc->norm == VIDEO_MODE_SECAM)
state->std = V4L2_STD_SECAM;
else
state->std = V4L2_STD_NTSC;
msp_wake_thread(client); msp_wake_thread(client);
break; break;
} }
...@@ -709,15 +700,8 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) ...@@ -709,15 +700,8 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
{ {
v4l2_std_id *id = arg; v4l2_std_id *id = arg;
/*FIXME: use V4L2 mode flags on msp3400 instead of V4L1*/ state->std = *id;
if (*id & V4L2_STD_PAL) { state->radio = 0;
state->norm = VIDEO_MODE_PAL;
} else if (*id & V4L2_STD_SECAM) {
state->norm = VIDEO_MODE_SECAM;
} else {
state->norm = VIDEO_MODE_NTSC;
}
msp_wake_thread(client); msp_wake_thread(client);
return 0; return 0;
} }
...@@ -965,6 +949,11 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind) ...@@ -965,6 +949,11 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind)
struct i2c_client *client; struct i2c_client *client;
struct msp_state *state; struct msp_state *state;
int (*thread_func)(void *data) = NULL; int (*thread_func)(void *data) = NULL;
int msp_hard;
int msp_family;
int msp_revision;
int msp_product, msp_prod_hi, msp_prod_lo;
int msp_rom;
client = kmalloc(sizeof(*client), GFP_KERNEL); client = kmalloc(sizeof(*client), GFP_KERNEL);
if (client == NULL) if (client == NULL)
...@@ -989,7 +978,7 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind) ...@@ -989,7 +978,7 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind)
i2c_set_clientdata(client, state); i2c_set_clientdata(client, state);
memset(state, 0, sizeof(*state)); memset(state, 0, sizeof(*state));
state->norm = VIDEO_MODE_NTSC; state->std = V4L2_STD_NTSC;
state->volume = 58880; /* 0db gain */ state->volume = 58880; /* 0db gain */
state->balance = 32768; /* 0db gain */ state->balance = 32768; /* 0db gain */
state->bass = 32768; state->bass = 32768;
...@@ -1012,20 +1001,45 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind) ...@@ -1012,20 +1001,45 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind)
msp_set_audio(client); msp_set_audio(client);
snprintf(client->name, sizeof(client->name), "MSP%c4%02d%c-%c%d", msp_family = ((state->rev1 >> 4) & 0x0f) + 3;
((state->rev1 >> 4) & 0x0f) + '3', msp_product = (state->rev2 >> 8) & 0xff;
(state->rev2 >> 8) & 0xff, msp_prod_hi = msp_product / 10;
(state->rev1 & 0x0f) + '@', msp_prod_lo = msp_product % 10;
((state->rev1 >> 8) & 0xff) + '@', msp_revision = (state->rev1 & 0x0f) + '@';
state->rev2 & 0x1f); msp_hard = ((state->rev1 >> 8) & 0xff) + '@';
msp_rom = state->rev2 & 0x1f;
snprintf(client->name, sizeof(client->name), "MSP%d4%02d%c-%c%d",
msp_family, msp_product,
msp_revision, msp_hard, msp_rom);
/* Has NICAM support: all mspx41x and mspx45x products have NICAM */
state->has_nicam = msp_prod_hi == 1 || msp_prod_hi == 5;
/* Has radio support: was added with revision G */
state->has_radio = msp_revision >= 'G';
/* Has headphones output: not for stripped down products */
state->has_headphones = msp_prod_lo < 5;
/* Has scart4 input: not in pre D revisions, not in stripped D revs */
state->has_scart4 = msp_family >= 4 || (msp_revision >= 'D' && msp_prod_lo < 5);
/* Has scart2 and scart3 inputs and scart2 output: not in stripped
down products of the '3' family */
state->has_scart23_in_scart2_out = msp_family >= 4 || msp_prod_lo < 5;
/* Has subwoofer output: not in pre-D revs and not in stripped down products */
state->has_subwoofer = msp_revision >= 'D' && msp_prod_lo < 5;
/* Has soundprocessing (bass/treble/balance/loudness/equalizer): not in
stripped down products */
state->has_sound_processing = msp_prod_lo < 7;
/* Has Virtual Dolby Surround: only in msp34x1 */
state->has_virtual_dolby_surround = msp_revision == 'G' && msp_prod_lo == 1;
/* Has Virtual Dolby Surround & Dolby Pro Logic: only in msp34x2 */
state->has_dolby_pro_logic = msp_revision == 'G' && msp_prod_lo == 2;
state->opmode = opmode; state->opmode = opmode;
if (state->opmode == OPMODE_AUTO) { if (state->opmode == OPMODE_AUTO) {
/* MSP revision G and up have both autodetect and autoselect */ /* MSP revision G and up have both autodetect and autoselect */
if ((state->rev1 & 0x0f) >= 'G'-'@') if (msp_revision >= 'G')
state->opmode = OPMODE_AUTOSELECT; state->opmode = OPMODE_AUTOSELECT;
/* MSP revision D and up have autodetect */ /* MSP revision D and up have autodetect */
else if ((state->rev1 & 0x0f) >= 'D'-'@') else if (msp_revision >= 'D')
state->opmode = OPMODE_AUTODETECT; state->opmode = OPMODE_AUTODETECT;
else else
state->opmode = OPMODE_MANUAL; state->opmode = OPMODE_MANUAL;
...@@ -1034,11 +1048,11 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind) ...@@ -1034,11 +1048,11 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind)
/* hello world :-) */ /* hello world :-) */
v4l_info(client, "%s found @ 0x%x (%s)\n", client->name, address << 1, adapter->name); v4l_info(client, "%s found @ 0x%x (%s)\n", client->name, address << 1, adapter->name);
v4l_info(client, "%s ", client->name); v4l_info(client, "%s ", client->name);
if (HAVE_NICAM(state) && HAVE_RADIO(state)) if (state->has_nicam && state->has_radio)
printk("supports nicam and radio, "); printk("supports nicam and radio, ");
else if (HAVE_NICAM(state)) else if (state->has_nicam)
printk("supports nicam, "); printk("supports nicam, ");
else if (HAVE_RADIO(state)) else if (state->has_radio)
printk("supports radio, "); printk("supports radio, ");
printk("mode is "); printk("mode is ");
......
...@@ -203,7 +203,7 @@ void msp3400c_setmode(struct i2c_client *client, int type) ...@@ -203,7 +203,7 @@ void msp3400c_setmode(struct i2c_client *client, int type)
msp_write_dsp(client, 0x000a, msp3400c_init_data[type].dsp_src); msp_write_dsp(client, 0x000a, msp3400c_init_data[type].dsp_src);
msp_write_dsp(client, 0x000e, msp3400c_init_data[type].dsp_matrix); msp_write_dsp(client, 0x000e, msp3400c_init_data[type].dsp_matrix);
if (HAVE_NICAM(state)) { if (state->has_nicam) {
/* nicam prescale */ /* nicam prescale */
msp_write_dsp(client, 0x0010, 0x5a00); /* was: 0x3000 */ msp_write_dsp(client, 0x0010, 0x5a00); /* was: 0x3000 */
} }
...@@ -487,8 +487,7 @@ int msp3400c_thread(void *data) ...@@ -487,8 +487,7 @@ int msp3400c_thread(void *data)
if (kthread_should_stop()) if (kthread_should_stop())
break; break;
if (VIDEO_MODE_RADIO == state->norm || if (state->radio || MSP_MODE_EXTERN == state->mode) {
MSP_MODE_EXTERN == state->mode) {
/* no carrier scan, just unmute */ /* no carrier scan, just unmute */
v4l_dbg(1, client, "thread: no carrier scan\n"); v4l_dbg(1, client, "thread: no carrier scan\n");
msp_set_audio(client); msp_set_audio(client);
...@@ -510,7 +509,7 @@ int msp3400c_thread(void *data) ...@@ -510,7 +509,7 @@ int msp3400c_thread(void *data)
cd = msp3400c_carrier_detect_main; cd = msp3400c_carrier_detect_main;
count = ARRAY_SIZE(msp3400c_carrier_detect_main); count = ARRAY_SIZE(msp3400c_carrier_detect_main);
if (amsound && (state->norm == VIDEO_MODE_SECAM)) { if (amsound && (state->std & V4L2_STD_SECAM)) {
/* autodetect doesn't work well with AM ... */ /* autodetect doesn't work well with AM ... */
max1 = 3; max1 = 3;
count = 0; count = 0;
...@@ -547,7 +546,7 @@ int msp3400c_thread(void *data) ...@@ -547,7 +546,7 @@ int msp3400c_thread(void *data)
break; break;
} }
if (amsound && (state->norm == VIDEO_MODE_SECAM)) { if (amsound && (state->std & V4L2_STD_SECAM)) {
/* autodetect doesn't work well with AM ... */ /* autodetect doesn't work well with AM ... */
cd = NULL; cd = NULL;
count = 0; count = 0;
...@@ -576,7 +575,7 @@ int msp3400c_thread(void *data) ...@@ -576,7 +575,7 @@ int msp3400c_thread(void *data)
state->nicam_on = 0; state->nicam_on = 0;
msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO); msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
state->watch_stereo = 1; state->watch_stereo = 1;
} else if (max2 == 1 && HAVE_NICAM(state)) { } else if (max2 == 1 && state->has_nicam) {
/* B/G NICAM */ /* B/G NICAM */
state->second = msp3400c_carrier_detect_55[max2].cdo; state->second = msp3400c_carrier_detect_55[max2].cdo;
msp3400c_setmode(client, MSP_MODE_FM_NICAM1); msp3400c_setmode(client, MSP_MODE_FM_NICAM1);
...@@ -603,8 +602,7 @@ int msp3400c_thread(void *data) ...@@ -603,8 +602,7 @@ int msp3400c_thread(void *data)
state->nicam_on = 0; state->nicam_on = 0;
msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO); msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
state->watch_stereo = 1; state->watch_stereo = 1;
} else if (max2 == 0 && } else if (max2 == 0 && (state->std & V4L2_STD_SECAM)) {
state->norm == VIDEO_MODE_SECAM) {
/* L NICAM or AM-mono */ /* L NICAM or AM-mono */
state->second = msp3400c_carrier_detect_65[max2].cdo; state->second = msp3400c_carrier_detect_65[max2].cdo;
msp3400c_setmode(client, MSP_MODE_AM_NICAM); msp3400c_setmode(client, MSP_MODE_AM_NICAM);
...@@ -614,7 +612,7 @@ int msp3400c_thread(void *data) ...@@ -614,7 +612,7 @@ int msp3400c_thread(void *data)
/* volume prescale for SCART (AM mono input) */ /* volume prescale for SCART (AM mono input) */
msp_write_dsp(client, 0x000d, 0x1900); msp_write_dsp(client, 0x000d, 0x1900);
state->watch_stereo = 1; state->watch_stereo = 1;
} else if (max2 == 0 && HAVE_NICAM(state)) { } else if (max2 == 0 && state->has_nicam) {
/* D/K NICAM */ /* D/K NICAM */
state->second = msp3400c_carrier_detect_65[max2].cdo; state->second = msp3400c_carrier_detect_65[max2].cdo;
msp3400c_setmode(client, MSP_MODE_FM_NICAM1); msp3400c_setmode(client, MSP_MODE_FM_NICAM1);
...@@ -689,8 +687,8 @@ int msp3410d_thread(void *data) ...@@ -689,8 +687,8 @@ int msp3410d_thread(void *data)
goto restart; goto restart;
/* start autodetect */ /* start autodetect */
mode = msp_modus(client, state->norm); mode = msp_modus(client);
std = msp_standard(state->norm); std = (state->std & V4L2_STD_NTSC) ? 0x20 : 1;
msp_write_dem(client, 0x30, mode); msp_write_dem(client, 0x30, mode);
msp_write_dem(client, 0x20, std); msp_write_dem(client, 0x20, std);
state->watch_stereo = 0; state->watch_stereo = 0;
...@@ -723,7 +721,7 @@ int msp3410d_thread(void *data) ...@@ -723,7 +721,7 @@ int msp3410d_thread(void *data)
state->main = msp_modelist[i].main; state->main = msp_modelist[i].main;
state->second = msp_modelist[i].second; state->second = msp_modelist[i].second;
if (amsound && (state->norm == VIDEO_MODE_SECAM) && (val != 0x0009)) { if (amsound && (state->std & V4L2_STD_SECAM) && (val != 0x0009)) {
/* autodetection has failed, let backup */ /* autodetection has failed, let backup */
v4l_dbg(1, client, "autodetection failed," v4l_dbg(1, client, "autodetection failed,"
" switching to backup mode: %s (0x%04x)\n", " switching to backup mode: %s (0x%04x)\n",
...@@ -767,12 +765,12 @@ int msp3410d_thread(void *data) ...@@ -767,12 +765,12 @@ int msp3410d_thread(void *data)
msp3400c_setstereo(client,V4L2_TUNER_MODE_STEREO); msp3400c_setstereo(client,V4L2_TUNER_MODE_STEREO);
break; break;
case 0x0040: /* FM radio */ case 0x0040: /* FM radio */
state->mode = MSP_MODE_FM_RADIO; state->mode = MSP_MODE_FM_RADIO;
state->rxsubchans = V4L2_TUNER_SUB_STEREO; state->rxsubchans = V4L2_TUNER_SUB_STEREO;
state->audmode = V4L2_TUNER_MODE_STEREO; state->audmode = V4L2_TUNER_MODE_STEREO;
state->nicam_on = 0; state->nicam_on = 0;
state->watch_stereo = 0; state->watch_stereo = 0;
/* not needed in theory if HAVE_RADIO(), but /* not needed in theory if we have radio, but
short programming enables carrier mute */ short programming enables carrier mute */
msp3400c_setmode(client,MSP_MODE_FM_RADIO); msp3400c_setmode(client,MSP_MODE_FM_RADIO);
msp3400c_setcarrier(client, MSP_CARRIER(10.7), msp3400c_setcarrier(client, MSP_CARRIER(10.7),
...@@ -872,8 +870,11 @@ static int msp34xxg_reset(struct i2c_client *client) ...@@ -872,8 +870,11 @@ static int msp34xxg_reset(struct i2c_client *client)
msp_write_dem(client, 0x40, state->i2s_mode); msp_write_dem(client, 0x40, state->i2s_mode);
/* step-by-step initialisation, as described in the manual */ /* step-by-step initialisation, as described in the manual */
modus = msp_modus(client, state->norm); modus = msp_modus(client);
std = msp_standard(state->norm); if (state->radio)
std = 0x40;
else
std = (state->std & V4L2_STD_NTSC) ? 0x20 : 1;
modus &= ~0x03; /* STATUS_CHANGE = 0 */ modus &= ~0x03; /* STATUS_CHANGE = 0 */
modus |= 0x01; /* AUTOMATIC_SOUND_DETECTION = 1 */ modus |= 0x01; /* AUTOMATIC_SOUND_DETECTION = 1 */
if (msp_write_dem(client, 0x30, modus)) if (msp_write_dem(client, 0x30, modus))
......
...@@ -57,10 +57,21 @@ extern int stereo_threshold; ...@@ -57,10 +57,21 @@ extern int stereo_threshold;
struct msp_state { struct msp_state {
int rev1, rev2; int rev1, rev2;
int has_nicam;
int has_radio;
int has_headphones;
int has_ntsc_jp_d_k3;
int has_scart4;
int has_scart23_in_scart2_out;
int has_subwoofer;
int has_sound_processing;
int has_virtual_dolby_surround;
int has_dolby_pro_logic;
int radio;
int opmode; int opmode;
int mode; int mode;
int norm; v4l2_std_id std;
int stereo; int stereo;
int nicam_on; int nicam_on;
int acb; int acb;
...@@ -85,11 +96,6 @@ struct msp_state { ...@@ -85,11 +96,6 @@ struct msp_state {
int watch_stereo:1; int watch_stereo:1;
}; };
#define VIDEO_MODE_RADIO 16 /* norm magic for radio mode */
#define HAVE_NICAM(state) (((state->rev2 >> 8) & 0xff) != 0)
#define HAVE_RADIO(state) ((state->rev1 & 0x0f) >= 'G'-'@')
/* msp3400-driver.c */ /* msp3400-driver.c */
int msp_write_dem(struct i2c_client *client, int addr, int val); int msp_write_dem(struct i2c_client *client, int addr, int val);
int msp_write_dsp(struct i2c_client *client, int addr, int val); int msp_write_dsp(struct i2c_client *client, int addr, int val);
...@@ -99,8 +105,7 @@ int msp_reset(struct i2c_client *client); ...@@ -99,8 +105,7 @@ int msp_reset(struct i2c_client *client);
void msp_set_scart(struct i2c_client *client, int in, int out); void msp_set_scart(struct i2c_client *client, int in, int out);
void msp_set_mute(struct i2c_client *client); void msp_set_mute(struct i2c_client *client);
void msp_set_audio(struct i2c_client *client); void msp_set_audio(struct i2c_client *client);
int msp_modus(struct i2c_client *client, int norm); int msp_modus(struct i2c_client *client);
int msp_standard(int norm);
int msp_sleep(struct msp_state *state, int timeout); int msp_sleep(struct msp_state *state, int timeout);
/* msp3400-kthreads.c */ /* msp3400-kthreads.c */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment