From f98c55ea18e87905bdf69eb4a187e94572ed9494 Mon Sep 17 00:00:00 2001
From: Hans Verkuil <hverkuil@xs4all.nl>
Date: Mon, 9 Jan 2006 15:25:18 -0200
Subject: V4L/DVB (3116): tda9887 improvements: better defaults, better
 configurability.

- Set the tuner takeover point to 0x10 for NTSC/radio and 0x14 for PAL/SECAM.
- Allow override through TDA9887_SET_CONFIG
- PAL-N belongs with PAL-BG as does PAL-H. PAL-Nc belongs to PAL-M
- Add SECAM-BGH
- Set video freq to cVideoIF_38_90 for DK standards.
- Add cTunerGainLow to radio, change deemphasis to 75 for mono.
- Add ntsc module param for 'M' and 'J' (Japanese) standards.
- Fix module handling for 2.4.
- Now able to select all standards through pal/secam/ntsc module options

Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@brturbo.com.br>
---
 drivers/media/video/tda9887.c | 164 +++++++++++++++++++++++++++++++++---------
 include/media/tuner.h         |  31 ++++----
 2 files changed, 150 insertions(+), 45 deletions(-)

diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c
index ceaa29975c8e..32f133ed0b0b 100644
--- a/drivers/media/video/tda9887.c
+++ b/drivers/media/video/tda9887.c
@@ -114,6 +114,9 @@ static struct i2c_client client_template;
 #define cAudioGain0             0x00    // bit c7
 #define cAudioGain6             0x80    // bit c7
 
+#define cTopMask                0x1f    // bit c0:4
+#define cTopPalSecamDefault	0x14 	// bit c0:4
+#define cTopNtscRadioDefault 	0x10 	// bit c0:4
 
 //// third reg (e)
 #define cAudioIF_4_5             0x00    // bit e0:1
