Hi Vaibhav, See below for my comments. On Wednesday 26 November 2008 18:05:01 hvaibhav@xxxxxx wrote: > From: Vaibhav Hiremath <hvaibhav@xxxxxx> > > I have fixed most of the review comments received so far. > Here are the details: > > FIXES > Wrong use of CONFIG_VIDEO_ADV_DEBUG option: > Implemented module parameter based approach for debugging. > > Bridge driver and access to TVP registers: > The bridge driver will now provide only neccessary > information depending on platform/board/interface. In case of > TVP5146, we do require clk_polarity, input, number of input, HS/VS > polarity, etc.. which is interface dependent. > All register access and values are limited to TVP driver. > > V4L2-int framework: > The new sub-device framework is a new development and will > take its own time to mature and stabilize. The implementation is > rightly placed in a different branch for the same reason. > > I beleive till this time, we should move ahead with current > framework. This patch provides base for V4L2-int capture-master > driver and patch for the same will be posted in couple of weeks. we > are in the process of code clean-up. > > It would be good if we can get this patch into the current codebase > till the 'sub-device' framework stabilizes. The migration can be > planned immediately. I've no problem with this. > i2c table: > Specified the name of chip. > > Code cleanup: > Multiple changes as suggested. > > PENDING (TO DO) > > I2C Legacy framework support: > Still no change for Legacy support (Hans agreed on this). > Can be added while we move to sub-device framework. > > New sub-device framework support: > Will be taken up immediately. > > Signed-off-by: Brijesh Jadav <brijesh.j@xxxxxx> > Signed-off-by: Hardik Shah <hardik.shah@xxxxxx> > Signed-off-by: Manjunath Hadli <mrh@xxxxxx> > Signed-off-by: R Sivaraj <sivaraj@xxxxxx> > Signed-off-by: Vaibhav Hiremath <hvaibhav@xxxxxx> > Signed-off-by: Karicheri Muralidharan <m-karicheri2@xxxxxx> > --- > drivers/media/video/Kconfig | 11 + > drivers/media/video/Makefile | 1 + > drivers/media/video/tvp514x.c | 1551 > +++++++++++++++++++++++++++++++++++++++++ include/media/tvp514x.h > | 461 ++++++++++++ > 4 files changed, 2024 insertions(+), 0 deletions(-) > create mode 100644 drivers/media/video/tvp514x.c > create mode 100644 include/media/tvp514x.h > > diff --git a/drivers/media/video/Kconfig > b/drivers/media/video/Kconfig index 47102c2..2e5dc3e 100644 > --- a/drivers/media/video/Kconfig > +++ b/drivers/media/video/Kconfig > @@ -361,6 +361,17 @@ config VIDEO_SAA7191 > To compile this driver as a module, choose M here: the > module will be called saa7191. > > +config VIDEO_TVP514X > + tristate "Texas Instruments TVP514x video decoder" > + depends on VIDEO_V4L2 && I2C > + ---help--- > + This is a Video4Linux2 sensor-level driver for the TI TVP5146/47 > + decoder. It is currently working with the TI OMAP3 camera > + controller. > + > + To compile this driver as a module, choose M here: the > + module will be called tvp514x. > + > config VIDEO_TVP5150 > tristate "Texas Instruments TVP5150 video decoder" > depends on VIDEO_V4L2 && I2C > diff --git a/drivers/media/video/Makefile > b/drivers/media/video/Makefile index 16962f3..cdbbf38 100644 > --- a/drivers/media/video/Makefile > +++ b/drivers/media/video/Makefile > @@ -66,6 +66,7 @@ obj-$(CONFIG_VIDEO_CX88) += cx88/ > obj-$(CONFIG_VIDEO_EM28XX) += em28xx/ > obj-$(CONFIG_VIDEO_USBVISION) += usbvision/ > obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o > +obj-$(CONFIG_VIDEO_TVP514X) += tvp514x.o > obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/ > obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o > obj-$(CONFIG_VIDEO_CS5345) += cs5345.o > diff --git a/drivers/media/video/tvp514x.c > b/drivers/media/video/tvp514x.c new file mode 100644 > index 0000000..187a063 > --- /dev/null > +++ b/drivers/media/video/tvp514x.c > @@ -0,0 +1,1551 @@ > +/* > + * drivers/media/video/tvp514x.c > + * > + * TI TVP5146/47 decoder driver > + * > + * Copyright (C) 2008 Texas Instruments Inc > + * > + * Contributors: > + * Brijesh R Jadav <brijesh.j@xxxxxx> > + * Hardik Shah <hardik.shah@xxxxxx> > + * Manjunath Hadli <mrh@xxxxxx> > + * Sivaraj R <sivaraj@xxxxxx> > + * Vaibhav Hiremath <hvaibhav@xxxxxx> > + * > + * 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/delay.h> > +#include <linux/videodev2.h> > +#include <media/v4l2-int-device.h> > +#include <media/tvp514x.h> > + > +#define MODULE_NAME TVP514X_MODULE_NAME > + > +/* Debug functions */ > +#ifdef TVP514X_DEBUG There is no need to put this under an #ifdef. I would also recommend having just one debug level. Usually errors and 'significant info' messages are always printed. Debugging messages are printed only when debug == 1. Some drivers have a debug level 2 to enable very frequently occuring messages. The default debug level is usually 0 since you never want debugging messages in a module. > +static unsigned short debug = 3; > +module_param(debug, ushort, 0644); > +MODULE_PARM_DESC(debug, > + "\n<n> Debugging information level, from 0 to 3:" > + "\n0 = none (use carefully)" > + "\n1 = critical errors" > + "\n2 = significant informations" > + "\n3 = more verbose messages" > + "\nLevel 3 is useful for testing only, when only " > + "one device is used." > + "\nDefault value is "__MODULE_STRING(2)"." > + "\n"); > + > +#define DBG(dev, level, fmt, args...) > \ + do { > \ + if (debug >= (level)) { \ > + if ((level) == 1) \ > + dev_err(dev, fmt "\n", ## args); \ > + else if ((level) == 2) \ > + dev_info(dev, fmt "\n", ## args); \ > + else if ((level) >= 3) \ > + dev_info(dev, "[%s:%s:%d] " fmt "\n", \ > + __FILE__, __func__, __LINE__ , ## args); \ > + } \ > + } while (0) Please use the v4l_* macros from v4l2-common.h. They are used in most other i2c drivers as well. > + > +#define dump_reg(client, reg, val) \ > + do { \ > + tvp514x_read_reg(client, reg, &val); \ > + dev_dbg(&(client)->dev, "Reg(0x%.2X): 0x%.2X\n", reg, val); \ > + } while (0) > + > +#else > +#define DBG(dev, level, fmt, args...) do {; } while (0) > +#endif /* #ifdef TVP514X_DEBUG */ > + > +/* TVP514x default register values */ > +static struct tvp514x_reg tvp514x_reg_list[] = { > + {TOK_WRITE, REG_INPUT_SEL, 0x05}, /* Composite selected */ > + {TOK_WRITE, REG_AFE_GAIN_CTRL, 0x0F}, > + {TOK_WRITE, REG_VIDEO_STD, 0x00}, /* Auto mode */ > + {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}, > + {TOK_SKIP, 0x0F, 0x00}, /* Reserved */ > + {TOK_WRITE, REG_COMP_PR_SATURATION, 0x80}, > + {TOK_WRITE, REG_COMP_Y_CONTRAST, 0x80}, > + {TOK_WRITE, REG_COMP_PB_SATURATION, 0x80}, > + {TOK_SKIP, 0x13, 0x00}, /* Reserved */ > + {TOK_WRITE, REG_COMP_Y_BRIGHTNESS, 0x80}, > + {TOK_SKIP, 0x15, 0x00}, /* Reserved */ > + {TOK_SKIP, REG_AVID_START_PIXEL_LSB, 0x55}, /* NTSC timing */ > + {TOK_SKIP, REG_AVID_START_PIXEL_MSB, 0x00}, > + {TOK_SKIP, REG_AVID_STOP_PIXEL_LSB, 0x25}, > + {TOK_SKIP, REG_AVID_STOP_PIXEL_MSB, 0x03}, > + {TOK_SKIP, REG_HSYNC_START_PIXEL_LSB, 0x00}, /* NTSC timing */ > + {TOK_SKIP, REG_HSYNC_START_PIXEL_MSB, 0x00}, > + {TOK_SKIP, REG_HSYNC_STOP_PIXEL_LSB, 0x40}, > + {TOK_SKIP, REG_HSYNC_STOP_PIXEL_MSB, 0x00}, > + {TOK_SKIP, REG_VSYNC_START_LINE_LSB, 0x04}, /* NTSC timing */ > + {TOK_SKIP, REG_VSYNC_START_LINE_MSB, 0x00}, > + {TOK_SKIP, REG_VSYNC_STOP_LINE_LSB, 0x07}, > + {TOK_SKIP, REG_VSYNC_STOP_LINE_MSB, 0x00}, > + {TOK_SKIP, REG_VBLK_START_LINE_LSB, 0x01}, /* NTSC timing */ > + {TOK_SKIP, REG_VBLK_START_LINE_MSB, 0x00}, > + {TOK_SKIP, REG_VBLK_STOP_LINE_LSB, 0x15}, > + {TOK_SKIP, REG_VBLK_STOP_LINE_MSB, 0x00}, > + {TOK_SKIP, 0x26, 0x00}, /* Reserved */ > + {TOK_SKIP, 0x27, 0x00}, /* Reserved */ > + {TOK_SKIP, REG_FAST_SWTICH_CONTROL, 0xCC}, > + {TOK_SKIP, 0x29, 0x00}, /* Reserved */ > + {TOK_SKIP, REG_FAST_SWTICH_SCART_DELAY, 0x00}, > + {TOK_SKIP, 0x2B, 0x00}, /* Reserved */ > + {TOK_SKIP, REG_SCART_DELAY, 0x00}, > + {TOK_SKIP, REG_CTI_DELAY, 0x00}, > + {TOK_SKIP, REG_CTI_CONTROL, 0x00}, > + {TOK_SKIP, 0x2F, 0x00}, /* Reserved */ > + {TOK_SKIP, 0x30, 0x00}, /* Reserved */ > + {TOK_SKIP, 0x31, 0x00}, /* Reserved */ > + {TOK_WRITE, REG_SYNC_CONTROL, 0x00}, /* HS, VS active high */ > + {TOK_WRITE, REG_OUTPUT_FORMATTER1, 0x00}, /* 10-bit BT.656 */ > + {TOK_WRITE, REG_OUTPUT_FORMATTER2, 0x11}, /* Enable clk & data */ > + {TOK_WRITE, REG_OUTPUT_FORMATTER3, 0xEE}, /* Enable AVID & FLD */ > + {TOK_WRITE, REG_OUTPUT_FORMATTER4, 0xAF}, /* Enable VS & HS */ > + {TOK_WRITE, REG_OUTPUT_FORMATTER5, 0xFF}, > + {TOK_WRITE, REG_OUTPUT_FORMATTER6, 0xFF}, > + {TOK_WRITE, REG_CLEAR_LOST_LOCK, 0x01}, /* Clear status */ > + {TOK_TERM, 0, 0}, > +}; > + > +/* List of image formats supported by TVP5146/47 decoder > + * Currently we are using 8 bit mode only, but can be > + * extended to 10/20 bit mode. > + */ > +static const struct v4l2_fmtdesc tvp514x_fmt_list[] = { > + { > + .index = 0, > + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, > + .flags = 0, > + .description = "8-bit UYVY 4:2:2 Format", > + .pixelformat = V4L2_PIX_FMT_UYVY, > + }, > +}; > + > +#define TVP514X_NUM_FORMATS ARRAY_SIZE(tvp514x_fmt_list) > + > +/* > + * Supported standards - These must be ordered according to enum > tvp514x_std + * order. > + * Currently supports two standards only, need to add support for > rest of the + * modes, like SECAM, etc... > + */ > +static struct tvp514x_std_info tvp514x_std_list[] = { > + { > + .width = NTSC_NUM_ACTIVE_PIXELS, > + .height = NTSC_NUM_ACTIVE_LINES, > + .video_std = VIDEO_STD_NTSC_MJ_BIT, > + .standard = { > + .index = 0, > + .id = V4L2_STD_NTSC, > + .name = "NTSC", > + .frameperiod = {1001, 30000}, > + .framelines = 525 > + }, > + }, { > + .width = PAL_NUM_ACTIVE_PIXELS, > + .height = PAL_NUM_ACTIVE_LINES, > + .video_std = VIDEO_STD_PAL_BDGHIN_BIT, > + .standard = { > + .index = 1, > + .id = V4L2_STD_PAL, > + .name = "PAL", > + .frameperiod = {1, 25}, > + .framelines = 625 > + }, > + }, > +}; > + > +#define TVP514X_NUM_STANDARDS ARRAY_SIZE(tvp514x_std_list) > + > +/* Supported controls */ > +static const struct tvp514x_ctrl_info tvp514x_ctrl_list[] = { > + { > + .reg_address = REG_BRIGHTNESS, > + .query_ctrl = { > + .id = V4L2_CID_BRIGHTNESS, > + .name = "BRIGHTNESS", > + .type = V4L2_CTRL_TYPE_INTEGER, > + .minimum = 0, > + .maximum = 255, > + .step = 1, > + .default_value = 128 > + }, > + }, { > + .reg_address = REG_CONTRAST, > + .query_ctrl = { > + .id = V4L2_CID_CONTRAST, > + .name = "CONTRAST", > + .type = V4L2_CTRL_TYPE_INTEGER, > + .minimum = 0, > + .maximum = 255, > + .step = 1, > + .default_value = 128 > + }, > + }, { > + .reg_address = REG_SATURATION, > + .query_ctrl = { > + .id = V4L2_CID_SATURATION, > + .name = "SATURATION", > + .type = V4L2_CTRL_TYPE_INTEGER, > + .minimum = 0, > + .maximum = 255, > + .step = 1, > + .default_value = 128 > + }, > + }, { > + .reg_address = REG_HUE, > + .query_ctrl = { > + .id = V4L2_CID_HUE, > + .name = "HUE", > + .type = V4L2_CTRL_TYPE_INTEGER, > + .minimum = -180, > + .maximum = 180, > + .step = 180, > + .default_value = 0 > + }, > + }, { > + .reg_address = REG_AFE_GAIN_CTRL, > + .query_ctrl = { > + .id = V4L2_CID_AUTOGAIN, > + .name = "Automatic Gain Control", > + .type = V4L2_CTRL_TYPE_BOOLEAN, > + .minimum = 0, > + .maximum = 1, > + .step = 1, > + .default_value = 1 > + }, > + }, > +}; > + > +#define TVP514X_NUM_CONTROLS ARRAY_SIZE(tvp514x_ctrl_list) > + > +/* > + * Read a value from a register in an TVP5146/47 decoder device. > + * The value is returned in 'val'. > + * Returns zero if successful, or non-zero otherwise. > + */ > +static int tvp514x_read_reg(struct i2c_client *client, u8 reg, u8 > *val) +{ > + int err; > + struct i2c_msg msg[2]; > + u8 data; > + > + if (!client->adapter) > + return -ENODEV; > + > + /* [MSG1] fill the register address data */ > + data = reg; > + msg[0].addr = client->addr; > + msg[0].len = 1; > + msg[0].flags = 0; > + msg[0].buf = &data; > + > + /* [MSG2] fill the data rx buffer */ > + msg[1].addr = client->addr; > + msg[1].len = 1; /* only 1 byte */ > + msg[1].flags = I2C_M_RD; /* Read the register values */ > + msg[1].buf = val; > + err = i2c_transfer(client->adapter, msg, 2); > + if (err >= 0) > + return 0; > + > + DBG(&client->dev, 1, > + "read from device 0x%.2x, offset 0x%.2x error %d\n", > + client->addr, reg, err); > + > + return err; > +} > + > +/* > + * 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 i2c_client *client, u8 reg, u8 > val) +{ > + int err; > + int retry = 0; > + struct i2c_msg msg[1]; > + u8 data[2]; > + > + if (!client->adapter) > + return -ENODEV; > + > +again: > + data[0] = reg; /* Register offset */ > + data[1] = val; /* Register value */ > + msg->addr = client->addr; > + msg->len = 2; > + msg->flags = 0; /* write operation */ > + msg->buf = data; > + > + err = i2c_transfer(client->adapter, msg, 1); > + if (err >= 0) > + return 0; > + > + DBG(&client->dev, 1, > + "wrote 0x%.2x to offset 0x%.2x error %d\n", val, reg, err); > + if (retry <= I2C_RETRY_COUNT) { > + DBG(&client->dev, 2, "retry ... %d\n", retry); > + retry++; > + schedule_timeout(msecs_to_jiffies(20)); > + goto again; > + } > + return err; > +} > + > +/* > + * tvp514x_write_regs : 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 > + * > + * reglist - list of registers to be written > + * Returns zero if successful, or non-zero otherwise. > + */ > +static int tvp514x_write_regs(struct i2c_client *client, > + const struct tvp514x_reg reglist[]) > +{ > + int err; > + const struct tvp514x_reg *next = reglist; > + > + for (; next->token != TOK_TERM; next++) { > + if (next->token == TOK_DELAY) { > + schedule_timeout(msecs_to_jiffies(next->val)); > + continue; > + } > + > + if (next->token == TOK_SKIP) > + continue; > + > + err = tvp514x_write_reg(client, next->reg, (u8) next->val); > + if (err) { > + DBG(&client->dev, 1, "write failed. Err[%d]\n", > + err); > + return err; > + } > + } > + return 0; > +} > + > +/* > + * tvp514x_get_current_std: > + * Returns the current standard detected by TVP5146/47 > + */ > +static enum tvp514x_std tvp514x_get_current_std(struct > tvp514x_decoder + *decoder) > +{ > + u8 std, std_status; > + > + if (tvp514x_read_reg(decoder->client, REG_VIDEO_STD, &std)) > + return STD_INVALID; > + > + if ((std & VIDEO_STD_MASK) == VIDEO_STD_AUTO_SWITCH_BIT) { > + /* use the standard status register */ > + if (tvp514x_read_reg(decoder->client, REG_VIDEO_STD_STATUS, > + &std_status)) > + return STD_INVALID; > + } else > + std_status = std; /* use the standard register itself */ > + > + 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; > +} > + > +#ifdef TVP514X_DEBUG > +/* > + * TVP5146/47 register dump function > + */ > +void tvp514x_reg_dump(struct tvp514x_decoder *decoder) > +{ > + u8 value; > + > + dump_reg(decoder->client, REG_INPUT_SEL, value); > + dump_reg(decoder->client, REG_AFE_GAIN_CTRL, value); > + dump_reg(decoder->client, REG_VIDEO_STD, value); > + dump_reg(decoder->client, REG_OPERATION_MODE, value); > + dump_reg(decoder->client, REG_COLOR_KILLER, value); > + dump_reg(decoder->client, REG_LUMA_CONTROL1, value); > + dump_reg(decoder->client, REG_LUMA_CONTROL2, value); > + dump_reg(decoder->client, REG_LUMA_CONTROL3, value); > + dump_reg(decoder->client, REG_BRIGHTNESS, value); > + dump_reg(decoder->client, REG_CONTRAST, value); > + dump_reg(decoder->client, REG_SATURATION, value); > + dump_reg(decoder->client, REG_HUE, value); > + dump_reg(decoder->client, REG_CHROMA_CONTROL1, value); > + dump_reg(decoder->client, REG_CHROMA_CONTROL2, value); > + dump_reg(decoder->client, REG_COMP_PR_SATURATION, value); > + dump_reg(decoder->client, REG_COMP_Y_CONTRAST, value); > + dump_reg(decoder->client, REG_COMP_PB_SATURATION, value); > + dump_reg(decoder->client, REG_COMP_Y_BRIGHTNESS, value); > + dump_reg(decoder->client, REG_AVID_START_PIXEL_LSB, value); > + dump_reg(decoder->client, REG_AVID_START_PIXEL_MSB, value); > + dump_reg(decoder->client, REG_AVID_STOP_PIXEL_LSB, value); > + dump_reg(decoder->client, REG_AVID_STOP_PIXEL_MSB, value); > + dump_reg(decoder->client, REG_HSYNC_START_PIXEL_LSB, value); > + dump_reg(decoder->client, REG_HSYNC_START_PIXEL_MSB, value); > + dump_reg(decoder->client, REG_HSYNC_STOP_PIXEL_LSB, value); > + dump_reg(decoder->client, REG_HSYNC_STOP_PIXEL_MSB, value); > + dump_reg(decoder->client, REG_VSYNC_START_LINE_LSB, value); > + dump_reg(decoder->client, REG_VSYNC_START_LINE_MSB, value); > + dump_reg(decoder->client, REG_VSYNC_STOP_LINE_LSB, value); > + dump_reg(decoder->client, REG_VSYNC_STOP_LINE_MSB, value); > + dump_reg(decoder->client, REG_VBLK_START_LINE_LSB, value); > + dump_reg(decoder->client, REG_VBLK_START_LINE_MSB, value); > + dump_reg(decoder->client, REG_VBLK_STOP_LINE_LSB, value); > + dump_reg(decoder->client, REG_VBLK_STOP_LINE_MSB, value); > + dump_reg(decoder->client, REG_SYNC_CONTROL, value); > + dump_reg(decoder->client, REG_OUTPUT_FORMATTER1, value); > + dump_reg(decoder->client, REG_OUTPUT_FORMATTER2, value); > + dump_reg(decoder->client, REG_OUTPUT_FORMATTER3, value); > + dump_reg(decoder->client, REG_OUTPUT_FORMATTER4, value); > + dump_reg(decoder->client, REG_OUTPUT_FORMATTER5, value); > + dump_reg(decoder->client, REG_OUTPUT_FORMATTER6, value); > + dump_reg(decoder->client, REG_CLEAR_LOST_LOCK, value); > +} > +#endif > + > +/* > + * Configure the TVP5146/47 with the current register settings > + * Returns zero if successful, or non-zero otherwise. > + */ > +static int tvp514x_configure(struct tvp514x_decoder *decoder) > +{ > + int err; > + > + /* common register initialization */ > + err = > + tvp514x_write_regs(decoder->client, tvp514x_reg_list); > + if (err) > + return err; > + > +#ifdef TVP514X_DEBUG > + tvp514x_reg_dump(decoder); > +#endif > + > + return 0; > +} > + > +/* > + * Detect if an tvp514x is present, and if so which revision. > + * 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 tvp514x_decoder *decoder) > +{ > + u8 chip_id_msb, chip_id_lsb, rom_ver; > + > + if (tvp514x_read_reg > + (decoder->client, REG_CHIP_ID_MSB, &chip_id_msb)) > + return -ENODEV; > + if (tvp514x_read_reg > + (decoder->client, REG_CHIP_ID_LSB, &chip_id_lsb)) > + return -ENODEV; > + if (tvp514x_read_reg(decoder->client, REG_ROM_VERSION, &rom_ver)) > + return -ENODEV; > + > + DBG(&decoder->client->dev, 2, > + "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. > + */ > + DBG(&decoder->client->dev, 1, > + "chip id mismatch msb:0x%x lsb:0x%x\n", > + chip_id_msb, chip_id_lsb); > + return -ENODEV; > + } > + > + decoder->ver = rom_ver; > + decoder->state = STATE_DETECTED; Please add a line like this: v4l_info(client, "%s found @ 0x%x (%s)\n", client->name, client->addr << 1, client->adapter->name); It is good to log that the driver has detected a chip and on which adapter and address. The v4l_info above is the standard text that is printed. > + > + return 0; > +} > + > +/* > + * following are decoder interface functions implemented by > + * TVP5146/47 decoder driver. > + */ > + > +/** > + * ioctl_querystd - V4L2 decoder interface handler for > VIDIOC_QUERYSTD ioctl + * @s: pointer to standard V4L2 device > structure > + * @std_id: standard V4L2 std_id ioctl enum > + * > + * Returns the current standard detected by TVP5146/47. If no active > input is + * detected, returns -EINVAL > + */ > +static int ioctl_querystd(struct v4l2_int_device *s, v4l2_std_id > *std_id) +{ > + struct tvp514x_decoder *decoder = s->priv; > + enum tvp514x_std current_std; > + enum tvp514x_input input_sel; > + u8 sync_lock_status, lock_mask; > + > + if (std_id == NULL) > + return -EINVAL; > + > + /* get the current standard */ > + current_std = tvp514x_get_current_std(decoder); > + if (current_std == STD_INVALID) > + return -EINVAL; > + > + /* check whether signal is locked */ > + if (tvp514x_read_reg > + (decoder->client, REG_STATUS1, &sync_lock_status)) > + return -EINVAL; > + > + input_sel = > decoder->pdata->input_list[decoder->inputidx].input_sel; + > + 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; > + } > + > + if (lock_mask != (sync_lock_status & lock_mask)) > + return -EINVAL; /* No input detected */ > + > + decoder->current_std = current_std; > + *std_id = decoder->std_list[current_std].standard.id; > + > + DBG(&decoder->client->dev, 3, > + "Current STD: %s", > + decoder->std_list[current_std].standard.name); > + return 0; > +} > + > +/** > + * ioctl_s_std - V4L2 decoder interface handler for VIDIOC_S_STD > ioctl + * @s: pointer to standard V4L2 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 ioctl_s_std(struct v4l2_int_device *s, v4l2_std_id > *std_id) +{ > + struct tvp514x_decoder *decoder = s->priv; > + int err, i; > + > + if (std_id == NULL) > + return -EINVAL; > + > + for (i = 0; i < decoder->num_stds; i++) > + if (*std_id & decoder->std_list[i].standard.id) > + break; > + > + if (i == decoder->num_stds) > + return -EINVAL; > + > + err = tvp514x_write_reg(decoder->client, REG_VIDEO_STD, > + decoder->std_list[i].video_std); > + if (err) > + return err; > + > + decoder->current_std = i; > + tvp514x_reg_list[REG_VIDEO_STD].val = > + decoder->std_list[i].video_std; > + > + DBG(&decoder->client->dev, 3, > + "Standard set to: %s", > + decoder->std_list[i].standard.name); > + return 0; > +} > + > +/** > + * ioctl_enum_input - V4L2 decoder interface handler for > VIDIOC_ENUMINPUT ioctl + * @s: pointer to standard V4L2 device > structure > + * @input: standard V4L2 VIDIOC_ENUMINPUT ioctl structure > + * > + * If index is valid, returns the description of the input. > Otherwise, returns + * -EINVAL if any error occurs > + */ > +static int > +ioctl_enum_input(struct v4l2_int_device *s, struct v4l2_input > *input) +{ > + struct tvp514x_decoder *decoder = s->priv; > + int index; > + > + if (input == NULL) > + return -EINVAL; > + > + index = input->index; > + if ((index >= decoder->pdata->num_inputs) || (index < 0)) > + return -EINVAL; /* Index out of bound */ > + > + memcpy(input, &decoder->pdata->input_list[index].input, > + sizeof(struct v4l2_input)); > + > + DBG(&decoder->client->dev, 3, > + "Current input is: index - %d (%s)", > + decoder->pdata->input_list[index].input.index, > + decoder->pdata->input_list[index].input.name); > + return 0; > +} > + > +/** > + * ioctl_s_input - V4L2 decoder interface handler for VIDIOC_S_INPUT > ioctl + * @s: pointer to standard V4L2 device structure > + * @index: number of the input > + * > + * 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. > + */ What sort of input are we talking about here? The VIDIOC_S_INPUT ioctl deals with user-visible inputs (e.g. S-Video, HDMI, DVI, etc). That is quite different from the inputs on the chip-level. An input there corresponds to a pin. The VIDIOC_INT_S_VIDEO_ROUTING ioctl exists for that purpose. Mixing these two will leads to very hard to maintain code (really, I had to fix a bunch of drivers in the past that did it all wrong). If the s_input function is meant for chip inputs, then I strongly recommend that it is renamed (ioctl_s_routing or ioctl_s_input_pins) to prevent this confusion. > +static int ioctl_s_input(struct v4l2_int_device *s, int index) > +{ > + struct tvp514x_decoder *decoder = s->priv; > + int err; > + enum tvp514x_input input_sel; > + enum tvp514x_std current_std = STD_INVALID; > + u8 sync_lock_status, lock_mask; > + int try_count = LOCK_RETRY_COUNT; > + > + if ((index >= decoder->pdata->num_inputs) || (index < 0)) > + return -EINVAL; /* Index out of bound */ > + > + /* Get the register value to be written to select the requested > input */ + input_sel = decoder->pdata->input_list[index].input_sel; > + err = tvp514x_write_reg(decoder->client, REG_INPUT_SEL, input_sel); > + if (err) > + return err; > + > + decoder->inputidx = index; > + tvp514x_reg_list[REG_INPUT_SEL].val = input_sel; > + > + /* Clear status */ > + msleep(LOCK_RETRY_DELAY); > + err = > + tvp514x_write_reg(decoder->client, 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); > + > + /* get the current standard for future reference */ > + current_std = tvp514x_get_current_std(decoder); > + if (current_std == STD_INVALID) > + continue; > + > + if (tvp514x_read_reg(decoder->client, REG_STATUS1, > + &sync_lock_status)) > + return -EINVAL; > + > + if (lock_mask == (sync_lock_status & lock_mask)) > + break; /* Input detected */ > + } > + > + if ((current_std == STD_INVALID) || (try_count < 0)) > + return -EINVAL; > + > + decoder->current_std = current_std; > + > + DBG(&decoder->client->dev, 3, > + "Input set to: index - %d (%s)", > + decoder->pdata->input_list[index].input.index, > + decoder->pdata->input_list[index].input.name); > + return 0; > +} > + > +/** > + * ioctl_g_input - V4L2 decoder interface handler for VIDIOC_G_INPUT > ioctl + * @s: pointer to standard V4L2 device structure > + * @index: returns the current selected input > + * > + * Returns the current selected input. Returns -EINVAL if any error > occurs + */ > +static int ioctl_g_input(struct v4l2_int_device *s, int *index) > +{ > + struct tvp514x_decoder *decoder = s->priv; > + int err = -EINVAL, i, inputidx; > + > + if (index == NULL) > + return -EINVAL; > + > + /* Search through the input list for active inputs */ > + inputidx = decoder->inputidx; > + for (i = 0; i < decoder->pdata->num_inputs; i++) { > + inputidx++; /* Move to next input */ > + if (inputidx >= decoder->pdata->num_inputs) > + inputidx = 0; /* fall back to first input */ > + > + err = ioctl_s_input(s, inputidx); > + if (!err) { > + /* Active input found - select it and return success */ > + *index = inputidx; > + return 0; > + } > + } > + > + return err; > +} > + > +/** > + * ioctl_queryctrl - V4L2 decoder interface handler for > VIDIOC_QUERYCTRL ioctl + * @s: pointer to standard V4L2 device > structure > + * @qc: standard V4L2 VIDIOC_QUERYCTRL ioctl structure > + * > + * If the requested control is supported, returns the control > information + * from the ctrl_list[] array. Otherwise, returns > -EINVAL if the + * control is not supported. > + */ > +static int > +ioctl_queryctrl(struct v4l2_int_device *s, struct v4l2_queryctrl > *qctrl) +{ > + struct tvp514x_decoder *decoder = s->priv; > + int id, index; > + const struct tvp514x_ctrl_info *control = NULL; > + > + if (qctrl == NULL) > + return -EINVAL; > + > + id = qctrl->id; > + memset(qctrl, 0, sizeof(struct v4l2_queryctrl)); > + qctrl->id = id; > + > + for (index = 0; index < decoder->num_ctrls; index++) { > + control = &decoder->ctrl_list[index]; > + if (control->query_ctrl.id == qctrl->id) > + break; /* Match found */ > + } > + if (index == decoder->num_ctrls) > + return -EINVAL; /* Index out of bound */ > + > + memcpy(qctrl, &control->query_ctrl, sizeof(struct v4l2_queryctrl)); > + > + DBG(&decoder->client->dev, 3, > + "Query Cotrol: %s : Min - %d, Max - %d, Def - %d", Typo: 'Cotrol' instead of 'Control'. Happens multiple times in the source. > + control->query_ctrl.name, > + control->query_ctrl.minimum, > + control->query_ctrl.maximum, > + control->query_ctrl.default_value); > + return 0; > +} > + > +/** > + * ioctl_g_ctrl - V4L2 decoder interface handler for VIDIOC_G_CTRL > ioctl + * @s: pointer to standard V4L2 device structure > + * @vc: standard V4L2 VIDIOC_G_CTRL ioctl 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 > +ioctl_g_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl) > +{ > + struct tvp514x_decoder *decoder = s->priv; > + int err, index; > + u8 val; > + int value; > + const struct tvp514x_ctrl_info *control = NULL; > + > + if (ctrl == NULL) > + return -EINVAL; > + > + for (index = 0; index < decoder->num_ctrls; index++) { > + control = &decoder->ctrl_list[index]; > + if (control->query_ctrl.id == ctrl->id) > + break; /* Match found */ > + } > + if (index == decoder->num_ctrls) > + return -EINVAL; /* Index out of bound */ > + > + err = > + tvp514x_read_reg(decoder->client, control->reg_address, &val); > + if (err < 0) > + return err; > + > + /* cross check */ > + if (val != tvp514x_reg_list[control->reg_address].val) > + return -EINVAL; /* Driver & TVP5146/47 setting mismatch */ > + > + value = val; > + if (V4L2_CID_AUTOGAIN == ctrl->id) { > + if ((value & 0x3) == 3) > + value = 1; > + else > + value = 0; > + } > + > + if (V4L2_CID_HUE == ctrl->id) { > + if (value == 0x7F) > + value = 180; > + else if (value == 0x80) > + value = -180; > + else > + value = 0; > + } > + > + ctrl->value = value; > + > + DBG(&decoder->client->dev, 3, > + "Get Cotrol: %s - %d", > + control->query_ctrl.name, value); > + return err; > +} > + > +/** > + * ioctl_s_ctrl - V4L2 decoder interface handler for VIDIOC_S_CTRL > ioctl + * @s: pointer to standard V4L2 device structure > + * @vc: standard V4L2 VIDIOC_S_CTRL ioctl 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 > +ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl) > +{ > + struct tvp514x_decoder *decoder = s->priv; > + int err, value, index; > + const struct tvp514x_ctrl_info *control = NULL; > + > + if (ctrl == NULL) > + return -EINVAL; > + > + value = (__s32) ctrl->value; > + for (index = 0; index < decoder->num_ctrls; index++) { > + control = &decoder->ctrl_list[index]; > + if (control->query_ctrl.id == ctrl->id) > + break; /* Match found */ > + } > + if (index == decoder->num_ctrls) > + return -EINVAL; /* Index out of bound */ > + > + if (V4L2_CID_AUTOGAIN == ctrl->id) { > + if (value == 1) > + value = 0x0F; > + else if (value == 0) > + value = 0x0C; > + else > + return -ERANGE; > + } else if (V4L2_CID_HUE == ctrl->id) { > + if (value == 180) > + value = 0x7F; > + else if (value == -180) > + value = 0x80; > + else if (value == 0) > + value = 0; > + else > + return -ERANGE; > + } else { > + if ((value < control->query_ctrl.minimum) > + || (value > control->query_ctrl.maximum)) > + return -ERANGE; > + } > + > + err = > + tvp514x_write_reg(decoder->client, control->reg_address, > + value); > + if (err < 0) > + return err; > + > + tvp514x_reg_list[control->reg_address].val = value; > + > + DBG(&decoder->client->dev, 3, > + "Set Cotrol: %s - %d", > + control->query_ctrl.name, value); > + return err; > +} > + > +/** > + * ioctl_enum_fmt_cap - Implement the CAPTURE buffer VIDIOC_ENUM_FMT > ioctl + * @s: pointer to standard V4L2 device structure > + * @fmt: standard V4L2 VIDIOC_ENUM_FMT ioctl structure > + * > + * Implement the VIDIOC_ENUM_FMT ioctl to enumerate supported > formats + */ > +static int > +ioctl_enum_fmt_cap(struct v4l2_int_device *s, struct v4l2_fmtdesc > *fmt) +{ > + struct tvp514x_decoder *decoder = s->priv; > + int index; > + > + if (fmt == NULL) > + return -EINVAL; > + > + index = fmt->index; > + if ((index >= decoder->num_fmts) || (index < 0)) > + return -EINVAL; /* Index out of bound */ > + > + if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) > + return -EINVAL; /* only capture is supported */ > + > + memcpy(fmt, &decoder->fmt_list[index], > + sizeof(struct v4l2_fmtdesc)); > + > + DBG(&decoder->client->dev, 3, > + "Current FMT: index - %d (%s)", > + decoder->fmt_list[index].index, > + decoder->fmt_list[index].description); > + return 0; > +} > + > +/** > + * ioctl_try_fmt_cap - Implement the CAPTURE buffer VIDIOC_TRY_FMT > ioctl + * @s: pointer to standard V4L2 device structure > + * @f: pointer to standard V4L2 VIDIOC_TRY_FMT ioctl structure > + * > + * Implement the VIDIOC_TRY_FMT ioctl for the CAPTURE buffer type. > This + * ioctl is used to negotiate the image capture size and pixel > format + * without actually making it take effect. > + */ > +static int > +ioctl_try_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f) > +{ > + struct tvp514x_decoder *decoder = s->priv; > + int ifmt; > + struct v4l2_pix_format *pix; > + enum tvp514x_std current_std; > + > + if (f == NULL) > + return -EINVAL; > + > + if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) > + f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; > + > + pix = &f->fmt.pix; > + > + /* Calculate height and width based on current standard */ > + current_std = tvp514x_get_current_std(decoder); > + if (current_std == STD_INVALID) > + return -EINVAL; > + > + decoder->current_std = current_std; > + pix->width = decoder->std_list[current_std].width; > + pix->height = decoder->std_list[current_std].height; > + > + for (ifmt = 0; ifmt < decoder->num_fmts; ifmt++) { > + if (pix->pixelformat == > + decoder->fmt_list[ifmt].pixelformat) > + break; > + } > + if (ifmt == decoder->num_fmts) > + ifmt = 0; /* None of the format matched, select default */ > + pix->pixelformat = decoder->fmt_list[ifmt].pixelformat; > + > + pix->field = V4L2_FIELD_INTERLACED; > + pix->bytesperline = pix->width * 2; > + pix->sizeimage = pix->bytesperline * pix->height; > + pix->colorspace = V4L2_COLORSPACE_SMPTE170M; > + pix->priv = 0; > + > + DBG(&decoder->client->dev, 3, > + "Try FMT: pixelformat - %s, bytesperline - %d" > + "Width - %d, Height - %d", > + decoder->fmt_list[ifmt].description, pix->bytesperline, > + pix->width, pix->height); > + return 0; > +} > + > +/** > + * ioctl_s_fmt_cap - V4L2 decoder interface handler for VIDIOC_S_FMT > ioctl + * @s: pointer to standard V4L2 device structure > + * @f: pointer to standard V4L2 VIDIOC_S_FMT ioctl structure > + * > + * If the requested format is supported, configures the HW to use > that + * format, returns error code if format not supported or HW > can't be + * correctly configured. > + */ > +static int > +ioctl_s_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f) > +{ > + struct tvp514x_decoder *decoder = s->priv; > + struct v4l2_pix_format *pix; > + int rval; > + > + if (f == NULL) > + return -EINVAL; > + > + if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) > + return -EINVAL; /* only capture is supported */ > + > + pix = &f->fmt.pix; > + rval = ioctl_try_fmt_cap(s, f); > + if (rval) > + return rval; > + else > + decoder->pix = *pix; > + > + return rval; > +} > + > +/** > + * ioctl_g_fmt_cap - V4L2 decoder interface handler for > ioctl_g_fmt_cap + * @s: pointer to standard V4L2 device structure > + * @f: pointer to standard V4L2 v4l2_format structure > + * > + * Returns the decoder's current pixel format in the v4l2_format > + * parameter. > + */ > +static int > +ioctl_g_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f) > +{ > + struct tvp514x_decoder *decoder = s->priv; > + > + if (f == NULL) > + return -EINVAL; > + > + if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) > + return -EINVAL; /* only capture is supported */ > + > + f->fmt.pix = decoder->pix; > + > + DBG(&decoder->client->dev, 3, > + "Current FMT: bytesperline - %d" > + "Width - %d, Height - %d", > + decoder->pix.bytesperline, > + decoder->pix.width, decoder->pix.height); > + return 0; > +} > + > +/** > + * ioctl_g_parm - V4L2 decoder interface handler for VIDIOC_G_PARM > ioctl + * @s: pointer to standard V4L2 device structure > + * @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure > + * > + * Returns the decoder's video CAPTURE parameters. > + */ > +static int > +ioctl_g_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a) > +{ > + struct tvp514x_decoder *decoder = s->priv; > + struct v4l2_captureparm *cparm; > + enum tvp514x_std current_std; > + > + if (a == NULL) > + return -EINVAL; > + > + if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) > + return -EINVAL; /* only capture is supported */ > + > + memset(a, 0, sizeof(*a)); > + a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; > + > + /* get the current standard */ > + current_std = tvp514x_get_current_std(decoder); > + decoder->current_std = current_std; > + > + cparm = &a->parm.capture; > + cparm->capability = V4L2_CAP_TIMEPERFRAME; > + cparm->timeperframe > + = decoder->std_list[current_std].standard.frameperiod; > + > + return 0; > +} > + > +/** > + * ioctl_s_parm - V4L2 decoder interface handler for VIDIOC_S_PARM > ioctl + * @s: pointer to standard V4L2 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 > +ioctl_s_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a) > +{ > + struct tvp514x_decoder *decoder = s->priv; > + struct v4l2_fract *timeperframe; > + enum tvp514x_std current_std; > + > + if (a == NULL) > + return -EINVAL; > + > + if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) > + return -EINVAL; /* only capture is supported */ > + > + timeperframe = &a->parm.capture.timeperframe; > + > + /* get the current standard */ > + current_std = tvp514x_get_current_std(decoder); > + decoder->current_std = current_std; > + > + *timeperframe = > + decoder->std_list[current_std].standard.frameperiod; > + > + return 0; > +} > + > +/** > + * ioctl_g_ifparm - V4L2 decoder interface handler for > vidioc_int_g_ifparm_num + * @s: pointer to standard V4L2 device > structure > + * @p: pointer to standard V4L2 vidioc_int_g_ifparm_num ioctl > structure + * > + * Gets slave interface parameters. > + * Calculates the required xclk value to support the requested > + * clock parameters in p. This value is returned in the p > + * parameter. > + */ > +static int ioctl_g_ifparm(struct v4l2_int_device *s, struct > v4l2_ifparm *p) +{ > + struct tvp514x_decoder *decoder = s->priv; > + int rval; > + > + if (p == NULL) > + return -EINVAL; > + > + if (NULL == decoder->pdata->ifparm) > + return -EINVAL; > + > + rval = decoder->pdata->ifparm(p); > + if (rval) { > + DBG(&decoder->client->dev, 1, "error. Err[%d]\n", rval); > + return rval; > + } > + > + p->u.bt656.clock_curr = TVP514X_XCLK_BT656; > + > + return 0; > +} > + > +/** > + * ioctl_g_priv - V4L2 decoder interface handler for > vidioc_int_g_priv_num + * @s: pointer to standard V4L2 device > structure > + * @p: void pointer to hold decoder's private data address > + * > + * Returns device's (decoder's) private data area address in p > parameter + */ > +static int ioctl_g_priv(struct v4l2_int_device *s, void *p) > +{ > + struct tvp514x_decoder *decoder = s->priv; > + > + if (NULL == decoder->pdata->priv_data_set) > + return -EINVAL; > + > + return decoder->pdata->priv_data_set(p); > +} > + > +/** > + * ioctl_s_power - V4L2 decoder interface handler for > vidioc_int_s_power_num + * @s: pointer to standard V4L2 device > structure > + * @on: power state to which device is to be set > + * > + * Sets devices power state to requrested state, if possible. > + */ > +static int ioctl_s_power(struct v4l2_int_device *s, enum v4l2_power > on) +{ > + struct tvp514x_decoder *decoder = s->priv; > + int err = 0; > + > + switch (on) { > + case V4L2_POWER_OFF: > + /* Power Down Sequence */ > + err = > + tvp514x_write_reg(decoder->client, REG_OPERATION_MODE, > + 0x01); > + /* Disable mux for TVP5146/47 decoder data path */ > + if (decoder->pdata->power_set) > + err |= decoder->pdata->power_set(on); > + break; > + > + case V4L2_POWER_STANDBY: > + if (decoder->pdata->power_set) > + err = decoder->pdata->power_set(on); > + break; > + > + case V4L2_POWER_ON: > + /* Enable mux for TVP5146/47 decoder data path */ > + if (decoder->pdata->power_set) > + err = decoder->pdata->power_set(on); > + > + /* Power Up Sequence */ > + err |= > + tvp514x_write_reg(decoder->client, REG_OPERATION_MODE, > + 0x01); > + err |= > + tvp514x_write_reg(decoder->client, REG_OPERATION_MODE, > + 0x00); > + > + /* Detect the sensor is not already detected */ > + if (decoder->state == STATE_NOT_DETECTED) { > + err |= tvp514x_detect(decoder); > + if (err < 0) { > + DBG(&decoder->client->dev, 1, > + "Unable to detect decoder\n"); > + return err; > + } > + DBG(&decoder->client->dev, 2, > + "chip version 0x%.2x detected\n", > + decoder->ver); > + } > + break; > + > + case V4L2_POWER_RESUME: > + if (decoder->pdata->power_set) > + err = decoder->pdata->power_set(on); > + if (decoder->state == STATE_DETECTED) > + err |= tvp514x_configure(decoder); > + break; > + > + default: > + err = -ENODEV; > + break; > + } > + > + return err; > +} > + > +/** > + * ioctl_init - V4L2 decoder interface handler for VIDIOC_INT_INIT > + * @s: pointer to standard V4L2 device structure > + * > + * Initialize the decoder device (calls tvp514x_configure()) > + */ > +static int ioctl_init(struct v4l2_int_device *s) > +{ > + struct tvp514x_decoder *decoder = s->priv; > + > + /* Set default standard to auto */ > + tvp514x_reg_list[REG_VIDEO_STD].val = > + VIDEO_STD_AUTO_SWITCH_BIT; > + > + return tvp514x_configure(decoder); > +} > + > +/** > + * ioctl_dev_exit - V4L2 decoder interface handler for > vidioc_int_dev_exit_num + * @s: pointer to standard V4L2 device > structure > + * > + * Delinitialise the dev. at slave detach. The complement of > ioctl_dev_init. + */ > +static int ioctl_dev_exit(struct v4l2_int_device *s) > +{ > + return 0; > +} > + > +/** > + * ioctl_dev_init - V4L2 decoder interface handler for > vidioc_int_dev_init_num + * @s: pointer to standard V4L2 device > structure > + * > + * Initialise the device when slave attaches to the master. Returns > 0 if + * TVP5146/47 device could be found, otherwise returns > appropriate error. + */ > +static int ioctl_dev_init(struct v4l2_int_device *s) > +{ > + struct tvp514x_decoder *decoder = s->priv; > + int err; > + > + err = tvp514x_detect(decoder); > + if (err < 0) { > + DBG(&decoder->client->dev, 1, > + "Unable to detect decoder\n"); > + return err; > + } > + > + DBG(&decoder->client->dev, 2, > + "chip version 0x%.2x detected\n", decoder->ver); > + > + return 0; > +} > + > +static struct v4l2_int_ioctl_desc tvp514x_ioctl_desc[] = { > + {vidioc_int_dev_init_num, (v4l2_int_ioctl_func*) ioctl_dev_init}, > + {vidioc_int_dev_exit_num, (v4l2_int_ioctl_func*) ioctl_dev_exit}, > + {vidioc_int_s_power_num, (v4l2_int_ioctl_func*) ioctl_s_power}, > + {vidioc_int_g_priv_num, (v4l2_int_ioctl_func*) ioctl_g_priv}, > + {vidioc_int_g_ifparm_num, (v4l2_int_ioctl_func*) ioctl_g_ifparm}, > + {vidioc_int_init_num, (v4l2_int_ioctl_func*) ioctl_init}, > + {vidioc_int_enum_fmt_cap_num, > + (v4l2_int_ioctl_func *) ioctl_enum_fmt_cap}, > + {vidioc_int_try_fmt_cap_num, > + (v4l2_int_ioctl_func *) ioctl_try_fmt_cap}, > + {vidioc_int_g_fmt_cap_num, > + (v4l2_int_ioctl_func *) ioctl_g_fmt_cap}, > + {vidioc_int_s_fmt_cap_num, > + (v4l2_int_ioctl_func *) ioctl_s_fmt_cap}, > + {vidioc_int_g_parm_num, (v4l2_int_ioctl_func *) ioctl_g_parm}, > + {vidioc_int_s_parm_num, (v4l2_int_ioctl_func *) ioctl_s_parm}, > + {vidioc_int_queryctrl_num, > + (v4l2_int_ioctl_func *) ioctl_queryctrl}, > + {vidioc_int_g_ctrl_num, (v4l2_int_ioctl_func *) ioctl_g_ctrl}, > + {vidioc_int_s_ctrl_num, (v4l2_int_ioctl_func *) ioctl_s_ctrl}, > + {vidioc_int_querystd_num, (v4l2_int_ioctl_func *) ioctl_querystd}, > + {vidioc_int_s_std_num, (v4l2_int_ioctl_func *) ioctl_s_std}, > + {vidioc_int_enum_input_num, > + (v4l2_int_ioctl_func *) ioctl_enum_input}, > + {vidioc_int_g_input_num, (v4l2_int_ioctl_func *) ioctl_g_input}, > + {vidioc_int_s_input_num, (v4l2_int_ioctl_func *) ioctl_s_input}, > +}; > + > +static struct v4l2_int_slave tvp514x_slave = { > + .ioctls = tvp514x_ioctl_desc, > + .num_ioctls = ARRAY_SIZE(tvp514x_ioctl_desc), > +}; > + > +static struct tvp514x_decoder tvp514x_dev = { > + .state = STATE_NOT_DETECTED, > + > + .num_fmts = TVP514X_NUM_FORMATS, > + .fmt_list = tvp514x_fmt_list, > + > + .pix = { /* Default to NTSC 8-bit YUV 422 */ > + .width = NTSC_NUM_ACTIVE_PIXELS, > + .height = NTSC_NUM_ACTIVE_LINES, > + .pixelformat = V4L2_PIX_FMT_UYVY, > + .field = V4L2_FIELD_INTERLACED, > + .bytesperline = NTSC_NUM_ACTIVE_PIXELS * 2, > + .sizeimage = > + NTSC_NUM_ACTIVE_PIXELS * 2 * NTSC_NUM_ACTIVE_LINES, > + .colorspace = V4L2_COLORSPACE_SMPTE170M, > + }, > + > + .current_std = STD_NTSC_MJ, > + .num_stds = TVP514X_NUM_STANDARDS, > + .std_list = tvp514x_std_list, > + > + .num_ctrls = TVP514X_NUM_CONTROLS, > + .ctrl_list = tvp514x_ctrl_list, > + > +}; > + > +static struct v4l2_int_device tvp514x_int_device = { > + .module = THIS_MODULE, > + .name = MODULE_NAME, > + .priv = &tvp514x_dev, > + .type = v4l2_int_type_slave, > + .u = { > + .slave = &tvp514x_slave, > + }, > +}; > + > +/** > + * tvp514x_probe - decoder driver i2c probe handler > + * @client: i2c driver client device structure > + * > + * 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 = &tvp514x_dev; > + int err; > + > + if (i2c_get_clientdata(client)) > + return -EBUSY; > + > + decoder->pdata = client->dev.platform_data; > + if (!decoder->pdata) { > + DBG(&client->dev, 1, "No platform data\n!!"); > + return -ENODEV; > + } > + /* > + * Fetch platform specific data, and configure the > + * tvp514x_reg_list[] accordingly. Since this is one > + * time configuration, no need to preserve. > + */ > + decoder->inputidx = decoder->pdata->default_input; > + tvp514x_reg_list[REG_OUTPUT_FORMATTER2].val |= > + (decoder->pdata->clk_polarity << 1); > + tvp514x_reg_list[REG_OUTPUT_FORMATTER1].val |= > + decoder->pdata->fmt; > + tvp514x_reg_list[REG_SYNC_CONTROL].val |= > + ((decoder->pdata->hs_polarity << 2) | > + (decoder->pdata->vs_polarity << 3)); > + > + /* Attach to Master */ > + strcpy(tvp514x_int_device.u.slave->attach_to, > decoder->pdata->master); + decoder->v4l2_int_device = > &tvp514x_int_device; > + decoder->client = client; > + i2c_set_clientdata(client, decoder); > + > + /* Register with V4L2 layer as slave device */ > + err = v4l2_int_device_register(decoder->v4l2_int_device); > + if (err) { > + i2c_set_clientdata(client, NULL); > + DBG(&client->dev, 1, > + "Unable to register to v4l2. Err[%d]\n", err); > + > + } else > + DBG(&client->dev, 3, "Registered to v4l2 master %s!!\n", > + decoder->pdata->master); > + > + 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 __exit tvp514x_remove(struct i2c_client *client) > +{ > + struct tvp514x_decoder *decoder = i2c_get_clientdata(client); > + > + if (!client->adapter) > + return -ENODEV; /* our client isn't attached */ > + > + v4l2_int_device_unregister(decoder->v4l2_int_device); > + i2c_set_clientdata(client, NULL); > + > + return 0; > +} > + > +static const struct i2c_device_id tvp514x_id[] = { > + {"tvp5146", 0}, > + {"tvp5147", 0}, > + {}, > +}; > + > +MODULE_DEVICE_TABLE(i2c, tvp514x_id); > + > +static struct i2c_driver tvp514x_i2c_driver = { > + .driver = { > + .name = MODULE_NAME, > + .owner = THIS_MODULE, > + }, > + .probe = tvp514x_probe, > + .remove = __exit_p(tvp514x_remove), > + .id_table = tvp514x_id, > +}; > + > +/** > + * tvp514x_init > + * > + * Module init function > + */ > +static int __init tvp514x_init(void) > +{ > + int err; > + > + err = i2c_add_driver(&tvp514x_i2c_driver); > + if (err) { > + printk(KERN_ERR "Failed to register " MODULE_NAME ".\n"); > + return err; > + } > + return 0; > +} > + > +/** > + * tvp514x_cleanup > + * > + * Module exit function > + */ > +static void __exit tvp514x_cleanup(void) > +{ > + i2c_del_driver(&tvp514x_i2c_driver); > +} > + > +module_init(tvp514x_init); > +module_exit(tvp514x_cleanup); > + > +MODULE_AUTHOR("Texas Instruments"); > +MODULE_DESCRIPTION("TVP514X linux decoder driver"); > +MODULE_LICENSE("GPL"); > diff --git a/include/media/tvp514x.h b/include/media/tvp514x.h > new file mode 100644 > index 0000000..5a4e2d5 > --- /dev/null > +++ b/include/media/tvp514x.h I strongly recommend splitting this header up into two parts: all the register defines etc. should go to a driver/media/video/tvp514x_regs.h leaving only the parts that host drivers will typically use in this header. Basically split it into a public header (this one) and a private one that's in the same directory as the source. Regards, Hans > @@ -0,0 +1,461 @@ > +/* > + * drivers/media/video/tvp514x.h > + * > + * Copyright (C) 2008 Texas Instruments Inc > + * > + * 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. > + * > + */ > + > +#ifndef _TVP514X_H > +#define _TVP514X_H > + > +/* > + * TVP5146/47 registers > + */ > +#define REG_INPUT_SEL (0x00) > +#define REG_AFE_GAIN_CTRL (0x01) > +#define REG_VIDEO_STD (0x02) > +#define REG_OPERATION_MODE (0x03) > +#define REG_AUTOSWITCH_MASK (0x04) > + > +#define REG_COLOR_KILLER (0x05) > +#define REG_LUMA_CONTROL1 (0x06) > +#define REG_LUMA_CONTROL2 (0x07) > +#define REG_LUMA_CONTROL3 (0x08) > + > +#define REG_BRIGHTNESS (0x09) > +#define REG_CONTRAST (0x0A) > +#define REG_SATURATION (0x0B) > +#define REG_HUE (0x0C) > + > +#define REG_CHROMA_CONTROL1 (0x0D) > +#define REG_CHROMA_CONTROL2 (0x0E) > + > +/* 0x0F Reserved */ > + > +#define REG_COMP_PR_SATURATION (0x10) > +#define REG_COMP_Y_CONTRAST (0x11) > +#define REG_COMP_PB_SATURATION (0x12) > + > +/* 0x13 Reserved */ > + > +#define REG_COMP_Y_BRIGHTNESS (0x14) > + > +/* 0x15 Reserved */ > + > +#define REG_AVID_START_PIXEL_LSB (0x16) > +#define REG_AVID_START_PIXEL_MSB (0x17) > +#define REG_AVID_STOP_PIXEL_LSB (0x18) > +#define REG_AVID_STOP_PIXEL_MSB (0x19) > + > +#define REG_HSYNC_START_PIXEL_LSB (0x1A) > +#define REG_HSYNC_START_PIXEL_MSB (0x1B) > +#define REG_HSYNC_STOP_PIXEL_LSB (0x1C) > +#define REG_HSYNC_STOP_PIXEL_MSB (0x1D) > + > +#define REG_VSYNC_START_LINE_LSB (0x1E) > +#define REG_VSYNC_START_LINE_MSB (0x1F) > +#define REG_VSYNC_STOP_LINE_LSB (0x20) > +#define REG_VSYNC_STOP_LINE_MSB (0x21) > + > +#define REG_VBLK_START_LINE_LSB (0x22) > +#define REG_VBLK_START_LINE_MSB (0x23) > +#define REG_VBLK_STOP_LINE_LSB (0x24) > +#define REG_VBLK_STOP_LINE_MSB (0x25) > + > +/* 0x26 - 0x27 Reserved */ > + > +#define REG_FAST_SWTICH_CONTROL (0x28) > + > +/* 0x29 Reserved */ > + > +#define REG_FAST_SWTICH_SCART_DELAY (0x2A) > + > +/* 0x2B Reserved */ > + > +#define REG_SCART_DELAY (0x2C) > +#define REG_CTI_DELAY (0x2D) > +#define REG_CTI_CONTROL (0x2E) > + > +/* 0x2F - 0x31 Reserved */ > + > +#define REG_SYNC_CONTROL (0x32) > +#define REG_OUTPUT_FORMATTER1 (0x33) > +#define REG_OUTPUT_FORMATTER2 (0x34) > +#define REG_OUTPUT_FORMATTER3 (0x35) > +#define REG_OUTPUT_FORMATTER4 (0x36) > +#define REG_OUTPUT_FORMATTER5 (0x37) > +#define REG_OUTPUT_FORMATTER6 (0x38) > +#define REG_CLEAR_LOST_LOCK (0x39) > + > +#define REG_STATUS1 (0x3A) > +#define REG_STATUS2 (0x3B) > + > +#define REG_AGC_GAIN_STATUS_LSB (0x3C) > +#define REG_AGC_GAIN_STATUS_MSB (0x3D) > + > +/* 0x3E Reserved */ > + > +#define REG_VIDEO_STD_STATUS (0x3F) > +#define REG_GPIO_INPUT1 (0x40) > +#define REG_GPIO_INPUT2 (0x41) > + > +/* 0x42 - 0x45 Reserved */ > + > +#define REG_AFE_COARSE_GAIN_CH1 (0x46) > +#define REG_AFE_COARSE_GAIN_CH2 (0x47) > +#define REG_AFE_COARSE_GAIN_CH3 (0x48) > +#define REG_AFE_COARSE_GAIN_CH4 (0x49) > + > +#define REG_AFE_FINE_GAIN_PB_B_LSB (0x4A) > +#define REG_AFE_FINE_GAIN_PB_B_MSB (0x4B) > +#define REG_AFE_FINE_GAIN_Y_G_CHROMA_LSB (0x4C) > +#define REG_AFE_FINE_GAIN_Y_G_CHROMA_MSB (0x4D) > +#define REG_AFE_FINE_GAIN_PR_R_LSB (0x4E) > +#define REG_AFE_FINE_GAIN_PR_R_MSB (0x4F) > +#define REG_AFE_FINE_GAIN_CVBS_LUMA_LSB (0x50) > +#define REG_AFE_FINE_GAIN_CVBS_LUMA_MSB (0x51) > + > +/* 0x52 - 0x68 Reserved */ > + > +#define REG_FBIT_VBIT_CONTROL1 (0x69) > + > +/* 0x6A - 0x6B Reserved */ > + > +#define REG_BACKEND_AGC_CONTROL (0x6C) > + > +/* 0x6D - 0x6E Reserved */ > + > +#define REG_AGC_DECREMENT_SPEED_CONTROL (0x6F) > +#define REG_ROM_VERSION (0x70) > + > +/* 0x71 - 0x73 Reserved */ > + > +#define REG_AGC_WHITE_PEAK_PROCESSING (0x74) > +#define REG_FBIT_VBIT_CONTROL2 (0x75) > +#define REG_VCR_TRICK_MODE_CONTROL (0x76) > +#define REG_HORIZONTAL_SHAKE_INCREMENT (0x77) > +#define REG_AGC_INCREMENT_SPEED (0x78) > +#define REG_AGC_INCREMENT_DELAY (0x79) > + > +/* 0x7A - 0x7F Reserved */ > + > +#define REG_CHIP_ID_MSB (0x80) > +#define REG_CHIP_ID_LSB (0x81) > + > +/* 0x82 Reserved */ > + > +#define REG_CPLL_SPEED_CONTROL (0x83) > + > +/* 0x84 - 0x96 Reserved */ > + > +#define REG_STATUS_REQUEST (0x97) > + > +/* 0x98 - 0x99 Reserved */ > + > +#define REG_VERTICAL_LINE_COUNT_LSB (0x9A) > +#define REG_VERTICAL_LINE_COUNT_MSB (0x9B) > + > +/* 0x9C - 0x9D Reserved */ > + > +#define REG_AGC_DECREMENT_DELAY (0x9E) > + > +/* 0x9F - 0xB0 Reserved */ > + > +#define REG_VDP_TTX_FILTER_1_MASK1 (0xB1) > +#define REG_VDP_TTX_FILTER_1_MASK2 (0xB2) > +#define REG_VDP_TTX_FILTER_1_MASK3 (0xB3) > +#define REG_VDP_TTX_FILTER_1_MASK4 (0xB4) > +#define REG_VDP_TTX_FILTER_1_MASK5 (0xB5) > +#define REG_VDP_TTX_FILTER_2_MASK1 (0xB6) > +#define REG_VDP_TTX_FILTER_2_MASK2 (0xB7) > +#define REG_VDP_TTX_FILTER_2_MASK3 (0xB8) > +#define REG_VDP_TTX_FILTER_2_MASK4 (0xB9) > +#define REG_VDP_TTX_FILTER_2_MASK5 (0xBA) > +#define REG_VDP_TTX_FILTER_CONTROL (0xBB) > +#define REG_VDP_FIFO_WORD_COUNT (0xBC) > +#define REG_VDP_FIFO_INTERRUPT_THRLD (0xBD) > + > +/* 0xBE Reserved */ > + > +#define REG_VDP_FIFO_RESET (0xBF) > +#define REG_VDP_FIFO_OUTPUT_CONTROL (0xC0) > +#define REG_VDP_LINE_NUMBER_INTERRUPT (0xC1) > +#define REG_VDP_PIXEL_ALIGNMENT_LSB (0xC2) > +#define REG_VDP_PIXEL_ALIGNMENT_MSB (0xC3) > + > +/* 0xC4 - 0xD5 Reserved */ > + > +#define REG_VDP_LINE_START (0xD6) > +#define REG_VDP_LINE_STOP (0xD7) > +#define REG_VDP_GLOBAL_LINE_MODE (0xD8) > +#define REG_VDP_FULL_FIELD_ENABLE (0xD9) > +#define REG_VDP_FULL_FIELD_MODE (0xDA) > + > +/* 0xDB - 0xDF Reserved */ > + > +#define REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR (0xE0) > +#define REG_VBUS_DATA_ACCESS_VBUS_ADDR_INCR (0xE1) > +#define REG_FIFO_READ_DATA (0xE2) > + > +/* 0xE3 - 0xE7 Reserved */ > + > +#define REG_VBUS_ADDRESS_ACCESS1 (0xE8) > +#define REG_VBUS_ADDRESS_ACCESS2 (0xE9) > +#define REG_VBUS_ADDRESS_ACCESS3 (0xEA) > + > +/* 0xEB - 0xEF Reserved */ > + > +#define REG_INTERRUPT_RAW_STATUS0 (0xF0) > +#define REG_INTERRUPT_RAW_STATUS1 (0xF1) > +#define REG_INTERRUPT_STATUS0 (0xF2) > +#define REG_INTERRUPT_STATUS1 (0xF3) > +#define REG_INTERRUPT_MASK0 (0xF4) > +#define REG_INTERRUPT_MASK1 (0xF5) > +#define REG_INTERRUPT_CLEAR0 (0xF6) > +#define REG_INTERRUPT_CLEAR1 (0xF7) > + > +/* 0xF8 - 0xFF Reserved */ > + > +/* > + * Mask and bit definitions of TVP5146/47 registers > + */ > +/* The ID values we are looking for */ > +#define TVP514X_CHIP_ID_MSB (0x51) > +#define TVP5146_CHIP_ID_LSB (0x46) > +#define TVP5147_CHIP_ID_LSB (0x47) > + > +#define VIDEO_STD_MASK (0x07) > +#define VIDEO_STD_AUTO_SWITCH_BIT (0x00) > +#define VIDEO_STD_NTSC_MJ_BIT (0x01) > +#define VIDEO_STD_PAL_BDGHIN_BIT (0x02) > +#define VIDEO_STD_PAL_M_BIT (0x03) > +#define VIDEO_STD_PAL_COMBINATION_N_BIT (0x04) > +#define VIDEO_STD_NTSC_4_43_BIT (0x05) > +#define VIDEO_STD_SECAM_BIT (0x06) > +#define VIDEO_STD_PAL_60_BIT (0x07) > + > +/* > + * Status bit > + */ > +#define STATUS_TV_VCR_BIT (1<<0) > +#define STATUS_HORZ_SYNC_LOCK_BIT (1<<1) > +#define STATUS_VIRT_SYNC_LOCK_BIT (1<<2) > +#define STATUS_CLR_SUBCAR_LOCK_BIT (1<<3) > +#define STATUS_LOST_LOCK_DETECT_BIT (1<<4) > +#define STATUS_FEILD_RATE_BIT (1<<5) > +#define STATUS_LINE_ALTERNATING_BIT (1<<6) > +#define STATUS_PEAK_WHITE_DETECT_BIT (1<<7) > +/* > + * Other macros > + */ > +#define TVP514X_MODULE_NAME "tvp514x" > +#define TVP514X_I2C_DELAY (3) > +#define I2C_RETRY_COUNT (5) > +#define LOCK_RETRY_COUNT (3) > +#define LOCK_RETRY_DELAY (200) > + > +#define TOK_WRITE (0) /* token for write operation */ > +#define TOK_TERM (1) /* terminating token */ > +#define TOK_DELAY (2) /* delay token for reg list */ > +#define TOK_SKIP (3) /* token to skip a register */ > + > +#define TVP514X_XCLK_BT656 (27000000) > + > +/* Number of pixels and number of lines per frame for different > standards */ +#define NTSC_NUM_ACTIVE_PIXELS (720) > +#define NTSC_NUM_ACTIVE_LINES (480) > +#define PAL_NUM_ACTIVE_PIXELS (720) > +#define PAL_NUM_ACTIVE_LINES (576) > + > +/** > + * enum tvp514x_std - enum for supported standards > + */ > +enum tvp514x_std { > + STD_NTSC_MJ = 0, > + STD_PAL_BDGHIN, > + STD_INVALID > +}; > + > +/** > + * enum tvp514x_state - enum for different decoder states > + */ > +enum tvp514x_state { > + STATE_NOT_DETECTED, > + STATE_DETECTED > +}; > + > +enum tvp514x_input { > + /* > + * CVBS input selection > + */ > + INPUT_CVBS_VI1A = 0x0, > + INPUT_CVBS_VI1B, > + INPUT_CVBS_VI1C, > + INPUT_CVBS_VI2A = 0x04, > + INPUT_CVBS_VI2B, > + INPUT_CVBS_VI2C, > + INPUT_CVBS_VI3A = 0x08, > + INPUT_CVBS_VI3B, > + INPUT_CVBS_VI3C, > + INPUT_CVBS_VI4A = 0x0C, > + /* > + * S-Video input selection > + */ > + INPUT_SVIDEO_VI2A_VI1A = 0x44, > + INPUT_SVIDEO_VI2B_VI1B, > + INPUT_SVIDEO_VI2C_VI1C, > + INPUT_SVIDEO_VI2A_VI3A = 0x54, > + INPUT_SVIDEO_VI2B_VI3B, > + INPUT_SVIDEO_VI2C_VI3C, > + INPUT_SVIDEO_VI4A_VI1A = 0x4C, > + INPUT_SVIDEO_VI4A_VI1B, > + INPUT_SVIDEO_VI4A_VI1C, > + INPUT_SVIDEO_VI4A_VI3A = 0x5C, > + INPUT_SVIDEO_VI4A_VI3B, > + INPUT_SVIDEO_VI4A_VI3C > + > + /* Need to add entries for > + * RGB, YPbPr and SCART. > + */ > +}; > + > +enum tvp514x_output_fmt { > + OUTPUT_10BIT_422_EMBEDDED_SYNC = 0, > + OUTPUT_20BIT_422_SEPERATE_SYNC, > + OUTPUT_10BIT_422_SEPERATE_SYNC = 3, > + OUTPUT_INVALID > +}; > +/** > + * struct tvp514x_reg - Structure for TVP5146/47 register > initialization values + * @token - Token: TOK_WRITE, TOK_TERM etc.. > + * @reg - Register offset > + * @val - Register Value for TOK_WRITE or delay in ms for TOK_DELAY > + */ > +struct tvp514x_reg { > + u8 token; > + u8 reg; > + u32 val; > +}; > + > +/** > + * 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; > +}; > + > +/** > + * struct tvp514x_ctrl_info - Information regarding supported > controls + * @reg_address: Register offset of control register > + * @query_ctrl: v4l2 query control information > + */ > +struct tvp514x_ctrl_info { > + u8 reg_address; > + struct v4l2_queryctrl query_ctrl; > +}; > + > +/** > + * struct tvp514x_input_info - Information regarding supported > inputs + * @input_sel: Input select register > + * @lock_mask: lock mask - depends on Svideo/CVBS > + * @input: v4l2 input information > + */ > +struct tvp514x_input_info { > + enum tvp514x_input input_sel; > + struct v4l2_input input; > +}; > + > +/** > + * struct tvp514x_platform_data - Platform data values and access > functions + * @power_set: Power state access function, zero is off, > non-zero is on. + * @ifparm: Interface parameters access function > + * @priv_data_set: Device private data (pointer) access function > + * @reg_list: The board dependent driver should fill the default > value for + * required registers depending on board > layout. The TVP5146/47 + * driver will update this > register list for the registers + * whose values should be > maintained across open()/close() like + * setting > brightness as defined in V4L2. > + * The register list should be in the same order as > defined in + * TVP5146/47 datasheet including reserved > registers. As of now + * the driver expects the size of > this list to be a minimum of + * 57 + 1 (upto regsiter > REG_CLEAR_LOST_LOCK). > + * The last member should be of the list should be > + * {TOK_TERM, 0, 0} to indicate the end of register list. > + * @num_inputs: Number of input connection in board > + * @input_list: Input information list for num_inputs > + */ > +struct tvp514x_platform_data { > + char *master; > + int (*power_set) (enum v4l2_power on); > + int (*ifparm) (struct v4l2_ifparm *p); > + int (*priv_data_set) (void *); > + /* Input params */ > + int num_inputs; > + const struct tvp514x_input_info *input_list; > + int default_input; > + /* Interface control params */ > + enum tvp514x_output_fmt fmt; > + bool clk_polarity; > + bool hs_polarity; > + bool vs_polarity; > +}; > + > +/** > + * struct tvp514x_decoded - TVP5146/47 decoder object > + * @v4l2_int_device: Slave handle > + * @pdata: Board specific > + * @client: I2C client data > + * @ver: Chip version > + * @state: TVP5146/47 decoder state - detected or not-detected > + * @pix: Current pixel format > + * @num_fmts: Number of formats > + * @fmt_list: Format list > + * @current_std: Current standard > + * @num_stds: Number of standards > + * @std_list: Standards list > + * @num_ctrls: Number of controls > + * @ctrl_list: Control list > + */ > +struct tvp514x_decoder { > + struct v4l2_int_device *v4l2_int_device; > + const struct tvp514x_platform_data *pdata; > + struct i2c_client *client; > + > + int ver; > + enum tvp514x_state state; > + > + struct v4l2_pix_format pix; > + int num_fmts; > + const struct v4l2_fmtdesc *fmt_list; > + > + enum tvp514x_std current_std; > + int num_stds; > + struct tvp514x_std_info *std_list; > + > + int num_ctrls; > + const struct tvp514x_ctrl_info *ctrl_list; > + > + int inputidx; > +}; > + > +#endif /* ifndef _TVP514X_H */ > -- > 1.5.6 > > -- > video4linux-list mailing list > Unsubscribe > mailto:video4linux-list-request@xxxxxxxxxx?subject=unsubscribe > https://www.redhat.com/mailman/listinfo/video4linux-list -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html