This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

AM/DM3730 and TVP5151 Interlacing Issues

Other Parts Discussed in Thread: TVP5151, DM3730, TVP5150, SYSCONFIG, TVP5150AM1

I have tried everything I can think of to get this working, so any ideas or help would be greatly appreciated. I have included everything I know below, hopefully it will be enough.

A little background as to the configuration I have, I am using the DM3730 Torpedo SOM by Logic PD on their development board. I am also using the TVP5151EVM board on which I have disconnected the i2c communications from the USB and wired in the i2c from the DM3730. The DM3730 is running the linux image that was provided by Logic PD which is running kernel 3.0. I had to modify the TVP5151 driver a bit to get it working, I have attached that file.

/*
 * tvp5150 - Texas Instruments TVP5150A/AM1 video decoder driver
 *
 * Copyright (c) 2005,2006 Mauro Carvalho Chehab (mchehab@infradead.org)
 * This code is placed under the terms of the GNU General Public License v2
 */

#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/videodev2.h>
#include <linux/delay.h>
#include <media/v4l2-device.h>
#include <media/tvp5150.h>
#include <media/v4l2-chip-ident.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-subdev.h>
#include <media/v4l2-mediabus.h>
#include "omap3isp/isp.h"

#include "tvp5150_reg.h"

MODULE_DESCRIPTION("Texas Instruments TVP5150A video decoder driver");
MODULE_AUTHOR("Mauro Carvalho Chehab");
MODULE_LICENSE("GPL");


static int debug;
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "Debug level (0-2)");

/* enum tvp515x_std - enum for supported standards */
enum tvp515x_std {
	STD_PAL_BDGHIN = 0,
	STD_NTSC_MJ,
	STD_INVALID
};

/**
 * struct tvp515x_std_info - Structure to store standard informations
 * @width: Line width in pixels
 * @height:Number of active lines
 * @video_std: Value to write in REG_VIDEO_STD register
 * @standard: v4l2 standard structure information
 */
struct tvp515x_std_info {
	u8 video_std;
	struct v4l2_standard standard;
	struct v4l2_mbus_framefmt format;
};

/**
 * Supported standards -
 *
 * Currently supports two standards only, need to add support for rest of the
 * modes, like SECAM, etc...
 */
static struct tvp515x_std_info tvp515x_std_list[] = {
	/* Standard: STD_NTSC_MJ */
	/* Standard: STD_PAL_BDGHIN */
	[STD_PAL_BDGHIN] = {
		.video_std = VIDEO_STD_PAL_BDGHIN_BIT,
		.standard = {
			.index = 1,
			.id = V4L2_STD_PAL,
			.name = "PAL",
			.frameperiod = {1, 25},
			.framelines = 625
		},
		.format = {
			.width = PAL_NUM_ACTIVE_PIXELS,
			.height = PAL_NUM_ACTIVE_LINES,
			.code = V4L2_MBUS_FMT_UYVY8_2X8,
			.field = V4L2_FIELD_INTERLACED,
			.colorspace = V4L2_COLORSPACE_SMPTE170M,
		},
	},
	[STD_NTSC_MJ] = {
		.video_std = VIDEO_STD_NTSC_MJ_BIT,
		.standard = {
			.index = 0,
			.id = V4L2_STD_NTSC,
			.name = "NTSC",
			.frameperiod = {1001, 30000},
			.framelines = 525
		},
		.format = {
			.width = NTSC_NUM_ACTIVE_PIXELS,
			.height = NTSC_NUM_ACTIVE_LINES,
			.code = V4L2_MBUS_FMT_UYVY8_2X8,
			.field = V4L2_FIELD_INTERLACED,
			.colorspace = V4L2_COLORSPACE_SMPTE170M,
		},
	},
	/* Standard: need to add for additional standard */
};

struct tvp5150 {
	struct v4l2_subdev sd;
	struct v4l2_ctrl_handler hdl;
	struct media_pad pad;
	struct v4l2_mbus_framefmt *format;
	v4l2_std_id std_idx;
	int norm;
	u32 input;
	u32 output;
	int enable;
};

static inline struct tvp5150 *to_tvp5150(struct v4l2_subdev *sd)
{
	return container_of(sd, struct tvp5150, sd);
}

static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
{
	return &container_of(ctrl->handler, struct tvp5150, hdl)->sd;
}

static int tvp5150_read(struct v4l2_subdev *sd, unsigned char addr)
{
	struct i2c_client *c = v4l2_get_subdevdata(sd);
	unsigned char buffer[1];
	int rc;

	buffer[0] = addr;
	if (1 != (rc = i2c_master_send(c, buffer, 1)))
		v4l2_dbg(0, debug, sd, "i2c i/o error: rc == %d (should be 1)\n", rc);

	msleep(10);

	if (1 != (rc = i2c_master_recv(c, buffer, 1)))
		v4l2_dbg(0, debug, sd, "i2c i/o error: rc == %d (should be 1)\n", rc);

	v4l2_dbg(2, debug, sd, "tvp5150: read 0x%02x = 0x%02x\n", addr, buffer[0]);

	return (buffer[0]);
}

static inline void tvp5150_write(struct v4l2_subdev *sd, unsigned char addr,
				 unsigned char value)
{
	struct i2c_client *c = v4l2_get_subdevdata(sd);
	unsigned char buffer[2];
	int rc;

	buffer[0] = addr;
	buffer[1] = value;
	v4l2_dbg(2, debug, sd, "tvp5150: writing 0x%02x 0x%02x\n", buffer[0], buffer[1]);
	if (2 != (rc = i2c_master_send(c, buffer, 2)))
		v4l2_dbg(0, debug, sd, "i2c i/o error: rc == %d (should be 2)\n", rc);
}

static void dump_reg_range(struct v4l2_subdev *sd, char *s, u8 init,
				const u8 end, int max_line)
{
	int i = 0;

	while (init != (u8)(end + 1)) {
		if ((i % max_line) == 0) {
			if (i > 0)
				printk("\n");
			printk("tvp5150: %s reg 0x%02x = ", s, init);
		}
		printk("%02x ", tvp5150_read(sd, init));

		init++;
		i++;
	}
	printk("\n");
}