@@ -145,13 +148,15 @@ static struct i2c_client client_template;
 
 static struct tvnorm tvnorms[] = {
 	{
-		.std   = V4L2_STD_PAL_BG,
-		.name  = "PAL-BG",
+		.std   = V4L2_STD_PAL_BG | V4L2_STD_PAL_H | V4L2_STD_PAL_N,
+		.name  = "PAL-BGHN",
 		.b     = ( cNegativeFmTV  |
 			   cQSS           ),
 		.c     = ( cDeemphasisON  |
-			   cDeemphasis50  ),
-		.e     = ( cAudioIF_5_5   |
+			   cDeemphasis50  |
+			   cTopPalSecamDefault),
+		.e     = ( cGating_36     |
+			   cAudioIF_5_5   |
 			   cVideoIF_38_90 ),
 	},{
 		.std   = V4L2_STD_PAL_I,
@@ -159,8 +164,10 @@ static struct tvnorm tvnorms[] = {
 		.b     = ( cNegativeFmTV  |
 			   cQSS           ),
 		.c     = ( cDeemphasisON  |
-			   cDeemphasis50  ),
-		.e     = ( cAudioIF_6_0   |
+			   cDeemphasis50  |
+			   cTopPalSecamDefault),
+		.e     = ( cGating_36     |
+			   cAudioIF_6_0   |
 			   cVideoIF_38_90 ),
 	},{
 		.std   = V4L2_STD_PAL_DK,
@@ -168,23 +175,37 @@ static struct tvnorm tvnorms[] = {
 		.b     = ( cNegativeFmTV  |
 			   cQSS           ),
 		.c     = ( cDeemphasisON  |
-			   cDeemphasis50  ),
-		.e     = ( cAudioIF_6_5   |
-			   cVideoIF_38_00 ),
+			   cDeemphasis50  |
+			   cTopPalSecamDefault),
+		.e     = ( cGating_36     |
+			   cAudioIF_6_5   |
+			   cVideoIF_38_90 ),
 	},{
-		.std   = V4L2_STD_PAL_M | V4L2_STD_PAL_N,
-		.name  = "PAL-M/N",
+		.std   = V4L2_STD_PAL_M | V4L2_STD_PAL_Nc,
+		.name  = "PAL-M/Nc",
 		.b     = ( cNegativeFmTV  |
 			   cQSS           ),
 		.c     = ( cDeemphasisON  |
-			   cDeemphasis75  ),
-		.e     = ( cAudioIF_4_5   |
+			   cDeemphasis75  |
+			   cTopNtscRadioDefault),
+		.e     = ( cGating_36     |
+			   cAudioIF_4_5   |
 			   cVideoIF_45_75 ),
+	},{
+		.std   = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H,
+		.name  = "SECAM-BGH",
+		.b     = ( cPositiveAmTV  |
+			   cQSS           ),
+		.c     = ( cTopPalSecamDefault),
+		.e     = ( cGating_36	  |
+			   cAudioIF_5_5   |
+			   cVideoIF_38_90 ),
 	},{
 		.std   = V4L2_STD_SECAM_L,
 		.name  = "SECAM-L",
 		.b     = ( cPositiveAmTV  |
 			   cQSS           ),
+		.c     = ( cTopPalSecamDefault),
 		.e     = ( cGating_36	  |
 			   cAudioIF_6_5   |
 			   cVideoIF_38_90 ),
@@ -194,6 +215,7 @@ static struct tvnorm tvnorms[] = {
 		.b     = ( cOutputPort2Inactive |
 			   cPositiveAmTV  |
 			   cQSS           ),
+		.c     = ( cTopPalSecamDefault),
 		.e     = ( cGating_36	  |
 			   cAudioIF_6_5   |
 			   cVideoIF_33_90 ),
@@ -203,26 +225,30 @@ static struct tvnorm tvnorms[] = {
 		.b     = ( cNegativeFmTV  |
 			   cQSS           ),
 		.c     = ( cDeemphasisON  |
-			   cDeemphasis50  ),
-		.e     = ( cAudioIF_6_5   |
-			   cVideoIF_38_00 ),
+			   cDeemphasis50  |
+			   cTopPalSecamDefault),
+		.e     = ( cGating_36     |
+			   cAudioIF_6_5   |
+			   cVideoIF_38_90 ),
 	},{
 		.std   = V4L2_STD_NTSC_M,
 		.name  = "NTSC-M",
 		.b     = ( cNegativeFmTV  |
 			   cQSS           ),
 		.c     = ( cDeemphasisON  |
-			   cDeemphasis75  ),
+			   cDeemphasis75  |
+			   cTopNtscRadioDefault),
 		.e     = ( cGating_36     |
 			   cAudioIF_4_5   |
 			   cVideoIF_45_75 ),
 	},{
 		.std   = V4L2_STD_NTSC_M_JP,
-		.name  = "NTSC-JP",
+		.name  = "NTSC-M-JP",
 		.b     = ( cNegativeFmTV  |
 			   cQSS           ),
 		.c     = ( cDeemphasisON  |
-			   cDeemphasis50  ),
+			   cDeemphasis50  |
+			   cTopNtscRadioDefault),
 		.e     = ( cGating_36     |
 			   cAudioIF_4_5   |
 			   cVideoIF_58_75 ),
@@ -234,8 +260,10 @@ static struct tvnorm radio_stereo = {
 	.b    = ( cFmRadio       |
 		  cQSS           ),
 	.c    = ( cDeemphasisOFF |
-		  cAudioGain6 ),
-	.e    = ( cAudioIF_5_5   |
+		  cAudioGain6    |
+		  cTopNtscRadioDefault),
+	.e    = ( cTunerGainLow  |
+		  cAudioIF_5_5   |
 		  cRadioIF_38_90 ),
 };
 
@@ -244,8 +272,10 @@ static struct tvnorm radio_mono = {
 	.b    = ( cFmRadio       |
 		  cQSS           ),
 	.c    = ( cDeemphasisON  |
-		  cDeemphasis50),
-	.e    = ( cAudioIF_5_5   |
+		  cDeemphasis75  |
+		  cTopNtscRadioDefault),
+	.e    = ( cTunerGainLow  |
+		  cAudioIF_5_5   |
 		  cRadioIF_38_90 ),
 };
 
@@ -408,7 +438,8 @@ static int tda9887_set_tvnorm(struct tda9887 *t, char *buf)
 static unsigned int port1  = UNSET;
 static unsigned int port2  = UNSET;
 static unsigned int qss    = UNSET;
-static unsigned int adjust = 0x10;
+static unsigned int adjust = UNSET;
+
 module_param(port1, int, 0644);
 module_param(port2, int, 0644);
 module_param(qss, int, 0644);
@@ -436,8 +467,10 @@ static int tda9887_set_insmod(struct tda9887 *t, char *buf)
 			buf[1] &= ~cQSS;
 	}
 
-	if (adjust >= 0x00 && adjust < 0x20)
+	if (adjust >= 0x00 && adjust < 0x20) {
+		buf[2] &= ~cTopMask;
 		buf[2] |= adjust;
+	}
 	return 0;
 }
 
