Other Parts Discussed in Thread: TVP5147, TVP7002, TVP5147M1
have a problem when i try tvp5147 working on 422 20bit mode.
When I used ioctl DQBUF to get data from tvp5147, the program suspended.
I have do 3 things:
1.I modified the code of tvp514x.c:
{TOK_WRITE, REG_OUTPUT_FORMATTER1, 0x01},
/*
* drivers/media/video/tvp514x.c
*
* TI TVP5146/47 decoder driver
*
* Copyright (C) 2008 Texas Instruments Inc
* Author: Vaibhav Hiremath <hvaibhav@ti.com>
*
* Contributors:
* Sivaraj R <sivaraj@ti.com>
* Brijesh R Jadav <brijesh.j@ti.com>
* Hardik Shah <hardik.shah@ti.com>
* Manjunath Hadli <mrh@ti.com>
* Karicheri Muralidharan <m-karicheri2@ti.com>
*
* This package is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/videodev2.h>
#include <linux/v4l2-mediabus.h>
#include <media/v4l2-device.h>
#include <media/v4l2-common.h>
#include <media/v4l2-chip-ident.h>
#include <media/v4l2-subdev.h>
#include <media/v4l2-ctrls.h>
#include <media/tvp514x.h>
#include "tvp514x_regs.h"
/* Module Name */
#define TVP514X_MODULE_NAME "tvp514x"
/* Private macros for TVP */
#define I2C_RETRY_COUNT (5)
#define LOCK_RETRY_COUNT (5)
#define LOCK_RETRY_DELAY (200)
/* Debug functions */
static int debug;
module_param(debug, bool, 0644);
MODULE_PARM_DESC(debug, "Debug level (0-1)");
MODULE_AUTHOR("Texas Instruments");
MODULE_DESCRIPTION("TVP514X linux decoder driver");
MODULE_LICENSE("GPL");
/* enum tvp514x_std - enum for supported standards */
enum tvp514x_std {
STD_NTSC_MJ = 0,
STD_PAL_BDGHIN,
STD_INVALID
};
/**
* struct tvp514x_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 tvp514x_std_info {
unsigned long width;
unsigned long height;
u8 video_std;
struct v4l2_standard standard;
unsigned int mbus_code;
struct v4l2_mbus_framefmt format;
};
static struct tvp514x_reg tvp514x_reg_list_default[0x40];
static int tvp514x_s_stream(struct v4l2_subdev *sd, int enable);
/**
* struct tvp514x_decoder - TVP5146/47 decoder object
* @sd: Subdevice Slave handle
* @tvp514x_regs: copy of hw's regs with preset values.
* @pdata: Board specific
* @ver: Chip version
* @streaming: TVP5146/47 decoder streaming - enabled or disabled.
* @current_std: Current standard
* @num_stds: Number of standards
* @std_list: Standards list
* @input: Input routing at chip level
* @output: Output routing at chip level
*/
struct tvp514x_decoder {
struct v4l2_subdev sd;
struct tvp514x_reg tvp514x_regs[ARRAY_SIZE(tvp514x_reg_list_default)];
const struct tvp514x_platform_data *pdata;
struct media_pad pad;
int ver;
int streaming;
enum tvp514x_std current_std;
int num_stds;
const struct tvp514x_std_info *std_list;
/* Input and Output Routing parameters */
u32 input;
u32 output;
};
/* TVP514x default register values */
static struct tvp514x_reg tvp514x_reg_list_default[] = {
/* Composite selected */
{TOK_WRITE, REG_INPUT_SEL, 0x05},
{TOK_WRITE, REG_AFE_GAIN_CTRL, 0x0F},
/* Auto mode */
{TOK_WRITE, REG_VIDEO_STD, 0x00},
{TOK_WRITE, REG_OPERATION_MODE, 0x00},
{TOK_SKIP, REG_AUTOSWITCH_MASK, 0x3F},
{TOK_WRITE, REG_COLOR_KILLER, 0x10},
{TOK_WRITE, REG_LUMA_CONTROL1, 0x00},
{TOK_WRITE, REG_LUMA_CONTROL2, 0x00},
{TOK_WRITE, REG_LUMA_CONTROL3, 0x02},
{TOK_WRITE, REG_BRIGHTNESS, 0x80},
{TOK_WRITE, REG_CONTRAST, 0x80},
{TOK_WRITE, REG_SATURATION, 0x80},
{TOK_WRITE, REG_HUE, 0x00},
{TOK_WRITE, REG_CHROMA_CONTROL1, 0x00},
{TOK_WRITE, REG_CHROMA_CONTROL2, 0x0E},
/* Reserved */
{TOK_SKIP, 0x0F, 0x00},
{TOK_WRITE, REG_COMP_PR_SATURATION, 0x80},
{TOK_WRITE, REG_COMP_Y_CONTRAST, 0x80},
{TOK_WRITE, REG_COMP_PB_SATURATION, 0x80},
/* Reserved */
{TOK_SKIP, 0x13, 0x00},
{TOK_WRITE, REG_COMP_Y_BRIGHTNESS, 0x80},
/* Reserved */
{TOK_SKIP, 0x15, 0x00},
/* NTSC timing */
/* {TOK_WRITE, REG_AVID_START_PIXEL_LSB, 0x7A},
{TOK_WRITE, REG_AVID_START_PIXEL_MSB, 0x00},
{TOK_WRITE, REG_AVID_STOP_PIXEL_LSB, 0x4a},
{TOK_WRITE, REG_AVID_STOP_PIXEL_MSB, 0x06},
{TOK_WRITE, REG_HSYNC_START_PIXEL_LSB, 0x00},
{TOK_WRITE, REG_HSYNC_START_PIXEL_MSB, 0x00},
{TOK_WRITE, REG_HSYNC_STOP_PIXEL_LSB, 0x80},
{TOK_WRITE, REG_HSYNC_STOP_PIXEL_MSB, 0x00},
*/
{TOK_WRITE, REG_AVID_START_PIXEL_LSB, 0x55},
{TOK_WRITE, REG_AVID_START_PIXEL_MSB, 0x00},
{TOK_WRITE, REG_AVID_STOP_PIXEL_LSB, 0x25},
{TOK_WRITE, REG_AVID_STOP_PIXEL_MSB, 0x03},
/* NTSC timing */
{TOK_WRITE, REG_HSYNC_START_PIXEL_LSB, 0x00},
{TOK_WRITE, REG_HSYNC_START_PIXEL_MSB, 0x00},
{TOK_WRITE, REG_HSYNC_STOP_PIXEL_LSB, 0x40},
{TOK_WRITE, REG_HSYNC_STOP_PIXEL_MSB, 0x00},
/* NTSC timing */
{TOK_SKIP, REG_VSYNC_START_LINE_LSB, 0x04},
{TOK_SKIP, REG_VSYNC_START_LINE_MSB, 0x00},
{TOK_SKIP, REG_VSYNC_STOP_LINE_LSB, 0x07},
{TOK_SKIP, REG_VSYNC_STOP_LINE_MSB, 0x00},
/* NTSC timing */
{TOK_SKIP, REG_VBLK_START_LINE_LSB, 0x01},
{TOK_SKIP, REG_VBLK_START_LINE_MSB, 0x00},
{TOK_SKIP, REG_VBLK_STOP_LINE_LSB, 0x15},
{TOK_SKIP, REG_VBLK_STOP_LINE_MSB, 0x00},
/* Reserved */
{TOK_SKIP, 0x26, 0x00},
/* Reserved */
{TOK_SKIP, 0x27, 0x00},
{TOK_SKIP, REG_FAST_SWTICH_CONTROL, 0xCC},
/* Reserved */
{TOK_SKIP, 0x29, 0x00},
{TOK_SKIP, REG_FAST_SWTICH_SCART_DELAY, 0x00},
/* Reserved */
{TOK_SKIP, 0x2B, 0x00},
{TOK_SKIP, REG_SCART_DELAY, 0x00},
{TOK_SKIP, REG_CTI_DELAY, 0x00},
{TOK_SKIP, REG_CTI_CONTROL, 0x00},
/* Reserved */
{TOK_SKIP, 0x2F, 0x00},
/* Reserved */
{TOK_SKIP, 0x30, 0x00},
/* Reserved */
{TOK_SKIP, 0x31, 0x00},
/* HS, VS active high */
{TOK_WRITE, REG_SYNC_CONTROL, 0x00},
/* 10-bit BT.656 */
{TOK_WRITE, REG_OUTPUT_FORMATTER1, 0x01},
/* Enable clk & data */
{TOK_WRITE, REG_OUTPUT_FORMATTER2, 0x11},
/* Enable AVID & FLD */
{TOK_WRITE, REG_OUTPUT_FORMATTER3, 0xEE},
/* Enable VS & HS */
{TOK_WRITE, REG_OUTPUT_FORMATTER4, 0xAF},
{TOK_WRITE, REG_OUTPUT_FORMATTER5, 0xFF},
{TOK_WRITE, REG_OUTPUT_FORMATTER6, 0xFF},
/* Clear status */
{TOK_WRITE, REG_CLEAR_LOST_LOCK, 0x01},
{TOK_TERM, 0, 0},
};
/**
* Supported standards -
*
* Currently supports two standards only, need to add support for rest of the
* modes, like SECAM, etc...
*/
static const struct tvp514x_std_info tvp514x_std_list[] = {
/* Standard: STD_NTSC_MJ */
[STD_NTSC_MJ] = {
.width = NTSC_NUM_ACTIVE_PIXELS,
.height = NTSC_NUM_ACTIVE_LINES,
.video_std = VIDEO_STD_NTSC_MJ_BIT,
.mbus_code = V4L2_MBUS_FMT_UYVY8_2X8,
.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: STD_PAL_BDGHIN */
[STD_PAL_BDGHIN] = {
.width = PAL_NUM_ACTIVE_PIXELS,
.height = PAL_NUM_ACTIVE_LINES,
.video_std = VIDEO_STD_PAL_BDGHIN_BIT,
.mbus_code = V4L2_MBUS_FMT_UYVY8_2X8,
.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,
},
},
/* Standard: need to add for additional standard */
};
static inline struct tvp514x_decoder *to_decoder(struct v4l2_subdev *sd)
{
return container_of(sd, struct tvp514x_decoder, sd);
}
/**
* tvp514x_read_reg() - Read a value from a register in an TVP5146/47.
* @sd: ptr to v4l2_subdev struct
* @reg: TVP5146/47 register address
*
* Returns value read if successful, or non-zero (-1) otherwise.
*/
static int tvp514x_read_reg(struct v4l2_subdev *sd, u8 reg)
{
int err, retry = 0;
struct i2c_client *client = v4l2_get_subdevdata(sd);
read_again:
err = i2c_smbus_read_byte_data(client, reg);
if (err < 0) {
if (retry <= I2C_RETRY_COUNT) {
v4l2_warn(sd, "Read: retry ... %d\n", retry);
retry++;
msleep_interruptible(10);
goto read_again;
}
}
printk("tvp5147 read reg = %x, data = %x\n", reg, err);
return err;
}
/**
* dump_reg() - dump the register content of TVP5146/47.
* @sd: ptr to v4l2_subdev struct
* @reg: TVP5146/47 register address
*/
static void dump_reg(struct v4l2_subdev *sd, u8 reg)
{
u32 val;
val = tvp514x_read_reg(sd, reg);
v4l2_info(sd, "Reg(0x%.2X): 0x%.2X\n", reg, val);
}
/**
* tvp514x_write_reg() - Write a value to a register in TVP5146/47
* @sd: ptr to v4l2_subdev struct
* @reg: TVP5146/47 register address
* @val: value to be written to the register
*
* Write a value to a register in an TVP5146/47 decoder device.
* Returns zero if successful, or non-zero otherwise.
*/
static int tvp514x_write_reg(struct v4l2_subdev *sd, u8 reg, u8 val)
{
int err, retry = 0;
struct i2c_client *client = v4l2_get_subdevdata(sd);
write_again:
printk("tvp5147 write reg = %x, data = %x\n", reg, val);
err = i2c_smbus_write_byte_data(client, reg, val);
if (err) {
if (retry <= I2C_RETRY_COUNT) {
v4l2_warn(sd, "Write: retry ... %d\n", retry);
retry++;
msleep_interruptible(10);
goto write_again;
}
}
return err;
}
/**
* tvp514x_write_regs() : Initializes a list of TVP5146/47 registers
* @sd: ptr to v4l2_subdev struct
* @reglist: list of TVP5146/47 registers and values
*
* Initializes a list of TVP5146/47 registers:-
* if token is TOK_TERM, then entire write operation terminates
* if token is TOK_DELAY, then a delay of 'val' msec is introduced
* if token is TOK_SKIP, then the register write is skipped
* if token is TOK_WRITE, then the register write is performed
* Returns zero if successful, or non-zero otherwise.
*/
static int tvp514x_write_regs(struct v4l2_subdev *sd,
const struct tvp514x_reg reglist[])
{
int err;
const struct tvp514x_reg *next = reglist;
for (; next->token != TOK_TERM; next++) {
if (next->token == TOK_DELAY) {
msleep(next->val);
continue;
}
if (next->token == TOK_SKIP)
continue;
err = tvp514x_write_reg(sd, next->reg, (u8) next->val);
if (err) {
v4l2_err(sd, "Write failed. Err[%d]\n", err);
return err;
}
}
return 0;
}
/**
* tvp514x_query_current_std() : Query the current standard detected by TVP5146/47
* @sd: ptr to v4l2_subdev struct
*
* Returns the current standard detected by TVP5146/47, STD_INVALID if there is no
* standard detected.
*/
static enum tvp514x_std tvp514x_query_current_std(struct v4l2_subdev *sd)
{
u8 std, std_status;
std = tvp514x_read_reg(sd, REG_VIDEO_STD);
if ((std & VIDEO_STD_MASK) == VIDEO_STD_AUTO_SWITCH_BIT)
/* use the standard status register */
std_status = tvp514x_read_reg(sd, REG_VIDEO_STD_STATUS);
else
/* use the standard register itself */
std_status = std;
switch (std_status & VIDEO_STD_MASK) {
case VIDEO_STD_NTSC_MJ_BIT:
return STD_NTSC_MJ;
case VIDEO_STD_PAL_BDGHIN_BIT:
return STD_PAL_BDGHIN;
default:
return STD_INVALID;
}
return STD_INVALID;
}
/* TVP5146/47 register dump function */
static void tvp514x_reg_dump(struct v4l2_subdev *sd)
{
dump_reg(sd, REG_INPUT_SEL);
dump_reg(sd, REG_AFE_GAIN_CTRL);
dump_reg(sd, REG_VIDEO_STD);
dump_reg(sd, REG_OPERATION_MODE);
dump_reg(sd, REG_COLOR_KILLER);
dump_reg(sd, REG_LUMA_CONTROL1);
dump_reg(sd, REG_LUMA_CONTROL2);
dump_reg(sd, REG_LUMA_CONTROL3);
dump_reg(sd, REG_BRIGHTNESS);
dump_reg(sd, REG_CONTRAST);
dump_reg(sd, REG_SATURATION);
dump_reg(sd, REG_HUE);
dump_reg(sd, REG_CHROMA_CONTROL1);
dump_reg(sd, REG_CHROMA_CONTROL2);
dump_reg(sd, REG_COMP_PR_SATURATION);
dump_reg(sd, REG_COMP_Y_CONTRAST);
dump_reg(sd, REG_COMP_PB_SATURATION);
dump_reg(sd, REG_COMP_Y_BRIGHTNESS);
dump_reg(sd, REG_AVID_START_PIXEL_LSB);
dump_reg(sd, REG_AVID_START_PIXEL_MSB);
dump_reg(sd, REG_AVID_STOP_PIXEL_LSB);
dump_reg(sd, REG_AVID_STOP_PIXEL_MSB);
dump_reg(sd, REG_HSYNC_START_PIXEL_LSB);
dump_reg(sd, REG_HSYNC_START_PIXEL_MSB);
dump_reg(sd, REG_HSYNC_STOP_PIXEL_LSB);
dump_reg(sd, REG_HSYNC_STOP_PIXEL_MSB);
dump_reg(sd, REG_VSYNC_START_LINE_LSB);
dump_reg(sd, REG_VSYNC_START_LINE_MSB);
dump_reg(sd, REG_VSYNC_STOP_LINE_LSB);
dump_reg(sd, REG_VSYNC_STOP_LINE_MSB);
dump_reg(sd, REG_VBLK_START_LINE_LSB);
dump_reg(sd, REG_VBLK_START_LINE_MSB);
dump_reg(sd, REG_VBLK_STOP_LINE_LSB);
dump_reg(sd, REG_VBLK_STOP_LINE_MSB);
dump_reg(sd, REG_SYNC_CONTROL);
dump_reg(sd, REG_OUTPUT_FORMATTER1);
dump_reg(sd, REG_OUTPUT_FORMATTER2);
dump_reg(sd, REG_OUTPUT_FORMATTER3);
dump_reg(sd, REG_OUTPUT_FORMATTER4);
dump_reg(sd, REG_OUTPUT_FORMATTER5);
dump_reg(sd, REG_OUTPUT_FORMATTER6);
dump_reg(sd, REG_CLEAR_LOST_LOCK);
}
/**
* tvp514x_configure() - Configure the TVP5146/47 registers
* @sd: ptr to v4l2_subdev struct
* @decoder: ptr to tvp514x_decoder structure
*
* Returns zero if successful, or non-zero otherwise.
*/
static int tvp514x_configure(struct v4l2_subdev *sd,
struct tvp514x_decoder *decoder)
{
int err;
/* common register initialization */
err =
tvp514x_write_regs(sd, decoder->tvp514x_regs);
if (err)
return err;
if (debug)
tvp514x_reg_dump(sd);
return 0;
}
/**
* tvp514x_detect() - Detect if an tvp514x is present, and if so which revision.
* @sd: pointer to standard V4L2 sub-device structure
* @decoder: pointer to tvp514x_decoder structure
*
* A device is considered to be detected if the chip ID (LSB and MSB)
* registers match the expected values.
* Any value of the rom version register is accepted.
* Returns ENODEV error number if no device is detected, or zero
* if a device is detected.
*/
static int tvp514x_detect(struct v4l2_subdev *sd,
struct tvp514x_decoder *decoder)
{
u8 chip_id_msb, chip_id_lsb, rom_ver;
struct i2c_client *client = v4l2_get_subdevdata(sd);
chip_id_msb = tvp514x_read_reg(sd, REG_CHIP_ID_MSB);
chip_id_lsb = tvp514x_read_reg(sd, REG_CHIP_ID_LSB);
rom_ver = tvp514x_read_reg(sd, REG_ROM_VERSION);
v4l2_dbg(1, debug, sd,
"chip id detected msb:0x%x lsb:0x%x rom version:0x%x\n",
chip_id_msb, chip_id_lsb, rom_ver);
if ((chip_id_msb != TVP514X_CHIP_ID_MSB)
|| ((chip_id_lsb != TVP5146_CHIP_ID_LSB)
&& (chip_id_lsb != TVP5147_CHIP_ID_LSB))) {
/* We didn't read the values we expected, so this must not be
* an TVP5146/47.
*/
v4l2_err(sd, "chip id mismatch msb:0x%x lsb:0x%x\n",
chip_id_msb, chip_id_lsb);
return -ENODEV;
}
decoder->ver = rom_ver;
v4l2_info(sd, "%s (Version - 0x%.2x) found at 0x%x (%s)\n",
client->name, decoder->ver,
client->addr << 1, client->adapter->name);
return 0;
}
/**
* tvp514x_querystd() - V4L2 decoder interface handler for querystd
* @sd: pointer to standard V4L2 sub-device structure
* @std_id: standard V4L2 std_id ioctl enum
*
* Returns the current standard detected by TVP5146/47. If no active input is
* detected then *std_id is set to 0 and the function returns 0.
*/
static int tvp514x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std_id)
{
struct tvp514x_decoder *decoder = to_decoder(sd);
enum tvp514x_std current_std;
enum tvp514x_input input_sel;
u8 sync_lock_status, lock_mask;
if (std_id == NULL)
return -EINVAL;
*std_id = V4L2_STD_UNKNOWN;
/* query the current standard */
current_std = tvp514x_query_current_std(sd);
if (current_std == STD_INVALID)
return 0;
input_sel = decoder->input;
switch (input_sel) {
case INPUT_CVBS_VI1A:
case INPUT_CVBS_VI1B:
case INPUT_CVBS_VI1C:
case INPUT_CVBS_VI2A:
case INPUT_CVBS_VI2B:
case INPUT_CVBS_VI2C:
case INPUT_CVBS_VI3A:
case INPUT_CVBS_VI3B:
case INPUT_CVBS_VI3C:
case INPUT_CVBS_VI4A:
lock_mask = STATUS_CLR_SUBCAR_LOCK_BIT |
STATUS_HORZ_SYNC_LOCK_BIT |
STATUS_VIRT_SYNC_LOCK_BIT;
break;
case INPUT_SVIDEO_VI2A_VI1A:
case INPUT_SVIDEO_VI2B_VI1B:
case INPUT_SVIDEO_VI2C_VI1C:
case INPUT_SVIDEO_VI2A_VI3A:
case INPUT_SVIDEO_VI2B_VI3B:
case INPUT_SVIDEO_VI2C_VI3C:
case INPUT_SVIDEO_VI4A_VI1A:
case INPUT_SVIDEO_VI4A_VI1B:
case INPUT_SVIDEO_VI4A_VI1C:
case INPUT_SVIDEO_VI4A_VI3A:
case INPUT_SVIDEO_VI4A_VI3B:
case INPUT_SVIDEO_VI4A_VI3C:
lock_mask = STATUS_HORZ_SYNC_LOCK_BIT |
STATUS_VIRT_SYNC_LOCK_BIT;
break;
/*Need to add other interfaces*/
default:
return -EINVAL;
}
/* check whether signal is locked */
sync_lock_status = tvp514x_read_reg(sd, REG_STATUS1);
if (lock_mask != (sync_lock_status & lock_mask))
return 0; /* No input detected */
*std_id = decoder->std_list[current_std].standard.id;
v4l2_dbg(1, debug, sd, "Current STD: %s\n",
decoder->std_list[current_std].standard.name);
return 0;
}
/**
* tvp514x_s_std() - V4L2 decoder interface handler for s_std
* @sd: pointer to standard V4L2 sub-device structure
* @std_id: standard V4L2 v4l2_std_id ioctl enum
*
* If std_id is supported, sets the requested standard. Otherwise, returns
* -EINVAL
*/
static int tvp514x_s_std(struct v4l2_subdev *sd, v4l2_std_id std_id)
{
struct tvp514x_decoder *decoder = to_decoder(sd);
int err, i;
for (i = 0; i < decoder->num_stds; i++)
if (std_id & decoder->std_list[i].standard.id)
break;
if ((i == decoder->num_stds) || (i == STD_INVALID))
return -EINVAL;
err = tvp514x_write_reg(sd, REG_VIDEO_STD,
decoder->std_list[i].video_std);
if (err)
return err;
decoder->current_std = i;
decoder->tvp514x_regs[REG_VIDEO_STD].val =
decoder->std_list[i].video_std;
v4l2_dbg(1, debug, sd, "Standard set to: %s\n",
decoder->std_list[i].standard.name);
return 0;
}
/**
* tvp514x_s_routing() - V4L2 decoder interface handler for s_routing
* @sd: pointer to standard V4L2 sub-device structure
* @input: input selector for routing the signal
* @output: output selector for routing the signal
* @config: config value. Not used
*
* If index is valid, selects the requested input. Otherwise, returns -EINVAL if
* the input is not supported or there is no active signal present in the
* selected input.
*/
static int tvp514x_s_routing(struct v4l2_subdev *sd,
u32 input, u32 output, u32 config)
{
struct tvp514x_decoder *decoder = to_decoder(sd);
int err;
enum tvp514x_input input_sel;
enum tvp514x_output output_sel;
u8 sync_lock_status, lock_mask;
int try_count = LOCK_RETRY_COUNT;
if ((input >= INPUT_INVALID) ||
(output >= OUTPUT_INVALID))
/* Index out of bound */
return -EINVAL;
/*
* For the sequence streamon -> streamoff and again s_input
* it fails to lock the signal, since streamoff puts TVP514x
* into power off state which leads to failure in sub-sequent s_input.
*
* So power up the TVP514x device here, since it is important to lock
* the signal at this stage.
*/
if (!decoder->streaming)
tvp514x_s_stream(sd, 1);
input_sel = input;
output_sel = output;
err = tvp514x_write_reg(sd, REG_INPUT_SEL, input_sel);
if (err)
return err;
output_sel |= tvp514x_read_reg(sd,
REG_OUTPUT_FORMATTER1) & 0x7;
err = tvp514x_write_reg(sd, REG_OUTPUT_FORMATTER1,
output_sel);
if (err)
return err;
decoder->tvp514x_regs[REG_INPUT_SEL].val = input_sel;
decoder->tvp514x_regs[REG_OUTPUT_FORMATTER1].val = output_sel;
/* Clear status */
msleep(LOCK_RETRY_DELAY);
err =
tvp514x_write_reg(sd, REG_CLEAR_LOST_LOCK, 0x01);
if (err)
return err;
switch (input_sel) {
case INPUT_CVBS_VI1A:
case INPUT_CVBS_VI1B:
case INPUT_CVBS_VI1C:
case INPUT_CVBS_VI2A:
case INPUT_CVBS_VI2B:
case INPUT_CVBS_VI2C:
case INPUT_CVBS_VI3A:
case INPUT_CVBS_VI3B:
case INPUT_CVBS_VI3C:
case INPUT_CVBS_VI4A:
lock_mask = STATUS_CLR_SUBCAR_LOCK_BIT |
STATUS_HORZ_SYNC_LOCK_BIT |
STATUS_VIRT_SYNC_LOCK_BIT;
break;
case INPUT_SVIDEO_VI2A_VI1A:
case INPUT_SVIDEO_VI2B_VI1B:
case INPUT_SVIDEO_VI2C_VI1C:
case INPUT_SVIDEO_VI2A_VI3A:
case INPUT_SVIDEO_VI2B_VI3B:
case INPUT_SVIDEO_VI2C_VI3C:
case INPUT_SVIDEO_VI4A_VI1A:
case INPUT_SVIDEO_VI4A_VI1B:
case INPUT_SVIDEO_VI4A_VI1C:
case INPUT_SVIDEO_VI4A_VI3A:
case INPUT_SVIDEO_VI4A_VI3B:
case INPUT_SVIDEO_VI4A_VI3C:
lock_mask = STATUS_HORZ_SYNC_LOCK_BIT |
STATUS_VIRT_SYNC_LOCK_BIT;
break;
/* Need to add other interfaces*/
default:
return -EINVAL;
}
while (try_count-- > 0) {
/* Allow decoder to sync up with new input */
msleep(LOCK_RETRY_DELAY);
sync_lock_status = tvp514x_read_reg(sd,
REG_STATUS1);
if (lock_mask == (sync_lock_status & lock_mask))
/* Input detected */
break;
}
if (try_count < 0)
return -EINVAL;
decoder->input = input;
decoder->output = output;
v4l2_dbg(1, debug, sd, "Input set to: %d\n", input_sel);
return 0;
}
/**
* tvp514x_queryctrl() - V4L2 decoder interface handler for queryctrl
* @sd: pointer to standard V4L2 sub-device structure
* @qctrl: standard V4L2 v4l2_queryctrl structure
*
* If the requested control is supported, returns the control information.
* Otherwise, returns -EINVAL if the control is not supported.
*/
static int
tvp514x_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qctrl)
{
int err = -EINVAL;
if (qctrl == NULL)
return err;
switch (qctrl->id) {
case V4L2_CID_BRIGHTNESS:
/* Brightness supported is (0-255), */
err = v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 128);
break;
case V4L2_CID_CONTRAST:
case V4L2_CID_SATURATION:
/**
* Saturation and Contrast supported is -
* Contrast: 0 - 255 (Default - 128)
* Saturation: 0 - 255 (Default - 128)
*/
err = v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 128);
break;
case V4L2_CID_HUE:
/* Hue Supported is -
* Hue - -180 - +180 (Default - 0, Step - +180)
*/
err = v4l2_ctrl_query_fill(qctrl, -180, 180, 180, 0);
break;
case V4L2_CID_AUTOGAIN:
/**
* Auto Gain supported is -
* 0 - 1 (Default - 1)
*/
err = v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 1);
break;
default:
v4l2_err(sd, "invalid control id %d\n", qctrl->id);
return err;
}
v4l2_dbg(1, debug, sd, "Query Control:%s: Min - %d, Max - %d, Def - %d\n",
qctrl->name, qctrl->minimum, qctrl->maximum,
qctrl->default_value);
return err;
}
/**
* tvp514x_g_ctrl() - V4L2 decoder interface handler for g_ctrl
* @sd: pointer to standard V4L2 sub-device structure
* @ctrl: pointer to v4l2_control structure
*
* If the requested control is supported, returns the control's current
* value from the decoder. Otherwise, returns -EINVAL if the control is not
* supported.
*/
static int
tvp514x_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
struct tvp514x_decoder *decoder = to_decoder(sd);
if (ctrl == NULL)
return -EINVAL;
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
ctrl->value = decoder->tvp514x_regs[REG_BRIGHTNESS].val;
break;
case V4L2_CID_CONTRAST:
ctrl->value = decoder->tvp514x_regs[REG_CONTRAST].val;
break;
case V4L2_CID_SATURATION:
ctrl->value = decoder->tvp514x_regs[REG_SATURATION].val;
break;
case V4L2_CID_HUE:
ctrl->value = decoder->tvp514x_regs[REG_HUE].val;
if (ctrl->value == 0x7F)
ctrl->value = 180;
else if (ctrl->value == 0x80)
ctrl->value = -180;
else
ctrl->value = 0;
break;
case V4L2_CID_AUTOGAIN:
ctrl->value = decoder->tvp514x_regs[REG_AFE_GAIN_CTRL].val;
if ((ctrl->value & 0x3) == 3)
ctrl->value = 1;
else
ctrl->value = 0;
break;
default:
v4l2_err(sd, "invalid control id %d\n", ctrl->id);
return -EINVAL;
}
v4l2_dbg(1, debug, sd, "Get Control: ID - %d - %d\n",
ctrl->id, ctrl->value);
return 0;
}
/**
* tvp514x_s_ctrl() - V4L2 decoder interface handler for s_ctrl
* @sd: pointer to standard V4L2 sub-device structure
* @ctrl: pointer to v4l2_control structure
*
* If the requested control is supported, sets the control's current
* value in HW. Otherwise, returns -EINVAL if the control is not supported.
*/
static int
tvp514x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
struct tvp514x_decoder *decoder = to_decoder(sd);
int err = -EINVAL, value;
if (ctrl == NULL)
return err;
value = ctrl->value;
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
if (ctrl->value < 0 || ctrl->value > 255) {
v4l2_err(sd, "invalid brightness setting %d\n",
ctrl->value);
return -ERANGE;
}
err = tvp514x_write_reg(sd, REG_BRIGHTNESS,
value);
if (err)
return err;
decoder->tvp514x_regs[REG_BRIGHTNESS].val = value;
break;
case V4L2_CID_CONTRAST:
if (ctrl->value < 0 || ctrl->value > 255) {
v4l2_err(sd, "invalid contrast setting %d\n",
ctrl->value);
return -ERANGE;
}
err = tvp514x_write_reg(sd, REG_CONTRAST, value);
if (err)
return err;
decoder->tvp514x_regs[REG_CONTRAST].val = value;
break;
case V4L2_CID_SATURATION:
if (ctrl->value < 0 || ctrl->value > 255) {
v4l2_err(sd, "invalid saturation setting %d\n",
ctrl->value);
return -ERANGE;
}
err = tvp514x_write_reg(sd, REG_SATURATION, value);
if (err)
return err;
decoder->tvp514x_regs[REG_SATURATION].val = value;
break;
case V4L2_CID_HUE:
if (value == 180)
value = 0x7F;
else if (value == -180)
value = 0x80;
else if (value == 0)
value = 0;
else {
v4l2_err(sd, "invalid hue setting %d\n", ctrl->value);
return -ERANGE;
}
err = tvp514x_write_reg(sd, REG_HUE, value);
if (err)
return err;
decoder->tvp514x_regs[REG_HUE].val = value;
break;
case V4L2_CID_AUTOGAIN:
if (value == 1)
value = 0x0F;
else if (value == 0)
value = 0x0C;
else {
v4l2_err(sd, "invalid auto gain setting %d\n",
ctrl->value);
return -ERANGE;
}
err = tvp514x_write_reg(sd, REG_AFE_GAIN_CTRL, value);
if (err)
return err;
decoder->tvp514x_regs[REG_AFE_GAIN_CTRL].val = value;
break;
default:
v4l2_err(sd, "invalid control id %d\n", ctrl->id);
return err;
}
v4l2_dbg(1, debug, sd, "Set Control: ID - %d - %d\n",
ctrl->id, ctrl->value);
return err;
}
/**
* tvp514x_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
tvp514x_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index,
enum v4l2_mbus_pixelcode *code)
{
if (index)
return -EINVAL;
*code = V4L2_MBUS_FMT_UYVY8_2X8;
return 0;
}
/**
* tvp514x_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
tvp514x_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f)
{
struct tvp514x_decoder *decoder = to_decoder(sd);
enum tvp514x_std current_std;
if (f == NULL)
return -EINVAL;
/* Calculate height and width based on current standard */
current_std = decoder->current_std;
f->code = V4L2_MBUS_FMT_UYVY8_2X8;
f->width = decoder->std_list[current_std].width;
f->height = decoder->std_list[current_std].height;
f->field = V4L2_FIELD_INTERLACED;
f->colorspace = V4L2_COLORSPACE_SMPTE170M;
v4l2_dbg(1, debug, sd, "MBUS_FMT: Width - %d, Height - %d\n",
f->width, f->height);
return 0;
}
/**
* tvp514x_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
tvp514x_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
{
struct tvp514x_decoder *decoder = to_decoder(sd);
struct v4l2_captureparm *cparm;
enum tvp514x_std current_std;
if (a == NULL)
return -EINVAL;
if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
/* only capture is supported */
return -EINVAL;
/* get the current standard */
current_std = decoder->current_std;
cparm = &a->parm.capture;
cparm->capability = V4L2_CAP_TIMEPERFRAME;
cparm->timeperframe =
decoder->std_list[current_std].standard.frameperiod;
return 0;
}
/**
* tvp514x_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
tvp514x_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
{
struct tvp514x_decoder *decoder = to_decoder(sd);
struct v4l2_fract *timeperframe;
enum tvp514x_std current_std;
if (a == NULL)
return -EINVAL;
if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
/* only capture is supported */
return -EINVAL;
timeperframe = &a->parm.capture.timeperframe;
/* get the current standard */
current_std = decoder->current_std;
*timeperframe =
decoder->std_list[current_std].standard.frameperiod;
return 0;
}
/**
* tvp514x_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 tvp514x_s_stream(struct v4l2_subdev *sd, int enable)
{
int err = 0;
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct tvp514x_decoder *decoder = to_decoder(sd);
if (decoder->streaming == enable)
return 0;
switch (enable) {
case 0:
{
/* Power Down Sequence */
err = tvp514x_write_reg(sd, REG_OPERATION_MODE, 0x01);
if (err) {
v4l2_err(sd, "Unable to turn off decoder\n");
return err;
}
decoder->streaming = enable;
break;
}
case 1:
{
struct tvp514x_reg *int_seq = (struct tvp514x_reg *)
client->driver->id_table->driver_data;
/* Power Up Sequence */
err = tvp514x_write_regs(sd, int_seq);
if (err) {
v4l2_err(sd, "Unable to turn on decoder\n");
return err;
}
/* Detect if not already detected */
err = tvp514x_detect(sd, decoder);
if (err) {
v4l2_err(sd, "Unable to detect decoder\n");
return err;
}
err = tvp514x_configure(sd, decoder);
if (err) {
v4l2_err(sd, "Unable to configure decoder\n");
return err;
}
decoder->streaming = enable;
break;
}
default:
err = -ENODEV;
break;
}
return err;
}
static int tvp514x_s_power(struct v4l2_subdev *sd, int on)
{
struct tvp514x_decoder *decoder = to_decoder(sd);
if (decoder->pdata && decoder->pdata->s_power)
return decoder->pdata->s_power(sd, on);
return 0;
}
/*
* tvp514x_enum_mbus_code - V4L2 sensor interface handler for pad_ops
* @subdev: pointer to standard V4L2 sub-device structure
* @fh: pointer to standard V4L2 sub-device file handle
* @code: pointer to v4l2_subdev_pad_mbus_code_enum structure
*
*/
static int tvp514x_enum_mbus_code(struct v4l2_subdev *subdev,
struct v4l2_subdev_fh *fh,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->index >= ARRAY_SIZE(tvp514x_std_list))
return -EINVAL;
code->code = V4L2_MBUS_FMT_UYVY8_2X8;
return 0;
}
static int tvp514x_get_pad_format(struct v4l2_subdev *subdev,
struct v4l2_subdev_fh *fh,
struct v4l2_subdev_format *fmt)
{
struct tvp514x_decoder *decoder = to_decoder(subdev);
enum tvp514x_std current_std;
/* query the current standard */
current_std = tvp514x_query_current_std(subdev);
if (current_std == STD_INVALID) {
v4l2_err(subdev, "Unable to query std\n");
return 0;
}
fmt->format = decoder->std_list[current_std].format;
return 0;
}
static int tvp514x_set_pad_format(struct v4l2_subdev *subdev,
struct v4l2_subdev_fh *fh,
struct v4l2_subdev_format *fmt)
{
struct tvp514x_decoder *decoder = to_decoder(subdev);
enum tvp514x_std current_std;
/* query the current standard */
current_std = tvp514x_query_current_std(subdev);
if (current_std == STD_INVALID) {
v4l2_err(subdev, "Unable to query std\n");
return 0;
}
fmt->format.width = decoder->std_list[current_std].width;
fmt->format.height = decoder->std_list[current_std].height;
fmt->format.code = V4L2_MBUS_FMT_UYVY8_2X8;
fmt->format.field = V4L2_FIELD_INTERLACED;
fmt->format.colorspace = V4L2_COLORSPACE_SMPTE170M;
return 0;
}
static int tvp514x_enum_frame_size(struct v4l2_subdev *subdev,
struct v4l2_subdev_fh *fh,
struct v4l2_subdev_frame_size_enum *fse)
{
struct tvp514x_decoder *decoder = to_decoder(subdev);
enum tvp514x_std current_std;
if (fse->code != V4L2_MBUS_FMT_UYVY8_2X8)
return -EINVAL;
/* query the current standard */
current_std = tvp514x_query_current_std(subdev);
if (current_std == STD_INVALID) {
v4l2_err(subdev, "Unable to query std\n");
return 0;
}
fse->min_width = decoder->std_list[current_std].width;
fse->min_height = decoder->std_list[current_std].height;
fse->max_width = fse->min_width;
fse->max_height = fse->min_height;
return 0;
}
static int tvp514x_s_config(struct v4l2_subdev *subdev, int irq,
void *platform_data)
{
enum tvp514x_std current_std;
tvp514x_s_stream(subdev, 1);
/* query the current standard */
current_std = tvp514x_query_current_std(subdev);
if (current_std == STD_INVALID) {
v4l2_err(subdev, "Unable to query std\n");
return 0;
}
tvp514x_s_stream(subdev, 0);
return 0;
}
/* --------------------------------------------------------------------------
* V4L2 subdev file operations
*/
static int tvp514x_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
{
enum tvp514x_std current_std;
tvp514x_s_stream(subdev, 1);
/* query the current standard */
current_std = tvp514x_query_current_std(subdev);
if (current_std == STD_INVALID) {
v4l2_err(subdev, "Unable to query std\n");
return 0;
}
tvp514x_s_stream(subdev, 0);
return 0;
}
/* --------------------------------------------------------------------------
* V4L2 subdev core operations
*/
static int tvp514x_g_chip_ident(struct v4l2_subdev *subdev,
struct v4l2_dbg_chip_ident *chip)
{
struct i2c_client *client = v4l2_get_subdevdata(subdev);
return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TVP5146, 0);
}
static const struct v4l2_subdev_core_ops tvp514x_core_ops = {
.g_chip_ident = tvp514x_g_chip_ident,
.s_config = tvp514x_s_config,
.queryctrl = tvp514x_queryctrl,
.g_ctrl = tvp514x_g_ctrl,
.s_ctrl = tvp514x_s_ctrl,
.s_std = tvp514x_s_std,
.s_power = tvp514x_s_power,
};
static struct v4l2_subdev_file_ops tvp514x_subdev_file_ops = {
.open = tvp514x_open,
};
static const struct v4l2_subdev_video_ops tvp514x_video_ops = {
.s_routing = tvp514x_s_routing,
.querystd = tvp514x_querystd,
.enum_mbus_fmt = tvp514x_enum_mbus_fmt,
.g_mbus_fmt = tvp514x_mbus_fmt,
.try_mbus_fmt = tvp514x_mbus_fmt,
.s_mbus_fmt = tvp514x_mbus_fmt,
.g_parm = tvp514x_g_parm,
.s_parm = tvp514x_s_parm,
.s_stream = tvp514x_s_stream,
};
static const struct v4l2_subdev_pad_ops tvp514x_pad_ops = {
.enum_mbus_code = tvp514x_enum_mbus_code,
.enum_frame_size = tvp514x_enum_frame_size,
.get_fmt = tvp514x_get_pad_format,
.set_fmt = tvp514x_set_pad_format,
};
static const struct v4l2_subdev_ops tvp514x_ops = {
.core = &tvp514x_core_ops,
.file = &tvp514x_subdev_file_ops,
.video = &tvp514x_video_ops,
.pad = &tvp514x_pad_ops,
};
static struct tvp514x_decoder tvp514x_dev = {
.streaming = 0,
.current_std = STD_NTSC_MJ,
.std_list = tvp514x_std_list,
.num_stds = ARRAY_SIZE(tvp514x_std_list),
};
/**
* tvp514x_probe() - decoder driver i2c probe handler
* @client: i2c driver client device structure
* @id: i2c driver id table
*
* Register decoder as an i2c client device and V4L2
* device.
*/
static int
tvp514x_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
struct tvp514x_decoder *decoder;
struct v4l2_subdev *sd;
int ret;
/* Check if the adapter supports the needed features */
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -EIO;
if (!client->dev.platform_data) {
v4l2_err(client, "No platform data!!\n");
return -ENODEV;
}
decoder = kzalloc(sizeof(*decoder), GFP_KERNEL);
if (!decoder)
return -ENOMEM;
/* Initialize the tvp514x_decoder with default configuration */
*decoder = tvp514x_dev;
/* Copy default register configuration */
memcpy(decoder->tvp514x_regs, tvp514x_reg_list_default,
sizeof(tvp514x_reg_list_default));
/* Copy board specific information here */
decoder->pdata = client->dev.platform_data;
/**
* Fetch platform specific data, and configure the
* tvp514x_reg_list[] accordingly. Since this is one
* time configuration, no need to preserve.
*/
decoder->tvp514x_regs[REG_OUTPUT_FORMATTER2].val |=
(decoder->pdata->clk_polarity << 1);
decoder->tvp514x_regs[REG_SYNC_CONTROL].val |=
((decoder->pdata->hs_polarity << 2) |
(decoder->pdata->vs_polarity << 3));
/* Set default standard to auto */
decoder->tvp514x_regs[REG_VIDEO_STD].val =
VIDEO_STD_AUTO_SWITCH_BIT;
/* Register with V4L2 layer as slave device */
sd = &decoder->sd;
v4l2_i2c_subdev_init(sd, client, &tvp514x_ops);
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
decoder->pad.flags = MEDIA_PAD_FLAG_OUTPUT;
decoder->sd.entity.type = MEDIA_ENTITY_TYPE_V4L2_SUBDEV;
ret = media_entity_init(&decoder->sd.entity, 1, &decoder->pad, 0);
if (ret < 0) {
v4l2_err(client, "failed to register as a media entity!!\n");
kfree(decoder);
return ret;
}
v4l2_info(sd, "%s decoder driver registered !!\n", sd->name);
return 0;
}
/**
* tvp514x_remove() - decoder driver i2c remove handler
* @client: i2c driver client device structure
*
* Unregister decoder as an i2c client device and V4L2
* device. Complement of tvp514x_probe().
*/
static int tvp514x_remove(struct i2c_client *client)
{
struct v4l2_subdev *sd = i2c_get_clientdata(client);
struct tvp514x_decoder *decoder = to_decoder(sd);
v4l2_device_unregister_subdev(sd);
media_entity_cleanup(&decoder->sd.entity);
kfree(decoder);
return 0;
}
/* TVP5146 Init/Power on Sequence */
static const struct tvp514x_reg tvp5146_init_reg_seq[] = {
{TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x02},
{TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00},
{TOK_WRITE, REG_VBUS_ADDRESS_ACCESS3, 0x80},
{TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x01},
{TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x60},
{TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00},
{TOK_WRITE, REG_VBUS_ADDRESS_ACCESS3, 0xB0},
{TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x01},
{TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x00},
{TOK_WRITE, REG_OPERATION_MODE, 0x01},
{TOK_WRITE, REG_OPERATION_MODE, 0x00},
{TOK_TERM, 0, 0},
};
/* TVP5147 Init/Power on Sequence */
static const struct tvp514x_reg tvp5147_init_reg_seq[] = {
{TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x02},
{TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00},
{TOK_WRITE, REG_VBUS_ADDRESS_ACCESS3, 0x80},
{TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x01},
{TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x60},
{TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00},
{TOK_WRITE, REG_VBUS_ADDRESS_ACCESS3, 0xB0},
{TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x01},
{TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x16},
{TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00},
{TOK_WRITE, REG_VBUS_ADDRESS_ACCESS3, 0xA0},
{TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x16},
{TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x60},
{TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00},
{TOK_WRITE, REG_VBUS_ADDRESS_ACCESS3, 0xB0},
{TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x00},
{TOK_WRITE, REG_OPERATION_MODE, 0x01},
{TOK_WRITE, REG_OPERATION_MODE, 0x00},
{TOK_TERM, 0, 0},
};
/* TVP5146M2/TVP5147M1 Init/Power on Sequence */
static const struct tvp514x_reg tvp514xm_init_reg_seq[] = {
{TOK_WRITE, REG_OPERATION_MODE, 0x01},
{TOK_WRITE, REG_OPERATION_MODE, 0x00},
{TOK_TERM, 0, 0},
};
/**
* I2C Device Table -
*
* name - Name of the actual device/chip.
* driver_data - Driver data
*/
static const struct i2c_device_id tvp514x_id[] = {
{"tvp5146", (unsigned long)tvp5146_init_reg_seq},
{"tvp5146m2", (unsigned long)tvp514xm_init_reg_seq},
{"tvp5147", (unsigned long)tvp5147_init_reg_seq},
{"tvp5147m1", (unsigned long)tvp514xm_init_reg_seq},
{},
};
MODULE_DEVICE_TABLE(i2c, tvp514x_id);
static struct i2c_driver tvp514x_driver = {
.driver = {
.owner = THIS_MODULE,
.name = TVP514X_MODULE_NAME,
},
.probe = tvp514x_probe,
.remove = tvp514x_remove,
.id_table = tvp514x_id,
};
static int __init tvp514x_init(void)
{
return i2c_add_driver(&tvp514x_driver);
}
static void __exit tvp514x_exit(void)
{
i2c_del_driver(&tvp514x_driver);
}
module_init(tvp514x_init);
module_exit(tvp514x_exit);
2.I modified the code of ti81xx_vpss.c:
/*
*
* Framebuffer device registration for TI TI816x platforms
*
* Copyright (C) 2009 Texas Instruments Inc.
* Author: Yihe Hu <yihehu@ti.com>
*
* Some code and ideas taken from TI OMAP2 Platforms
* by Tomi Valkeinen.
*
* 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 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/bootmem.h>
#include <linux/io.h>
#include <linux/vps_capture.h>
#include <linux/ti81xxfb.h>
#include <linux/ti81xx.h>
#include <mach/hardware.h>
#include <mach/board-ti814x.h>
#include <mach/board-ti816x.h>
#include <asm/mach/map.h>
#if defined(CONFIG_TI81XX_VPSS) || defined(CONFIG_TI81XX_VPSS_MODULE)
static u64 ti81xx_dma_mask = ~(u32)0;
static struct platform_device vpss_device = {
.name = "vpss",
.id = -1,
.dev = {
.platform_data = NULL,
},
};
static struct vps_platform_data vps_pdata;
static int __init ti81xx_vpss_init(void)
{
/*FIXME add platform data here*/
int r;
if (cpu_is_ti816x() || cpu_is_dm385()) {
if (cpu_is_dm385())
vps_pdata.cpu = CPU_DM813X;
else
vps_pdata.cpu = CPU_DM816X;
vps_pdata.numvencs = 4;
vps_pdata.vencmask = (1 << VPS_DC_MAX_VENC) - 1;
} else if (cpu_is_ti814x()) {
vps_pdata.cpu = CPU_DM814X;
vps_pdata.numvencs = 3;
vps_pdata.vencmask = (1 << VPS_DC_MAX_VENC) - 1 \
- VPS_DC_VENC_HDCOMP;
}
vpss_device.dev.platform_data = &vps_pdata;
r = platform_device_register(&vpss_device);
if (r)
printk(KERN_ERR "unable to register ti81xx_vpss device\n");
else
printk(KERN_INFO "registered ti81xx_vpss device\n");
return r;
}
#if defined(CONFIG_TI81XX_HDMI_MODULE) || defined(CONFIG_TI81XX_HDMI)
static struct platform_device ti81xx_hdmi_plat_device = {
.name = "TI81XX_HDMI",
.id = -1,
.num_resources = 0,
.dev = {
/*.release = ti81xx_hdmi_platform_release,*/
.platform_data = NULL,
}
};
static int __init ti81xx_hdmi_init(void)
{
int r;
/*FIXME add platform data here*/
r = platform_device_register(&ti81xx_hdmi_plat_device);
if (r)
printk(KERN_ERR "Unable to register ti81xx onchip-HDMI device\n");
else
printk(KERN_INFO "registered ti81xx on-chip HDMI device\n");
return r;
}
#else
static int __init ti81xx_hdmi_init(void)
{
return 0;
}
#endif
#if defined(CONFIG_VIDEO_TI81XX_VIDIN_MODULE) || \
defined(CONFIG_VIDEO_TI81XX_VIDIN)
#define HDVPSS_CAPTURE_INST0_BASE 0x48105500
#define HDVPSS_CAPTURE_INST0_SIZE 1024u
#define HDVPSS_CAPTURE_INST2_BASE 0x48105A00
#define HDVPSS_CAPTURE_INST2_SIZE 1024u
u8 ti81xx_card_name[] = "TI81xx_catalogue";
struct ti81xxvin_interface tvp5147_pdata = {
.clk_polarity = 0,
.hs_polarity = 0,
.vs_polarity = 1,
.fid_polarity = 0,
.sog_polarity = 0,
};
struct ti81xxvin_interface tvp7002_pdata = {
.clk_polarity = 0,
.hs_polarity = 0,
.vs_polarity = 1,
.fid_polarity = 0,
.sog_polarity = 0,
};
static struct ti81xxvin_subdev_info hdvpss_capture_sdev_info[] = {
{
.name = TVP7002_INST0,
.board_info = {
/* TODO Find the correct address
of the TVP7002 connected */
I2C_BOARD_INFO("tvp7002", 0x5d),
.platform_data = &tvp7002_pdata,
},
.force_sd_video = 0,
.vip_port_cfg = {
.ctrlChanSel = VPS_VIP_CTRL_CHAN_SEL_15_8,
.ancChSel8b = VPS_VIP_ANC_CH_SEL_DONT_CARE,
.pixClkEdgePol = VPS_VIP_PIX_CLK_EDGE_POL_RISING,
.invertFidPol = 0,
.embConfig = {
.errCorrEnable = 1,
.srcNumPos = VPS_VIP_SRC_NUM_POS_DONT_CARE,
.isMaxChan3Bits = 0,
},
.disConfig = {
.fidSkewPostCnt = 0,
.fidSkewPreCnt = 0,
.lineCaptureStyle =
VPS_VIP_LINE_CAPTURE_STYLE_DONT_CARE,
.fidDetectMode =
VPS_VIP_FID_DETECT_MODE_DONT_CARE,
.actvidPol = VPS_VIP_POLARITY_DONT_CARE,
.vsyncPol = VPS_VIP_POLARITY_DONT_CARE,
.hsyncPol = VPS_VIP_POLARITY_DONT_CARE,
}
},
.video_capture_mode =
VPS_CAPT_VIDEO_CAPTURE_MODE_SINGLE_CH_NON_MUX_EMBEDDED_SYNC,
.video_if_mode = VPS_CAPT_VIDEO_IF_MODE_16BIT,
.input_data_format = FVID2_DF_YUV422P,
},
/* {
.name = TVP7002_INST1,
.board_info = {
I2C_BOARD_INFO("tvp7002", 0x5c),
.platform_data = &tvp7002_pdata,
},
.vip_port_cfg = {
.ctrlChanSel = VPS_VIP_CTRL_CHAN_SEL_15_8,
.ancChSel8b = VPS_VIP_ANC_CH_SEL_DONT_CARE,
.pixClkEdgePol = VPS_VIP_PIX_CLK_EDGE_POL_RISING,
.invertFidPol = 0,
.embConfig = {
.errCorrEnable = 1,
.srcNumPos = VPS_VIP_SRC_NUM_POS_DONT_CARE,
.isMaxChan3Bits = 0,
},
.disConfig = {
.fidSkewPostCnt = 0,
.fidSkewPreCnt = 0,
.lineCaptureStyle =
VPS_VIP_LINE_CAPTURE_STYLE_DONT_CARE,
.fidDetectMode =
VPS_VIP_FID_DETECT_MODE_DONT_CARE,
.actvidPol = VPS_VIP_POLARITY_DONT_CARE,
.vsyncPol = VPS_VIP_POLARITY_DONT_CARE,
.hsyncPol = VPS_VIP_POLARITY_DONT_CARE,
}
},
.video_capture_mode =
VPS_CAPT_VIDEO_CAPTURE_MODE_SINGLE_CH_NON_MUX_EMBEDDED_SYNC,
.video_if_mode = VPS_CAPT_VIDEO_IF_MODE_16BIT,
.input_data_format = FVID2_DF_YUV422P,
},
*/
{
.name = TVP5147_INST0,
.board_info = {
I2C_BOARD_INFO("tvp5147m1", 0x5c),
.platform_data = &tvp5147_pdata,
},
.force_sd_video = 1,
.vip_port_cfg = {
.ctrlChanSel = VPS_VIP_CTRL_CHAN_DONT_CARE,
.ancChSel8b = VPS_VIP_ANC_CH_SEL_DONT_CARE,
.pixClkEdgePol = VPS_VIP_PIX_CLK_EDGE_POL_RISING,
.invertFidPol = 0,
.embConfig = {
.errCorrEnable = 1,
.srcNumPos = VPS_VIP_SRC_NUM_POS_DONT_CARE,
.isMaxChan3Bits = 0,
},
.disConfig = {
.fidSkewPostCnt = 0,
.fidSkewPreCnt = 0,
.lineCaptureStyle =
VPS_VIP_LINE_CAPTURE_STYLE_HSYNC,
.fidDetectMode =
VPS_VIP_FID_DETECT_MODE_DONT_CARE,
.actvidPol = VPS_VIP_POLARITY_DONT_CARE,
.vsyncPol = VPS_VIP_POLARITY_DONT_CARE,
.hsyncPol = VPS_VIP_POLARITY_LOW,
}
},
.video_capture_mode =
VPS_CAPT_VIDEO_CAPTURE_MODE_SINGLE_CH_NON_MUX_DISCRETE_SYNC_HSYNC_VBLK,
.video_if_mode = VPS_CAPT_VIDEO_IF_MODE_16BIT,
.input_data_format = FVID2_DF_YUV422P,
},
};
static const struct v4l2_dv_preset hdvpss_inst0_inp0_presets[] = {
{
.preset = V4L2_DV_720P60,
},
{
.preset = V4L2_DV_1080I60,
},
{
.preset = V4L2_DV_1080P60,
},
{
.preset = V4L2_DV_1080P30,
},
{
.preset = V4L2_DV_480P59_94,
},
};
static const struct v4l2_dv_preset hdvpss_inst2_inp0_presets[] = {
{
.preset = V4L2_DV_720P60,
},
{
.preset = V4L2_DV_1080I60,
},
{
.preset = V4L2_DV_1080P60,
},
{
.preset = V4L2_DV_1080P30,
},
};
static const struct ti81xxvin_input hdvpss_inst0_inputs[] = {
{
.input = {
.index = 0,
.name = "Component",
.type = V4L2_INPUT_TYPE_CAMERA,
.std = V4L2_STD_UNKNOWN,
.capabilities = V4L2_OUT_CAP_PRESETS,
},
.subdev_name = TVP7002_INST0,
.dv_presets = hdvpss_inst0_inp0_presets,
.num_dv_presets = ARRAY_SIZE(hdvpss_inst0_inp0_presets),
},
};
static const struct ti81xxvin_input hdvpss_inst1_inputs[] = {
{
.input = {
.index = 0,
.name = "Component",
.type = V4L2_INPUT_TYPE_CAMERA,
.std = V4L2_STD_UNKNOWN,
.capabilities = V4L2_OUT_CAP_PRESETS,
},
.subdev_name = TVP7002_INST1,
.dv_presets = hdvpss_inst2_inp0_presets,
.num_dv_presets = ARRAY_SIZE(hdvpss_inst2_inp0_presets),
},
};
static const struct ti81xxvin_input hdvpss_inst2_inputs[] = {
{
.input = {
.index = 0,
.name = "Composite",
.type = V4L2_INPUT_TYPE_CAMERA,
.std = V4L2_STD_525_60,
.capabilities = V4L2_OUT_CAP_PRESETS,
},
.subdev_name = TVP5147_INST0,
.dv_presets = NULL,
.num_dv_presets = 0,
},
};
/* 16 bit decoders are present on the Port A of VIP0 and VIP1 instances. Which
represents the VIP0 and VIP2 instances in software. While Port B of VIP0 and
VIP1 are represented by VIP1 and VIP3 instances. On these two instances no
decoders are present.
*/
static struct ti81xxvin_config ti81xx_hsvpss_capture_cfg = {
.subdev_info = hdvpss_capture_sdev_info,
.subdev_count = ARRAY_SIZE(hdvpss_capture_sdev_info),
.card_name = ti81xx_card_name,
.inst_config[0] = {
.inputs = hdvpss_inst0_inputs,
.input_count = ARRAY_SIZE(hdvpss_inst0_inputs),
},
.inst_config[1] = {
.inputs = hdvpss_inst0_inputs,
.input_count = 0,
},
.inst_config[2] = {
.inputs = hdvpss_inst2_inputs,
},
.inst_config[3] = {
.inputs = hdvpss_inst2_inputs,
.input_count = ARRAY_SIZE(hdvpss_inst2_inputs),
},
};
static struct resource ti81xx_hdvpss_capture_resource[] = {
[0] = {
.start = HDVPSS_CAPTURE_INST0_BASE,
.end = (HDVPSS_CAPTURE_INST0_BASE +
HDVPSS_CAPTURE_INST0_SIZE - 1),
.flags = IORESOURCE_MEM,
},
[1] = {
.start = HDVPSS_CAPTURE_INST2_BASE,
.end = (HDVPSS_CAPTURE_INST2_BASE +
HDVPSS_CAPTURE_INST2_SIZE - 1),
.flags = IORESOURCE_MEM,
},
};
static struct platform_device hdvpss_capture_dev = {
.name = "ti81xxvin",
.id = -1,
.dev = {
.dma_mask = &ti81xx_dma_mask,
.coherent_dma_mask = ~(u32)0,
},
.num_resources = 2,
.resource = ti81xx_hdvpss_capture_resource,
};
static int __init ti81xx_vin_init(void)
{
int r;
hdvpss_capture_dev.dev.platform_data = &ti81xx_hsvpss_capture_cfg;
if (cpu_is_ti814x()) {
hdvpss_capture_sdev_info[0].ti81xxvin_select_decoder =
vps_ti814x_select_video_decoder;
hdvpss_capture_sdev_info[0].ti81xxvin_set_mode =
vps_ti814x_set_tvp7002_filter;
hdvpss_capture_sdev_info[0].decoder_id = 0;
hdvpss_capture_sdev_info[1].ti81xxvin_select_decoder =
NULL;
hdvpss_capture_sdev_info[1].ti81xxvin_set_mode =
NULL;
hdvpss_capture_sdev_info[1].decoder_id = 0;
} else {
hdvpss_capture_sdev_info[0].ti81xxvin_select_decoder =
vps_ti816x_select_video_decoder;
hdvpss_capture_sdev_info[0].ti81xxvin_set_mode =
vps_ti816x_set_tvp7002_filter;
hdvpss_capture_sdev_info[0].decoder_id = 0;
hdvpss_capture_sdev_info[1].ti81xxvin_select_decoder =
NULL;
hdvpss_capture_sdev_info[1].ti81xxvin_set_mode =
NULL;
hdvpss_capture_sdev_info[1].decoder_id = 0;
}
r = platform_device_register(&hdvpss_capture_dev);
if (r)
printk(KERN_ERR "unable to register ti81xx_vin device\n");
else
printk(KERN_INFO "registered ti81xx_vin device\n");
return r;
}
#else
static int __init ti81xx_vin_init(void)
{
return 0;
}
#endif
#if defined(CONFIG_FB_TI81XX_MODULE) || defined(CONFIG_FB_TI81XX)
static struct ti81xxfb_platform_data ti81xxfb_config;
static struct platform_device ti81xx_fb_device = {
.name = "ti81xxfb",
.id = -1,
.dev = {
.dma_mask = &ti81xx_dma_mask,
.coherent_dma_mask = ~(u32)0,
.platform_data = &ti81xxfb_config,
},
.num_resources = 0,
};
void ti81xxfb_set_platform_data(struct ti81xxfb_platform_data *data)
{
ti81xxfb_config = *data;
}
static int __init ti81xx_fb_init(void)
{
int r;
r = platform_device_register(&ti81xx_fb_device);
if (r)
printk(KERN_ERR "unable to register ti81xx_fb device\n");
else
printk(KERN_INFO "registered ti81xx_fb device\n");
return r;
}
#else
static int __init ti81xx_fb_init(void)
{
return 0;
}
void ti81xxfb_set_platform_data(struct ti81xxfb_platform_data *data)
{
}
#endif
#if defined(CONFIG_VIDEO_TI81XX_VIDOUT_MODULE) || \
defined(CONFIG_VIDEO_TI81XX_VIDOUT)
static struct resource ti81xx_vidout_resource[VPS_DISPLAY_INST_MAX] = {
};
static struct platform_device ti81xx_vidout_device = {
.name = "t81xx_vidout",
.num_resources = ARRAY_SIZE(ti81xx_vidout_resource),
.resource = &ti81xx_vidout_resource[0],
.id = -1,
};
static int __init ti81xx_init_vout(void)
{
int r;
r = platform_device_register(&ti81xx_vidout_device);
if (r)
printk(KERN_ERR "Unable to register ti81xx_vidout device\n");
else
printk(KERN_INFO "registered ti81xx_vidout device\n");
return r;
}
#else
static int __init ti81xx_init_vout(void)
{
return 0;
}
#endif
static int __init ti81xx_init_vpss(void)
{
int retval = 0;
/*if vpss failed to register, none of the below could works*/
if (ti81xx_vpss_init())
return -1;
retval = ti81xx_init_vout();
retval += ti81xx_hdmi_init();
retval += ti81xx_fb_init();
retval += ti81xx_vin_init();
return retval;
}
arch_initcall(ti81xx_init_vpss);
#endif
3.I modify the saLoopBack.c
/*
* saLoopBack.c
*
* Copyright (C) 2011 TI
* Author: Hardik Shah <hardik.shah@ti.com>
*
* This is a sample for loopback application. This application captures through
* V4L2 capture driver on TVP7002 input and displays the captured content
* on the V4L2 display driver. Application uses userpointer mechanism for
* both capture and display drivers. Buffers for the userpointer are taken from
* framebuffer driver (fbdev).
*
* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
*
* Neither the name of Texas Instruments Incorporated nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/*
* Header File Inclusion
*/
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <errno.h>
#include <string.h>
#include <linux/videodev2.h>
#include <linux/fb.h>
#include <linux/ti81xxfb.h>
#include <linux/ti81xxhdmi.h>
#include <linux/ti81xxvin.h>
/* Number of buffers required for application. Less that this may cause
* considerable frame drops
*/
#define MAX_BUFFER 8
/* device node to be used for capture */
#define CAPTURE_DEVICE "/dev/video5"
#define CAPTURE_NAME "Capture"
/* device node to be used for display */
#define DISPLAY_DEVICE "/dev/video3"
#define DISPLAY_NAME "Display"
/* number of frames to be captured and displayed
* Increase this for long runs
*/
#define MAXLOOPCOUNT 500
/* Pixel format for capture and display. Capture supports
* V4L2_PIX_FMT_NV12, V4L2_PIX_FMT_NV16, V4L2_PIX_FMT_RGB24 but display
* supports only V4L2_PIX_FMT_YUYV. So this has to be V4L2_PIX_FMT_YUYV
*/
#define DEF_PIX_FMT V4L2_PIX_FMT_YUYV
/* Application name */
#define APP_NAME "saLoopBack"
/* Define below #def for debug information enable */
#undef SALOOPBACK_DEBUG
/* Structure for storing buffer information */
struct buf_info {
int index;
unsigned int length;
char *start;
};
/* Structure for storing application data like file pointers, format etc. */
struct app_obj {
int fd;
struct v4l2_capability cap;
struct v4l2_format fmt;
struct v4l2_dv_preset dv_preset;
struct v4l2_requestbuffers reqbuf;
struct v4l2_dv_timings timings;
int numbuffers;
struct v4l2_buffer buf;
struct ti81xxvin_overflow_status over_flow;
};
/* Globals for capture and display application objects */
struct app_obj disp, capt;
/* File pointer for fbdev. fbdev is only used to get buffers
*/
static int fbdev_fd;
/* Pointers for storing buffer addresses */
unsigned char *buffer_addr[MAX_BUFFER];
/* Utility function for printing format */
static void printFormat(char *string, struct v4l2_format *fmt)
{
printf("=============================================================\n");
printf("%s Format:\n", string);
printf("=============================================================\n");
printf("fmt.type\t\t = %d\n", fmt->type);
printf("fmt.width\t\t = %d\n", fmt->fmt.pix.width);
printf("fmt.height\t\t = %d\n", fmt->fmt.pix.height);
printf("fmt.pixelformat\t = %d\n", fmt->fmt.pix.pixelformat);
printf("fmt.bytesperline\t = %d\n", fmt->fmt.pix.bytesperline);
printf("fmt.sizeimage\t = %d\n", fmt->fmt.pix.sizeimage);
printf("=============================================================\n");
}
/* Open and query dv preset for capture driver*/
static int initCapture(void)
{
int mode = O_RDWR;
/* Open capture driver */
capt.fd = open((const char *)CAPTURE_DEVICE, mode);
if (capt.fd == -1) {
printf("failed to open capture device\n");
return -1;
}
/* Query for capabilities */
if (ioctl(capt.fd, VIDIOC_QUERYCAP, &capt.cap)) {
printf("Query capability failed\n");
exit(2);
} else {
printf("Driver Name: %s\n", capt.cap.driver);
printf("Driver bus info: %s\n", capt.cap.bus_info);
if (capt.cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)
printf("Driver is capable of doing capture\n");
if (capt.cap.capabilities & V4L2_CAP_VIDEO_OVERLAY)
printf("Driver is capabled of scaling and cropping\n");
}
system("echo 0 > /sys/devices/platform/vpss/display0/enabled");
/* Query the preset. Set it to invalid and query for it */
capt.dv_preset.preset = 0x0;
if (ioctl(capt.fd, VIDIOC_QUERY_DV_PRESET, &capt.dv_preset)) {
printf("Querying DV Preset failed\n");
exit(2);
}
switch (capt.dv_preset.preset) {
case V4L2_DV_720P60:
printf("%s:\n Mode set is 720P60\n", APP_NAME);
system ("echo 720p-60 > /sys/devices/platform/vpss/display0/mode");
break;
case V4L2_DV_1080I60:
printf("%s:\n Mode set is 1080I60\n", APP_NAME);
system ("echo 1080i-60 > /sys/devices/platform/vpss/display0/mode");
break;
case V4L2_DV_1080P60:
printf("%s:\n Mode set is 1080P60\n", APP_NAME);
system ("echo 1080p-60 > /sys/devices/platform/vpss/display0/mode");
break;
case V4L2_DV_1080P30:
printf("%s:\n Mode set is 1080P30\n", APP_NAME);
system ("echo 1080p-30 > /sys/devices/platform/vpss/display0/mode");
break;
default:
//system ("echo 1080p-60 > /sys/devices/platform/vpss/display0/mode");
printf("%s:\n Mode set is %d\n", APP_NAME, capt.dv_preset.preset);
}
capt.dv_preset.preset = V4L2_DV_480P59_94;
if (ioctl(capt.fd, VIDIOC_S_DV_PRESET, &capt.dv_preset)) {
printf("Setting DV Preset failed\n");
exit(2);
}
system("echo 1 > /sys/devices/platform/vpss/display0/enabled");
return 0;
}
/* Open display driver and set format according to resolution on capture */
static int initDisplay(void)
{
int mode = O_RDWR;
struct v4l2_capability cap;
/* Open display driver */
disp.fd = open((const char *)DISPLAY_DEVICE, mode);
if (disp.fd == -1) {
printf("failed to open display device\n");
return -1;
}
/* Query driver capability */
if (ioctl(disp.fd, VIDIOC_QUERYCAP, &disp.cap)) {
printf("Query capability failed for display\n");
exit(2);
} else {
printf("Driver Name: %s\n", cap.driver);
printf("Driver bus info: %s\n", cap.bus_info);
if (cap.capabilities & V4L2_CAP_VIDEO_OUTPUT)
printf("Driver is capable of doing capture\n");
if (cap.capabilities & V4L2_CAP_VIDEO_OVERLAY)
printf("Driver is capabled of scaling and cropping\n");
}
return 0;
}
/* Setup capture driver */
int setupCapture(void)
{
int ret;
/* Get current format */
capt.fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ret = ioctl(capt.fd, VIDIOC_G_FMT, &capt.fmt);
if (ret < 0) {
printf("Set Format failed\n");
return -1;
}
/* Set format according to mode detected */
if(capt.dv_preset.preset == V4L2_DV_480P59_94) {
capt.fmt.fmt.pix.width = 720;
capt.fmt.fmt.pix.height = 480;
} else if(capt.dv_preset.preset == V4L2_DV_576P50) {
capt.fmt.fmt.pix.width = 720;
capt.fmt.fmt.pix.height = 576;
} else {
printf("%s: Wrong preset value\n", APP_NAME);
capt.fmt.fmt.pix.width = 720;
capt.fmt.fmt.pix.height = 480;
}
capt.fmt.fmt.pix.bytesperline = capt.fmt.fmt.pix.width * 2;
capt.fmt.fmt.pix.sizeimage = capt.fmt.fmt.pix.bytesperline *
capt.fmt.fmt.pix.height;
capt.fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YVYU;
ret = ioctl(capt.fd, VIDIOC_S_FMT, &capt.fmt);
if (ret < 0) {
printf("Set Format failed\n");
return -1;
}
/* Get format again and print it on console */
capt.fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ret = ioctl(capt.fd, VIDIOC_G_FMT, &capt.fmt);
if (ret < 0) {
printf("Set Format failed\n");
return -1;
}
printFormat("Capture", &capt.fmt);
/* Request buffers. We are operating in userPtr mode */
capt.reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
capt.reqbuf.count = MAX_BUFFER;
capt.reqbuf.memory = V4L2_MEMORY_USERPTR;
ret = ioctl(capt.fd, VIDIOC_REQBUFS, &capt.reqbuf);
if (ret < 0) {
printf("Could not allocate the buffers\n");
return -1;
}
return 0;
}
int setupCapTiming(void)
{
int ret;
memset(&capt.timings, 0 ,sizeof(capt.timings));
ret = ioctl(disp.fd, VIDIOC_G_DV_TIMINGS, &capt.timings);
if (ret < 0) {
printf("get timings failed\n");
return -1;
}
struct v4l2_dv_timings *p = &capt.timings;
printf("bt-656/1120:interlaced=%d,"
" pixelclock=%lld,"
" width=%d, height=%d, polarities=%x,"
" hfrontporch=%d, hsync=%d,"
" hbackporch=%d, vfrontporch=%d,"
" vsync=%d, vbackporch=%d,"
" il_vfrontporch=%d, il_vsync=%d,"
" il_vbackporch=%d\n",
p->bt.interlaced, p->bt.pixelclock,
p->bt.width, p->bt.height,
p->bt.polarities, p->bt.hfrontporch,
p->bt.hsync, p->bt.hbackporch,
p->bt.vfrontporch, p->bt.vsync,
p->bt.vbackporch, p->bt.il_vfrontporch,
p->bt.il_vsync, p->bt.il_vbackporch);
}
/* Setup display driver */
int setupDisplay(void)
{
int ret;
/* Get format */
disp.fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
ret = ioctl(disp.fd, VIDIOC_G_FMT, &disp.fmt);
if (ret < 0) {
printf("Get Format failed\n");
return -1;
}
/* Set format according to display mode */
if(capt.dv_preset.preset == V4L2_DV_480P59_94) {
capt.fmt.fmt.pix.width = 720;
capt.fmt.fmt.pix.height = 480;
} else if(capt.dv_preset.preset == V4L2_DV_576P50) {
capt.fmt.fmt.pix.width = 720;
capt.fmt.fmt.pix.height = 576;
} else {
printf("%s: Wrong preset value\n", APP_NAME);
capt.fmt.fmt.pix.width = 720;
capt.fmt.fmt.pix.height = 480;
}
disp.fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YVYU;
disp.fmt.fmt.pix.bytesperline = disp.fmt.fmt.pix.width * 2;
disp.fmt.fmt.pix.sizeimage = disp.fmt.fmt.pix.bytesperline *
disp.fmt.fmt.pix.height;
ret = ioctl(disp.fd, VIDIOC_S_FMT, &disp.fmt);
if (ret < 0) {
printf("Set Format failed\n");
return -1;
}
/* Get format again and display it on console */
disp.fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
ret = ioctl(disp.fd, VIDIOC_G_FMT, &disp.fmt);
if (ret < 0) {
printf("Get Format failed for display\n");
return -1;
}
printFormat("Display", &disp.fmt);
/* Requests buffers, we are operating in userPtr mode */
disp.reqbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
disp.reqbuf.count = MAX_BUFFER;
disp.reqbuf.memory = V4L2_MEMORY_USERPTR;
ret = ioctl(disp.fd, VIDIOC_REQBUFS, &disp.reqbuf);
if (ret < 0) {
perror("Could not allocate the buffers\n");
return -1;
}
return 0;
}
/* Stop capture */
static int stopCapture(void)
{
/* Stop capture */
int a = V4L2_BUF_TYPE_VIDEO_CAPTURE, ret;
ret = ioctl(capt.fd, VIDIOC_STREAMOFF, &a);
if (ret < 0) {
perror("VIDIOC_STREAMOFF\n");
return -1;
}
return 0;
}
/* Stop display */
static int stopDisplay(void)
{
int a = V4L2_BUF_TYPE_VIDEO_OUTPUT, ret;
ret = ioctl(disp.fd, VIDIOC_STREAMOFF, &a);
if (ret < 0) {
perror("VIDIOC_STREAMOFF\n");
return -1;
}
return 0;
}
/* Start display */
static int startDisplay(void)
{
int a = V4L2_BUF_TYPE_VIDEO_OUTPUT, ret;
ret = ioctl(disp.fd, VIDIOC_STREAMON, &a);
if (ret < 0) {
perror("VIDIOC_STREAMON\n");
return -1;
}
return 0;
}
/* Start capture */
static int startCapture(void)
{
int a = V4L2_BUF_TYPE_VIDEO_CAPTURE, ret;
ret = ioctl(capt.fd, VIDIOC_STREAMON, &a);
if (ret < 0) {
perror("VIDIOC_STREAMON\n");
return -1;
}
return 0;
}
/* Start display */
static int deInitCapture(void)
{
if (close(capt.fd))
return -1;
return 0;
}
/* Close display */
static int deInitDisplay(void)
{
if (close(disp.fd))
return -1;
return 0;
}
/* Get fix screeninfo on fbdev */
static int get_fixinfo(struct fb_fix_screeninfo *fixinfo)
{
int ret;
ret = ioctl(fbdev_fd, FBIOGET_FSCREENINFO, fixinfo);
if (ret < 0) {
perror("Error reading fixed information.\n");
return ret;
}
#ifdef SALOOPBACK_DEBUG
printf("\nFix Screen Info:\n");
printf("----------------\n");
printf("Line Length - %d\n", fixinfo->line_length);
printf("Physical Address = %lx\n", fixinfo->smem_start);
printf("Buffer Length = %d\n", fixinfo->smem_len);
#endif
return 0;
}
/* Get variable screeninfo on FBDEV */
static int get_varinfo(struct fb_var_screeninfo *varinfo)
{
int ret;
ret = ioctl(fbdev_fd, FBIOGET_VSCREENINFO, varinfo);
if (ret < 0) {
perror("Error reading variable information.\n");
return ret;
}
#ifdef SALOOPBACK_DEBUG
printf("\nVar Screen Info:\n");
printf("----------------\n");
printf("Xres - %d\n", varinfo->xres);
printf("Yres - %d\n", varinfo->yres);
printf("Xres Virtual - %d\n", varinfo->xres_virtual);
printf("Yres Virtual - %d\n", varinfo->yres_virtual);
printf("nonstd - %d\n", varinfo->nonstd);
printf("Bits Per Pixel - %d\n", varinfo->bits_per_pixel);
printf("blue lenth %d msb %d offset %d\n",
varinfo->blue.length,
varinfo->blue.msb_right,
varinfo->blue.offset);
printf("red lenth %d msb %d offset %d\n",
varinfo->red.length,
varinfo->red.msb_right,
varinfo->red.offset);
printf("green lenth %d msb %d offset %d\n",
varinfo->green.length,
varinfo->green.msb_right,
varinfo->green.offset);
printf("trans lenth %d msb %d offset %d\n",
varinfo->transp.length,
varinfo->transp.msb_right,
varinfo->transp.offset);
#endif
return 0;
}
/* We derive buffers from fbdev for userpointer operation.
* We have to setupBuffers
* fbdev to get enough number of buffers and with enough size
*
*/
static int setupBuffers(void)
{
struct fb_fix_screeninfo fixinfo;
struct fb_var_screeninfo varinfo, org_varinfo;
int ret;
int buffersize;
int i;
/*Open FB device*/
fbdev_fd = open("/dev/fb0", O_RDWR);
if (fbdev_fd <= 0) {
perror("Could not open fb device\n");
return -1;
}
/* Get fix screen information. Fix screen information gives
* fix information like panning step for horizontal and vertical
* direction, line length, memory mapped start address and length etc.
*/
if (get_fixinfo(&fixinfo)) {
perror("Could not get fixed screen info\n");
return -1;
}
/* Get variable screen information. Variable screen information
* gives informtion like size of the image, bites per pixel,
* virtual size of the image etc. */
if (get_varinfo(&varinfo)) {
perror("getting variable screen info failed\n");
return -1;
}
/*store the original information*/
memcpy(&org_varinfo, &varinfo, sizeof(varinfo));
/*
* Set the resolution which read before again to prove the
* FBIOPUT_VSCREENINFO ioctl, except virtual part which is required for
* panning.
*/
varinfo.xres = disp.fmt.fmt.pix.width;
varinfo.yres = disp.fmt.fmt.pix.height;
varinfo.xres_virtual = varinfo.xres;
varinfo.yres_virtual = varinfo.yres * MAX_BUFFER;
varinfo.bits_per_pixel = 16;
varinfo.transp.offset = 0;
varinfo.transp.length = 0;
varinfo.transp.msb_right = 0;
varinfo.red.offset = 11;
varinfo.red.length = 5;
varinfo.blue.offset = 0;
varinfo.blue.length = 5;
varinfo.green.offset = 5;
varinfo.green.length = 6;
ret = ioctl(fbdev_fd, FBIOPUT_VSCREENINFO, &varinfo);
if (ret < 0) {
perror("Error writing variable information.\n");
return -1;
}
if (get_varinfo(&varinfo)) {
perror("Error getting variable screen information\n");
return -1;
}
/* It is better to get fix screen information again. its because
* changing variable screen info may also change fix screen info. */
ret = ioctl(fbdev_fd, FBIOGET_FSCREENINFO, &fixinfo);
if (ret < 0) {
perror("Error reading fixed information.\n");
return -1;
}
/* Get fix screen information. Fix screen information gives
* fix information like panning step for horizontal and vertical
* direction, line length, memory mapped start address and length etc.
*/
if (get_fixinfo(&fixinfo)) {
perror("Getting fixed screen info failed\n");
return -1;
}
/* Mmap the driver buffers in application space so that application
* can write on to them. Driver allocates contiguous memory for
* three buffers. These buffers can be displayed one by one. */
buffersize = fixinfo.line_length * varinfo.yres;
buffer_addr[0] = (unsigned char *)mmap(0,
buffersize * MAX_BUFFER,
(PROT_READ | PROT_WRITE),
MAP_SHARED, fbdev_fd, 0);
for (i = 1; i < MAX_BUFFER; i++)
buffer_addr[i] = buffer_addr[i-1] + buffersize;
memset(buffer_addr[0], 0xFF, buffersize * MAX_BUFFER);
return 0;
}
/* Prime capture buffers */
static int queueCaptureBuffers(void)
{
int ret, i;
for (i = 0; i < (MAX_BUFFER / 2); i++) {
capt.buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
capt.buf.memory = V4L2_MEMORY_USERPTR;
capt.buf.index = i;
capt.buf.m.userptr = (unsigned long)buffer_addr[capt.buf.index];
capt.buf.length = capt.fmt.fmt.pix.sizeimage;
ret = ioctl(capt.fd, VIDIOC_QBUF, &capt.buf);
if (ret < 0) {
perror("VIDIOC_QBUF\n");
return -1;
}
}
return ret;
}
/* Prime display buffers */
static int queueDisplayBuffers(void)
{
int ret, i;
for (i = (MAX_BUFFER / 2); i < MAX_BUFFER; i++) {
disp.buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
disp.buf.memory = V4L2_MEMORY_USERPTR;
disp.buf.index = i - (MAX_BUFFER / 2);
disp.buf.m.userptr = (unsigned long)buffer_addr[i];
disp.buf.length = capt.fmt.fmt.pix.sizeimage;
ret = ioctl(disp.fd, VIDIOC_QBUF, &disp.buf);
if (ret < 0) {
perror("VIDIOC_QBUF\n");
return -1;
}
}
return 0;
}
/* This is a utility function to calculate time between start and stop. This
* is used to calculate FPS
*/
static int calc_result_time(struct timeval *result, struct timeval *after,
struct timeval *before)
{
/* Perform the carry for the later subtraction by updating "before" */
if (after->tv_usec < before->tv_usec) {
int nsec = (before->tv_usec - after->tv_usec) / 1000000 + 1;
before->tv_usec -= 1000000 * nsec;
before->tv_sec += nsec;
}
if (after->tv_usec - before->tv_usec > 1000000) {
int nsec = (after->tv_usec - before->tv_usec) / 1000000;
before->tv_usec += 1000000 * nsec;
before->tv_sec -= nsec;
}
/* Compute the time remaining to wait, tv_usec is certainly positive.
* */
result->tv_sec = after->tv_sec - before->tv_sec;
result->tv_usec = after->tv_usec - before->tv_usec;
/* Return 1 if result is negative. */
return after->tv_sec < before->tv_sec;
}
/* Main function */
int main(int argc, char *argv[])
{
int i = 0, ret = 0;
struct v4l2_buffer temp_buf;
struct timeval before, after, result;
/* Divert fbdev to dvo2 so that it does not do blending with display*/
system ("echo 1:sd > /sys/devices/platform/vpss/graphics0/nodes");
/* Open the capture driver. Query the resolution from the capture driver
*/
ret = initCapture();
if (ret < 0) {
printf("Error in opening capture device for channel 0\n");
return ret;
}
/* Open the Display driver. */
ret = initDisplay();
if (ret < 0) {
printf("Error in opening display device for channel 0\n");
return ret;
}
restart:
/* Setup the capture driver Step includes
* Set the format according to the resolution queried.
* request for buffer descriptors for userpointer buffers
*/
ret = setupCapture();
if (ret < 0) {
printf("Error in setting up of capture\n");
return ret;
}
/* Setup the display driver Step includes
* Set the format according to the resolution queried by capture.
* request for buffer descriptors for userpointer buffers
*/
ret = setupDisplay();
if (ret < 0) {
printf("Error in setting up of Display\n");
return ret;
}
/* As application works on userPointer, Buffers for both capture and
* display driver are allocated using the fbdev, buffers. Below functionality
* setups the fbdev to mmap the buffers and later capture and display
* will use those buffers
*/
ret = setupBuffers();
if (ret < 0) {
printf("Error in setting up of Buffers\n");
return ret;
}
/* Total 8 buffers are allocated using fbdev, 4 buffers are primed to
* capture driver.
*/
ret = queueCaptureBuffers();
if (ret < 0) {
printf("Error in queuing capture buffers\n");
return ret;
}
/* Total 8 buffers are allocated using fbdev, 4 buffers are primed to
* display driver.
*/
ret = queueDisplayBuffers();
if (ret < 0) {
printf("Error in queuing display buffers\n");
return ret;
}
/* Start display driver always first. This is because display driver
* takes 2 frames to come out of start. If capture is started first
* frame drops will be seen, since capture will already complete two
* frame by time display starts
*/
ret = startDisplay();
if (ret < 0) {
printf("Error starring capture \n");
return ret;
}
/* Start capture driver after display driver */
ret = startCapture();
if (ret < 0) {
printf("Error starring capture \n");
return ret;
}
/* Get time of day to calculate FPS */
gettimeofday(&before, NULL);
/* Start the steady state loop. Following steps are followed
* 1 dequeue buffer from capture
* 2 dequeue buffer from display
* 3 exchange capture and display buffer pointers
* 4 queue dislay buffer pointer to capture
* 5 queue capture buffer pointer to display
*/
int fd;
#define FIFO_CHANNEL "/home/root/fifo/my_fifo" /* �궨�壬fifo·�� */
if((fd=open(FIFO_CHANNEL,O_RDWR))==-1) /* ��ֻ����ʽ�������ܵ� */
{
if(mkfifo(FIFO_CHANNEL,0777)==-1) /* ���������ܵ�������-1��ʾʧ�� */
{
perror("Can't create FIFO channel");
return 1;
}
if((fd=open(FIFO_CHANNEL,O_RDWR))==-1) /* ��ֻ����ʽ�������ܵ� */
{
perror("Can't open the FIFO");
return 1;
}
}
FILE * hFile = fopen("captest.bin", "wb");
for (i = 0;; i++) {
/* Dq capture buffer */
ret = ioctl(capt.fd, VIDIOC_DQBUF, &capt.buf);
if (ret < 0) {
perror("VIDIOC_DQBUF\n");
return -1;
}
/* Because of IP bugs, capture hardware gets locked up once in
* a while. In that case DQbuf will return V4L2_BUF_FLAG_ERROR
* in flags.
*/
if (capt.buf.flags & V4L2_BUF_FLAG_ERROR) {
/* If DQbuf returned error check for the hardware lockup
*/
ret = ioctl(capt.fd, TICAPT_CHECK_OVERFLOW, &capt.over_flow);
if (ret < 0) {
perror("TICAPT_CHECK_OVERFLOW\n");
return -1;
} else {
/* If hardware locked up, restart display and
* capture driver
*/
if (capt.over_flow.porta_overflow) {
printf("Port a overflowed\n\n\n\n\n\n\n");
stopCapture();
stopDisplay();
goto restart;
}
if (capt.over_flow.portb_overflow) {
printf("Port b overflowed\n\n\n\n\n\n\n");
stopCapture();
stopDisplay();
goto restart;
}
}
}
/* DQ display buffer */
ret = ioctl(disp.fd, VIDIOC_DQBUF, &disp.buf);
if (ret < 0) {
perror("VIDIOC_DQBUF Display\n");
return -1;
}
/* Exchange display and capture buffer pointers */
temp_buf.m.userptr = capt.buf.m.userptr;
capt.buf.m.userptr = disp.buf.m.userptr;
disp.buf.m.userptr = temp_buf.m.userptr;
/* Queue the capture buffer with updated address */
ret = ioctl(capt.fd, VIDIOC_QBUF, &capt.buf);
if (ret < 0) {
perror("VIDIOC_QBUF\n");
return -1;
}
disp.buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
disp.buf.memory = V4L2_MEMORY_USERPTR;
disp.buf.length = capt.fmt.fmt.pix.sizeimage;
// write(fd, disp.buf.m.userptr, disp.buf.length);
fwrite(disp.buf.m.userptr, 1, disp.buf.length, hFile);
printf("write len = %d\n", disp.buf.length);
/* Queue the display buffer back with updated address */
ret = ioctl(disp.fd, VIDIOC_QBUF, &disp.buf);
if (ret < 0) {
perror("VIDIOC_QBUF Display\n");
return -1;
}
if ((i % 1000) == 0)
printf("Count=%d\n", i);
}
fclose(hFile);
close(fd);
/* Get end time to calculate FPS */
gettimeofday(&after, NULL);
/* Calculate FPS */
calc_result_time(&result, &after, &before);
printf("Frame rate = %lu\n", MAXLOOPCOUNT/result.tv_sec);
/* Stop capture driver */
ret = stopCapture();
if (ret < 0) {
printf("Error in stopping capture\n");
return ret;
}
/* Stop display driver */
ret = stopDisplay();
if (ret < 0) {
printf("Error in stopping display\n");
return ret;
}
/* Deinit capture driver */
ret = deInitCapture();
if (ret < 0) {
printf("Error in capture deInit\n");
return ret;
}
/* Deinit display driver */
ret = deInitDisplay();
if (ret < 0) {
printf("Error in display deInit\n");
return ret;
}
close(fbdev_fd);
system("echo 0 > /sys/devices/platform/vpss/display0/enabled");
system ("echo 1080p-60 > /sys/devices/platform/vpss/display0/mode");
system("echo 0 > /sys/devices/platform/vpss/graphics0/enabled");
system("echo 1 > /sys/devices/platform/vpss/display0/enabled");
system("echo 1:hdmi > /sys/devices/platform/vpss/graphics0/nodes");
return 0;
}
The demo call Ioctl DQBUF , it don't return .
I have try to set the params of disConfig of vip_port_cfg, it failed.
Can some tell me what params i have set is not right?