static int tvp5150_log_status(struct v4l2_subdev *sd)
{
	printk("tvp5150: Video input source selection #1 = 0x%02x\n",
			tvp5150_read(sd, TVP5150_VD_IN_SRC_SEL_1));
	printk("tvp5150: Analog channel controls = 0x%02x\n",
			tvp5150_read(sd, TVP5150_ANAL_CHL_CTL));
	printk("tvp5150: Operation mode controls = 0x%02x\n",
			tvp5150_read(sd, TVP5150_OP_MODE_CTL));
	printk("tvp5150: Miscellaneous controls = 0x%02x\n",
			tvp5150_read(sd, TVP5150_MISC_CTL));
	printk("tvp5150: Autoswitch mask= 0x%02x\n",
			tvp5150_read(sd, TVP5150_AUTOSW_MSK));
	printk("tvp5150: Color killer threshold control = 0x%02x\n",
			tvp5150_read(sd, TVP5150_COLOR_KIL_THSH_CTL));
	printk("tvp5150: Luminance processing controls #1 #2 and #3 = %02x %02x %02x\n",
			tvp5150_read(sd, TVP5150_LUMA_PROC_CTL_1),
			tvp5150_read(sd, TVP5150_LUMA_PROC_CTL_2),
			tvp5150_read(sd, TVP5150_LUMA_PROC_CTL_3));
	printk("tvp5150: Brightness control = 0x%02x\n",
			tvp5150_read(sd, TVP5150_BRIGHT_CTL));
	printk("tvp5150: Color saturation control = 0x%02x\n",
			tvp5150_read(sd, TVP5150_SATURATION_CTL));
	printk("tvp5150: Hue control = 0x%02x\n",
			tvp5150_read(sd, TVP5150_HUE_CTL));
	printk("tvp5150: Contrast control = 0x%02x\n",
			tvp5150_read(sd, TVP5150_CONTRAST_CTL));
	printk("tvp5150: Outputs and data rates select = 0x%02x\n",
			tvp5150_read(sd, TVP5150_DATA_RATE_SEL));
	printk("tvp5150: Configuration shared pins = 0x%02x\n",
			tvp5150_read(sd, TVP5150_CONF_SHARED_PIN));
	printk("tvp5150: Active video cropping start = 0x%02x%02x\n",
			tvp5150_read(sd, TVP5150_ACT_VD_CROP_ST_MSB),
			tvp5150_read(sd, TVP5150_ACT_VD_CROP_ST_LSB));
	printk("tvp5150: Active video cropping stop  = 0x%02x%02x\n",
			tvp5150_read(sd, TVP5150_ACT_VD_CROP_STP_MSB),
			tvp5150_read(sd, TVP5150_ACT_VD_CROP_STP_LSB));
	printk("tvp5150: Genlock/RTC = 0x%02x\n",
			tvp5150_read(sd, TVP5150_GENLOCK));
	printk("tvp5150: Horizontal sync start = 0x%02x\n",
			tvp5150_read(sd, TVP5150_HORIZ_SYNC_START));
	printk("tvp5150: Vertical blanking start = 0x%02x\n",
			tvp5150_read(sd, TVP5150_VERT_BLANKING_START));
	printk("tvp5150: Vertical blanking stop = 0x%02x\n",
			tvp5150_read(sd, TVP5150_VERT_BLANKING_STOP));
	printk("tvp5150: Chrominance processing control #1 and #2 = %02x %02x\n",
			tvp5150_read(sd, TVP5150_CHROMA_PROC_CTL_1),
			tvp5150_read(sd, TVP5150_CHROMA_PROC_CTL_2));
	printk("tvp5150: Interrupt reset register B = 0x%02x\n",
			tvp5150_read(sd, TVP5150_INT_RESET_REG_B));
	printk("tvp5150: Interrupt enable register B = 0x%02x\n",
			tvp5150_read(sd, TVP5150_INT_ENABLE_REG_B));
	printk("tvp5150: Interrupt configuration register B = 0x%02x\n",
			tvp5150_read(sd, TVP5150_INTT_CONFIG_REG_B));
	printk("tvp5150: Video standard = 0x%02x\n",
			tvp5150_read(sd, TVP5150_VIDEO_STD));
	printk("tvp5150: Chroma gain factor: Cb=0x%02x Cr=0x%02x\n",
			tvp5150_read(sd, TVP5150_CB_GAIN_FACT),
			tvp5150_read(sd, TVP5150_CR_GAIN_FACTOR));
	printk("tvp5150: Macrovision on counter = 0x%02x\n",
			tvp5150_read(sd, TVP5150_MACROVISION_ON_CTR));
	printk("tvp5150: Macrovision off counter = 0x%02x\n",
			tvp5150_read(sd, TVP5150_MACROVISION_OFF_CTR));
	printk("tvp5150: ITU-R BT.656.%d timing(TVP5150AM1 only)\n",
			(tvp5150_read(sd, TVP5150_REV_SELECT) & 1) ? 3 : 4);
	printk("tvp5150: Device ID = %02x%02x\n",
			tvp5150_read(sd, TVP5150_MSB_DEV_ID),
			tvp5150_read(sd, TVP5150_LSB_DEV_ID));
	printk("tvp5150: ROM version = (hex) %02x.%02x\n",
			tvp5150_read(sd, TVP5150_ROM_MAJOR_VER),
			tvp5150_read(sd, TVP5150_ROM_MINOR_VER));
	printk("tvp5150: Vertical line count = 0x%02x%02x\n",
			tvp5150_read(sd, TVP5150_VERT_LN_COUNT_MSB),
			tvp5150_read(sd, TVP5150_VERT_LN_COUNT_LSB));
	printk("tvp5150: Interrupt status register B = 0x%02x\n",
			tvp5150_read(sd, TVP5150_INT_STATUS_REG_B));
	printk("tvp5150: Interrupt active register B = 0x%02x\n",
			tvp5150_read(sd, TVP5150_INT_ACTIVE_REG_B));
	printk("tvp5150: Status regs #1 to #5 = %02x %02x %02x %02x %02x\n",
			tvp5150_read(sd, TVP5150_STATUS_REG_1),
			tvp5150_read(sd, TVP5150_STATUS_REG_2),
			tvp5150_read(sd, TVP5150_STATUS_REG_3),
			tvp5150_read(sd, TVP5150_STATUS_REG_4),
			tvp5150_read(sd, TVP5150_STATUS_REG_5));

	dump_reg_range(sd, "Teletext filter 1",   TVP5150_TELETEXT_FIL1_INI,
			TVP5150_TELETEXT_FIL1_END, 8);
	dump_reg_range(sd, "Teletext filter 2",   TVP5150_TELETEXT_FIL2_INI,
			TVP5150_TELETEXT_FIL2_END, 8);

	printk("tvp5150: Teletext filter enable = 0x%02x\n",
			tvp5150_read(sd, TVP5150_TELETEXT_FIL_ENA));
	printk("tvp5150: Interrupt status register A = 0x%02x\n",
			tvp5150_read(sd, TVP5150_INT_STATUS_REG_A));
	printk("tvp5150: Interrupt enable register A = 0x%02x\n",
			tvp5150_read(sd, TVP5150_INT_ENABLE_REG_A));
	printk("tvp5150: Interrupt configuration = 0x%02x\n",
			tvp5150_read(sd, TVP5150_INT_CONF));
	printk("tvp5150: VDP status register = 0x%02x\n",
			tvp5150_read(sd, TVP5150_VDP_STATUS_REG));
	printk("tvp5150: FIFO word count = 0x%02x\n",
			tvp5150_read(sd, TVP5150_FIFO_WORD_COUNT));
	printk("tvp5150: FIFO interrupt threshold = 0x%02x\n",
			tvp5150_read(sd, TVP5150_FIFO_INT_THRESHOLD));
	printk("tvp5150: FIFO reset = 0x%02x\n",
			tvp5150_read(sd, TVP5150_FIFO_RESET));
	printk("tvp5150: Line number interrupt = 0x%02x\n",
			tvp5150_read(sd, TVP5150_LINE_NUMBER_INT));
	printk("tvp5150: Pixel alignment register = 0x%02x%02x\n",
			tvp5150_read(sd, TVP5150_PIX_ALIGN_REG_HIGH),
			tvp5150_read(sd, TVP5150_PIX_ALIGN_REG_LOW));
	printk("tvp5150: FIFO output control = 0x%02x\n",
			tvp5150_read(sd, TVP5150_FIFO_OUT_CTRL));
	printk("tvp5150: Full field enable = 0x%02x\n",
			tvp5150_read(sd, TVP5150_FULL_FIELD_ENA));
	printk("tvp5150: Full field mode register = 0x%02x\n",
			tvp5150_read(sd, TVP5150_FULL_FIELD_MODE_REG));

	dump_reg_range(sd, "CC   data",   TVP5150_CC_DATA_INI,
			TVP5150_CC_DATA_END, 8);

	dump_reg_range(sd, "WSS  data",   TVP5150_WSS_DATA_INI,
			TVP5150_WSS_DATA_END, 8);

	dump_reg_range(sd, "VPS  data",   TVP5150_VPS_DATA_INI,
			TVP5150_VPS_DATA_END, 8);

	dump_reg_range(sd, "VITC data",   TVP5150_VITC_DATA_INI,
			TVP5150_VITC_DATA_END, 10);

	dump_reg_range(sd, "Line mode",   TVP5150_LINE_MODE_INI,
			TVP5150_LINE_MODE_END, 8);
	return 0;
}

/****************************************************************************
			Basic functions
 ****************************************************************************/

static inline void tvp5150_selmux(struct v4l2_subdev *sd)
{
	int opmode = 0;
	struct tvp5150 *decoder = to_tvp5150(sd);
	int input = 0;
	unsigned char val;

	if ((decoder->output & TVP5150_BLACK_SCREEN) || !decoder->enable)
		input = 8;

	switch (decoder->input) {
	case TVP5150_COMPOSITE1:
		input |= 2;
		/* fall through */
	case TVP5150_COMPOSITE0:
		break;
	case TVP5150_SVIDEO:
	default:
		input |= 1;
		break;
	}

	v4l2_dbg(1, debug, sd, "Selecting video route: route input=%i, output=%i "
			"=> tvp5150 input=%i, opmode=%i\n",
			decoder->input, decoder->output,
			input, opmode);

	tvp5150_write(sd, TVP5150_OP_MODE_CTL, opmode);
	tvp5150_write(sd, TVP5150_VD_IN_SRC_SEL_1, input);

	/* Svideo should enable YCrCb output and disable GPCL output
	 * For Composite and TV, it should be the reverse
	 */
	val = tvp5150_read(sd, TVP5150_MISC_CTL);
	if (decoder->input == TVP5150_SVIDEO)
		val = (val & ~0x40) | 0x10;
	else
		val = (val & ~0x10) | 0x40;
	tvp5150_write(sd, TVP5150_MISC_CTL, val);
};

struct i2c_reg_value {
	unsigned char reg;
	unsigned char value;
};

/* Default values as sugested at TVP5150AM1 datasheet */
static const struct i2c_reg_value tvp5150_init_default[] = {
	{ /* 0x00 */
		TVP5150_VD_IN_SRC_SEL_1,0x00
	},
	{ /* 0x01 */
		TVP5150_ANAL_CHL_CTL,0x15
	},
	{ /* 0x02 */
		TVP5150_OP_MODE_CTL,0x00
	},
	{ /* 0x03 */
		TVP5150_MISC_CTL,0x01
	},
	{ /* 0x06 */
		TVP5150_COLOR_KIL_THSH_CTL,0x10
	},
	{ /* 0x07 */
		TVP5150_LUMA_PROC_CTL_1,0x60
	},
	{ /* 0x08 */
		TVP5150_LUMA_PROC_CTL_2,0x00
	},
	{ /* 0x09 */
		TVP5150_BRIGHT_CTL,0x80
	},
	{ /* 0x0a */
		TVP5150_SATURATION_CTL,0x80
	},
	{ /* 0x0b */
		TVP5150_HUE_CTL,0x00
	},
	{ /* 0x0c */
		TVP5150_CONTRAST_CTL,0x80
	},
	{ /* 0x0d */
		TVP5150_DATA_RATE_SEL,0x47
	},
	{ /* 0x0e */
		TVP5150_LUMA_PROC_CTL_3,0x00
	},
	{ /* 0x0f */
		TVP5150_CONF_SHARED_PIN,0x08
	},
	{ /* 0x11 */
		TVP5150_ACT_VD_CROP_ST_MSB,0x00
	},
	{ /* 0x12 */
		TVP5150_ACT_VD_CROP_ST_LSB,0x00
	},
	{ /* 0x13 */
		TVP5150_ACT_VD_CROP_STP_MSB,0x00
	},
	{ /* 0x14 */
		TVP5150_ACT_VD_CROP_STP_LSB,0x00
	},
	{ /* 0x15 */
		TVP5150_GENLOCK,0x01
	},
	{ /* 0x16 */
		TVP5150_HORIZ_SYNC_START,0x80
	},
	{ /* 0x18 */
		TVP5150_VERT_BLANKING_START,0x00
	},
	{ /* 0x19 */
		TVP5150_VERT_BLANKING_STOP,0x00
	},
	{ /* 0x1a */
		TVP5150_CHROMA_PROC_CTL_1,0x0c
	},
	{ /* 0x1b */
		TVP5150_CHROMA_PROC_CTL_2,0x14
	},
	{ /* 0x1c */
		TVP5150_INT_RESET_REG_B,0x00
	},
	{ /* 0x1d */
		TVP5150_INT_ENABLE_REG_B,0x00
	},
	{ /* 0x1e */
		TVP5150_INTT_CONFIG_REG_B,0x00
	},
	{ /* 0x28 */
		TVP5150_VIDEO_STD,0x00
	},
	{ /* 0x2e */
		TVP5150_MACROVISION_ON_CTR,0x0f
	},
	{ /* 0x2f */
		TVP5150_MACROVISION_OFF_CTR,0x01
	},
	{ /* 0xbb */
		TVP5150_TELETEXT_FIL_ENA,0x00
	},
	{ /* 0xc0 */
		TVP5150_INT_STATUS_REG_A,0x00
	},
	{ /* 0xc1 */
		TVP5150_INT_ENABLE_REG_A,0x00
	},
	{ /* 0xc2 */
		TVP5150_INT_CONF,0x04
	},
	{ /* 0xc8 */
		TVP5150_FIFO_INT_THRESHOLD,0x80
	},
	{ /* 0xc9 */
		TVP5150_FIFO_RESET,0x00
	},
	{ /* 0xca */
		TVP5150_LINE_NUMBER_INT,0x00
	},
	{ /* 0xcb */
		TVP5150_PIX_ALIGN_REG_LOW,0x4e
	},
	{ /* 0xcc */
		TVP5150_PIX_ALIGN_REG_HIGH,0x00
	},
	{ /* 0xcd */
		TVP5150_FIFO_OUT_CTRL,0x01
	},
	{ /* 0xcf */
		TVP5150_FULL_FIELD_ENA,0x00
	},
	{ /* 0xd0 */
		TVP5150_LINE_MODE_INI,0x00
	},
	{ /* 0xfc */
		TVP5150_FULL_FIELD_MODE_REG,0x7f
	},
	{ /* end of data */
		0xff,0xff
	}
};