@@ -473,6 +506,10 @@ static int tda9887_set_config(struct tda9887 *t, char *buf)
 			break;
 		}
 	}
+	if (t->config & TDA9887_TOP_SET) {
+		buf[2] &= ~cTopMask;
+		buf[2] |= (t->config >> 8) & cTopMask;
+	}
 	if ((t->config & TDA9887_INTERCARRIER_NTSC) && (t->std & V4L2_STD_NTSC))
 		buf[1] &= ~cQSS;
 	return 0;
@@ -480,10 +517,13 @@ static int tda9887_set_config(struct tda9887 *t, char *buf)
 
 /* ---------------------------------------------------------------------- */
 
-static char pal[] = "-";
+static char pal[] = "--";
+static char secam[] = "--";
+static char ntsc[] = "-";
+
 module_param_string(pal, pal, sizeof(pal), 0644);
-static char secam[] = "-";
 module_param_string(secam, secam, sizeof(secam), 0644);
+module_param_string(ntsc, ntsc, sizeof(ntsc), 0644);
 
 static int tda9887_fixup_std(struct tda9887 *t)
 {
@@ -494,8 +534,17 @@ static int tda9887_fixup_std(struct tda9887 *t)
 		case 'B':
 		case 'g':
 		case 'G':
-			tda9887_dbg("insmod fixup: PAL => PAL-BG\n");
-			t->std = V4L2_STD_PAL_BG;
+		case 'h':
+		case 'H':
+		case 'n':
+		case 'N':
+			if (pal[1] == 'c' || pal[1] == 'C') {
+				tda9887_dbg("insmod fixup: PAL => PAL-Nc\n");
+				t->std = V4L2_STD_PAL_Nc;
+			} else {
+				tda9887_dbg("insmod fixup: PAL => PAL-BGHN\n");
+				t->std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H | V4L2_STD_PAL_N;
+			}
 			break;
 		case 'i':
 		case 'I':
@@ -509,6 +558,11 @@ static int tda9887_fixup_std(struct tda9887 *t)
 			tda9887_dbg("insmod fixup: PAL => PAL-DK\n");
 			t->std = V4L2_STD_PAL_DK;
 			break;
+		case 'm':
+		case 'M':
+			tda9887_dbg("insmod fixup: PAL => PAL-M\n");
+			t->std = V4L2_STD_PAL_M;
+			break;
 		case '-':
 			/* default parameter, do nothing */
 			break;
@@ -519,6 +573,15 @@ static int tda9887_fixup_std(struct tda9887 *t)
 	}
 	if ((t->std & V4L2_STD_SECAM) == V4L2_STD_SECAM) {
 		switch (secam[0]) {
+		case 'b':
+		case 'B':
+		case 'g':
+		case 'G':
+		case 'h':
+		case 'H':
+			tda9887_dbg("insmod fixup: SECAM => SECAM-BGH\n");
+			t->std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H;
+			break;
 		case 'd':
 		case 'D':
 		case 'k':
@@ -528,8 +591,13 @@ static int tda9887_fixup_std(struct tda9887 *t)
 			break;
 		case 'l':
 		case 'L':
-			tda9887_dbg("insmod fixup: SECAM => SECAM-L\n");
-			t->std = V4L2_STD_SECAM_L;
+			if (secam[1] == 'c' || secam[1] == 'C') {
+				tda9887_dbg("insmod fixup: SECAM => SECAM-L'\n");
+				t->std = V4L2_STD_SECAM_LC;
+			} else {
+				tda9887_dbg("insmod fixup: SECAM => SECAM-L\n");
+				t->std = V4L2_STD_SECAM_L;
+			}
 			break;
 		case '-':
 			/* default parameter, do nothing */
@@ -539,6 +607,26 @@ static int tda9887_fixup_std(struct tda9887 *t)
 			break;
 		}
 	}
