V4L/DVB (4050): Add NTSC sliced VBI support to the cx25840 module.

NTSC sliced VBI support by Christopher Neufeld <television@cneufeld.ca>
with additional fixes by Hans Verkuil <hverkuil@xs4all.nl>.

Signed-off-by: Christopher Neufeld <television@cneufeld.ca>
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c
index e4655e3..6d7207e 100644
--- a/drivers/media/video/cx25840/cx25840-core.c
+++ b/drivers/media/video/cx25840/cx25840-core.c
@@ -10,6 +10,9 @@
  *
  * VBI support by Hans Verkuil <hverkuil@xs4all.nl>.
  *
+ * NTSC sliced VBI support by Christopher Neufeld <television@cneufeld.ca>
+ * with additional fixes by Hans Verkuil <hverkuil@xs4all.nl>.
+ *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2
@@ -982,6 +985,7 @@
 	state->audclk_freq = 48000;
 	state->pvr150_workaround = 0;
 	state->audmode = V4L2_TUNER_MODE_LANG1;
+	state->vbi_line_offset = 8;
 	state->id = id;
 
 	if (state->is_cx25836)
diff --git a/drivers/media/video/cx25840/cx25840-core.h b/drivers/media/video/cx25840/cx25840-core.h
index 69d7bd2..b132192 100644
--- a/drivers/media/video/cx25840/cx25840-core.h
+++ b/drivers/media/video/cx25840/cx25840-core.h
@@ -40,6 +40,7 @@
 	enum cx25840_audio_input aud_input;
 	u32 audclk_freq;
 	int audmode;
+	int vbi_line_offset;
 	enum v4l2_chip_ident id;
 	int is_cx25836;
 };
diff --git a/drivers/media/video/cx25840/cx25840-vbi.c b/drivers/media/video/cx25840/cx25840-vbi.c
index 57feca2..c124974 100644
--- a/drivers/media/video/cx25840/cx25840-vbi.c
+++ b/drivers/media/video/cx25840/cx25840-vbi.c
@@ -84,6 +84,7 @@
 
 void cx25840_vbi_setup(struct i2c_client *client)
 {
+	struct cx25840_state *state = i2c_get_clientdata(client);
 	v4l2_std_id std = cx25840_get_v4lstd(client);
 
 	if (std & ~V4L2_STD_NTSC) {
@@ -117,6 +118,7 @@
 
 		cx25840_write(client, 0x47e, 0x0a);
 		cx25840_write(client, 0x47f, 0x01);
+		state->vbi_line_offset = 5;
 	} else {
 		/* datasheet startup, step 8d */
 		cx25840_write(client, 0x49f, 0x14);
@@ -140,11 +142,13 @@
 		cx25840_write(client, 0x47d, 0x7c);
 		cx25840_write(client, 0x47e, 0x08);
 		cx25840_write(client, 0x47f, 0x00);
+		state->vbi_line_offset = 8;
 	}
 }
 
 int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg)
 {
+	struct cx25840_state *state = i2c_get_clientdata(client);
 	struct v4l2_format *fmt;
 	struct v4l2_sliced_vbi_format *svbi;
 
@@ -211,7 +215,7 @@
 		cx25840_vbi_setup(client);
 
 		/* Sliced VBI */
-		cx25840_write(client, 0x404, 0x36);	/* Ancillery data */
+		cx25840_write(client, 0x404, 0x32);	/* Ancillary data */
 		cx25840_write(client, 0x406, 0x13);
 		cx25840_write(client, 0x47f, vbi_offset);
 
@@ -248,8 +252,18 @@
 			}
 		}
 
-		for (x = 1, i = 0x424; i <= 0x434; i++, x++) {
-			cx25840_write(client, i, lcr[6 + x]);
+		if (is_pal) {
+			for (x = 1, i = 0x424; i <= 0x434; i++, x++) {
+				cx25840_write(client, i, lcr[6 + x]);
+			}
+		}
+		else {
+			for (x = 1, i = 0x424; i <= 0x430; i++, x++) {
+				cx25840_write(client, i, lcr[9 + x]);
+			}
+			for (i = 0x431; i <= 0x434; i++) {
+				cx25840_write(client, i, 0);
+			}
 		}
 
 		cx25840_write(client, 0x43c, 0x16);
@@ -257,7 +271,7 @@
 		if (is_pal) {
 			cx25840_write(client, 0x474, 0x2a);
 		} else {
-			cx25840_write(client, 0x474, 0x1a + 6);
+			cx25840_write(client, 0x474, 0x22);
 		}
 		break;
 	}
@@ -278,7 +292,7 @@
 		id1 = p[-1];
 		id2 = p[0] & 0xf;
 		l = p[2] & 0x3f;
-		l += 5;
+		l += state->vbi_line_offset;
 		p += 4;
 
 		switch (id2) {