/* Default values as sugested at TVP5150AM1 datasheet */
static const struct i2c_reg_value tvp5150_init_enable[] = {
	{
		TVP5150_CONF_SHARED_PIN, 3
	},{	/* Automatic offset and AGC enabled */
		TVP5150_ANAL_CHL_CTL, 0x15
	},{	/* Activate YCrCb output 0x9 or 0xd ? */
		TVP5150_MISC_CTL, 0x6f
	},{	/* Activates video std autodetection for all standards */
		TVP5150_AUTOSW_MSK, 0x0
	},{	/* Default format: 0x47. For 4:2:2: 0x40 */
		TVP5150_DATA_RATE_SEL, 0x47
	},{
		TVP5150_CHROMA_PROC_CTL_1, 0x0c
	},{
		TVP5150_CHROMA_PROC_CTL_2, 0x54
	},{	/* Non documented, but initialized on WinTV USB2 */
		0x27, 0x20
	},{
		0xff,0xff
	}
};

struct tvp5150_vbi_type {
	unsigned int vbi_type;
	unsigned int ini_line;
	unsigned int end_line;
	unsigned int by_field :1;
};

struct i2c_vbi_ram_value {
	u16 reg;
	struct tvp5150_vbi_type type;
	unsigned char values[16];
};

/* This struct have the values for each supported VBI Standard
 * by
 tvp5150_vbi_types should follow the same order as vbi_ram_default
 * value 0 means rom position 0x10, value 1 means rom position 0x30
 * and so on. There are 16 possible locations from 0 to 15.
 */

static struct i2c_vbi_ram_value vbi_ram_default[] =
{
	/* FIXME: Current api doesn't handle all VBI types, those not
	   yet supported are placed under #if 0 */
#if 0
	{0x010, /* Teletext, SECAM, WST System A */
		{V4L2_SLICED_TELETEXT_SECAM,6,23,1},
		{ 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x26,
		  0xe6, 0xb4, 0x0e, 0x00, 0x00, 0x00, 0x10, 0x00 }
	},
#endif
	{0x030, /* Teletext, PAL, WST System B */
		{V4L2_SLICED_TELETEXT_B,6,22,1},
		{ 0xaa, 0xaa, 0xff, 0xff, 0x27, 0x2e, 0x20, 0x2b,
		  0xa6, 0x72, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00 }
	},
#if 0
	{0x050, /* Teletext, PAL, WST System C */
		{V4L2_SLICED_TELETEXT_PAL_C,6,22,1},
		{ 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x22,
		  0xa6, 0x98, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 }
	},
	{0x070, /* Teletext, NTSC, WST System B */
		{V4L2_SLICED_TELETEXT_NTSC_B,10,21,1},
		{ 0xaa, 0xaa, 0xff, 0xff, 0x27, 0x2e, 0x20, 0x23,
		  0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 }
	},
	{0x090, /* Tetetext, NTSC NABTS System C */
		{V4L2_SLICED_TELETEXT_NTSC_C,10,21,1},
		{ 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x22,
		  0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x15, 0x00 }
	},
	{0x0b0, /* Teletext, NTSC-J, NABTS System D */
		{V4L2_SLICED_TELETEXT_NTSC_D,10,21,1},
		{ 0xaa, 0xaa, 0xff, 0xff, 0xa7, 0x2e, 0x20, 0x23,
		  0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 }
	},
	{0x0d0, /* Closed Caption, PAL/SECAM */
		{V4L2_SLICED_CAPTION_625,22,22,1},
		{ 0xaa, 0x2a, 0xff, 0x3f, 0x04, 0x51, 0x6e, 0x02,
		  0xa6, 0x7b, 0x09, 0x00, 0x00, 0x00, 0x27, 0x00 }
	},
#endif
	{0x0f0, /* Closed Caption, NTSC */
		{V4L2_SLICED_CAPTION_525,21,21,1},
		{ 0xaa, 0x2a, 0xff, 0x3f, 0x04, 0x51, 0x6e, 0x02,
		  0x69, 0x8c, 0x09, 0x00, 0x00, 0x00, 0x27, 0x00 }
	},
	{0x110, /* Wide Screen Signal, PAL/SECAM */
		{V4L2_SLICED_WSS_625,23,23,1},
		{ 0x5b, 0x55, 0xc5, 0xff, 0x00, 0x71, 0x6e, 0x42,
		  0xa6, 0xcd, 0x0f, 0x00, 0x00, 0x00, 0x3a, 0x00 }
	},
#if 0
	{0x130, /* Wide Screen Signal, NTSC C */
		{V4L2_SLICED_WSS_525,20,20,1},
		{ 0x38, 0x00, 0x3f, 0x00, 0x00, 0x71, 0x6e, 0x43,
		  0x69, 0x7c, 0x08, 0x00, 0x00, 0x00, 0x39, 0x00 }
	},
	{0x150, /* Vertical Interval Timecode (VITC), PAL/SECAM */
		{V4l2_SLICED_VITC_625,6,22,0},
		{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x6d, 0x49,
		  0xa6, 0x85, 0x08, 0x00, 0x00, 0x00, 0x4c, 0x00 }
	},
	{0x170, /* Vertical Interval Timecode (VITC), NTSC */
		{V4l2_SLICED_VITC_525,10,20,0},
		{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x6d, 0x49,
		  0x69, 0x94, 0x08, 0x00, 0x00, 0x00, 0x4c, 0x00 }
	},
#endif
	{0x190, /* Video Program System (VPS), PAL */
		{V4L2_SLICED_VPS,16,16,0},
		{ 0xaa, 0xaa, 0xff, 0xff, 0xba, 0xce, 0x2b, 0x0d,
		  0xa6, 0xda, 0x0b, 0x00, 0x00, 0x00, 0x60, 0x00 }
	},
	/* 0x1d0 User programmable */

	/* End of struct */
	{ (u16)-1 }
};

static int tvp5150_write_inittab(struct v4l2_subdev *sd,
				const struct i2c_reg_value *regs)
{
	while (regs->reg != 0xff) {
		tvp5150_write(sd, regs->reg, regs->value);
		regs++;
	}
	return 0;
}

static int tvp5150_vdp_init(struct v4l2_subdev *sd,
				const struct i2c_vbi_ram_value *regs)
{
	unsigned int i;

	/* Disable Full Field */
	tvp5150_write(sd, TVP5150_FULL_FIELD_ENA, 0);

	/* Before programming, Line mode should be at 0xff */
	for (i = TVP5150_LINE_MODE_INI; i <= TVP5150_LINE_MODE_END; i++)
		tvp5150_write(sd, i, 0xff);

	/* Load Ram Table */
	while (regs->reg != (u16)-1) {
		tvp5150_write(sd, TVP5150_CONF_RAM_ADDR_HIGH, regs->reg >> 8);
		tvp5150_write(sd, TVP5150_CONF_RAM_ADDR_LOW, regs->reg);

		for (i = 0; i < 16; i++)
			tvp5150_write(sd, TVP5150_VDP_CONF_RAM_DATA, regs->values[i]);

		regs++;
	}
	return 0;
}

/* Fills VBI capabilities based on i2c_vbi_ram_value struct */
static int tvp5150_g_sliced_vbi_cap(struct v4l2_subdev *sd,
				struct v4l2_sliced_vbi_cap *cap)
{
	const struct i2c_vbi_ram_value *regs = vbi_ram_default;
	int line;

	v4l2_dbg(1, debug, sd, "g_sliced_vbi_cap\n");
	memset(cap, 0, sizeof *cap);

	while (regs->reg != (u16)-1 ) {
		for (line=regs->type.ini_line;line<=regs->type.end_line;line++) {
			cap->service_lines[0][line] |= regs->type.vbi_type;
		}
		cap->service_set |= regs->type.vbi_type;

		regs++;
	}
	return 0;
}

/* Set vbi processing
 * type - one of tvp5150_vbi_types
 * line - line to gather data
 * fields: bit 0 field1, bit 1, field2
 * flags (default=0xf0) is a bitmask, were set means:
 *	bit 7: enable filtering null bytes on CC
 *	bit 6: send data also to FIFO
 *	bit 5: don't allow data with errors on FIFO
 *	bit 4: enable ECC when possible
 * pix_align = pix alignment:
 *	LSB = field1
 *	MSB = field2
 */
static int tvp5150_set_vbi(struct v4l2_subdev *sd,
			const struct i2c_vbi_ram_value *regs,
			unsigned int type,u8 flags, int line,
			const int fields)
{
	struct tvp5150 *decoder = to_tvp5150(sd);
	v4l2_std_id std = decoder->norm;
	u8 reg;
	int pos=0;

	if (std == V4L2_STD_ALL) {
		v4l2_err(sd, "VBI can't be configured without knowing number of lines\n");
		return 0;
	} else if (std & V4L2_STD_625_50) {
		/* Don't follow NTSC Line number convension */
		line += 3;
	}

	if (line<6||line>27)
		return 0;

	while (regs->reg != (u16)-1 ) {
		if ((type & regs->type.vbi_type) &&
		    (line>=regs->type.ini_line) &&
		    (line<=regs->type.end_line)) {
			type=regs->type.vbi_type;
			break;
		}

		regs++;
		pos++;
	}
	if (regs->reg == (u16)-1)
		return 0;

	type=pos | (flags & 0xf0);
	reg=((line-6)<<1)+TVP5150_LINE_MODE_INI;

	if (fields&1) {
		tvp5150_write(sd, reg, type);
	}

	if (fields&2) {
		tvp5150_write(sd, reg+1, type);
	}

	return type;
}