+	if ((t->std & V4L2_STD_NTSC) == V4L2_STD_NTSC) {
+		switch (ntsc[0]) {
+		case 'm':
+		case 'M':
+			tda9887_dbg("insmod fixup: NTSC => NTSC-M\n");
+			t->std = V4L2_STD_NTSC_M;
+			break;
+		case 'j':
+		case 'J':
+			tda9887_dbg("insmod fixup: NTSC => NTSC_M_JP\n");
+			t->std = V4L2_STD_NTSC_M_JP;
+			break;
+		case '-':
+			/* default parameter, do nothing */
+			break;
+		default:
+			tda9887_info("ntsc= argument not recognised\n");
+			break;
+		}
+	}
 	return 0;
 }
 
@@ -561,6 +649,19 @@ static int tda9887_configure(struct tda9887 *t)
 	memset(t->data,0,sizeof(t->data));
 	tda9887_set_tvnorm(t,t->data);
 
+	/* A note on the port settings:
+	   These settings tend to depend on the specifics of the board.
+	   By default they are set to inactive (bit value 1) by this driver,
+	   overwriting any changes made by the tvnorm. This means that it
+	   is the responsibility of the module using the tda9887 to set
+	   these values in case of changes in the tvnorm.
+	   In many cases port 2 should be made active (0) when selecting
+	   SECAM-L, and port 2 should remain inactive (1) for SECAM-L'.
+
+	   For the other standards the tda9887 application note says that
+	   the ports should be set to active (0), but, again, that may
+	   differ depending on the precise hardware configuration.
+	 */
 	t->data[1] |= cOutputPort1Inactive;
 	t->data[1] |= cOutputPort2Inactive;
 
@@ -571,7 +672,6 @@ static int tda9887_configure(struct tda9887 *t)
 		t->data[1] |= cForcedMuteAudioON;
 	}
 
-
 	tda9887_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n",
 		t->data[1],t->data[2],t->data[3]);
 	if (debug > 1)
diff --git a/include/media/tuner.h b/include/media/tuner.h
index e224722a7ff7..567f05549e3a 100644
--- a/include/media/tuner.h
+++ b/include/media/tuner.h
@@ -120,20 +120,25 @@
 #define TDA9887_SET_CONFIG           _IOW('t',5,int)
 
 /* tv card specific */
-# define TDA9887_PRESENT             (1<<0)
-# define TDA9887_PORT1_INACTIVE      (1<<1)
-# define TDA9887_PORT2_INACTIVE      (1<<2)
-# define TDA9887_QSS                 (1<<3)
-# define TDA9887_INTERCARRIER        (1<<4)
-# define TDA9887_PORT1_ACTIVE        (1<<5)
-# define TDA9887_PORT2_ACTIVE        (1<<6)
-# define TDA9887_INTERCARRIER_NTSC   (1<<7)
+#define TDA9887_PRESENT 		(1<<0)
+#define TDA9887_PORT1_INACTIVE 		(1<<1)
+#define TDA9887_PORT2_INACTIVE 		(1<<2)
+#define TDA9887_QSS 			(1<<3)
+#define TDA9887_INTERCARRIER 		(1<<4)
+#define TDA9887_PORT1_ACTIVE 		(1<<5)
+#define TDA9887_PORT2_ACTIVE 		(1<<6)
+#define TDA9887_INTERCARRIER_NTSC 	(1<<7)
+/* Tuner takeover point adjustment, in dB, -16 <= top <= 15 */
+#define TDA9887_TOP_MASK 		(0x3f << 8)
+#define TDA9887_TOP_SET 		(1 << 13)
+#define TDA9887_TOP(top) 		(TDA9887_TOP_SET | (((16 + (top)) & 0x1f) << 8))
+
 /* config options */
-# define TDA9887_DEEMPHASIS_MASK     (3<<16)
-# define TDA9887_DEEMPHASIS_NONE     (1<<16)
-# define TDA9887_DEEMPHASIS_50       (2<<16)
-# define TDA9887_DEEMPHASIS_75       (3<<16)
-# define TDA9887_AUTOMUTE            (1<<18)
+#define TDA9887_DEEMPHASIS_MASK 	(3<<16)
+#define TDA9887_DEEMPHASIS_NONE 	(1<<16)
+#define TDA9887_DEEMPHASIS_50 		(2<<16)
+#define TDA9887_DEEMPHASIS_75 		(3<<16)
+#define TDA9887_AUTOMUTE 		(1<<18)
 
 #ifdef __KERNEL__
 
-- 
cgit v1.2.1