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: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@brturbo.com.br>
diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c
index fbd8512..0c2ab7e 100644
--- a/drivers/media/video/msp3400-driver.c
+++ b/drivers/media/video/msp3400-driver.c
@@ -312,10 +312,16 @@
 	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) {
-	case VIDEO_MODE_PAL:
+	struct msp_state *state = i2c_get_clientdata(client);
+
+	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");
 
 #if 1
@@ -325,37 +331,16 @@
 		/* previous value, try this if it breaks ... */
 		return 0x1003;
 #endif
-	case VIDEO_MODE_NTSC:  /* BTSC */
+	}
+	if (state->std & V4L2_STD_NTSC) {
 		v4l_dbg(1, client, "video mode selected to NTSC\n");
 		return 0x2003;
-	case VIDEO_MODE_SECAM:
+	}
+	if (state->std & V4L2_STD_SECAM) {
 		v4l_dbg(1, client, "video mode selected to SECAM\n");
 		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 @@
 		break;
 
 	case AUDC_SET_RADIO:
-		state->norm = VIDEO_MODE_RADIO;
+		state->radio = 1;
 		v4l_dbg(1, client, "switching to radio mode\n");
 		state->watch_stereo = 0;
 		switch (state->opmode) {
@@ -673,7 +658,7 @@
 		state->treble = va->treble;
 		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));
 		break;
 	}
@@ -682,7 +667,13 @@
 	{
 		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);
 		break;
 	}
@@ -709,15 +700,8 @@
 	{
 		v4l2_std_id *id = arg;
 
-		/*FIXME: use V4L2 mode flags on msp3400 instead of V4L1*/
-		if (*id & V4L2_STD_PAL) {
-			state->norm = VIDEO_MODE_PAL;
-		} else if (*id & V4L2_STD_SECAM) {
-			state->norm = VIDEO_MODE_SECAM;
-		} else {
-			state->norm = VIDEO_MODE_NTSC;
-		}
-
+		state->std = *id;
+		state->radio = 0;
 		msp_wake_thread(client);
 		return 0;
 	}
@@ -965,6 +949,11 @@
 	struct i2c_client *client;
 	struct msp_state *state;
 	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);
 	if (client == NULL)
@@ -989,7 +978,7 @@
 	i2c_set_clientdata(client, state);
 
 	memset(state, 0, sizeof(*state));
-	state->norm = VIDEO_MODE_NTSC;
+	state->std = V4L2_STD_NTSC;
 	state->volume = 58880;	/* 0db gain */
 	state->balance = 32768;	/* 0db gain */
 	state->bass = 32768;
@@ -1012,20 +1001,45 @@
 
 	msp_set_audio(client);
 
-	snprintf(client->name, sizeof(client->name), "MSP%c4%02d%c-%c%d",
-		 ((state->rev1 >> 4) & 0x0f) + '3',
-		 (state->rev2 >> 8) & 0xff,
-		 (state->rev1 & 0x0f) + '@',
-		 ((state->rev1 >> 8) & 0xff) + '@',
-		 state->rev2 & 0x1f);
+	msp_family = ((state->rev1 >> 4) & 0x0f) + 3;
+	msp_product = (state->rev2 >> 8) & 0xff;
+	msp_prod_hi = msp_product / 10;
+	msp_prod_lo = msp_product % 10;
+	msp_revision = (state->rev1 & 0x0f) + '@';
+	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;
 	if (state->opmode == OPMODE_AUTO) {
 		/* MSP revision G and up have both autodetect and autoselect */
-		if ((state->rev1 & 0x0f) >= 'G'-'@')
+		if (msp_revision >= 'G')
 			state->opmode = OPMODE_AUTOSELECT;
 		/* MSP revision D and up have autodetect */
-		else if ((state->rev1 & 0x0f) >= 'D'-'@')
+		else if (msp_revision >= 'D')
 			state->opmode = OPMODE_AUTODETECT;
 		else
 			state->opmode = OPMODE_MANUAL;
@@ -1034,11 +1048,11 @@
 	/* hello world :-) */
 	v4l_info(client, "%s found @ 0x%x (%s)\n", client->name, address << 1, adapter->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, ");
-	else if (HAVE_NICAM(state))
+	else if (state->has_nicam)
 		printk("supports nicam, ");
-	else if (HAVE_RADIO(state))
+	else if (state->has_radio)
 		printk("supports radio, ");
 	printk("mode is ");