static int tvp5150_get_vbi(struct v4l2_subdev *sd,
			const struct i2c_vbi_ram_value *regs, int line)
{
	struct tvp5150 *decoder = to_tvp5150(sd);
	v4l2_std_id std = decoder->norm;
	u8 reg;
	int pos, type = 0;

	if (std == V4L2_STD_ALL) {
		v4l2_err(sd, "VBI can't be configured without knowing number of lines\n");
		return 0;
	} else if (std & V4L2_STD_625_50) {
		/* Don't follow NTSC Line number convension */
		line += 3;
	}

	if (line < 6 || line > 27)
		return 0;

	reg = ((line - 6) << 1) + TVP5150_LINE_MODE_INI;

	pos = tvp5150_read(sd, reg) & 0x0f;
	if (pos < 0x0f)
		type = regs[pos].type.vbi_type;

	pos = tvp5150_read(sd, reg + 1) & 0x0f;
	if (pos < 0x0f)
		type |= regs[pos].type.vbi_type;

	return type;
}

/**
 * tvp515x_query_current_std() : Query the current standard detected by TVP5151
 * @sd: ptr to v4l2_subdev struct
 *
 * Returns the current standard detected by TVP5151, STD_INVALID if there is no
 * standard detected.
 */
static int tvp515x_query_current_std(struct v4l2_subdev *sd)
{
	u8 std, std_status;

	std = tvp5150_read(sd, TVP5150_VIDEO_STD);
	if ((std & VIDEO_STD_MASK) == VIDEO_STD_AUTO_SWITCH_BIT)
		/* use the standard status register */
		std_status = tvp5150_read(sd, TVP5150_STATUS_REG_5);
	else
		/* use the standard register itself */
		std_status = std;

	switch (std_status & VIDEO_STD_MASK) {
	case VIDEO_STD_NTSC_MJ_BIT:
	case VIDEO_STD_NTSC_MJ_BIT_AS:
		return STD_NTSC_MJ;

	case VIDEO_STD_PAL_BDGHIN_BIT:
	case VIDEO_STD_PAL_BDGHIN_BIT_AS:
		return STD_PAL_BDGHIN;

	default:
		return STD_INVALID;
	}

	return STD_INVALID;
}

/****************************************************************************
			V4L2 subdev video operations
 ****************************************************************************/

static int tvp5150_set_std(struct v4l2_subdev *sd, v4l2_std_id std)
{
	struct tvp5150 *decoder = to_tvp5150(sd);
	int fmt = 0;

	decoder->norm = std;

	/* First tests should be against specific std */

	if (std == V4L2_STD_ALL) {
		fmt = 0;	/* Autodetect mode */
	} else if (std & V4L2_STD_NTSC_443) {
		fmt = VIDEO_STD_NTSC_4_43_BIT;
	} else if (std & V4L2_STD_PAL_M) {
		fmt = VIDEO_STD_PAL_M_BIT;
	} else if (std & (V4L2_STD_PAL_N | V4L2_STD_PAL_Nc)) {
		fmt = VIDEO_STD_PAL_COMBINATION_N_BIT;
	} else {
		/* Then, test against generic ones */
		if (std & V4L2_STD_NTSC)
			fmt = VIDEO_STD_NTSC_MJ_BIT;
		else if (std & V4L2_STD_PAL)
			fmt = VIDEO_STD_PAL_BDGHIN_BIT;
		else if (std & V4L2_STD_SECAM)
			fmt = VIDEO_STD_SECAM_BIT;
	}

	v4l2_dbg(1, debug, sd, "Set video std register to %d.\n", fmt);
	tvp5150_write(sd, TVP5150_VIDEO_STD, fmt);
	return 0;
}

static int tvp5150_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
{
	struct tvp5150 *decoder = to_tvp5150(sd);
	int i;
	int num_stds = ARRAY_SIZE(tvp515x_std_list);

	if (decoder->norm == std)
		return 0;

	for (i = 0; i < num_stds; i++)
		if (std & tvp515x_std_list[i].standard.id)
			break;

	if ((i == num_stds) || (i == STD_INVALID))
		return -EINVAL;

	tvp5150_write(sd, TVP5150_VIDEO_STD, tvp515x_std_list[i].video_std);

	decoder->norm = i;
	decoder->norm = std;

/*	return tvp5150_set_std(sd, std); */
	return 0;
}

static int tvp5150_reset(struct v4l2_subdev *sd, u32 val)
{
	struct tvp5150 *decoder = to_tvp5150(sd);

	/* Initializes TVP5150 to its default values */
	tvp5150_write_inittab(sd, tvp5150_init_default);

	/* Initializes VDP registers */
	tvp5150_vdp_init(sd, vbi_ram_default);

	/* Selects decoder input */
	tvp5150_selmux(sd);

	/* Initializes TVP5150 to stream enabled values */
	tvp5150_write_inittab(sd, tvp5150_init_enable);

	/* Initialize image preferences */
	v4l2_ctrl_handler_setup(&decoder->hdl);

	tvp5150_set_std(sd, decoder->norm);
	return 0;
};

static int tvp5150_s_ctrl(struct v4l2_ctrl *ctrl)
{
	struct v4l2_subdev *sd = to_sd(ctrl);

	switch (ctrl->id) {
	case V4L2_CID_BRIGHTNESS:
		tvp5150_write(sd, TVP5150_BRIGHT_CTL, ctrl->val);
		return 0;
	case V4L2_CID_CONTRAST:
		tvp5150_write(sd, TVP5150_CONTRAST_CTL, ctrl->val);
		return 0;
	case V4L2_CID_SATURATION:
		tvp5150_write(sd, TVP5150_SATURATION_CTL, ctrl->val);
		return 0;
	case V4L2_CID_HUE:
		tvp5150_write(sd, TVP5150_HUE_CTL, ctrl->val);
		return 0;
	}
	return -EINVAL;
}

static struct v4l2_mbus_framefmt *
__tvp5150_get_pad_format(struct tvp5150 *tvp5150, struct v4l2_subdev_fh *fh,
			 unsigned int pad, enum v4l2_subdev_format_whence which)
{
	printk(KERN_CONT "\nTVP5150_GET_PAD_FORMAT\n");
	switch (which) {
	case V4L2_SUBDEV_FORMAT_TRY:
		return v4l2_subdev_get_try_format(fh, pad);
	case V4L2_SUBDEV_FORMAT_ACTIVE:
		return tvp5150->format;
	default:
		return NULL;
	}
}

static int tvp5150_get_pad_format(struct v4l2_subdev *subdev,
			      struct v4l2_subdev_fh *fh,
			      struct v4l2_subdev_format *format)
{
	struct tvp5150 *tvp5150 = to_tvp5150(subdev);

	format->format = *__tvp5150_get_pad_format(tvp5150, fh, format->pad,
						   format->which);

	return 0;
}

static int tvp5150_set_pad_format(struct v4l2_subdev *subdev,
			      struct v4l2_subdev_fh *fh,
			      struct v4l2_subdev_format *format)
{
	struct tvp5150 *tvp5150 = to_tvp5150(subdev);
	tvp5150->std_idx = STD_INVALID;
	printk(KERN_CONT "\nTVP5150_SET_PAD_FORMAT\n");

	tvp5150->std_idx = tvp515x_query_current_std(subdev);
	if (tvp5150->std_idx == STD_INVALID) {
		v4l2_err(subdev, "Unable to query std\n");
		printk(KERN_CONT "\nTVP5150_SET_PAD_FORMAT unable to query std\n");
		return 0;
	}

	tvp5150->norm = tvp515x_std_list[tvp5150->std_idx].standard.id;

	tvp5150->format = &tvp515x_std_list[tvp5150->std_idx].format;
	tvp5150->format->height = format->format.height;
	tvp5150->format->width = format->format.width;

	format->format = *__tvp5150_get_pad_format(tvp5150, fh, format->pad,
	format->which);

	printk(subdev, "code=x%x width=%u height=%u colorspace=0x%x\n",
			format->format.code, format->format.width,
			format->format.height, format->format.colorspace);

	return 0;
}

/**
 * tvp515x_mbus_fmt_cap() - V4L2 decoder interface handler for try/s/g_mbus_fmt
 * @sd: pointer to standard V4L2 sub-device structure
 * @f: pointer to the mediabus format structure
 *
 * Negotiates the image capture size and mediabus format.
 */
static int
tvp515x_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f)
{
	struct tvp5150 *decoder = to_tvp5150(sd);
	printk(KERN_CONT "\nTVP5150_MBUS_FMT\n");

	if (f == NULL)
		return -EINVAL;

	f = decoder->format;

	v4l2_dbg(1, debug, sd, "MBUS_FMT: Width - %d, Height - %d\n",
			f->width, f->height);
	return 0;
}

/*
 * tvp515x_s_stream() - V4L2 decoder i/f handler for s_stream
 * @sd: pointer to standard V4L2 sub-device structure
 * @enable: streaming enable or disable
 *
 * Sets streaming to enable or disable, if possible.
 */
static int tvp515x_s_stream(struct v4l2_subdev *subdev, int enable)
{
	struct isp_device *isp = v4l2_dev_to_isp_device(subdev->v4l2_dev);

	/* Initializes TVP5150 to its default values */
	/* # set PCLK (27MHz) */
	tvp5150_write(subdev, TVP5150_CONF_SHARED_PIN, 0x00);

	/* Output format: 8-bit ITU-R BT.656 with embedded syncs */
	if (enable) {
		tvp5150_write(subdev, TVP5150_MISC_CTL, 0x6D);//0x09);
		tvp5150_write(subdev, TVP5150_DATA_RATE_SEL, 0x40);
		if(isp->platform_cb.set_xclk)
			isp->platform_cb.set_xclk(isp, 24000000, 1);
	}
	else {
		tvp5150_write(subdev, TVP5150_MISC_CTL, 0x00);
		tvp5150_write(subdev, TVP5150_DATA_RATE_SEL, 0x47);
		if(isp->platform_cb.set_xclk)
				isp->platform_cb.set_xclk(isp, 0, 1);
	}

	//tvp5150_log_status(subdev);

	return 0;
}

/**
 * tvp515x_enum_mbus_fmt() - V4L2 decoder interface handler for enum_mbus_fmt
 * @sd: pointer to standard V4L2 sub-device structure
 * @index: index of pixelcode to retrieve
 * @code: receives the pixelcode
 *
 * Enumerates supported mediabus formats
 */
static int
tvp515x_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index,
					enum v4l2_mbus_pixelcode *code)
{
	printk(KERN_CONT "\nTVP5150_GET_PAD_FORMAT\n");
	if (index)
		return -EINVAL;

	*code = V4L2_MBUS_FMT_SGRBG8_1X8;
	return 0;
}

/**
 * tvp515x_g_parm() - V4L2 decoder interface handler for g_parm
 * @sd: pointer to standard V4L2 sub-device structure
 * @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure
 *
 * Returns the decoder's video CAPTURE parameters.
 */
static int
tvp515x_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
{
	struct v4l2_captureparm *cparm;
	printk(KERN_CONT "\nTVP5150_G_PARAM\n");

	if (a == NULL)
		return -EINVAL;

	if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
		/* only capture is supported */
		return -EINVAL;

	cparm = &a->parm.capture;
	cparm->capability = V4L2_CAP_TIMEPERFRAME;
	cparm->timeperframe = a->parm.capture.timeperframe;

	return 0;
}

/**
 * tvp515x_s_parm() - V4L2 decoder interface handler for s_parm
 * @sd: pointer to standard V4L2 sub-device structure
 * @a: pointer to standard V4L2 VIDIOC_S_PARM ioctl structure
 *
 * Configures the decoder to use the input parameters, if possible. If
 * not possible, returns the appropriate error code.
 */
static int
tvp515x_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
{
	struct v4l2_fract *timeperframe;
	printk(KERN_CONT "\nTVP5150_S_PARAM\n");

	if (a == NULL)
		return -EINVAL;

	if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
		/* only capture is supported */
		return -EINVAL;

	timeperframe = &a->parm.capture.timeperframe;

	return 0;
}



/****************************************************************************
			I2C Command
 ****************************************************************************/

static int tvp5150_s_routing(struct v4l2_subdev *sd,
			     u32 input, u32 output, u32 config)
{
	printk(KERN_CONT "\nTVP5150_S_Routing\n");
	struct tvp5150 *decoder = to_tvp5150(sd);

	decoder->input = input;
	decoder->output = output;
	tvp5150_selmux(sd);
	return 0;
}

static int tvp5150_s_raw_fmt(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt)
{
	printk(KERN_CONT "\nTVP5150_S_Raw_FMT\n");
	/* this is for capturing 36 raw vbi lines
	   if there's a way to cut off the beginning 2 vbi lines
	   with the tvp5150 then the vbi line count could be lowered
	   to 17 lines/field again, although I couldn't find a register
	   which could do that cropping */
	if (fmt->sample_format == V4L2_PIX_FMT_GREY)
		tvp5150_write(sd, TVP5150_LUMA_PROC_CTL_1, 0x70);
	if (fmt->count[0] == 18 && fmt->count[1] == 18) {
		tvp5150_write(sd, TVP5150_VERT_BLANKING_START, 0x00);
		tvp5150_write(sd, TVP5150_VERT_BLANKING_STOP, 0x01);
	}
	return 0;
}

static int tvp5150_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *svbi)
{
	int i;
	printk(KERN_CONT "\nTVP5150_S_Sliced_Fmt\n");

	if (svbi->service_set != 0) {
		for (i = 0; i <= 23; i++) {
			svbi->service_lines[1][i] = 0;
			svbi->service_lines[0][i] =
				tvp5150_set_vbi(sd, vbi_ram_default,
				       svbi->service_lines[0][i], 0xf0, i, 3);
		}
		/* Enables FIFO */
		tvp5150_write(sd, TVP5150_FIFO_OUT_CTRL, 1);
	} else {
		/* Disables FIFO*/
		tvp5150_write(sd, TVP5150_FIFO_OUT_CTRL, 0);

		/* Disable Full Field */
		tvp5150_write(sd, TVP5150_FULL_FIELD_ENA, 0);

		/* Disable Line modes */
		for (i = TVP5150_LINE_MODE_INI; i <= TVP5150_LINE_MODE_END; i++)
			tvp5150_write(sd, i, 0xff);
	}
	return 0;
}

static int tvp5150_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *svbi)
{
	int i, mask = 0;
	printk(KERN_CONT "\nTVP5150_G_Sliced_Fmt\n");

	memset(svbi, 0, sizeof(*svbi));

	for (i = 0; i <= 23; i++) {
		svbi->service_lines[0][i] =
			tvp5150_get_vbi(sd, vbi_ram_default, i);
		mask |= svbi->service_lines[0][i];
	}
	svbi->service_set = mask;
	return 0;
}

static int tvp5150_g_chip_ident(struct v4l2_subdev *sd,
				struct v4l2_dbg_chip_ident *chip)
{
	printk(KERN_CONT "\nTVP5150_G_Chip_Ident\n");
	int rev;
	struct i2c_client *client = v4l2_get_subdevdata(sd);

	rev = tvp5150_read(sd, TVP5150_ROM_MAJOR_VER) << 8 |
	      tvp5150_read(sd, TVP5150_ROM_MINOR_VER);

	return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TVP5150,
					  rev);
}


#ifdef CONFIG_VIDEO_ADV_DEBUG
static int tvp5150_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
{
	struct i2c_client *client = v4l2_get_subdevdata(sd);
	printk(KERN_CONT "\nTVP5150_G_REGISTER\n");

	if (!v4l2_chip_match_i2c_client(client, &reg->match))
		return -EINVAL;
	if (!capable(CAP_SYS_ADMIN))
		return -EPERM;
	reg->val = tvp5150_read(sd, reg->reg & 0xff);
	reg->size = 1;
	return 0;
}

static int tvp5150_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
{
	struct i2c_client *client = v4l2_get_subdevdata(sd);
	printk(KERN_CONT "\nTVP5150_S_REGISTER\n");

	if (!v4l2_chip_match_i2c_client(client, &reg->match))
		return -EINVAL;
	if (!capable(CAP_SYS_ADMIN))
		return -EPERM;
	tvp5150_write(sd, reg->reg & 0xff, reg->val & 0xff);
	return 0;
}
#endif

static int tvp5150_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
{
	printk(KERN_CONT "\nTVP5150_G_Tuner\n");
	int status = tvp5150_read(sd, 0x88);

	vt->signal = ((status & 0x04) && (status & 0x02)) ? 0xffff : 0x0;
	return 0;
}

/****************************************************************************
		    V4L2 subdev core operations
 ****************************************************************************/

static int tvp5150_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
{
	struct tvp5150 *decoder = to_tvp5150(subdev);
	printk(KERN_CONT "\nTVP5150_OPEN\n");

	decoder->std_idx = STD_INVALID;

	decoder->std_idx = tvp515x_query_current_std(subdev);

	if (decoder->std_idx == STD_INVALID) {
		v4l2_err(subdev, "Unable to query std\n");
		return 0;
	}

	decoder->format = (&(tvp515x_std_list[decoder->std_idx].format));
	decoder->norm = tvp515x_std_list[decoder->std_idx].standard.id;

	return 0;
}

static int tvp5150_close(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
{
	printk(KERN_CONT "\nTVP5150_CLOSE\n");
	return 0;
}

static const struct v4l2_ctrl_ops tvp5150_ctrl_ops = {
	.s_ctrl = tvp5150_s_ctrl,
};

static const struct v4l2_subdev_core_ops tvp5150_core_ops = {
	.log_status = tvp5150_log_status,
	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
	.g_ctrl = v4l2_subdev_g_ctrl,
	.s_ctrl = v4l2_subdev_s_ctrl,
	.queryctrl = v4l2_subdev_queryctrl,
	.querymenu = v4l2_subdev_querymenu,
	.s_std = tvp5150_s_std,
	.reset = tvp5150_reset,
	.g_chip_ident = tvp5150_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
	.g_register = tvp5150_g_register,
	.s_register = tvp5150_s_register,
#endif
};

static struct v4l2_subdev_internal_ops tvp5150_subdev_internal_ops = {
	.open		= tvp5150_open,
	.close		= tvp5150_close,
};

static const struct v4l2_subdev_tuner_ops tvp5150_tuner_ops = {
	.g_tuner = tvp5150_g_tuner,
};

static const struct v4l2_subdev_video_ops tvp5150_video_ops = {
	.s_routing = tvp5150_s_routing,
	.s_stream = tvp515x_s_stream,
	.enum_mbus_fmt = tvp515x_enum_mbus_fmt,
	.g_mbus_fmt = tvp515x_mbus_fmt,
	.try_mbus_fmt = tvp515x_mbus_fmt,
	.s_mbus_fmt = tvp515x_mbus_fmt,
	.g_parm = tvp515x_g_parm,
	.s_parm = tvp515x_s_parm,
	.s_std_output = tvp5150_s_std,
};

static const struct v4l2_subdev_vbi_ops tvp5150_vbi_ops = {
	.g_sliced_vbi_cap = tvp5150_g_sliced_vbi_cap,
	.g_sliced_fmt = tvp5150_g_sliced_fmt,
	.s_sliced_fmt = tvp5150_s_sliced_fmt,
	.s_raw_fmt = tvp5150_s_raw_fmt,
};

static int tvp515x_enum_mbus_code(struct v4l2_subdev *subdev,
				  struct v4l2_subdev_fh *fh,
				  struct v4l2_subdev_mbus_code_enum *code)
{
	printk(KERN_CONT "\nTVP5150_ENUM_MBUS_CODE\n");
	if (code->index >= ARRAY_SIZE(tvp515x_std_list))
		return -EINVAL;

	code->code = V4L2_MBUS_FMT_YUYV8_2X8;

	return 0;
}

static int tvp515x_enum_frame_size(struct v4l2_subdev *subdev,
				   struct v4l2_subdev_fh *fh,
				   struct v4l2_subdev_frame_size_enum *fse)
{
	int current_std = STD_INVALID;
	printk(KERN_CONT "\nTVP5150_ENUM_FRAME_SIZE\n");

	if (fse->code != V4L2_MBUS_FMT_UYVY8_2X8)
		return -EINVAL;

	/* query the current standard */
	current_std = tvp515x_query_current_std(subdev);
	if (current_std == STD_INVALID) {
		v4l2_err(subdev, "Unable to query std\n");
		return 0;
	}

	fse->min_width = tvp515x_std_list[current_std].format.width;
	fse->min_height = tvp515x_std_list[current_std].format.height;
	fse->max_width = fse->min_width;
	fse->max_height = fse->min_height;
	return 0;
}

static struct v4l2_subdev_pad_ops tvp5150_pad_ops = {
	.enum_mbus_code = tvp515x_enum_mbus_code,
	.enum_frame_size = tvp515x_enum_frame_size,
	.get_fmt = tvp5150_get_pad_format,
	.set_fmt = tvp5150_set_pad_format,
};

static const struct v4l2_subdev_ops tvp5150_ops = {
	.core = &tvp5150_core_ops,
	.tuner = &tvp5150_tuner_ops,
	.video = &tvp5150_video_ops,
	.vbi = &tvp5150_vbi_ops,
	.pad = &tvp5150_pad_ops,
};

/****************************************************************************
			I2C Client & Driver
 ****************************************************************************/

static int tvp5150_probe(struct i2c_client *c,
			 const struct i2c_device_id *id)
{
	struct tvp5150 *core;
	struct v4l2_subdev *sd;
	u8 msb_id, lsb_id, msb_rom, lsb_rom;
	int ret;
	printk(KERN_CONT "\nTVP5150_PROBE\n");

	/* Check if the adapter supports the needed features */
	if (!i2c_check_functionality(c->adapter,
	     I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
		return -EIO;

	core = kzalloc(sizeof(struct tvp5150), GFP_KERNEL);
	if (!core) {
		return -ENOMEM;
	}
	sd = &core->sd;
	v4l2_i2c_subdev_init(sd, c, &tvp5150_ops);
	v4l_info(c, "chip found @ 0x%02x (%s)\n",
		 c->addr << 1, c->adapter->name);

	msb_id = tvp5150_read(sd, TVP5150_MSB_DEV_ID);
	lsb_id = tvp5150_read(sd, TVP5150_LSB_DEV_ID);
	msb_rom = tvp5150_read(sd, TVP5150_ROM_MAJOR_VER);
	lsb_rom = tvp5150_read(sd, TVP5150_ROM_MINOR_VER);

	if (msb_rom == 4 && lsb_rom == 0) { /* Is TVP5150AM1 */
		v4l2_info(sd, "tvp%02x%02xam1 detected.\n", msb_id, lsb_id);

		/* ITU-T BT.656.4 timing */
		tvp5150_write(sd, TVP5150_REV_SELECT, 0);
	} else {
		if (msb_rom == 3 || lsb_rom == 0x21) { /* Is TVP5150A */
			v4l2_info(sd, "tvp%02x%02xa detected.\n", msb_id, lsb_id);
		} else {
			v4l2_info(sd, "*** unknown tvp%02x%02x chip detected.\n",
					msb_id, lsb_id);
			v4l2_info(sd, "*** Rom ver is %d.%d\n", msb_rom, lsb_rom);
		}
	}

	core->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
	core->sd.internal_ops = &tvp5150_subdev_internal_ops;
	core->norm = V4L2_STD_ALL;	/* Default is autodetect */
	core->input = TVP5150_COMPOSITE1;
	core->enable = 1;

	v4l2_ctrl_handler_init(&core->hdl, 4);
	v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops,
			V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
	v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops,
			V4L2_CID_CONTRAST, 0, 255, 1, 128);
	v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops,
			V4L2_CID_SATURATION, 0, 255, 1, 128);
	v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops,
			V4L2_CID_HUE, -128, 127, 1, 0);
	sd->ctrl_handler = &core->hdl;
	if (core->hdl.error) {
		int err = core->hdl.error;

		v4l2_ctrl_handler_free(&core->hdl);
		kfree(core);
		return err;
	}
	v4l2_ctrl_handler_setup(&core->hdl);

	//if (debug > 1)
		tvp5150_log_status(sd);

	core->pad.flags = MEDIA_PAD_FL_SOURCE;
	ret = media_entity_init(&core->sd.entity, 1, &core->pad, 0);
	if (ret < 0)
		kfree(core);

	return 0;
}

static int tvp5150_remove(struct i2c_client *c)
{
	struct v4l2_subdev *sd = i2c_get_clientdata(c);
	struct tvp5150 *decoder = to_tvp5150(sd);
	printk(KERN_CONT "\nTVP5150_REMOVE\n");

	v4l2_dbg(1, debug, sd,
		"tvp5150.c: removing tvp5150 adapter on address 0x%x\n",
		c->addr << 1);

	v4l2_device_unregister_subdev(sd);
	v4l2_ctrl_handler_free(&decoder->hdl);
	media_entity_cleanup(&sd->entity);
	kfree(to_tvp5150(sd));
	return 0;
}

/* ----------------------------------------------------------------------- */

static const struct i2c_device_id tvp5150_id[] = {
	{ "tvp5150", 0 },
	{ }
};
MODULE_DEVICE_TABLE(i2c, tvp5150_id);

static struct i2c_driver tvp5150_driver = {
	.driver = {
		.owner	= THIS_MODULE,
		.name	= "tvp5150",
	},
	.probe		= tvp5150_probe,
	.remove		= tvp5150_remove,
	.id_table	= tvp5150_id,
};

static __init int init_tvp5150(void)
{
	printk(KERN_CONT "\nTVP5150_INIT\n");
	return i2c_add_driver(&tvp5150_driver);
}

static __exit void exit_tvp5150(void)
{
	printk(KERN_CONT "\nTVP5150_Exit\n");
	i2c_del_driver(&tvp5150_driver);
}

module_init(init_tvp5150);
module_exit(exit_tvp5150);

I am trying to get an NTSC signal into the DM3730, which doesn’t accept NTSC so I am using the TVP5151 to convert from NTSC to UYVY. I am not using BT.656 so I have everything configured to use discrete HS and VS signals. I also have the FLD signal connected between the two chips. I have confirmed that the DM3730 is in fact receiving all of these signals (Both via a scope and by printing info from the driver). I have posted all of my register dumps for the two chips at the bottom.

So now all of my registers and wiring seems correct so I try to use gstreamer to look at the video. The first issue is that I am only getting 1 of the fields, so every other line is missing. The second issue is that I only get one frame about every 5 seconds. Here are my settings that I used for gstreamer.

media-ctl -v -r -l '"tvp5150 2-005c":0->"OMAP3 ISP CCDC":0[1], "OMAP3 ISP CCDC":1->"OMAP3 ISP CCDC output":0[1]'
media-ctl -v --set-format '"tvp5150 2-005c":0 [UYVY2X8 720x525]'
media-ctl -v --set-format '"OMAP3 ISP CCDC":0 [UYVY2X8 720x525]'
media-ctl -v --set-format '"OMAP3 ISP CCDC":1 [UYVY2X8 720x525]'
gst-launch -v v4l2src device="/dev/video2" num-buffers=50 always-copy=false queue-size=50 ! 'video/x-raw-yuv,format=(fourcc)YUY2,width=720,height=525,framerate=30/1' ! ffmpegcolorspace ! tidisplaysink2

I would like to get rid of the ffmpegcolorspace filter but the CCDC will only accept YUY2 (I have put the format structure from ispccdc.c below) and tidisplaysink will only accept UYVY so this is what I am forced to do for now. I don’t really intend to use gstreamer anyways so it really doesn't matter. I am just mentioning it because it is possible the slow speed comes from ffmpegcolorspace.

static const unsigned int ccdc_fmts[] = {
                        V4L2_MBUS_FMT_Y8_1X8,
                        V4L2_MBUS_FMT_Y10_1X10,
                        V4L2_MBUS_FMT_Y12_1X12,
                        V4L2_MBUS_FMT_SGRBG8_1X8,
                        V4L2_MBUS_FMT_SRGGB8_1X8,
                        V4L2_MBUS_FMT_SBGGR8_1X8,
                        V4L2_MBUS_FMT_SGBRG8_1X8,
                        V4L2_MBUS_FMT_SGRBG10_1X10,
                        V4L2_MBUS_FMT_SRGGB10_1X10,
                        V4L2_MBUS_FMT_SBGGR10_1X10,
                        V4L2_MBUS_FMT_SGBRG10_1X10,
                        V4L2_MBUS_FMT_SGRBG12_1X12,
                        V4L2_MBUS_FMT_SRGGB12_1X12,
                        V4L2_MBUS_FMT_SBGGR12_1X12,
                        V4L2_MBUS_FMT_SGBRG12_1X12,
                        V4L2_MBUS_FMT_YUYV8_2X8,
                        V4L2_MBUS_FMT_UYVY8_2X8,
                        V4L2_MBUS_FMT_YUYV8_2X8,
};

 

So to rule out gstreamer I wrote my own program using V4L2 which would grab frames and save them to disk. I just used a V4L2 sample I found and modified it to do what I needed. I have attached the file (“hello_world.c”), sorry for the messy code. If I skip the saving to disk part it appears that I am able to pull frames at 30 fps as would be expected. An interesting fact is if I unplug the FLD wire between the TVP5151 and the DM3730 I start getting frames at 60 fps. But if I save frames from that program I am still missing every other line.

#define DEBUG

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

#include <getopt.h>             /* getopt_long() */

#include <fcntl.h>              /* low-level i/o */
#include <unistd.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <sys/ioctl.h>

#include <linux/videodev2.h>
#include "RegisterLookup.h"

#define CLEAR(x) memset(&(x), 0, sizeof(x))

#ifndef V4L2_PIX_FMT_H264
#define V4L2_PIX_FMT_H264     v4l2_fourcc('Y', 'U', 'Y', 'V') /* H264 with start codes */
#endif

enum io_method {
        IO_METHOD_READ,
        IO_METHOD_MMAP,
        IO_METHOD_USERPTR,
};

struct buffer {
        void   *start;
        size_t  length;
};

static char            *dev_name;
static enum io_method   io = IO_METHOD_MMAP;
static int              fd = -1;
struct buffer          *buffers;
static unsigned int     n_buffers;
static int              out_buf;
static int              force_format;
static int              frame_count = 10;
static int              frame_number = 0;

static void errno_exit(const char *s)
{
        fprintf(stderr, "%s error %d, %s\n", s, errno, strerror(errno));
        exit(EXIT_FAILURE);
}

static int xioctl(int fh, int request, void *arg)
{
        int r;

        do {
                r = ioctl(fh, request, arg);
        } while (-1 == r && EINTR == errno);

        return r;
}
static double time_diff(struct timeval x , struct timeval y)
{
    double x_ms , y_ms , diff;

    x_ms = (double)x.tv_sec*1000 + (double)(x.tv_usec / 1000.0);
    y_ms = (double)y.tv_sec*1000 + (double)(y.tv_usec / 1000.0);

    diff = (double)y_ms - (double)x_ms;

    return diff;
}

static void open_device(void)
{
	struct stat st;

	if (-1 == stat(dev_name, &st)) {
			fprintf(stderr, "Cannot identify '%s': %d, %s\n",
					 dev_name, errno, strerror(errno));
			exit(EXIT_FAILURE);
	}

	if (!S_ISCHR(st.st_mode)) {
			fprintf(stderr, "%s is no device\n", dev_name);
			exit(EXIT_FAILURE);
	}

	fd = open(dev_name, O_RDWR /* required */ | O_NONBLOCK, 0);

	if (-1 == fd) {
			fprintf(stderr, "Cannot open '%s': %d, %s\n",
					 dev_name, errno, strerror(errno));
			exit(EXIT_FAILURE);
	}
}

static void init_mmap(void)
{
	struct v4l2_requestbuffers req;

	CLEAR(req);

	req.count = frame_count;
	req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	req.memory = V4L2_MEMORY_MMAP;

	if (-1 == xioctl(fd, VIDIOC_REQBUFS, &req)) {
			if (EINVAL == errno) {
					fprintf(stderr, "%s does not support "
							 "memory mapping\n", dev_name);
					exit(EXIT_FAILURE);
			} else {
					errno_exit("VIDIOC_REQBUFS");
			}
	}

	if (req.count < 2) {
			fprintf(stderr, "Insufficient buffer memory on %s\n",
					 dev_name);
			exit(EXIT_FAILURE);
	}

	buffers = calloc(req.count, sizeof(*buffers));

	if (!buffers) {
			fprintf(stderr, "Out of memory\n");
			exit(EXIT_FAILURE);
	}

	for (n_buffers = 0; n_buffers < req.count; ++n_buffers) {
			struct v4l2_buffer buf;

			CLEAR(buf);

			buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
			buf.memory      = V4L2_MEMORY_MMAP;
			buf.index       = n_buffers;

			if (-1 == xioctl(fd, VIDIOC_QUERYBUF, &buf))
					errno_exit("VIDIOC_QUERYBUF");

			buffers[n_buffers].length = buf.length;
			buffers[n_buffers].start =
					mmap(NULL /* start anywhere */,
						  buf.length,
						  PROT_READ | PROT_WRITE /* required */,
						  MAP_SHARED /* recommended */,
						  fd, buf.m.offset);

			if (MAP_FAILED == buffers[n_buffers].start)
					errno_exit("mmap");
	}
}
static void init_device(void)
{
	struct v4l2_capability cap;
	struct v4l2_cropcap cropcap;
	struct v4l2_crop crop;
	struct v4l2_format fmt;
	unsigned int min;

	if (-1 == xioctl(fd, VIDIOC_QUERYCAP, &cap)) {
			if (EINVAL == errno) {
					fprintf(stderr, "%s is no V4L2 device\n",
							 dev_name);
					exit(EXIT_FAILURE);
			} else {
					errno_exit("VIDIOC_QUERYCAP");
			}
	}

	if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
			fprintf(stderr, "%s is no video capture device\n",
					 dev_name);
			exit(EXIT_FAILURE);
	}

	if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
			fprintf(stderr, "%s does not support streaming i/o\n",
					 dev_name);
			exit(EXIT_FAILURE);
	}

	/* Select video input, video standard and tune here. */
	CLEAR(cropcap);

	cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

	if (0 == xioctl(fd, VIDIOC_CROPCAP, &cropcap)) {
			crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
			crop.c = cropcap.defrect; /* reset to default */

			if (-1 == xioctl(fd, VIDIOC_S_CROP, &crop)) {
					switch (errno) {
					case EINVAL:
							/* Cropping not supported. */
							break;
					default:
							/* Errors ignored. */
							break;
					}
			}
	} else {
			/* Errors ignored. */
	}


	CLEAR(fmt);

	fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	if (force_format) {
fprintf(stderr, "Set H264\r\n");
			fmt.fmt.pix.width       = 640; //replace
			fmt.fmt.pix.height      = 480; //replace
			fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_H264; //replace
			fmt.fmt.pix.field       = V4L2_FIELD_INTERLACED;

			if (-1 == xioctl(fd, VIDIOC_S_FMT, &fmt))
					errno_exit("VIDIOC_S_FMT");

			/* Note VIDIOC_S_FMT may change width and height. */
	} else {
			/* Preserve original settings as set by v4l2-ctl for example */
			if (-1 == xioctl(fd, VIDIOC_G_FMT, &fmt))
					errno_exit("VIDIOC_G_FMT");
	}

	/* Buggy driver paranoia. */
	min = fmt.fmt.pix.width * 2;
	if (fmt.fmt.pix.bytesperline < min)
			fmt.fmt.pix.bytesperline = min;
	min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height;
	if (fmt.fmt.pix.sizeimage < min)
			fmt.fmt.pix.sizeimage = min;

	init_mmap();
}

static void start_capturing(void)
{
	unsigned int i;
	enum v4l2_buf_type type;

	for (i = 0; i < n_buffers; ++i) {
		struct v4l2_buffer buf;

		CLEAR(buf);
		buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
		buf.memory = V4L2_MEMORY_MMAP;
		buf.index = i;

		if (-1 == xioctl(fd, VIDIOC_QBUF, &buf))
				errno_exit("VIDIOC_QBUF");
	}
	type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	if (-1 == xioctl(fd, VIDIOC_STREAMON, &type))
			errno_exit("VIDIOC_STREAMON");
}

static void process_image(const void *p, int size)
{
	frame_number++;
	char filename[15];
	sprintf(filename, "frame-%d.raw", frame_number);
	FILE *fp=fopen(filename,"wb");

	fwrite(p, size, 1, fp);

	fflush(fp);
	fclose(fp);
}

static int read_frame(void)
{
	struct v4l2_buffer buf;
	unsigned int i;

	CLEAR(buf);

	buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	buf.memory = V4L2_MEMORY_MMAP;

	if (-1 == xioctl(fd, VIDIOC_DQBUF, &buf)) {
			switch (errno) {
			case EAGAIN:
					return 0;

			case EIO:
					/* Could ignore EIO, see spec. */

					/* fall through */

			default:
					errno_exit("VIDIOC_DQBUF");
			}
	}

	assert(buf.index < n_buffers);

	process_image(buffers[buf.index].start, buf.bytesused);

	if (-1 == xioctl(fd, VIDIOC_QBUF, &buf))
			errno_exit("VIDIOC_QBUF");

	return 1;
}

static void mainloop(void)
{
	unsigned int count;
	struct timeval startTime;
	struct timeval endTime;
	unsigned int timeCount = 0;
	double totalTime = 0, fps = 0;

	count = frame_count;

	while (count-- > 0) {
	//while(1) {

		gettimeofday(&startTime, NULL);
		for (;;) {
			/*fd_set fds;
			struct timeval tv;
			int r;

			FD_ZERO(&fds);
			FD_SET(fd, &fds);

			 Timeout.
			tv.tv_sec = 2;
			tv.tv_usec = 0;

			r = select(fd + 1, &fds, NULL, NULL, &tv);

			if (-1 == r) {
					if (EINTR == errno)
							continue;
					errno_exit("select");
			}

			if (0 == r) {
					fprintf(stderr, "select timeout\n");
					exit(EXIT_FAILURE);
			}
			*/

			if (read_frame())
					break;
			/* EAGAIN - continue select loop. */
		}
		gettimeofday(&endTime, NULL);

		++timeCount;
		totalTime += time_diff(startTime, endTime);
		if(totalTime >= 1000)
		{
			fps = ((double)timeCount) / (totalTime / 1000.0);
			printf("%f FPS\n", fps);

			timeCount = 0;
			totalTime = 0;
		}
	}
}

int main()
{
   printf("Hello\n");
   dev_name = "/dev/video2";
   io = IO_METHOD_MMAP;
   force_format = 1;

   open_device();
   init_device();
   start_capturing();
   mainloop();

   return 0;
}


I have spent weeks tweaking register values and coming up with new tests. I am considering moving to BT.656, the only reason I didn’t use it was because I assumed it would be easier to debug with the discrete syncs. I hoping I am just overlooking a register setting somewhere and someone who has experience with these chips will be able to notice it.Again, any help or ideas would be greatly appreciated as the only one I have left is to try BT.656. Thanks for your time.

omap3isp omap3isp: -------------CCDC Register dump-------------
omap3isp omap3isp: ###CCDC PCR=0x00000000
omap3isp omap3isp: ###CCDC SYN_MODE=0x00031084
omap3isp omap3isp: ###CCDC HD_VD_WID=0x00000000
omap3isp omap3isp: ###CCDC PIX_LINES=0x00000000
omap3isp omap3isp: ###CCDC HORZ_INFO=0x009f027f
omap3isp omap3isp: ###CCDC VERT_START=0x00190019
omap3isp omap3isp: ###CCDC VERT_LINES=0x000001df
omap3isp omap3isp: ###CCDC CULLING=0xffff00ff
omap3isp omap3isp: ###CCDC HSIZE_OFF=0x00000500
omap3isp omap3isp: ###CCDC SDOFST=0x00000249
omap3isp omap3isp: ###CCDC SDR_ADDR=0x00001000
omap3isp omap3isp: ###CCDC CLAMP=0x00000010
omap3isp omap3isp: ###CCDC DCSUB=0x00000000
omap3isp omap3isp: ###CCDC COLPTN=0x00000000
omap3isp omap3isp: ###CCDC BLKCMP=0x00000000
omap3isp omap3isp: ###CCDC FPC=0x00000000
omap3isp omap3isp: ###CCDC FPC_ADDR=0x00000000
omap3isp omap3isp: ###CCDC VDINT=0x010400ae
omap3isp omap3isp: ###CCDC ALAW=0x00000004
omap3isp omap3isp: ###CCDC REC656IF=0x00000000
omap3isp omap3isp: ###CCDC CFG=0x00008880
omap3isp omap3isp: ###CCDC FMTCFG=0x00006000
omap3isp omap3isp: ###CCDC FMT_HORZ=0x000002d0
omap3isp omap3isp: ###CCDC FMT_VERT=0x0000020d
omap3isp omap3isp: ###CCDC PRGEVEN0=0x00000000
omap3isp omap3isp: ###CCDC PRGEVEN1=0x00000000
omap3isp omap3isp: ###CCDC PRGODD0=0x00000000
omap3isp omap3isp: ###CCDC PRGODD1=0x00000000
omap3isp omap3isp: ###CCDC VP_OUT=0x04182d00
omap3isp omap3isp: ###CCDC LSC_CONFIG=0x00006600
omap3isp omap3isp: ###CCDC LSC_INITIAL=0x00000000
omap3isp omap3isp: ###CCDC LSC_TABLE_BASE=0x00000000
omap3isp omap3isp: ###CCDC LSC_TABLE_OFFSET=0x00000000
omap3isp omap3isp: --------------------------------------------
omap3isp omap3isp: -------------ISP Register dump--------------
omap3isp omap3isp: ###ISP SYSCONFIG=0x00002001
omap3isp omap3isp: ###ISP SYSSTATUS=0x00000001
omap3isp omap3isp: ###ISP IRQ0ENABLE=0x811b33f9
omap3isp omap3isp: ###ISP IRQ0STATUS=0x00000000
omap3isp omap3isp: ###ISP TCTRL_GRESET_LENGTH=0x00000000
omap3isp omap3isp: ###ISP TCTRL_PSTRB_REPLAY=0x00000000
omap3isp omap3isp: ###ISP CTRL=0x00290108
omap3isp omap3isp: ###ISP TCTRL_CTRL=0x00000000
omap3isp omap3isp: ###ISP TCTRL_FRAME=0x000c0000
omap3isp omap3isp: ###ISP TCTRL_PSTRB_DELAY=0x00000000
omap3isp omap3isp: ###ISP TCTRL_STRB_DELAY=0x00000000
omap3isp omap3isp: ###ISP TCTRL_SHUT_DELAY=0x00000000
omap3isp omap3isp: ###ISP TCTRL_PSTRB_LENGTH=0x00000000
omap3isp omap3isp: ###ISP TCTRL_STRB_LENGTH=0x00000000
omap3isp omap3isp: ###ISP TCTRL_SHUT_LENGTH=0x00000000
omap3isp omap3isp: ###SBL PCR=0x00000000
omap3isp omap3isp: ###SBL SDR_REQ_EXP=0x00000000
omap3isp omap3isp: --------------------------------------------

  

tvp5150: Video input source selection #1 = 0x00
tvp5150: Analog channel controls = 0x15
tvp5150: Operation mode controls = 0x00
tvp5150: Miscellaneous controls = 0x6D
tvp5150: Autoswitch mask= 0xdc
tvp5150: Color killer threshold control = 0x10
tvp5150: Luminance processing controls #1 #2 and #3 = 60 00 00
tvp5150: Brightness control = 0x80
tvp5150: Color saturation control = 0x80
tvp5150: Hue control = 0x00
tvp5150: Contrast control = 0x80
tvp5150: Outputs and data rates select = 0x40
tvp5150: Configuration shared pins = 0x00
tvp5150: Active video cropping start = 0x0000
tvp5150: Active video cropping stop  = 0x0000
tvp5150: Genlock/RTC = 0x01
tvp5150: Horizontal sync start = 0x80
tvp5150: Vertical blanking start = 0x00
tvp5150: Vertical blanking stop = 0x00
tvp5150: Chrominance processing control #1 and #2 = 0c 14
tvp5150: Interrupt reset register B = 0x00
tvp5150: Interrupt enable register B = 0x00
tvp5150: Interrupt configuration register B = 0x00
tvp5150: Video standard = 0x00
tvp5150: Chroma gain factor: Cb=0x00 Cr=0x00
tvp5150: Macrovision on counter = 0x0f
tvp5150: Macrovision off counter = 0x01
tvp5150: ITU-R BT.656.4 timing(TVP5150AM1 only)
tvp5150: Device ID = 5151
tvp5150: ROM version = (hex) 01.00
tvp5150: Vertical line count = 0x020d
tvp5150: Interrupt status register B = 0x80
tvp5150: Interrupt active register B = 0x00
tvp5150: Status regs #1 to #5 = 10 08 00 55 81
tvp5150: Teletext filter 1 reg 0xb1 = 00 00 00 00 00
tvp5150: Teletext filter 2 reg 0xb6 = 00 00 00 00 00
tvp5150: Teletext filter enable = 0x00
tvp5150: Interrupt status register A = 0x00
tvp5150: Interrupt enable register A = 0x00
tvp5150: Interrupt configuration = 0x04
tvp5150: VDP status register = 0xc0
tvp5150: FIFO word count = 0x00
tvp5150: FIFO interrupt threshold = 0x80
tvp5150: FIFO reset = 0x00
tvp5150: Line number interrupt = 0x00
tvp5150: Pixel alignment register = 0x004e
tvp5150: FIFO output control = 0x00
tvp5150: Full field enable = 0x00
tvp5150: Full field mode register = 0x7f
tvp5150: CC   data reg 0x90 = 00 00 00 00
tvp5150: WSS  data reg 0x94 = 00 00 00 00 00 00
tvp5150: VPS  data reg 0x9a = 00 00 00 00 00 00 00 00
tvp5150: VPS  data reg 0xa2 = 00 00 00 00 00
tvp5150: VITC data reg 0xa7 = 00 00 00 00 00 00 00 00 00
tvp5150: Line mode reg 0xd0 = 00 ff ff ff ff ff ff ff
tvp5150: Line mode reg 0xd8 = ff ff ff ff ff ff ff ff
tvp5150: Line mode reg 0xe0 = ff ff ff ff ff ff ff ff
tvp5150: Line mode reg 0xe8 = ff ff ff ff ff ff ff ff
tvp5150: Line mode reg 0xf0 = ff ff ff ff ff ff ff ff
tvp5150: Line mode reg 0xf8 = ff ff ff ff
  • Hi Matthew,

    The registers configuration which you are using seems correct. Therefore I'm focusing on the software implementation of data writing. I will try to give you an idea for improve the frame rate performance when writing the data to the disk. The disk operations are slow therefore I recommend you to try to move data writing in a separate thread.

    BR

    Tsvetolin Shulev

  • Thanks for the advice. Unfortunately, while that would solve my frame rate issue I will still be missing half the image.

  • Matthew,

    This is very difficult to solve over forum.If you can spare one hardware and schematics, I can get it resolved.

  • Ok, here's and update. I have confirmed with a scope that the TVP5150 is outputting correctly. I also confirmed by switching the pins to GPIO inputs that the DM3730 is getting the correct signals. I have narrowed the problem down to the FLDSTAT in CCDC_SYN_MODE. For some reason even though I have confirmed the cam_fld signal is switching properly the FLDSTAT bit does not change. Maybe that helps narrow down the problem.

  • Hello,

    Matthew Adams said:
    gst-launch -v v4l2src device="/dev/video2" num-buffers=50 always-copy=false queue-size=50 ! 'video/x-raw-yuv,format=(fourcc)YUY2,width=720,height=525,framerate=30/1' ! ffmpegcolorspace ! tidisplaysink2

    I am not familiar with DM37x.

    Regarding the frame rate:

    One of the reason for frame drop could be  that you are using ffmpegcolorspace this leads to  ARM load also.

    ffmpegcolorspace — converts video from one colorspace to another and it is implemented in the gstreamer plugin, so it doesn't use hardware acceleration. You could try to avoid this, if it is possible .

    You could try by enlarging the buffers too. You have to enlarge the queues as well as the buffers of your sources,e.g. 

    queue max-size-buffers=XX max-size-time=XX max-size-bytes=XX

     v4l2src queue-size=XX

    omxbufferalloc numBuffers=XX.


    BR

    Margarita

  • Yeah, I figured ffmpegcolorspace was causing me trouble but I quit using gstreamer to get around that problem.

    I have done some more testing and come up with some interesting results.

    The FLD line goes high 30 times a second and I don't see it change in the CCDC.

    Out of curiosity I manually drove the FLD line so that it went high only 15 times a second and I saw it change as expected in the CCDC.

    Any faster than 15hz and I got inconsistent results, this leads me to believe that the CCDC is only sampling the FLD line 15 times a second which would explain why I never sees a change if the FLD line is going high 30 times a second.

    So now I know the problem but I'm not sure how to fix it. 30 fps requires the FLD line to be at 30hz. It doesn't appear that the tvp5150 will allow me to drop to 15 fps. Any Ideas?

  • Hello,

    I am sorry. I am not a proper expert for DVSDK and dm37x.

    I will try to involve some expert here.

    BR

    Margarita

  • Mathew,

    Have you checked the master clock to TVP51xx and the pixel clock output as well? What is the frequency set?

  • The tvp5150 is on TI's EVM which has an external 27mhz clock. The TVP's pixel clock is 13.5mhz but the TVP's default is to use 2x the pixel clock (27mhz) as the output to the DM3730. I have verified this with a scope and I have also tried using the 13.5mhz clock which did not fix the issue.

  • I haven't had a chance to get back and update this thread but I finally got it working. Turns out I had two issues.

    1) I had my CCDC VERT_LINES register set to 479 since I was expecting 480 lines, turns out for interlaced video this needs to be cut in half to 239. This was the biggest problem and what was causing the odd frames to be black.

    2) The other problem which I never solved is that the FLDSTAT bit appears to be unreliable from where I am attempting to read it. I have tried reading it in both the VD0 interrupt and the VD1 interrupt and both provide incorrect results. I can tell it is being read by the CCDC correctly because the odd frames are offset by 1 line but when I read the register it rarely changes. Not a huge deal, it just means I can't verify I'm starting on an even frame so it is possible for me to be a half frame off. This is currently acceptable for my needs and if it does ever happen I haven't been able to detect it.