* [PATCH 2/2] TVP514x V4L int device driver support
@ 2008-11-21 15:22 ` hvaibhav
2008-11-21 16:16 ` Hans Verkuil
` (3 more replies)
0 siblings, 4 replies; 28+ messages in thread
From: hvaibhav @ 2008-11-21 15:22 UTC (permalink / raw)
To: video4linux-list; +Cc: linux-omap, davinci-linux-open-source-bounces
From: Vaibhav Hiremath <hvaibhav@ti.com>
Added new V4L2 slave driver for TVP514x.
The Driver interface has been tested on OMAP3EVM board
with TI daughter card (TVP5146). Soon the patch for Daughter card will
be posted on community.
Signed-off-by: Brijesh Jadav <brijesh.j@ti.com>
Hardik Shah <hardik.shah@ti.com>
Manjunath Hadli <mrh@ti.com>
R Sivaraj <sivaraj@ti.com>
Vaibhav Hiremath <hvaibhav@ti.com>
Karicheri Muralidharan <m-karicheri2@ti.com>
---
drivers/media/video/Kconfig | 11 +
drivers/media/video/Makefile | 1 +
drivers/media/video/tvp514x.c | 1331 +++++++++++++++++++++++++++++++++++++++++
include/media/tvp514x.h | 406 +++++++++++++
4 files changed, 1749 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..377d14e 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 TVP5146/47 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..b68ddf5
--- /dev/null
+++ b/drivers/media/video/tvp514x.c
@@ -0,0 +1,1331 @@
+/*
+ * drivers/media/video/tvp514x.c
+ *
+ * TI TVP5146/47 decoder driver
+ *
+ * Copyright (C) 2008 Texas Instruments Inc
+ *
+ * Contributors:
+ * Brijesh R Jadav <brijesh.j@ti.com>
+ * Hardik Shah <hardik.shah@ti.com>
+ * Manjunath Hadli <mrh@ti.com>
+ * Sivaraj R <sivaraj@ti.com>
+ * Vaibhav Hiremath <hvaibhav@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/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 CONFIG_VIDEO_ADV_DEBUG
+
+#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)
+
+#endif /* #ifdef CONFIG_VIDEO_ADV_DEBUG */
+
+/* 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;
+
+ dev_err(&client->dev,
+ "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;
+
+ dev_err(&client->dev,
+ "wrote 0x%.2x to offset 0x%.2x error %d\n", val, reg, err);
+ if (retry <= I2C_RETRY_COUNT) {
+ dev_info(&client->dev, "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) {
+ dev_err(&client->dev, "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;
+ break;
+
+ case VIDEO_STD_PAL_BDGHIN_BIT:
+ return STD_PAL_BDGHIN;
+ break;
+
+ default:
+ return STD_INVALID;
+ break;
+ }
+
+ return STD_INVALID;
+}
+
+#ifdef CONFIG_VIDEO_ADV_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 /* #ifdef CONFIG_VIDEO_ADV_DEBUG */
+
+/*
+ * 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, decoder->pdata->reg_list);
+ if (err)
+ return err;
+
+#ifdef CONFIG_VIDEO_ADV_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;
+
+ dev_info(&decoder->client->dev,
+ "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.
+ */
+ dev_err(&decoder->client->dev,
+ "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;
+
+ 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;
+ 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;
+
+ lock_mask =
+ decoder->pdata->input_list[decoder->inputidx].lock_mask;
+ 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;
+
+ 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;
+ decoder->pdata->reg_list[REG_VIDEO_STD].val =
+ decoder->std_list[i].video_std;
+
+ 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));
+
+ 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.
+ */
+static int ioctl_s_input(struct v4l2_int_device *s, int index)
+{
+ struct tvp514x_decoder *decoder = s->priv;
+ u8 input_sel;
+ int err;
+ 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;
+ decoder->pdata->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;
+
+ 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;
+
+ lock_mask =
+ decoder->pdata->input_list[decoder->inputidx].
+ lock_mask;
+ 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;
+
+ 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));
+
+ 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 != decoder->pdata->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;
+
+ 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;
+
+ decoder->pdata->reg_list[control->reg_address].val = 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));
+
+ 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;
+
+ 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;
+
+ 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) {
+ dev_err(&decoder->client->dev, "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) {
+ dev_err(&decoder->client->dev,
+ "Unable to detect decoder\n");
+ return err;
+ }
+ dev_info(&decoder->client->dev,
+ "chip version 0x%.2x detected\n",
+ decoder->ver);
+ }
+ break;
+
+ default:
+ return -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 */
+ decoder->pdata->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) {
+ dev_err(&decoder->client->dev,
+ "Unable to detect decoder\n");
+ return err;
+ }
+
+ dev_info(&decoder->client->dev,
+ "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,
+
+ .inputidx = 0, /* Composite selected */
+};
+
+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) {
+ dev_err(&client->dev, "No platform data\n!!");
+ return -ENODEV;
+ }
+
+ /* 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);
+ dev_err(&client->dev,
+ "Unable to register to v4l2. Err[%d]\n", err);
+
+ } else
+ dev_info(&client->dev, "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[] = {
+ {MODULE_NAME, 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);
+}
+
+late_initcall(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..4433b96
--- /dev/null
+++ b/include/media/tvp514x.h
@@ -0,0 +1,406 @@
+/*
+ * 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)
+
+/*
+ * 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
+};
+
+/**
+ * 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 {
+ u8 input_sel;
+ u8 lock_mask;
+ 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 *);
+
+ struct tvp514x_reg *reg_list;
+
+ int num_inputs;
+ const struct tvp514x_input_info *input_list;
+};
+
+/**
+ * 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@redhat.com?subject=unsubscribe
https://www.redhat.com/mailman/listinfo/video4linux-list
^ permalink raw reply related [flat|nested] 28+ messages in thread
* Re: [PATCH 2/2] TVP514x V4L int device driver support
2008-11-21 15:22 ` [PATCH 2/2] TVP514x V4L int device driver support hvaibhav
@ 2008-11-21 16:16 ` Hans Verkuil
2008-11-21 18:12 ` Trilok Soni
` (2 subsequent siblings)
3 siblings, 0 replies; 28+ messages in thread
From: Hans Verkuil @ 2008-11-21 16:16 UTC (permalink / raw)
To: video4linux-list; +Cc: linux-omap, davinci-linux-open-source-bounces
On Friday 21 November 2008 16:22:03 hvaibhav@ti.com wrote:
> From: Vaibhav Hiremath <hvaibhav@ti.com>
>
> Added new V4L2 slave driver for TVP514x.
>
> The Driver interface has been tested on OMAP3EVM board
> with TI daughter card (TVP5146). Soon the patch for Daughter card
> will be posted on community.
>
> Signed-off-by: Brijesh Jadav <brijesh.j@ti.com>
> Hardik Shah <hardik.shah@ti.com>
> Manjunath Hadli <mrh@ti.com>
> R Sivaraj <sivaraj@ti.com>
> Vaibhav Hiremath <hvaibhav@ti.com>
> Karicheri Muralidharan <m-karicheri2@ti.com>
> ---
> drivers/media/video/Kconfig | 11 +
> drivers/media/video/Makefile | 1 +
> drivers/media/video/tvp514x.c | 1331
> +++++++++++++++++++++++++++++++++++++++++ include/media/tvp514x.h
> | 406 +++++++++++++
> 4 files changed, 1749 insertions(+), 0 deletions(-)
> create mode 100644 drivers/media/video/tvp514x.c
> create mode 100644 include/media/tvp514x.h
>
I'll review this today or tomorrow.
Regards,
Hans
--
video4linux-list mailing list
Unsubscribe mailto:video4linux-list-request@redhat.com?subject=unsubscribe
https://www.redhat.com/mailman/listinfo/video4linux-list
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 2/2] TVP514x V4L int device driver support
2008-11-21 15:22 ` [PATCH 2/2] TVP514x V4L int device driver support hvaibhav
2008-11-21 16:16 ` Hans Verkuil
@ 2008-11-21 18:12 ` Trilok Soni
2008-11-21 19:07 ` Hiremath, Vaibhav
2008-11-21 19:11 ` David Brownell
2008-11-23 22:00 ` Hans Verkuil
2008-11-24 10:06 ` David Brownell
3 siblings, 2 replies; 28+ messages in thread
From: Trilok Soni @ 2008-11-21 18:12 UTC (permalink / raw)
To: hvaibhav; +Cc: video4linux-list, linux-omap, davinci-linux-open-source-bounces
Hi Vaibhav,
On Fri, Nov 21, 2008 at 8:52 PM, <hvaibhav@ti.com> wrote:
> From: Vaibhav Hiremath <hvaibhav@ti.com>
>
> Added new V4L2 slave driver for TVP514x.
>
> The Driver interface has been tested on OMAP3EVM board
> with TI daughter card (TVP5146). Soon the patch for Daughter card will
> be posted on community.
You may want to add some of the TVP5146 video decoder capabilities in
commit text. Useful for someone who just sees this chip for first
time.
>
> Signed-off-by: Brijesh Jadav <brijesh.j@ti.com>
> Hardik Shah <hardik.shah@ti.com>
> Manjunath Hadli <mrh@ti.com>
> R Sivaraj <sivaraj@ti.com>
> Vaibhav Hiremath <hvaibhav@ti.com>
> Karicheri Muralidharan <m-karicheri2@ti.com>
I suggested to change this in another email.
> +
> +#include <linux/i2c.h>
> +#include <linux/delay.h>
> +#include <linux/videodev2.h>
> +#include <media/v4l2-int-device.h>
Convention is is to put empty line between #include <linux/xxx.h> and
first #include <nonlinux/xxx.h> which is #include
<media/v4l2-int-device.h>
> +#include <media/tvp514x.h>
> +
> +
> +/* 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,
> + }
Good to add "," after the last element.
> +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}
"{" after 525 looks weird.
> + },
> + {
You can put "{" with "}" to save one line . Like this
"}, {"
You may want to make similar changes at other places in the patch.
> +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;
> + break;
No need of " break" here.
> +
> + case VIDEO_STD_PAL_BDGHIN_BIT:
> + return STD_PAL_BDGHIN;
> + break;
Ditto.
> +
> + default:
> + return STD_INVALID;
> + break;
Tritto?
> + }
> +
> + return STD_INVALID;
> +}
> +
> +
> +static int
> +tvp514x_probe(struct i2c_client *client, const struct i2c_device_id *id)
> +{
Mark this as __init please.
--
---Trilok Soni
http://triloksoni.wordpress.com
http://www.linkedin.com/in/triloksoni
^ permalink raw reply [flat|nested] 28+ messages in thread
* RE: [PATCH 2/2] TVP514x V4L int device driver support
2008-11-21 18:12 ` Trilok Soni
@ 2008-11-21 19:07 ` Hiremath, Vaibhav
2008-11-21 19:11 ` David Brownell
1 sibling, 0 replies; 28+ messages in thread
From: Hiremath, Vaibhav @ 2008-11-21 19:07 UTC (permalink / raw)
To: Trilok Soni
Cc: video4linux-list@redhat.com, linux-omap@vger.kernel.org,
davinci-linux-open-source-bounces@linux.davincidsp.com
Thanks,
Vaibhav Hiremath
> -----Original Message-----
> From: Trilok Soni [mailto:soni.trilok@gmail.com]
> Sent: Friday, November 21, 2008 11:43 PM
> To: Hiremath, Vaibhav
> Cc: video4linux-list@redhat.com; linux-omap@vger.kernel.org;
> davinci-linux-open-source-bounces@linux.davincidsp.com
> Subject: Re: [PATCH 2/2] TVP514x V4L int device driver support
>
> Hi Vaibhav,
>
> On Fri, Nov 21, 2008 at 8:52 PM, <hvaibhav@ti.com> wrote:
> > From: Vaibhav Hiremath <hvaibhav@ti.com>
> >
> > Added new V4L2 slave driver for TVP514x.
> >
> > The Driver interface has been tested on OMAP3EVM board
> > with TI daughter card (TVP5146). Soon the patch for Daughter card
> will
> > be posted on community.
>
> You may want to add some of the TVP5146 video decoder capabilities
> in
> commit text. Useful for someone who just sees this chip for first
> time.
>
[Hiremath, Vaibhav] Will take care next time.
> >
> > Signed-off-by: Brijesh Jadav <brijesh.j@ti.com>
> > Hardik Shah <hardik.shah@ti.com>
> > Manjunath Hadli <mrh@ti.com>
> > R Sivaraj <sivaraj@ti.com>
> > Vaibhav Hiremath <hvaibhav@ti.com>
> > Karicheri Muralidharan <m-karicheri2@ti.com>
>
> I suggested to change this in another email.
>
[Hiremath, Vaibhav] Point taken.
> > +
> > +#include <linux/i2c.h>
> > +#include <linux/delay.h>
> > +#include <linux/videodev2.h>
> > +#include <media/v4l2-int-device.h>
>
> Convention is is to put empty line between #include <linux/xxx.h>
> and
> first #include <nonlinux/xxx.h> which is #include
> <media/v4l2-int-device.h>
>
[Hiremath, Vaibhav] I had referred to the other driver files under media/video/ (e.g. tvp5150) which doesn't follow this. Not sure about actual convention, but it looks like line break is expected between standard include (linux or non-linux) and local include.
E.g.
include <linux/xxx.h>
include <media/yyy.h>
Include "zzz.h"
> > +#include <media/tvp514x.h>
> > +
>
> > +
> > +/* 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,
> > + }
>
> Good to add "," after the last element.
>
> > +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}
>
> "{" after 525 looks weird.
>
> > + },
> > + {
>
> You can put "{" with "}" to save one line . Like this
>
> "}, {"
>
[Hiremath, Vaibhav] Point taken.
> You may want to make similar changes at other places in the patch.
>
> > +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;
> > + break;
>
> No need of " break" here.
>
[Hiremath, Vaibhav] Point taken.
> > +
> > + case VIDEO_STD_PAL_BDGHIN_BIT:
> > + return STD_PAL_BDGHIN;
> > + break;
>
> Ditto.
>
> > +
> > + default:
> > + return STD_INVALID;
> > + break;
>
> Tritto?
>
> > + }
> > +
> > + return STD_INVALID;
> > +}
> > +
>
> > +
> > +static int
> > +tvp514x_probe(struct i2c_client *client, const struct
> i2c_device_id *id)
> > +{
>
> Mark this as __init please.
>
[Hiremath, Vaibhav] Again valid point. I will update the patch with review comments and post it again. Please let me know if there are any more comments.
> --
> ---Trilok Soni
> http://triloksoni.wordpress.com
> http://www.linkedin.com/in/triloksoni
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 2/2] TVP514x V4L int device driver support
2008-11-21 18:12 ` Trilok Soni
2008-11-21 19:07 ` Hiremath, Vaibhav
@ 2008-11-21 19:11 ` David Brownell
1 sibling, 0 replies; 28+ messages in thread
From: David Brownell @ 2008-11-21 19:11 UTC (permalink / raw)
To: Trilok Soni
Cc: hvaibhav, video4linux-list, linux-omap,
davinci-linux-open-source-bounces
On Friday 21 November 2008, Trilok Soni wrote:
> > +
> > +static int
> > +tvp514x_probe(struct i2c_client *client, const struct i2c_device_id *id)
> > +{
>
> Mark this as __init please.
No, don't. It's for an I2C device ... which means it needs
to stay hotpluggable.
There are *very* few places it's correct to mark probe()
methods as __init, or even __devinit, and this isn't one
of those exceptions.
- Dave
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 2/2] TVP514x V4L int device driver support
2008-11-21 15:22 ` [PATCH 2/2] TVP514x V4L int device driver support hvaibhav
2008-11-21 16:16 ` Hans Verkuil
2008-11-21 18:12 ` Trilok Soni
@ 2008-11-23 22:00 ` Hans Verkuil
2008-11-23 22:04 ` Koen Kooi
2008-11-24 6:16 ` Trilok Soni
2008-11-24 10:06 ` David Brownell
3 siblings, 2 replies; 28+ messages in thread
From: Hans Verkuil @ 2008-11-23 22:00 UTC (permalink / raw)
To: video4linux-list; +Cc: linux-omap, davinci-linux-open-source-bounces
Hi Vaibhav,
Here is my review as promised (although a day late). It's a mix of
smaller and larger issues:
1) CONFIG_VIDEO_ADV_DEBUG is meant to enable the ability to set/get
registers through the VIDIOC_DBG_G/S_REGISTER ioctls. For general
debugging you should use a debug module option (see e.g. saa7115.c).
2) Please use the media/v4l2-i2c-drv.h or media/v4l2-i2c-drv-legacy.h
header to hide some of the i2c complexity (again, see e.g. saa7115.c).
The i2c API tends to change a lot (and some changes are upcoming) so
using this header will mean that i2c driver changes will be minimal in
the future. In addition it will ensure that this driver can be compiled
with older kernels as well once it is part of the v4l-dvb repository.
3) Remember that the use of v4l2-int-device.h must be temporary only. It
will make it impossible to use this driver with any other platform but
omap. I had hoped to release my generic v4l2 subdevice support today
which should replace v4l2-int-device.h in time, but I hit a bug that
needs to be resolved first. I hope to fix it during the next week so
that I can finally make it available for use asap.
4) This is the really big problem I have with this driver: it relies on
the bridge driver to do the initialization of the registers. This is
very much the wrong approach. It would require all bridge drivers that
are going to use this chip to program the chips registers. That's not
the way to do it. The tvp514x driver should do this and the bridge
driver should only pass high-level config data (such as with
input/output pins are being used). Again, see saa7115, cx25840, etc.
This approach means that all the relevant programming is inside the
chip's driver and that bridge drivers can easily replace one chip for
another since except for a little bit of initialization (usually
routing, clock frequencies) there is otherwise no difference between
using one chip or another.
Remember that this is not a driver for use with omap, this is a generic
i2c driver for this chip. omap just happens to be the only bridge
driver using it right now, but that can easily change.
Yes, it makes it harder to write an i2c driver, but experience has shown
us that the advantages regarding reuse far outweigh this initial cost.
Regards,
Hans
On Friday 21 November 2008 16:22:03 hvaibhav@ti.com wrote:
> From: Vaibhav Hiremath <hvaibhav@ti.com>
>
> Added new V4L2 slave driver for TVP514x.
>
> The Driver interface has been tested on OMAP3EVM board
> with TI daughter card (TVP5146). Soon the patch for Daughter card
> will be posted on community.
>
> Signed-off-by: Brijesh Jadav <brijesh.j@ti.com>
> Hardik Shah <hardik.shah@ti.com>
> Manjunath Hadli <mrh@ti.com>
> R Sivaraj <sivaraj@ti.com>
> Vaibhav Hiremath <hvaibhav@ti.com>
> Karicheri Muralidharan <m-karicheri2@ti.com>
> ---
> drivers/media/video/Kconfig | 11 +
> drivers/media/video/Makefile | 1 +
> drivers/media/video/tvp514x.c | 1331
> +++++++++++++++++++++++++++++++++++++++++ include/media/tvp514x.h
> | 406 +++++++++++++
> 4 files changed, 1749 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..377d14e 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 TVP5146/47 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..b68ddf5
> --- /dev/null
> +++ b/drivers/media/video/tvp514x.c
> @@ -0,0 +1,1331 @@
> +/*
> + * drivers/media/video/tvp514x.c
> + *
> + * TI TVP5146/47 decoder driver
> + *
> + * Copyright (C) 2008 Texas Instruments Inc
> + *
> + * Contributors:
> + * Brijesh R Jadav <brijesh.j@ti.com>
> + * Hardik Shah <hardik.shah@ti.com>
> + * Manjunath Hadli <mrh@ti.com>
> + * Sivaraj R <sivaraj@ti.com>
> + * Vaibhav Hiremath <hvaibhav@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/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 CONFIG_VIDEO_ADV_DEBUG
> +
> +#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)
> +
> +#endif /* #ifdef CONFIG_VIDEO_ADV_DEBUG */
> +
> +/* 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;
> +
> + dev_err(&client->dev,
> + "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;
> +
> + dev_err(&client->dev,
> + "wrote 0x%.2x to offset 0x%.2x error %d\n", val, reg, err);
> + if (retry <= I2C_RETRY_COUNT) {
> + dev_info(&client->dev, "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) {
> + dev_err(&client->dev, "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;
> + break;
> +
> + case VIDEO_STD_PAL_BDGHIN_BIT:
> + return STD_PAL_BDGHIN;
> + break;
> +
> + default:
> + return STD_INVALID;
> + break;
> + }
> +
> + return STD_INVALID;
> +}
> +
> +#ifdef CONFIG_VIDEO_ADV_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 /* #ifdef CONFIG_VIDEO_ADV_DEBUG */
> +
> +/*
> + * 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, decoder->pdata->reg_list);
> + if (err)
> + return err;
> +
> +#ifdef CONFIG_VIDEO_ADV_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;
> +
> + dev_info(&decoder->client->dev,
> + "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.
> + */
> + dev_err(&decoder->client->dev,
> + "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;
> +
> + 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;
> + 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;
> +
> + lock_mask =
> + decoder->pdata->input_list[decoder->inputidx].lock_mask;
> + 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;
> +
> + 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;
> + decoder->pdata->reg_list[REG_VIDEO_STD].val =
> + decoder->std_list[i].video_std;
> +
> + 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));
> +
> + 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.
> + */
> +static int ioctl_s_input(struct v4l2_int_device *s, int index)
> +{
> + struct tvp514x_decoder *decoder = s->priv;
> + u8 input_sel;
> + int err;
> + 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;
> + decoder->pdata->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;
> +
> + 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;
> +
> + lock_mask =
> + decoder->pdata->input_list[decoder->inputidx].
> + lock_mask;
> + 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;
> +
> + 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));
> +
> + 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 != decoder->pdata->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;
> +
> + 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;
> +
> + decoder->pdata->reg_list[control->reg_address].val = 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));
> +
> + 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;
> +
> + 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;
> +
> + 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) {
> + dev_err(&decoder->client->dev, "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) {
> + dev_err(&decoder->client->dev,
> + "Unable to detect decoder\n");
> + return err;
> + }
> + dev_info(&decoder->client->dev,
> + "chip version 0x%.2x detected\n",
> + decoder->ver);
> + }
> + break;
> +
> + default:
> + return -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 */
> + decoder->pdata->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) {
> + dev_err(&decoder->client->dev,
> + "Unable to detect decoder\n");
> + return err;
> + }
> +
> + dev_info(&decoder->client->dev,
> + "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,
> +
> + .inputidx = 0, /* Composite selected */
> +};
> +
> +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) {
> + dev_err(&client->dev, "No platform data\n!!");
> + return -ENODEV;
> + }
> +
> + /* 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);
> + dev_err(&client->dev,
> + "Unable to register to v4l2. Err[%d]\n", err);
> +
> + } else
> + dev_info(&client->dev, "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[] = {
> + {MODULE_NAME, 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);
> +}
> +
> +late_initcall(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..4433b96
> --- /dev/null
> +++ b/include/media/tvp514x.h
> @@ -0,0 +1,406 @@
> +/*
> + * 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)
> +
> +/*
> + * 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
> +};
> +
> +/**
> + * 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 {
> + u8 input_sel;
> + u8 lock_mask;
> + 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 *);
> +
> + struct tvp514x_reg *reg_list;
> +
> + int num_inputs;
> + const struct tvp514x_input_info *input_list;
> +};
> +
> +/**
> + * 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@redhat.com?subject=unsubscribe
> https://www.redhat.com/mailman/listinfo/video4linux-list
--
video4linux-list mailing list
Unsubscribe mailto:video4linux-list-request@redhat.com?subject=unsubscribe
https://www.redhat.com/mailman/listinfo/video4linux-list
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 2/2] TVP514x V4L int device driver support
2008-11-23 22:00 ` Hans Verkuil
@ 2008-11-23 22:04 ` Koen Kooi
2008-11-24 6:16 ` Trilok Soni
1 sibling, 0 replies; 28+ messages in thread
From: Koen Kooi @ 2008-11-23 22:04 UTC (permalink / raw)
To: Hans Verkuil
Cc: video4linux-list, hvaibhav, linux-omap,
davinci-linux-open-source-bounces
[-- Attachment #1: Type: text/plain, Size: 535 bytes --]
Op 23 nov 2008, om 23:00 heeft Hans Verkuil het volgende geschreven:
> Remember that this is not a driver for use with omap, this is a
> generic
> i2c driver for this chip. omap just happens to be the only bridge
> driver using it right now, but that can easily change.
>
> Yes, it makes it harder to write an i2c driver, but experience has
> shown
> us that the advantages regarding reuse far outweigh this initial cost.
And google suggests that this chip is is used on dm35x and davinci
platforms as well :)
regards,
Koen
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 186 bytes --]
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 2/2] TVP514x V4L int device driver support
2008-11-23 22:00 ` Hans Verkuil
2008-11-23 22:04 ` Koen Kooi
@ 2008-11-24 6:16 ` Trilok Soni
2008-11-24 6:32 ` David Brownell
2008-11-24 8:04 ` Hans Verkuil
1 sibling, 2 replies; 28+ messages in thread
From: Trilok Soni @ 2008-11-24 6:16 UTC (permalink / raw)
To: Hans Verkuil
Cc: video4linux-list, linux-omap, davinci-linux-open-source-bounces
Hi Hans,
On Mon, Nov 24, 2008 at 3:30 AM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
> Hi Vaibhav,
>
> Here is my review as promised (although a day late). It's a mix of
> smaller and larger issues:
>
> 1) CONFIG_VIDEO_ADV_DEBUG is meant to enable the ability to set/get
> registers through the VIDIOC_DBG_G/S_REGISTER ioctls. For general
> debugging you should use a debug module option (see e.g. saa7115.c).
Local dprintk with log levels is fine, as far as it not misused.
>
> 2) Please use the media/v4l2-i2c-drv.h or media/v4l2-i2c-drv-legacy.h
> header to hide some of the i2c complexity (again, see e.g. saa7115.c).
> The i2c API tends to change a lot (and some changes are upcoming) so
> using this header will mean that i2c driver changes will be minimal in
> the future. In addition it will ensure that this driver can be compiled
> with older kernels as well once it is part of the v4l-dvb repository.
I don't agree with having support to compile with older kernels. Even
though I2C APIs change as lot it is for good, and creating
abstractions doesn't help as saa7xxx is family of chips where I don't
see the case here. Once this driver is mainlined if someone does i2c
subsystem change which breaks this driver from building then he/she
has to make changes to all the code affecting it.
I am not in favour of adding support to compile with older kernels.
>
> 3) Remember that the use of v4l2-int-device.h must be temporary only. It
> will make it impossible to use this driver with any other platform but
> omap. I had hoped to release my generic v4l2 subdevice support today
> which should replace v4l2-int-device.h in time, but I hit a bug that
> needs to be resolved first. I hope to fix it during the next week so
> that I can finally make it available for use asap.
Better step would be to have single camera-sensor framework or merge
with soc-camera framework. Two frameworks doesn't help anyone, but
creates more confusion for new developers.
--
---Trilok Soni
http://triloksoni.wordpress.com
http://www.linkedin.com/in/triloksoni
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 2/2] TVP514x V4L int device driver support
2008-11-24 6:16 ` Trilok Soni
@ 2008-11-24 6:32 ` David Brownell
2008-11-24 7:53 ` Hans Verkuil
2008-11-24 8:04 ` Hans Verkuil
1 sibling, 1 reply; 28+ messages in thread
From: David Brownell @ 2008-11-24 6:32 UTC (permalink / raw)
To: Trilok Soni, Hans Verkuil
Cc: video4linux-list, linux-omap, davinci-linux-open-source-bounces
On Sunday 23 November 2008, Trilok Soni wrote:
> > 2) Please use the media/v4l2-i2c-drv.h or media/v4l2-i2c-drv-legacy.h
> > header to hide some of the i2c complexity (again, see e.g. saa7115.c).
> > The i2c API tends to change a lot (and some changes are upcoming) so
What "changes" do you mean? Since this is not a legacy-style
driver (yay!), the upcoming changes won't affect it at all.
> > using this header will mean that i2c driver changes will be minimal in
> > the future. In addition it will ensure that this driver can be compiled
> > with older kernels as well once it is part of the v4l-dvb repository.
>
> I don't agree with having support to compile with older kernels.
Right. Folk wanting legacy tvp5146 and tvp5140 support could
try to use the legacy drivers from the DaVinci tree.
> Even though I2C APIs change as lot it is for good, and creating
> abstractions doesn't help as saa7xxx is family of chips where I don't
> see the case here. Once this driver is mainlined if someone does i2c
> subsystem change which breaks this driver from building then he/she
> has to make changes to all the code affecting it.
And AFAIK no such change is anticipated. The conversion from
legacy style I2C drivers to "new style" driver-model friendly
drivers is progressing fairly well, so that legacy support can
be completely removed.
> I am not in favour of adding support to compile with older kernels.
My two cents: I'm not in favor either. In fact that's the
general policy for mainline drivers, and I'm surprised to hear
any maintainer suggest it be added.
- Dave
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 2/2] TVP514x V4L int device driver support
2008-11-24 6:32 ` David Brownell
@ 2008-11-24 7:53 ` Hans Verkuil
2008-11-24 8:53 ` Hiremath, Vaibhav
0 siblings, 1 reply; 28+ messages in thread
From: Hans Verkuil @ 2008-11-24 7:53 UTC (permalink / raw)
To: David Brownell
Cc: video4linux-list, linux-omap, davinci-linux-open-source-bounces
On Monday 24 November 2008 07:32:31 David Brownell wrote:
> On Sunday 23 November 2008, Trilok Soni wrote:
> > > 2) Please use the media/v4l2-i2c-drv.h or
> > > media/v4l2-i2c-drv-legacy.h header to hide some of the i2c
> > > complexity (again, see e.g. saa7115.c). The i2c API tends to
> > > change a lot (and some changes are upcoming) so
>
> What "changes" do you mean? Since this is not a legacy-style
> driver (yay!), the upcoming changes won't affect it at all.
Oops, sorry. I thought it was a legacy driver, but it isn't. There are
changes upcoming for legacy drivers, but not for new-style drivers.
> > > using this header will mean that i2c driver changes will be
> > > minimal in the future. In addition it will ensure that this
> > > driver can be compiled with older kernels as well once it is part
> > > of the v4l-dvb repository.
> >
> > I don't agree with having support to compile with older kernels.
>
> Right. Folk wanting legacy tvp5146 and tvp5140 support could
> try to use the legacy drivers from the DaVinci tree.
The v4l-dvb mercurial tree at www.linuxtv.org/hg which is the main
v4l-dvb repository can support kernels >= 2.6.16. Before new stuff is
merged with the git kernel all the compatibility stuff for old kernels
is stripped out, so you don't see it in the actual kernel code. Using
the media/v4l2-i2c-drv.h header makes it much easier to support these
older kernels and it actually reduces the code size as well. Most v4l
i2c drivers are already converted or will be converted soon. It's a v4l
thing.
> > Even though I2C APIs change as lot it is for good, and creating
> > abstractions doesn't help as saa7xxx is family of chips where I
> > don't see the case here. Once this driver is mainlined if someone
> > does i2c subsystem change which breaks this driver from building
> > then he/she has to make changes to all the code affecting it.
>
> And AFAIK no such change is anticipated. The conversion from
> legacy style I2C drivers to "new style" driver-model friendly
> drivers is progressing fairly well, so that legacy support can
> be completely removed.
>
> > I am not in favour of adding support to compile with older kernels.
>
> My two cents: I'm not in favor either. In fact that's the
> general policy for mainline drivers, and I'm surprised to hear
> any maintainer suggest it be added.
Again, it's specific to v4l drivers. You don't have to do it, but it
makes it consistent with the other v4l i2c drivers and when the driver
is in the v4l-dvb repository you get support for older kernels for
free.
Whether it is good or bad that the v4l-dvb repo works this way is a
completely different discussion.
Regards,
Hans
--
video4linux-list mailing list
Unsubscribe mailto:video4linux-list-request@redhat.com?subject=unsubscribe
https://www.redhat.com/mailman/listinfo/video4linux-list
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 2/2] TVP514x V4L int device driver support
2008-11-24 6:16 ` Trilok Soni
2008-11-24 6:32 ` David Brownell
@ 2008-11-24 8:04 ` Hans Verkuil
2008-11-24 8:43 ` Trilok Soni
1 sibling, 1 reply; 28+ messages in thread
From: Hans Verkuil @ 2008-11-24 8:04 UTC (permalink / raw)
To: Trilok Soni
Cc: video4linux-list, linux-omap, davinci-linux-open-source-bounces
On Monday 24 November 2008 07:16:12 Trilok Soni wrote:
> Hi Hans,
>
> On Mon, Nov 24, 2008 at 3:30 AM, Hans Verkuil <hverkuil@xs4all.nl>
wrote:
> > Hi Vaibhav,
> >
> > Here is my review as promised (although a day late). It's a mix of
> > smaller and larger issues:
> >
> > 1) CONFIG_VIDEO_ADV_DEBUG is meant to enable the ability to set/get
> > registers through the VIDIOC_DBG_G/S_REGISTER ioctls. For general
> > debugging you should use a debug module option (see e.g.
> > saa7115.c).
>
> Local dprintk with log levels is fine, as far as it not misused.
>
> > 2) Please use the media/v4l2-i2c-drv.h or
> > media/v4l2-i2c-drv-legacy.h header to hide some of the i2c
> > complexity (again, see e.g. saa7115.c). The i2c API tends to change
> > a lot (and some changes are upcoming) so using this header will
> > mean that i2c driver changes will be minimal in the future. In
> > addition it will ensure that this driver can be compiled with older
> > kernels as well once it is part of the v4l-dvb repository.
>
> I don't agree with having support to compile with older kernels. Even
> though I2C APIs change as lot it is for good, and creating
> abstractions doesn't help as saa7xxx is family of chips where I don't
> see the case here. Once this driver is mainlined if someone does i2c
> subsystem change which breaks this driver from building then he/she
> has to make changes to all the code affecting it.
>
> I am not in favour of adding support to compile with older kernels.
>
> > 3) Remember that the use of v4l2-int-device.h must be temporary
> > only. It will make it impossible to use this driver with any other
> > platform but omap. I had hoped to release my generic v4l2 subdevice
> > support today which should replace v4l2-int-device.h in time, but I
> > hit a bug that needs to be resolved first. I hope to fix it during
> > the next week so that I can finally make it available for use asap.
>
> Better step would be to have single camera-sensor framework or merge
> with soc-camera framework. Two frameworks doesn't help anyone, but
> creates more confusion for new developers.
The v4l2-int-device.h stuff should never have been added. Ditto for
parts of the soc-camera framework that duplicates v4l2-int-device.h. My
new v4l2_subdev support will replace the three methods of using i2c
devices (or similar) that are currently in use. It's exactly to reduce
the confusion that I'm working on this.
It's been discussed before on the v4l mailinglist and the relevant
developers are aware of this. It's almost finished, just need to track
down a single remaining oops.
Regards,
Hans
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 2/2] TVP514x V4L int device driver support
2008-11-24 8:04 ` Hans Verkuil
@ 2008-11-24 8:43 ` Trilok Soni
2008-11-24 8:59 ` Hiremath, Vaibhav
0 siblings, 1 reply; 28+ messages in thread
From: Trilok Soni @ 2008-11-24 8:43 UTC (permalink / raw)
To: Hans Verkuil
Cc: video4linux-list, linux-omap,
davinci-linux-open-source@linux.davincidsp.com
Hi Hans,
>
> The v4l2-int-device.h stuff should never have been added. Ditto for
> parts of the soc-camera framework that duplicates v4l2-int-device.h. My
> new v4l2_subdev support will replace the three methods of using i2c
> devices (or similar) that are currently in use. It's exactly to reduce
> the confusion that I'm working on this.
>
> It's been discussed before on the v4l mailinglist and the relevant
> developers are aware of this. It's almost finished, just need to track
> down a single remaining oops.
Right, I will wait for your updates.
I am planning to send omap24xxcam and ov9640 drivers (now deleted)
available from linux-omap tree after syncing them with latest
linux-2.6.x tree, and the whole driver and the sensor is written using
v4l2-int-device framework. I am going to send it anyway, so that it
can have some review comments.
--
---Trilok Soni
http://triloksoni.wordpress.com
http://www.linkedin.com/in/triloksoni
^ permalink raw reply [flat|nested] 28+ messages in thread
* RE: [PATCH 2/2] TVP514x V4L int device driver support
2008-11-24 7:53 ` Hans Verkuil
@ 2008-11-24 8:53 ` Hiremath, Vaibhav
0 siblings, 0 replies; 28+ messages in thread
From: Hiremath, Vaibhav @ 2008-11-24 8:53 UTC (permalink / raw)
To: Hans Verkuil, David Brownell
Cc: video4linux-list@redhat.com, linux-omap@vger.kernel.org,
davinci-linux-open-source-bounces@linux.davincidsp.com
Thanks,
Vaibhav Hiremath
> -----Original Message-----
> From: video4linux-list-bounces@redhat.com [mailto:video4linux-list-
> bounces@redhat.com] On Behalf Of Hans Verkuil
> Sent: Monday, November 24, 2008 1:24 PM
> To: David Brownell
> Cc: video4linux-list@redhat.com; linux-omap@vger.kernel.org;
> davinci-linux-open-source-bounces@linux.davincidsp.com
> Subject: Re: [PATCH 2/2] TVP514x V4L int device driver support
>
> On Monday 24 November 2008 07:32:31 David Brownell wrote:
> > On Sunday 23 November 2008, Trilok Soni wrote:
> > > > 2) Please use the media/v4l2-i2c-drv.h or
> > > > media/v4l2-i2c-drv-legacy.h header to hide some of the i2c
> > > > complexity (again, see e.g. saa7115.c). The i2c API tends to
> > > > change a lot (and some changes are upcoming) so
> >
> > What "changes" do you mean? Since this is not a legacy-style
> > driver (yay!), the upcoming changes won't affect it at all.
>
> Oops, sorry. I thought it was a legacy driver, but it isn't. There
> are
> changes upcoming for legacy drivers, but not for new-style drivers.
>
> > > > using this header will mean that i2c driver changes will be
> > > > minimal in the future. In addition it will ensure that this
> > > > driver can be compiled with older kernels as well once it is
> part
> > > > of the v4l-dvb repository.
> > >
> > > I don't agree with having support to compile with older kernels.
> >
> > Right. Folk wanting legacy tvp5146 and tvp5140 support could
> > try to use the legacy drivers from the DaVinci tree.
>
> The v4l-dvb mercurial tree at www.linuxtv.org/hg which is the main
> v4l-dvb repository can support kernels >= 2.6.16. Before new stuff
> is
> merged with the git kernel all the compatibility stuff for old
> kernels
> is stripped out, so you don't see it in the actual kernel code.
> Using
> the media/v4l2-i2c-drv.h header makes it much easier to support
> these
> older kernels and it actually reduces the code size as well. Most
> v4l
> i2c drivers are already converted or will be converted soon. It's a
> v4l
> thing.
>
> > > Even though I2C APIs change as lot it is for good, and creating
> > > abstractions doesn't help as saa7xxx is family of chips where I
> > > don't see the case here. Once this driver is mainlined if
> someone
> > > does i2c subsystem change which breaks this driver from building
> > > then he/she has to make changes to all the code affecting it.
> >
> > And AFAIK no such change is anticipated. The conversion from
> > legacy style I2C drivers to "new style" driver-model friendly
> > drivers is progressing fairly well, so that legacy support can
> > be completely removed.
> >
> > > I am not in favour of adding support to compile with older
> kernels.
> >
> > My two cents: I'm not in favor either. In fact that's the
> > general policy for mainline drivers, and I'm surprised to hear
> > any maintainer suggest it be added.
>
> Again, it's specific to v4l drivers. You don't have to do it, but it
> makes it consistent with the other v4l i2c drivers and when the
> driver
> is in the v4l-dvb repository you get support for older kernels for
> free.
>
[Hiremath, Vaibhav] Again only to maintain consistency, supporting legacy wrapper is not good practice (In my opinion). Why can't we have new driver coming with new interface and old drivers still can have legacy wrappers?
> Whether it is good or bad that the v4l-dvb repo works this way is a
> completely different discussion.
>
> Regards,
>
> Hans
>
> --
> video4linux-list mailing list
> Unsubscribe mailto:video4linux-list-
> request@redhat.com?subject=unsubscribe
> https://www.redhat.com/mailman/listinfo/video4linux-list
^ permalink raw reply [flat|nested] 28+ messages in thread
* RE: [PATCH 2/2] TVP514x V4L int device driver support
2008-11-24 8:43 ` Trilok Soni
@ 2008-11-24 8:59 ` Hiremath, Vaibhav
0 siblings, 0 replies; 28+ messages in thread
From: Hiremath, Vaibhav @ 2008-11-24 8:59 UTC (permalink / raw)
To: Trilok Soni, Hans Verkuil
Cc: video4linux-list@redhat.com, linux-omap@vger.kernel.org,
davinci-linux-open-source@linux.davincidsp.com
Hans,
Thanks,
Vaibhav Hiremath
> -----Original Message-----
> From: linux-omap-owner@vger.kernel.org [mailto:linux-omap-
> owner@vger.kernel.org] On Behalf Of Trilok Soni
> Sent: Monday, November 24, 2008 2:13 PM
> To: Hans Verkuil
> Cc: video4linux-list@redhat.com; linux-omap@vger.kernel.org;
> davinci-linux-open-source@linux.davincidsp.com
> Subject: Re: [PATCH 2/2] TVP514x V4L int device driver support
>
> Hi Hans,
>
> >
> > The v4l2-int-device.h stuff should never have been added. Ditto
> for
> > parts of the soc-camera framework that duplicates v4l2-int-
> device.h. My
> > new v4l2_subdev support will replace the three methods of using
> i2c
> > devices (or similar) that are currently in use. It's exactly to
> reduce
> > the confusion that I'm working on this.
> >
> > It's been discussed before on the v4l mailinglist and the relevant
> > developers are aware of this. It's almost finished, just need to
> track
> > down a single remaining oops.
>
> Right, I will wait for your updates.
>
> I am planning to send omap24xxcam and ov9640 drivers (now deleted)
> available from linux-omap tree after syncing them with latest
> linux-2.6.x tree, and the whole driver and the sensor is written
> using
> v4l2-int-device framework. I am going to send it anyway, so that it
> can have some review comments.
>
[Hiremath, Vaibhav] Is your current development accessible through linuxtv.org? Can you share it with us, so that we can have a look into it? Which driver you are migrating to new interface (which I can refer to as a sample)?
Again I would like to know, how are we handling current drivers (soc-camera and v4l2-int)?
> --
> ---Trilok Soni
> http://triloksoni.wordpress.com
> http://www.linkedin.com/in/triloksoni
> --
> To unsubscribe from this list: send the line "unsubscribe linux-
> omap" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 2/2] TVP514x V4L int device driver support
2008-11-21 15:22 ` [PATCH 2/2] TVP514x V4L int device driver support hvaibhav
` (2 preceding siblings ...)
2008-11-23 22:00 ` Hans Verkuil
@ 2008-11-24 10:06 ` David Brownell
3 siblings, 0 replies; 28+ messages in thread
From: David Brownell @ 2008-11-24 10:06 UTC (permalink / raw)
To: hvaibhav
Cc: video4linux-list, linux-omap, davinci-linux-open-source-bounces,
Brijesh Jadav
On Friday 21 November 2008, hvaibhav@ti.com wrote:
> +static const struct i2c_device_id tvp514x_id[] = {
> + {MODULE_NAME, 0},
> + {},
> +};
Don't do that. Instead:
{ "tvp5146", 0 },
{ "tvp5147", 0 },
and so on. Maybe pass a flag there to help determine which
chip reset/init message sequence to use. (Which, hmm, I did
not see in this code, although the data sheets are clear
that the '46 needs 12 writes and the '47 needs 18 ...) Or
tell if the extra '46 registers are available, etc.
> +late_initcall(tvp514x_init);
Why is this "late" instead of normal module_init()?
It's unusual for I2C...
- Dave
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH 2/2] TVP514x Driver with Review comments fixed
@ 2008-11-26 17:05 ` hvaibhav
2008-11-26 17:48 ` Hans Verkuil
0 siblings, 1 reply; 28+ messages in thread
From: hvaibhav @ 2008-11-26 17:05 UTC (permalink / raw)
To: video4linux-list
Cc: linux-omap, davinci-linux-open-source-bounces, Vaibhav Hiremath,
Brijesh Jadav, Hardik Shah, Manjunath Hadli, R Sivaraj,
Karicheri Muralidharan
From: Vaibhav Hiremath <hvaibhav@ti.com>
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.
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@ti.com>
Signed-off-by: Hardik Shah <hardik.shah@ti.com>
Signed-off-by: Manjunath Hadli <mrh@ti.com>
Signed-off-by: R Sivaraj <sivaraj@ti.com>
Signed-off-by: Vaibhav Hiremath <hvaibhav@ti.com>
Signed-off-by: Karicheri Muralidharan <m-karicheri2@ti.com>
---
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@ti.com>
+ * Hardik Shah <hardik.shah@ti.com>
+ * Manjunath Hadli <mrh@ti.com>
+ * Sivaraj R <sivaraj@ti.com>
+ * Vaibhav Hiremath <hvaibhav@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/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
+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)
+
+#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;
+
+ 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.
+ */
+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",
+ 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
@@ -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
^ permalink raw reply related [flat|nested] 28+ messages in thread
* Re: [PATCH 2/2] TVP514x Driver with Review comments fixed
2008-11-26 17:05 ` [PATCH 2/2] TVP514x Driver with Review comments fixed hvaibhav
@ 2008-11-26 17:48 ` Hans Verkuil
0 siblings, 0 replies; 28+ messages in thread
From: Hans Verkuil @ 2008-11-26 17:48 UTC (permalink / raw)
To: video4linux-list
Cc: linux-omap, Karicheri Muralidharan,
davinci-linux-open-source-bounces
Hi Vaibhav,
See below for my comments.
On Wednesday 26 November 2008 18:05:01 hvaibhav@ti.com wrote:
> From: Vaibhav Hiremath <hvaibhav@ti.com>
>
> 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@ti.com>
> Signed-off-by: Hardik Shah <hardik.shah@ti.com>
> Signed-off-by: Manjunath Hadli <mrh@ti.com>
> Signed-off-by: R Sivaraj <sivaraj@ti.com>
> Signed-off-by: Vaibhav Hiremath <hvaibhav@ti.com>
> Signed-off-by: Karicheri Muralidharan <m-karicheri2@ti.com>
> ---
> 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@ti.com>
> + * Hardik Shah <hardik.shah@ti.com>
> + * Manjunath Hadli <mrh@ti.com>
> + * Sivaraj R <sivaraj@ti.com>
> + * Vaibhav Hiremath <hvaibhav@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/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@redhat.com?subject=unsubscribe
> https://www.redhat.com/mailman/listinfo/video4linux-list
--
video4linux-list mailing list
Unsubscribe mailto:video4linux-list-request@redhat.com?subject=unsubscribe
https://www.redhat.com/mailman/listinfo/video4linux-list
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH 2/2] TVP514x Driver with Review comments fixed [V4]
@ 2008-12-02 15:35 ` hvaibhav
2008-12-02 17:20 ` Hans Verkuil
` (2 more replies)
0 siblings, 3 replies; 28+ messages in thread
From: hvaibhav @ 2008-12-02 15:35 UTC (permalink / raw)
To: video4linux-list
Cc: linux-omap, davinci-linux-open-source-bounces, Vaibhav Hiremath,
Brijesh Jadav, Hardik Shah, Manjunath Hadli, R Sivaraj,
Karicheri Muralidharan
From: Vaibhav Hiremath <hvaibhav@ti.com>
I have fixed all the review commentsreceived so far.
Here are the details -
FIXSES:
Make use of i2c_smbus_read/write_byte API:
Probe function now checks for SMBUS capability,
and read/write functions make use of the above API.
Error check for I2C Read/Write:
Added error condition check for both read and write
API.
This has been added for completeness.
input set/get ioctl:
As we do have support for set and get routing ioctl,
instead of adding new ioctl used them.
enum_ioctl:
After discussing with Hans verkuil, came to conclusion
that as of now just remove support for enum_ioctl from
decoder, since this has to handle at master driver level.
TODO LIST:
OMAP Master capture driver:
This should be completely aligned with the current
discussion.
Migration to sub_device framework:
Immediately after all the above task, migrate both
Master and slave driver to sub_device framework.
Signed-off-by: Brijesh Jadav <brijesh.j@ti.com>
Signed-off-by: Hardik Shah <hardik.shah@ti.com>
Signed-off-by: Manjunath Hadli <mrh@ti.com>
Signed-off-by: R Sivaraj <sivaraj@ti.com>
Signed-off-by: Vaibhav Hiremath <hvaibhav@ti.com>
Signed-off-by: Karicheri Muralidharan <m-karicheri2@ti.com>
---
drivers/media/video/Kconfig | 11 +
drivers/media/video/Makefile | 1 +
drivers/media/video/tvp514x.c | 1521 ++++++++++++++++++++++++++++++++++++
drivers/media/video/tvp514x_regs.h | 292 +++++++
include/media/tvp514x.h | 232 ++++++
5 files changed, 2057 insertions(+), 0 deletions(-)
create mode 100755 drivers/media/video/tvp514x.c
create mode 100755 drivers/media/video/tvp514x_regs.h
create mode 100755 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 100755
index 0000000..c0834e4
--- /dev/null
+++ b/drivers/media/video/tvp514x.c
@@ -0,0 +1,1521 @@
+/*
+ * 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/delay.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-int-device.h>
+#include <media/tvp514x.h>
+
+#include "tvp514x_regs.h"
+
+#define MODULE_NAME TVP514X_MODULE_NAME
+
+/* Debug functions */
+static int debug;
+module_param(debug, bool, 0644);
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+#define dump_reg(client, reg, val) \
+ do { \
+ val = tvp514x_read_reg(client, reg); \
+ v4l_info(client, "Reg(0x%.2X): 0x%.2X\n", reg, val); \
+ } while (0)
+
+
+/* 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 -
+ *
+ * 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[] = {
+ /* Standard: STD_NTSC_MJ */
+ [STD_NTSC_MJ] = {
+ .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
+ },
+ /* Standard: STD_PAL_BDGHIN */
+ },
+ [STD_PAL_BDGHIN] = {
+ .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
+ },
+ },
+ /* Standard: need to add for additional standard */
+};
+
+#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.
+ * Returns value read if successful, or non-zero (-1) otherwise.
+ */
+static int tvp514x_read_reg(struct i2c_client *client, u8 reg)
+{
+ int err;
+ int retry = 0;
+read_again:
+
+ err = i2c_smbus_read_byte_data(client, reg);
+ if (err == -1) {
+ if (retry <= I2C_RETRY_COUNT) {
+ v4l_warn(client, "Read: retry ... %d\n", retry);
+ retry++;
+ msleep_interruptible(10);
+ goto read_again;
+ }
+ }
+
+ 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;
+write_again:
+
+ err = i2c_smbus_write_byte_data(client, reg, val);
+ if (err) {
+ if (retry <= I2C_RETRY_COUNT) {
+ v4l_warn(client, "Write: retry ... %d\n", retry);
+ retry++;
+ msleep_interruptible(10);
+ goto write_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) {
+ msleep(next->val);
+ continue;
+ }
+
+ if (next->token == TOK_SKIP)
+ continue;
+
+ err = tvp514x_write_reg(client, next->reg, (u8) next->val);
+ if (err) {
+ v4l_err(client, "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;
+
+ std = tvp514x_read_reg(decoder->client, REG_VIDEO_STD);
+ if ((std & VIDEO_STD_MASK) == VIDEO_STD_AUTO_SWITCH_BIT) {
+ /* use the standard status register */
+ std_status = tvp514x_read_reg(decoder->client,
+ REG_VIDEO_STD_STATUS);
+ } 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;
+}
+
+/*
+ * 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);
+}
+
+/*
+ * 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;
+
+ if (debug)
+ tvp514x_reg_dump(decoder);
+
+ 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;
+
+ chip_id_msb = tvp514x_read_reg(decoder->client, REG_CHIP_ID_MSB);
+ chip_id_lsb = tvp514x_read_reg(decoder->client, REG_CHIP_ID_LSB);
+ rom_ver = tvp514x_read_reg(decoder->client, REG_ROM_VERSION);
+
+ v4l_dbg(1, debug, decoder->client,
+ "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.
+ */
+ v4l_err(decoder->client,
+ "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;
+
+ v4l_info(decoder->client,
+ "\n%s found at 0x%x (%s)\n", decoder->client->name,
+ decoder->client->addr << 1,
+ decoder->client->adapter->name);
+ 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;
+
+ 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;
+ }
+ /* check whether signal is locked */
+ sync_lock_status = tvp514x_read_reg(decoder->client, REG_STATUS1);
+ 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;
+
+ v4l_dbg(1, debug, decoder->client, "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) || (i == STD_INVALID))
+ 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;
+
+ v4l_dbg(1, debug, decoder->client, "Standard set to: %s",
+ decoder->std_list[i].standard.name);
+ return 0;
+}
+
+/**
+ * ioctl_s_routing - 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.
+ */
+static int ioctl_s_routing(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;
+
+ sync_lock_status = tvp514x_read_reg(decoder->client,
+ REG_STATUS1);
+ 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;
+
+ v4l_dbg(1, debug, decoder->client,
+ "Input set to: index - %d (%s)",
+ decoder->pdata->input_list[index].input.index,
+ decoder->pdata->input_list[index].input.name);
+ return 0;
+}
+
+/**
+ * ioctl_g_routing - 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_routing(struct v4l2_int_device *s, int *index)
+{
+ struct tvp514x_decoder *decoder = s->priv;
+ int err = -EINVAL, i, inputidx;
+
+ if (index == NULL)
+ return err;
+
+ /* 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_routing(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));
+
+ v4l_dbg(1, debug, decoder->client,
+ "Query Control: %s : Min - %d, Max - %d, Def - %d",
+ 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 index, 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 */
+
+ value =
+ tvp514x_read_reg(decoder->client, control->reg_address);
+
+ /* cross check */
+ if (value != tvp514x_reg_list[control->reg_address].val)
+ return -EINVAL; /* Driver & TVP5146/47 setting mismatch */
+
+ 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;
+
+ v4l_dbg(1, debug, decoder->client,
+ "Get Cotrol: %s - %d",
+ control->query_ctrl.name, value);
+ return 0;
+}
+
+/**
+ * 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)
+ return err;
+
+ tvp514x_reg_list[control->reg_address].val = value;
+
+ v4l_dbg(1, debug, decoder->client,
+ "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));
+
+ v4l_dbg(1, debug, decoder->client,
+ "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;
+
+ v4l_dbg(1, debug, decoder->client,
+ "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;
+
+ v4l_dbg(1, debug, decoder->client,
+ "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);
+ if (current_std == STD_INVALID)
+ return -EINVAL;
+
+ 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);
+ if (current_std == STD_INVALID)
+ return -EINVAL;
+
+ 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) {
+ v4l_err(decoder->client, "g_ifparm.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);
+ decoder->state = STATE_NOT_DETECTED;
+ 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) &&
+ (decoder->state == STATE_NOT_DETECTED)) {
+ int i;
+ struct tvp514x_init_seq *int_seq =
+ (struct tvp514x_init_seq *)
+ decoder->id->driver_data;
+
+ err = decoder->pdata->power_set(on);
+
+ /* Power Up Sequence */
+ for (i = 0; i < int_seq->no_regs; i++) {
+ err |= tvp514x_write_reg(decoder->client,
+ int_seq->init_reg_seq[i].reg,
+ int_seq->init_reg_seq[i].val);
+ }
+ /* Detect the sensor is not already detected */
+ err |= tvp514x_detect(decoder);
+ if (err) {
+ v4l_err(decoder->client,
+ "Unable to detect decoder\n");
+ return err;
+ }
+ }
+ 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) {
+ v4l_err(decoder->client,
+ "Unable to detect decoder\n");
+ return err;
+ }
+
+ v4l_info(decoder->client,
+ "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_g_video_routing_num,
+ (v4l2_int_ioctl_func *) ioctl_g_routing},
+ {vidioc_int_s_video_routing_num,
+ (v4l2_int_ioctl_func *) ioctl_s_routing},
+};
+
+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;
+
+ /* Check if the adapter supports the needed features */
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -EIO;
+
+ decoder->pdata = client->dev.platform_data;
+ if (!decoder->pdata) {
+ v4l_err(client, "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));
+ /*
+ * Save the id data, required for power up sequence
+ */
+ decoder->id = (struct i2c_device_id *)id;
+ /* 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);
+ v4l_err(client,
+ "Unable to register to v4l2. Err[%d]\n", err);
+
+ } else
+ v4l_info(client, "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;
+}
+/*
+ * TVP5146 Init/Power on Sequence
+ */
+static 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},
+};
+static struct tvp514x_init_seq tvp5146_init = {
+ .no_regs = ARRAY_SIZE(tvp5146_init_reg_seq),
+ .init_reg_seq = tvp5146_init_reg_seq,
+};
+/*
+ * TVP5147 Init/Power on Sequence
+ */
+static 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},
+};
+static struct tvp514x_init_seq tvp5147_init = {
+ .no_regs = ARRAY_SIZE(tvp5147_init_reg_seq),
+ .init_reg_seq = tvp5147_init_reg_seq,
+};
+/*
+ * TVP5146M2/TVP5147M1 Init/Power on Sequence
+ */
+static struct tvp514x_reg tvp514xm_init_reg_seq[] = {
+ {TOK_WRITE, REG_OPERATION_MODE, 0x01},
+ {TOK_WRITE, REG_OPERATION_MODE, 0x00},
+};
+static struct tvp514x_init_seq tvp514xm_init = {
+ .no_regs = ARRAY_SIZE(tvp514xm_init_reg_seq),
+ .init_reg_seq = tvp514xm_init_reg_seq,
+};
+/*
+ * I2C Device Table -
+ *
+ * name - Name of the actual device/chip.
+ * driver_data - Driver data
+ */
+static const struct i2c_device_id tvp514x_id[] = {
+ {"tvp5146", (unsigned int)&tvp5146_init},
+ {"tvp5146m2", (unsigned int)&tvp514xm_init},
+ {"tvp5147", (unsigned int)&tvp5147_init},
+ {"tvp5147m1", (unsigned int)&tvp514xm_init},
+ {},
+};
+
+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/drivers/media/video/tvp514x_regs.h b/drivers/media/video/tvp514x_regs.h
new file mode 100755
index 0000000..003a3c1
--- /dev/null
+++ b/drivers/media/video/tvp514x_regs.h
@@ -0,0 +1,292 @@
+/*
+ * drivers/media/video/tvp514x_regs.h
+ *
+ * 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.
+ *
+ */
+
+#ifndef _TVP514X_REGS_H
+#define _TVP514X_REGS_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)
+
+/**
+ * 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_init_seq - Structure for TVP5146/47/46M2/47M1 power up
+ * Sequence.
+ * @ no_regs - Number of registers to write for power up sequence.
+ * @ init_reg_seq - Array of registers and respective value to write.
+ */
+struct tvp514x_init_seq {
+ unsigned int no_regs;
+ struct tvp514x_reg *init_reg_seq;
+};
+#endif /* ifndef _TVP514X_REGS_H */
diff --git a/include/media/tvp514x.h b/include/media/tvp514x.h
new file mode 100755
index 0000000..2fee5e7
--- /dev/null
+++ b/include/media/tvp514x.h
@@ -0,0 +1,232 @@
+/*
+ * drivers/media/video/tvp514x.h
+ *
+ * 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.
+ *
+ */
+
+#ifndef _TVP514X_H
+#define _TVP514X_H
+
+/*
+ * Other macros
+ */
+#define TVP514X_MODULE_NAME "tvp514x"
+#define TVP514X_I2C_DELAY (3)
+#define I2C_RETRY_COUNT (5)
+#define LOCK_RETRY_COUNT (5)
+#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 - enum for different decoder input pin
+ * configuration.
+ */
+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 - enum for output format
+ * supported.
+ */
+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_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
+ * @id: Entry from I2C table
+ * @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;
+
+ struct i2c_device_id *id;
+
+ 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
^ permalink raw reply related [flat|nested] 28+ messages in thread
* Re: [PATCH 2/2] TVP514x Driver with Review comments fixed [V4]
2008-12-02 15:35 ` [PATCH 2/2] TVP514x Driver with Review comments fixed [V4] hvaibhav
@ 2008-12-02 17:20 ` Hans Verkuil
2008-12-03 3:58 ` Hiremath, Vaibhav
2008-12-02 19:29 ` David Brownell
2008-12-02 19:44 ` David Brownell
2 siblings, 1 reply; 28+ messages in thread
From: Hans Verkuil @ 2008-12-02 17:20 UTC (permalink / raw)
To: video4linux-list
Cc: linux-omap, Karicheri Muralidharan,
davinci-linux-open-source-bounces
Hi Vaibhav,
I'm sorry, but this is still wrong. You basically renamed s_input with
s_routing while still using the list with user inputs from the platform
data.
These three fields in struct tvp514x_platform_data should be removed as
they do not belong here:
> + /* Input params */
> + int num_inputs;
> + const struct tvp514x_input_info *input_list;
> + int default_input;
This is all high-level stuff that does not belong in an i2c driver. It's
the master driver that has to translate the input as specified by the
user to a pin of the tvp514x (like INPUT_CVBS_VI1A).
Also, ioctl_g_routing() can be removed as I have yet to see a master
driver that is interested in obtaining this information. Besides, that
function looks very strange because it is calling ioctl_s_routing. A
get function that sets something?!?
Eventually the whole tvp514x_platform_data will have to be removed.
Everything that's in there should be passed to the i2c driver using
v4l2_subdev ops. But that's something for the future.
I'm available in the #v4l IRC channel tomorrow for further discussions
on this.
BTW1, struct tvp514x_decoder shouldn't be in include/media/tvp514x.h.
It's internal to the driver (at least, I sincerely hope so), so it can
be moved to either the source or the tvp514x_regs.h header.
BTW2, I'm not going to make it a blocking issue, but those callback
functions in tvp514x_platform_data are horrible. The priv_data_set
callback is the clearest example of what's wrong with this design: a
master driver calls ioctl_g_priv in tvp whose only action is to call
priv_data_set in the platform code! The master driver shouldn't have to
go through the i2c driver for that! The only reason a low level v4l i2c
driver would ever make a call to higher level code is for
notifications.
Regards,
Hans
On Tuesday 02 December 2008 16:35:42 hvaibhav@ti.com wrote:
> From: Vaibhav Hiremath <hvaibhav@ti.com>
>
> I have fixed all the review commentsreceived so far.
> Here are the details -
>
> FIXSES:
> Make use of i2c_smbus_read/write_byte API:
> Probe function now checks for SMBUS capability,
> and read/write functions make use of the above API.
>
> Error check for I2C Read/Write:
> Added error condition check for both read and write
> API.
> This has been added for completeness.
>
> input set/get ioctl:
> As we do have support for set and get routing ioctl,
> instead of adding new ioctl used them.
>
> enum_ioctl:
> After discussing with Hans verkuil, came to conclusion
> that as of now just remove support for enum_ioctl from
> decoder, since this has to handle at master driver level.
>
> TODO LIST:
> OMAP Master capture driver:
> This should be completely aligned with the current
> discussion.
>
> Migration to sub_device framework:
> Immediately after all the above task, migrate both
> Master and slave driver to sub_device framework.
>
> Signed-off-by: Brijesh Jadav <brijesh.j@ti.com>
> Signed-off-by: Hardik Shah <hardik.shah@ti.com>
> Signed-off-by: Manjunath Hadli <mrh@ti.com>
> Signed-off-by: R Sivaraj <sivaraj@ti.com>
> Signed-off-by: Vaibhav Hiremath <hvaibhav@ti.com>
> Signed-off-by: Karicheri Muralidharan <m-karicheri2@ti.com>
> ---
> drivers/media/video/Kconfig | 11 +
> drivers/media/video/Makefile | 1 +
> drivers/media/video/tvp514x.c | 1521
> ++++++++++++++++++++++++++++++++++++
> drivers/media/video/tvp514x_regs.h | 292 +++++++
> include/media/tvp514x.h | 232 ++++++
> 5 files changed, 2057 insertions(+), 0 deletions(-)
> create mode 100755 drivers/media/video/tvp514x.c
> create mode 100755 drivers/media/video/tvp514x_regs.h
> create mode 100755 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 100755
> index 0000000..c0834e4
> --- /dev/null
> +++ b/drivers/media/video/tvp514x.c
> @@ -0,0 +1,1521 @@
> +/*
> + * 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/delay.h>
> +#include <linux/videodev2.h>
> +#include <media/v4l2-int-device.h>
> +#include <media/tvp514x.h>
> +
> +#include "tvp514x_regs.h"
> +
> +#define MODULE_NAME TVP514X_MODULE_NAME
> +
> +/* Debug functions */
> +static int debug;
> +module_param(debug, bool, 0644);
> +MODULE_PARM_DESC(debug, "Debug level (0-1)");
> +
> +#define dump_reg(client, reg, val) \
> + do { \
> + val = tvp514x_read_reg(client, reg); \
> + v4l_info(client, "Reg(0x%.2X): 0x%.2X\n", reg, val); \
> + } while (0)
> +
> +
> +/* 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 -
> + *
> + * 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[] = {
> + /* Standard: STD_NTSC_MJ */
> + [STD_NTSC_MJ] = {
> + .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
> + },
> + /* Standard: STD_PAL_BDGHIN */
> + },
> + [STD_PAL_BDGHIN] = {
> + .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
> + },
> + },
> + /* Standard: need to add for additional standard */
> +};
> +
> +#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.
> + * Returns value read if successful, or non-zero (-1) otherwise.
> + */
> +static int tvp514x_read_reg(struct i2c_client *client, u8 reg)
> +{
> + int err;
> + int retry = 0;
> +read_again:
> +
> + err = i2c_smbus_read_byte_data(client, reg);
> + if (err == -1) {
> + if (retry <= I2C_RETRY_COUNT) {
> + v4l_warn(client, "Read: retry ... %d\n", retry);
> + retry++;
> + msleep_interruptible(10);
> + goto read_again;
> + }
> + }
> +
> + 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;
> +write_again:
> +
> + err = i2c_smbus_write_byte_data(client, reg, val);
> + if (err) {
> + if (retry <= I2C_RETRY_COUNT) {
> + v4l_warn(client, "Write: retry ... %d\n", retry);
> + retry++;
> + msleep_interruptible(10);
> + goto write_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) {
> + msleep(next->val);
> + continue;
> + }
> +
> + if (next->token == TOK_SKIP)
> + continue;
> +
> + err = tvp514x_write_reg(client, next->reg, (u8) next->val);
> + if (err) {
> + v4l_err(client, "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;
> +
> + std = tvp514x_read_reg(decoder->client, REG_VIDEO_STD);
> + if ((std & VIDEO_STD_MASK) == VIDEO_STD_AUTO_SWITCH_BIT) {
> + /* use the standard status register */
> + std_status = tvp514x_read_reg(decoder->client,
> + REG_VIDEO_STD_STATUS);
> + } 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;
> +}
> +
> +/*
> + * 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);
> +}
> +
> +/*
> + * 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;
> +
> + if (debug)
> + tvp514x_reg_dump(decoder);
> +
> + 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;
> +
> + chip_id_msb = tvp514x_read_reg(decoder->client, REG_CHIP_ID_MSB);
> + chip_id_lsb = tvp514x_read_reg(decoder->client, REG_CHIP_ID_LSB);
> + rom_ver = tvp514x_read_reg(decoder->client, REG_ROM_VERSION);
> +
> + v4l_dbg(1, debug, decoder->client,
> + "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.
> + */
> + v4l_err(decoder->client,
> + "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;
> +
> + v4l_info(decoder->client,
> + "\n%s found at 0x%x (%s)\n", decoder->client->name,
> + decoder->client->addr << 1,
> + decoder->client->adapter->name);
> + 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;
> +
> + 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;
> + }
> + /* check whether signal is locked */
> + sync_lock_status = tvp514x_read_reg(decoder->client, REG_STATUS1);
> + 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;
> +
> + v4l_dbg(1, debug, decoder->client, "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) || (i == STD_INVALID))
> + 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; +
> + v4l_dbg(1, debug, decoder->client, "Standard set to: %s",
> + decoder->std_list[i].standard.name);
> + return 0;
> +}
> +
> +/**
> + * ioctl_s_routing - 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.
> + */
> +static int ioctl_s_routing(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;
> +
> + sync_lock_status = tvp514x_read_reg(decoder->client,
> + REG_STATUS1);
> + 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;
> +
> + v4l_dbg(1, debug, decoder->client,
> + "Input set to: index - %d (%s)",
> + decoder->pdata->input_list[index].input.index,
> + decoder->pdata->input_list[index].input.name);
> + return 0;
> +}
> +
> +/**
> + * ioctl_g_routing - 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_routing(struct v4l2_int_device *s, int *index)
> +{
> + struct tvp514x_decoder *decoder = s->priv;
> + int err = -EINVAL, i, inputidx;
> +
> + if (index == NULL)
> + return err;
> +
> + /* 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_routing(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));
> +
> + v4l_dbg(1, debug, decoder->client,
> + "Query Control: %s : Min - %d, Max - %d, Def - %d",
> + 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 index, 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 */
> +
> + value =
> + tvp514x_read_reg(decoder->client, control->reg_address);
> +
> + /* cross check */
> + if (value != tvp514x_reg_list[control->reg_address].val)
> + return -EINVAL; /* Driver & TVP5146/47 setting mismatch */
> +
> + 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;
> +
> + v4l_dbg(1, debug, decoder->client,
> + "Get Cotrol: %s - %d",
> + control->query_ctrl.name, value);
> + return 0;
> +}
> +
> +/**
> + * 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)
> + return err;
> +
> + tvp514x_reg_list[control->reg_address].val = value;
> +
> + v4l_dbg(1, debug, decoder->client,
> + "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));
> +
> + v4l_dbg(1, debug, decoder->client,
> + "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;
> +
> + v4l_dbg(1, debug, decoder->client,
> + "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;
> +
> + v4l_dbg(1, debug, decoder->client,
> + "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);
> + if (current_std == STD_INVALID)
> + return -EINVAL;
> +
> + 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);
> + if (current_std == STD_INVALID)
> + return -EINVAL;
> +
> + 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) {
> + v4l_err(decoder->client, "g_ifparm.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);
> + decoder->state = STATE_NOT_DETECTED;
> + 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) &&
> + (decoder->state == STATE_NOT_DETECTED)) {
> + int i;
> + struct tvp514x_init_seq *int_seq =
> + (struct tvp514x_init_seq *)
> + decoder->id->driver_data;
> +
> + err = decoder->pdata->power_set(on);
> +
> + /* Power Up Sequence */
> + for (i = 0; i < int_seq->no_regs; i++) {
> + err |= tvp514x_write_reg(decoder->client,
> + int_seq->init_reg_seq[i].reg,
> + int_seq->init_reg_seq[i].val);
> + }
> + /* Detect the sensor is not already detected */
> + err |= tvp514x_detect(decoder);
> + if (err) {
> + v4l_err(decoder->client,
> + "Unable to detect decoder\n");
> + return err;
> + }
> + }
> + 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) {
> + v4l_err(decoder->client,
> + "Unable to detect decoder\n");
> + return err;
> + }
> +
> + v4l_info(decoder->client,
> + "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_g_video_routing_num,
> + (v4l2_int_ioctl_func *) ioctl_g_routing},
> + {vidioc_int_s_video_routing_num,
> + (v4l2_int_ioctl_func *) ioctl_s_routing},
> +};
> +
> +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;
> +
> + /* Check if the adapter supports the needed features */
> + if (!i2c_check_functionality(client->adapter,
> I2C_FUNC_SMBUS_BYTE_DATA)) + return -EIO;
> +
> + decoder->pdata = client->dev.platform_data;
> + if (!decoder->pdata) {
> + v4l_err(client, "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));
> + /*
> + * Save the id data, required for power up sequence
> + */
> + decoder->id = (struct i2c_device_id *)id;
> + /* 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);
> + v4l_err(client,
> + "Unable to register to v4l2. Err[%d]\n", err);
> +
> + } else
> + v4l_info(client, "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;
> +}
> +/*
> + * TVP5146 Init/Power on Sequence
> + */
> +static 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},
> +};
> +static struct tvp514x_init_seq tvp5146_init = {
> + .no_regs = ARRAY_SIZE(tvp5146_init_reg_seq),
> + .init_reg_seq = tvp5146_init_reg_seq,
> +};
> +/*
> + * TVP5147 Init/Power on Sequence
> + */
> +static 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},
> +};
> +static struct tvp514x_init_seq tvp5147_init = {
> + .no_regs = ARRAY_SIZE(tvp5147_init_reg_seq),
> + .init_reg_seq = tvp5147_init_reg_seq,
> +};
> +/*
> + * TVP5146M2/TVP5147M1 Init/Power on Sequence
> + */
> +static struct tvp514x_reg tvp514xm_init_reg_seq[] = {
> + {TOK_WRITE, REG_OPERATION_MODE, 0x01},
> + {TOK_WRITE, REG_OPERATION_MODE, 0x00},
> +};
> +static struct tvp514x_init_seq tvp514xm_init = {
> + .no_regs = ARRAY_SIZE(tvp514xm_init_reg_seq),
> + .init_reg_seq = tvp514xm_init_reg_seq,
> +};
> +/*
> + * I2C Device Table -
> + *
> + * name - Name of the actual device/chip.
> + * driver_data - Driver data
> + */
> +static const struct i2c_device_id tvp514x_id[] = {
> + {"tvp5146", (unsigned int)&tvp5146_init},
> + {"tvp5146m2", (unsigned int)&tvp514xm_init},
> + {"tvp5147", (unsigned int)&tvp5147_init},
> + {"tvp5147m1", (unsigned int)&tvp514xm_init},
> + {},
> +};
> +
> +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/drivers/media/video/tvp514x_regs.h
> b/drivers/media/video/tvp514x_regs.h new file mode 100755
> index 0000000..003a3c1
> --- /dev/null
> +++ b/drivers/media/video/tvp514x_regs.h
> @@ -0,0 +1,292 @@
> +/*
> + * drivers/media/video/tvp514x_regs.h
> + *
> + * 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.
> + *
> + */
> +
> +#ifndef _TVP514X_REGS_H
> +#define _TVP514X_REGS_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)
> +
> +/**
> + * 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_init_seq - Structure for TVP5146/47/46M2/47M1
> power up + * Sequence.
> + * @ no_regs - Number of registers to write for power up sequence.
> + * @ init_reg_seq - Array of registers and respective value to
> write. + */
> +struct tvp514x_init_seq {
> + unsigned int no_regs;
> + struct tvp514x_reg *init_reg_seq;
> +};
> +#endif /* ifndef _TVP514X_REGS_H */
> diff --git a/include/media/tvp514x.h b/include/media/tvp514x.h
> new file mode 100755
> index 0000000..2fee5e7
> --- /dev/null
> +++ b/include/media/tvp514x.h
> @@ -0,0 +1,232 @@
> +/*
> + * drivers/media/video/tvp514x.h
> + *
> + * 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.
> + *
> + */
> +
> +#ifndef _TVP514X_H
> +#define _TVP514X_H
> +
> +/*
> + * Other macros
> + */
> +#define TVP514X_MODULE_NAME "tvp514x"
> +#define TVP514X_I2C_DELAY (3)
> +#define I2C_RETRY_COUNT (5)
> +#define LOCK_RETRY_COUNT (5)
> +#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 - enum for different decoder input pin
> + * configuration.
> + */
> +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 - enum for output format
> + * supported.
> + */
> +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_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
> + * @id: Entry from I2C table
> + * @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;
> +
> + struct i2c_device_id *id;
> +
> + 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@redhat.com?subject=unsubscribe
> https://www.redhat.com/mailman/listinfo/video4linux-list
--
Hans Verkuil - video4linux developer - sponsored by TANDBERG
--
video4linux-list mailing list
Unsubscribe mailto:video4linux-list-request@redhat.com?subject=unsubscribe
https://www.redhat.com/mailman/listinfo/video4linux-list
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 2/2] TVP514x Driver with Review comments fixed [V4]
2008-12-02 15:35 ` [PATCH 2/2] TVP514x Driver with Review comments fixed [V4] hvaibhav
2008-12-02 17:20 ` Hans Verkuil
@ 2008-12-02 19:29 ` David Brownell
2008-12-02 19:44 ` David Brownell
2 siblings, 0 replies; 28+ messages in thread
From: David Brownell @ 2008-12-02 19:29 UTC (permalink / raw)
To: hvaibhav
Cc: video4linux-list, linux-omap, davinci-linux-open-source-bounces,
Brijesh Jadav, Hardik Shah, Manjunath Hadli, R Sivaraj,
Karicheri Muralidharan
On Tuesday 02 December 2008, hvaibhav@ti.com wrote:
> +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;
> +}
Just do the normal
return i2c_add_driver(...);
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 2/2] TVP514x Driver with Review comments fixed [V4]
2008-12-02 15:35 ` [PATCH 2/2] TVP514x Driver with Review comments fixed [V4] hvaibhav
2008-12-02 17:20 ` Hans Verkuil
2008-12-02 19:29 ` David Brownell
@ 2008-12-02 19:44 ` David Brownell
2 siblings, 0 replies; 28+ messages in thread
From: David Brownell @ 2008-12-02 19:44 UTC (permalink / raw)
To: hvaibhav
Cc: video4linux-list, linux-omap, davinci-linux-open-source-bounces,
Brijesh Jadav, Hardik Shah, Manjunath Hadli, R Sivaraj,
Karicheri Muralidharan
Yep, nice to see an I2C driver that actually tries to cope
with errors when reading/writing registers. :)
I expect that I'll have some more comments later.
On Tuesday 02 December 2008, hvaibhav@ti.com wrote:
> +void tvp514x_reg_dump(struct tvp514x_decoder *decoder)
"static void" ... there probably shouldn't be any symbols
exported from this driver, except the ones handling module
init (which are in a section that's removed ASAP).
> +/*
> + * TVP5146 Init/Power on Sequence
> + */
> +static 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},
> + ...
> +};
> +static struct tvp514x_init_seq tvp5146_init = {
> + .no_regs = ARRAY_SIZE(tvp5146_init_reg_seq),
> + .init_reg_seq = tvp5146_init_reg_seq,
> +};
I suggest making all of those be "static const", along
with their friends :)
> + {"tvp5146", (unsigned int)&tvp5146_init},
As I noted earlier, best if this were "unsigned long".
I'm surprised you're only using the driver_data to hold
a pointer to a tvp514x_init_seq structure. That would
be the natural place to store other chip-specific
data ... like whatever is needed to ensure that this
driver never tries to access a '46-specific register
on a '47 chip.
- Dave
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 28+ messages in thread
* RE: [PATCH 2/2] TVP514x Driver with Review comments fixed [V4]
2008-12-02 17:20 ` Hans Verkuil
@ 2008-12-03 3:58 ` Hiremath, Vaibhav
0 siblings, 0 replies; 28+ messages in thread
From: Hiremath, Vaibhav @ 2008-12-03 3:58 UTC (permalink / raw)
To: Hans Verkuil, video4linux-list@redhat.com
Cc: davinci-linux-open-source-bounces@linux.davincidsp.com,
Karicheri, Muralidharan, linux-omap@vger.kernel.org
Thanks,
Vaibhav Hiremath
> -----Original Message-----
> From: Hans Verkuil [mailto:hverkuil@xs4all.nl]
> Sent: Tuesday, December 02, 2008 10:50 PM
> To: video4linux-list@redhat.com
> Cc: Hiremath, Vaibhav; davinci-linux-open-source-
> bounces@linux.davincidsp.com; Karicheri, Muralidharan; linux-
> omap@vger.kernel.org
> Subject: Re: [PATCH 2/2] TVP514x Driver with Review comments fixed
> [V4]
>
> Hi Vaibhav,
>
> I'm sorry, but this is still wrong. You basically renamed s_input
> with
> s_routing while still using the list with user inputs from the
> platform
> data.
>
> These three fields in struct tvp514x_platform_data should be removed
> as
> they do not belong here:
>
> > + /* Input params */
> > + int num_inputs;
> > + const struct tvp514x_input_info *input_list;
> > + int default_input;
>
> This is all high-level stuff that does not belong in an i2c driver.
> It's
> the master driver that has to translate the input as specified by
> the
> user to a pin of the tvp514x (like INPUT_CVBS_VI1A).
>
> Also, ioctl_g_routing() can be removed as I have yet to see a master
> driver that is interested in obtaining this information. Besides,
> that
> function looks very strange because it is calling ioctl_s_routing. A
> get function that sets something?!?
>
> Eventually the whole tvp514x_platform_data will have to be removed.
> Everything that's in there should be passed to the i2c driver using
> v4l2_subdev ops. But that's something for the future.
>
[Hiremath, Vaibhav] Definitely, as you mentioned eventually the platform data dependency from TVP driver will be removed. But I will have to start with master driver to do it, since now platform data will go to master driver which will maintain list or table at his level.
I think yesterday on chat I had mentioned clearly that, simultaneously I will have to start with master driver which will automatically address your all comments, like -
- g_routing: Since this will get handled at master level no need to support at slave or TVP level.
- s_routing: The input params will change to v4l2_routing, and argument will come directly from master. Master will now include "tvp514x.h" file to pass appropriate routing data.
- tvp514x_platform_data: Again, the data related to input will go to master.
Since it would take good amount of change and time, I thought to get reviewed first and while submitting master driver anyway I will have to change.
I believe once master driver becomes slave aware (including tvp514x.h); all issues automatically will get addressed.
Probably I missed to mention all these points in the patch, which lead to confusion.
Hope this clears.
> I'm available in the #v4l IRC channel tomorrow for further
> discussions
> on this.
>
> BTW1, struct tvp514x_decoder shouldn't be in
> include/media/tvp514x.h.
> It's internal to the driver (at least, I sincerely hope so), so it
> can
> be moved to either the source or the tvp514x_regs.h header.
>
> BTW2, I'm not going to make it a blocking issue, but those callback
> functions in tvp514x_platform_data are horrible. The priv_data_set
> callback is the clearest example of what's wrong with this design: a
> master driver calls ioctl_g_priv in tvp whose only action is to call
> priv_data_set in the platform code! The master driver shouldn't have
> to
> go through the i2c driver for that! The only reason a low level v4l
> i2c
> driver would ever make a call to higher level code is for
> notifications.
>
> Regards,
>
> Hans
>
> On Tuesday 02 December 2008 16:35:42 hvaibhav@ti.com wrote:
> > From: Vaibhav Hiremath <hvaibhav@ti.com>
> >
> > I have fixed all the review commentsreceived so far.
> > Here are the details -
> >
> > FIXSES:
> > Make use of i2c_smbus_read/write_byte API:
> > Probe function now checks for SMBUS capability,
> > and read/write functions make use of the above API.
> >
> > Error check for I2C Read/Write:
> > Added error condition check for both read and write
> > API.
> > This has been added for completeness.
> >
> > input set/get ioctl:
> > As we do have support for set and get routing ioctl,
> > instead of adding new ioctl used them.
> >
> > enum_ioctl:
> > After discussing with Hans verkuil, came to conclusion
> > that as of now just remove support for enum_ioctl from
> > decoder, since this has to handle at master driver level.
> >
> > TODO LIST:
> > OMAP Master capture driver:
> > This should be completely aligned with the current
> > discussion.
> >
> > Migration to sub_device framework:
> > Immediately after all the above task, migrate both
> > Master and slave driver to sub_device framework.
> >
> > Signed-off-by: Brijesh Jadav <brijesh.j@ti.com>
> > Signed-off-by: Hardik Shah <hardik.shah@ti.com>
> > Signed-off-by: Manjunath Hadli <mrh@ti.com>
> > Signed-off-by: R Sivaraj <sivaraj@ti.com>
> > Signed-off-by: Vaibhav Hiremath <hvaibhav@ti.com>
> > Signed-off-by: Karicheri Muralidharan <m-karicheri2@ti.com>
> > ---
> > drivers/media/video/Kconfig | 11 +
> > drivers/media/video/Makefile | 1 +
> > drivers/media/video/tvp514x.c | 1521
> > ++++++++++++++++++++++++++++++++++++
> > drivers/media/video/tvp514x_regs.h | 292 +++++++
> > include/media/tvp514x.h | 232 ++++++
> > 5 files changed, 2057 insertions(+), 0 deletions(-)
> > create mode 100755 drivers/media/video/tvp514x.c
> > create mode 100755 drivers/media/video/tvp514x_regs.h
> > create mode 100755 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 100755
> > index 0000000..c0834e4
> > --- /dev/null
> > +++ b/drivers/media/video/tvp514x.c
> > @@ -0,0 +1,1521 @@
> > +/*
> > + * 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/delay.h>
> > +#include <linux/videodev2.h>
> > +#include <media/v4l2-int-device.h>
> > +#include <media/tvp514x.h>
> > +
> > +#include "tvp514x_regs.h"
> > +
> > +#define MODULE_NAME TVP514X_MODULE_NAME
> > +
> > +/* Debug functions */
> > +static int debug;
> > +module_param(debug, bool, 0644);
> > +MODULE_PARM_DESC(debug, "Debug level (0-1)");
> > +
> > +#define dump_reg(client, reg, val) \
> > + do { \
> > + val = tvp514x_read_reg(client, reg); \
> > + v4l_info(client, "Reg(0x%.2X): 0x%.2X\n", reg, val); \
> > + } while (0)
> > +
> > +
> > +/* 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 -
> > + *
> > + * 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[] = {
> > + /* Standard: STD_NTSC_MJ */
> > + [STD_NTSC_MJ] = {
> > + .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
> > + },
> > + /* Standard: STD_PAL_BDGHIN */
> > + },
> > + [STD_PAL_BDGHIN] = {
> > + .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
> > + },
> > + },
> > + /* Standard: need to add for additional standard */
> > +};
> > +
> > +#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.
> > + * Returns value read if successful, or non-zero (-1) otherwise.
> > + */
> > +static int tvp514x_read_reg(struct i2c_client *client, u8 reg)
> > +{
> > + int err;
> > + int retry = 0;
> > +read_again:
> > +
> > + err = i2c_smbus_read_byte_data(client, reg);
> > + if (err == -1) {
> > + if (retry <= I2C_RETRY_COUNT) {
> > + v4l_warn(client, "Read: retry ... %d\n", retry);
> > + retry++;
> > + msleep_interruptible(10);
> > + goto read_again;
> > + }
> > + }
> > +
> > + 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;
> > +write_again:
> > +
> > + err = i2c_smbus_write_byte_data(client, reg, val);
> > + if (err) {
> > + if (retry <= I2C_RETRY_COUNT) {
> > + v4l_warn(client, "Write: retry ... %d\n", retry);
> > + retry++;
> > + msleep_interruptible(10);
> > + goto write_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) {
> > + msleep(next->val);
> > + continue;
> > + }
> > +
> > + if (next->token == TOK_SKIP)
> > + continue;
> > +
> > + err = tvp514x_write_reg(client, next->reg, (u8) next-
> >val);
> > + if (err) {
> > + v4l_err(client, "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;
> > +
> > + std = tvp514x_read_reg(decoder->client, REG_VIDEO_STD);
> > + if ((std & VIDEO_STD_MASK) == VIDEO_STD_AUTO_SWITCH_BIT) {
> > + /* use the standard status register */
> > + std_status = tvp514x_read_reg(decoder->client,
> > + REG_VIDEO_STD_STATUS);
> > + } 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;
> > +}
> > +
> > +/*
> > + * 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);
> > +}
> > +
> > +/*
> > + * 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;
> > +
> > + if (debug)
> > + tvp514x_reg_dump(decoder);
> > +
> > + 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;
> > +
> > + chip_id_msb = tvp514x_read_reg(decoder->client,
> REG_CHIP_ID_MSB);
> > + chip_id_lsb = tvp514x_read_reg(decoder->client,
> REG_CHIP_ID_LSB);
> > + rom_ver = tvp514x_read_reg(decoder->client, REG_ROM_VERSION);
> > +
> > + v4l_dbg(1, debug, decoder->client,
> > + "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.
> > + */
> > + v4l_err(decoder->client,
> > + "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;
> > +
> > + v4l_info(decoder->client,
> > + "\n%s found at 0x%x (%s)\n", decoder->client-
> >name,
> > + decoder->client->addr << 1,
> > + decoder->client->adapter->name);
> > + 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;
> > +
> > + 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;
> > + }
> > + /* check whether signal is locked */
> > + sync_lock_status = tvp514x_read_reg(decoder->client,
> REG_STATUS1);
> > + 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;
> > +
> > + v4l_dbg(1, debug, decoder->client, "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) || (i == STD_INVALID))
> > + 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; +
> > + v4l_dbg(1, debug, decoder->client, "Standard set to: %s",
> > + decoder->std_list[i].standard.name);
> > + return 0;
> > +}
> > +
> > +/**
> > + * ioctl_s_routing - 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.
> > + */
> > +static int ioctl_s_routing(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;
> > +
> > + sync_lock_status = tvp514x_read_reg(decoder->client,
> > + REG_STATUS1);
> > + 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;
> > +
> > + v4l_dbg(1, debug, decoder->client,
> > + "Input set to: index - %d (%s)",
> > + decoder->pdata->input_list[index].input.index,
> > + decoder->pdata->input_list[index].input.name);
> > + return 0;
> > +}
> > +
> > +/**
> > + * ioctl_g_routing - 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_routing(struct v4l2_int_device *s, int *index)
> > +{
> > + struct tvp514x_decoder *decoder = s->priv;
> > + int err = -EINVAL, i, inputidx;
> > +
> > + if (index == NULL)
> > + return err;
> > +
> > + /* 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_routing(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));
> > +
> > + v4l_dbg(1, debug, decoder->client,
> > + "Query Control: %s : Min - %d, Max - %d, Def -
> %d",
> > + 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 index, 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 */
> > +
> > + value =
> > + tvp514x_read_reg(decoder->client, control->reg_address);
> > +
> > + /* cross check */
> > + if (value != tvp514x_reg_list[control->reg_address].val)
> > + return -EINVAL; /* Driver & TVP5146/47 setting
> mismatch */
> > +
> > + 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;
> > +
> > + v4l_dbg(1, debug, decoder->client,
> > + "Get Cotrol: %s - %d",
> > + control->query_ctrl.name, value);
> > + return 0;
> > +}
> > +
> > +/**
> > + * 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)
> > + return err;
> > +
> > + tvp514x_reg_list[control->reg_address].val = value;
> > +
> > + v4l_dbg(1, debug, decoder->client,
> > + "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));
> > +
> > + v4l_dbg(1, debug, decoder->client,
> > + "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;
> > +
> > + v4l_dbg(1, debug, decoder->client,
> > + "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;
> > +
> > + v4l_dbg(1, debug, decoder->client,
> > + "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);
> > + if (current_std == STD_INVALID)
> > + return -EINVAL;
> > +
> > + 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);
> > + if (current_std == STD_INVALID)
> > + return -EINVAL;
> > +
> > + 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) {
> > + v4l_err(decoder->client, "g_ifparm.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);
> > + decoder->state = STATE_NOT_DETECTED;
> > + 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) &&
> > + (decoder->state == STATE_NOT_DETECTED)) {
> > + int i;
> > + struct tvp514x_init_seq *int_seq =
> > + (struct tvp514x_init_seq *)
> > + decoder->id->driver_data;
> > +
> > + err = decoder->pdata->power_set(on);
> > +
> > + /* Power Up Sequence */
> > + for (i = 0; i < int_seq->no_regs; i++) {
> > + err |= tvp514x_write_reg(decoder->client,
> > + int_seq->init_reg_seq[i].reg,
> > + int_seq->init_reg_seq[i].val);
> > + }
> > + /* Detect the sensor is not already detected */
> > + err |= tvp514x_detect(decoder);
> > + if (err) {
> > + v4l_err(decoder->client,
> > + "Unable to detect decoder\n");
> > + return err;
> > + }
> > + }
> > + 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) {
> > + v4l_err(decoder->client,
> > + "Unable to detect decoder\n");
> > + return err;
> > + }
> > +
> > + v4l_info(decoder->client,
> > + "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_g_video_routing_num,
> > + (v4l2_int_ioctl_func *) ioctl_g_routing},
> > + {vidioc_int_s_video_routing_num,
> > + (v4l2_int_ioctl_func *) ioctl_s_routing},
> > +};
> > +
> > +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;
> > +
> > + /* Check if the adapter supports the needed features */
> > + if (!i2c_check_functionality(client->adapter,
> > I2C_FUNC_SMBUS_BYTE_DATA)) + return -EIO;
> > +
> > + decoder->pdata = client->dev.platform_data;
> > + if (!decoder->pdata) {
> > + v4l_err(client, "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));
> > + /*
> > + * Save the id data, required for power up sequence
> > + */
> > + decoder->id = (struct i2c_device_id *)id;
> > + /* 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);
> > + v4l_err(client,
> > + "Unable to register to v4l2. Err[%d]\n", err);
> > +
> > + } else
> > + v4l_info(client, "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;
> > +}
> > +/*
> > + * TVP5146 Init/Power on Sequence
> > + */
> > +static 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},
> > +};
> > +static struct tvp514x_init_seq tvp5146_init = {
> > + .no_regs = ARRAY_SIZE(tvp5146_init_reg_seq),
> > + .init_reg_seq = tvp5146_init_reg_seq,
> > +};
> > +/*
> > + * TVP5147 Init/Power on Sequence
> > + */
> > +static 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},
> > +};
> > +static struct tvp514x_init_seq tvp5147_init = {
> > + .no_regs = ARRAY_SIZE(tvp5147_init_reg_seq),
> > + .init_reg_seq = tvp5147_init_reg_seq,
> > +};
> > +/*
> > + * TVP5146M2/TVP5147M1 Init/Power on Sequence
> > + */
> > +static struct tvp514x_reg tvp514xm_init_reg_seq[] = {
> > + {TOK_WRITE, REG_OPERATION_MODE, 0x01},
> > + {TOK_WRITE, REG_OPERATION_MODE, 0x00},
> > +};
> > +static struct tvp514x_init_seq tvp514xm_init = {
> > + .no_regs = ARRAY_SIZE(tvp514xm_init_reg_seq),
> > + .init_reg_seq = tvp514xm_init_reg_seq,
> > +};
> > +/*
> > + * I2C Device Table -
> > + *
> > + * name - Name of the actual device/chip.
> > + * driver_data - Driver data
> > + */
> > +static const struct i2c_device_id tvp514x_id[] = {
> > + {"tvp5146", (unsigned int)&tvp5146_init},
> > + {"tvp5146m2", (unsigned int)&tvp514xm_init},
> > + {"tvp5147", (unsigned int)&tvp5147_init},
> > + {"tvp5147m1", (unsigned int)&tvp514xm_init},
> > + {},
> > +};
> > +
> > +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/drivers/media/video/tvp514x_regs.h
> > b/drivers/media/video/tvp514x_regs.h new file mode 100755
> > index 0000000..003a3c1
> > --- /dev/null
> > +++ b/drivers/media/video/tvp514x_regs.h
> > @@ -0,0 +1,292 @@
> > +/*
> > + * drivers/media/video/tvp514x_regs.h
> > + *
> > + * 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.
> > + *
> > + */
> > +
> > +#ifndef _TVP514X_REGS_H
> > +#define _TVP514X_REGS_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)
> > +
> > +/**
> > + * 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_init_seq - Structure for TVP5146/47/46M2/47M1
> > power up + * Sequence.
> > + * @ no_regs - Number of registers to write for power up
> sequence.
> > + * @ init_reg_seq - Array of registers and respective value to
> > write. + */
> > +struct tvp514x_init_seq {
> > + unsigned int no_regs;
> > + struct tvp514x_reg *init_reg_seq;
> > +};
> > +#endif /* ifndef _TVP514X_REGS_H */
> > diff --git a/include/media/tvp514x.h b/include/media/tvp514x.h
> > new file mode 100755
> > index 0000000..2fee5e7
> > --- /dev/null
> > +++ b/include/media/tvp514x.h
> > @@ -0,0 +1,232 @@
> > +/*
> > + * drivers/media/video/tvp514x.h
> > + *
> > + * 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.
> > + *
> > + */
> > +
> > +#ifndef _TVP514X_H
> > +#define _TVP514X_H
> > +
> > +/*
> > + * Other macros
> > + */
> > +#define TVP514X_MODULE_NAME "tvp514x"
> > +#define TVP514X_I2C_DELAY (3)
> > +#define I2C_RETRY_COUNT (5)
> > +#define LOCK_RETRY_COUNT (5)
> > +#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 - enum for different decoder input pin
> > + * configuration.
> > + */
> > +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 - enum for output format
> > + * supported.
> > + */
> > +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_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
> > + * @id: Entry from I2C table
> > + * @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;
> > +
> > + struct i2c_device_id *id;
> > +
> > + 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@redhat.com?subject=unsubscribe
> > https://www.redhat.com/mailman/listinfo/video4linux-list
>
>
>
> --
> Hans Verkuil - video4linux developer - sponsored by TANDBERG
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH (V2)] TVP514x: Migration to sub-device framework
@ 2009-05-06 18:31 ` hvaibhav
2009-06-14 10:14 ` Hans Verkuil
0 siblings, 1 reply; 28+ messages in thread
From: hvaibhav @ 2009-05-06 18:31 UTC (permalink / raw)
To: linux-media
Cc: linux-omap, davinci-linux-open-source, Vaibhav Hiremath,
Brijesh Jadav, Hardik Shah
From: Vaibhav Hiremath <hvaibhav@ti.com>
This patch converts TVP514x driver to sub-device framework
from V4L2-int framework.
NOTE: Please note that this patch has not been tested on any board,
only compilation/build tested.
Changes (From Previous post):
- Added static function to_decoder which will replace all
container_of instances.
- "unsigned int" replaced with "u32".
- Cleaned up for line indentation.
- pdata initialized, was missing in earlier patch.
TODO:
- Add support for some basic video/core functionality like,
.g_chip_ident
.reset
.g_input_status
- Migration master driver to validate this driver.
- validate on Davinci and OMAP boards.
Reviewed By "Hans Verkuil".
Signed-off-by: Brijesh Jadav <brijesh.j@ti.com>
Signed-off-by: Hardik Shah <hardik.shah@ti.com>
Signed-off-by: Vaibhav Hiremath <hvaibhav@ti.com>
---
drivers/media/video/tvp514x.c | 854 ++++++++++++++----------------------
drivers/media/video/tvp514x_regs.h | 10 -
include/media/tvp514x.h | 4 -
3 files changed, 330 insertions(+), 538 deletions(-)
diff --git a/drivers/media/video/tvp514x.c b/drivers/media/video/tvp514x.c
index 4262e60..12b49ad 100644
--- a/drivers/media/video/tvp514x.c
+++ b/drivers/media/video/tvp514x.c
@@ -31,7 +31,11 @@
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/videodev2.h>
-#include <media/v4l2-int-device.h>
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-i2c-drv.h>
#include <media/tvp514x.h>
#include "tvp514x_regs.h"
@@ -49,13 +53,13 @@ static int debug;
module_param(debug, bool, 0644);
MODULE_PARM_DESC(debug, "Debug level (0-1)");
-#define dump_reg(client, reg, val) \
+#define dump_reg(sd, reg, val) \
do { \
- val = tvp514x_read_reg(client, reg); \
- v4l_info(client, "Reg(0x%.2X): 0x%.2X\n", reg, val); \
+ val = tvp514x_read_reg(sd, reg); \
+ v4l2_info(sd, "Reg(0x%.2X): 0x%.2X\n", reg, val); \
} while (0)
-/**
+/*
* enum tvp514x_std - enum for supported standards
*/
enum tvp514x_std {
@@ -64,15 +68,7 @@ enum tvp514x_std {
STD_INVALID
};
-/**
- * enum tvp514x_state - enum for different decoder states
- */
-enum tvp514x_state {
- STATE_NOT_DETECTED,
- STATE_DETECTED
-};
-
-/**
+/*
* struct tvp514x_std_info - Structure to store standard informations
* @width: Line width in pixels
* @height:Number of active lines
@@ -87,35 +83,29 @@ struct tvp514x_std_info {
};
static struct tvp514x_reg tvp514x_reg_list_default[0x40];
-/**
+/*
* struct tvp514x_decoder - TVP5146/47 decoder object
- * @v4l2_int_device: Slave handle
- * @tvp514x_slave: Slave pointer which is used by @v4l2_int_device
+ * @sd: Subdevice Slave handle
* @tvp514x_regs: copy of hw's regs with preset values.
* @pdata: Board specific
- * @client: I2C client data
- * @id: Entry from I2C table
* @ver: Chip version
- * @state: TVP5146/47 decoder state - detected or not-detected
+ * @state: TVP5146/47 decoder state - enabled or disabled.
* @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
- * @route: input and output routing at chip level
+ * @input: Input routing at chip level
+ * @output: Output routing at chip level
*/
struct tvp514x_decoder {
- struct v4l2_int_device v4l2_int_device;
- struct v4l2_int_slave tvp514x_slave;
+ struct v4l2_subdev sd;
struct tvp514x_reg tvp514x_regs[ARRAY_SIZE(tvp514x_reg_list_default)];
const struct tvp514x_platform_data *pdata;
- struct i2c_client *client;
-
- struct i2c_device_id *id;
int ver;
- enum tvp514x_state state;
+ int state;
struct v4l2_pix_format pix;
int num_fmts;
@@ -124,8 +114,11 @@ struct tvp514x_decoder {
enum tvp514x_std current_std;
int num_stds;
struct tvp514x_std_info *std_list;
-
- struct v4l2_routing route;
+ /*
+ * Input and Output Routing parameters
+ */
+ u32 input;
+ u32 output;
};
/* TVP514x default register values */
@@ -191,7 +184,8 @@ static struct tvp514x_reg tvp514x_reg_list_default[] = {
{TOK_TERM, 0, 0},
};
-/* List of image formats supported by TVP5146/47 decoder
+/*
+ * 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.
*/
@@ -240,35 +234,27 @@ static struct tvp514x_std_info tvp514x_std_list[] = {
},
/* Standard: need to add for additional standard */
};
-/*
- * Control structure for Auto Gain
- * This is temporary data, will get replaced once
- * v4l2_ctrl_query_fill supports it.
- */
-static const struct v4l2_queryctrl tvp514x_autogain_ctrl = {
- .id = V4L2_CID_AUTOGAIN,
- .name = "Gain, Automatic",
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 1,
-};
+
+static inline struct tvp514x_decoder *to_decoder(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct tvp514x_decoder, sd);
+}
/*
* Read a value from a register in an TVP5146/47 decoder device.
* Returns value read if successful, or non-zero (-1) otherwise.
*/
-static int tvp514x_read_reg(struct i2c_client *client, u8 reg)
+static int tvp514x_read_reg(struct v4l2_subdev *sd, u8 reg)
{
- int err;
- int retry = 0;
+ int err, retry = 0;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
read_again:
err = i2c_smbus_read_byte_data(client, reg);
if (err == -1) {
if (retry <= I2C_RETRY_COUNT) {
- v4l_warn(client, "Read: retry ... %d\n", retry);
+ v4l2_warn(sd, "Read: retry ... %d\n", retry);
retry++;
msleep_interruptible(10);
goto read_again;
@@ -282,16 +268,17 @@ read_again:
* 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)
+static int tvp514x_write_reg(struct v4l2_subdev *sd, u8 reg, u8 val)
{
- int err;
- int retry = 0;
+ int err, retry = 0;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
write_again:
err = i2c_smbus_write_byte_data(client, reg, val);
if (err) {
if (retry <= I2C_RETRY_COUNT) {
- v4l_warn(client, "Write: retry ... %d\n", retry);
+ v4l2_warn(sd, "Write: retry ... %d\n", retry);
retry++;
msleep_interruptible(10);
goto write_again;
@@ -311,7 +298,7 @@ write_again:
* reglist - list of registers to be written
* Returns zero if successful, or non-zero otherwise.
*/
-static int tvp514x_write_regs(struct i2c_client *client,
+static int tvp514x_write_regs(struct v4l2_subdev *sd,
const struct tvp514x_reg reglist[])
{
int err;
@@ -326,9 +313,9 @@ static int tvp514x_write_regs(struct i2c_client *client,
if (next->token == TOK_SKIP)
continue;
- err = tvp514x_write_reg(client, next->reg, (u8) next->val);
+ err = tvp514x_write_reg(sd, next->reg, (u8) next->val);
if (err) {
- v4l_err(client, "Write failed. Err[%d]\n", err);
+ v4l2_err(sd, "Write failed. Err[%d]\n", err);
return err;
}
}
@@ -339,17 +326,15 @@ static int tvp514x_write_regs(struct i2c_client *client,
* tvp514x_get_current_std:
* Returns the current standard detected by TVP5146/47
*/
-static enum tvp514x_std tvp514x_get_current_std(struct tvp514x_decoder
- *decoder)
+static enum tvp514x_std tvp514x_get_current_std(struct v4l2_subdev *sd)
{
u8 std, std_status;
- std = tvp514x_read_reg(decoder->client, REG_VIDEO_STD);
- if ((std & VIDEO_STD_MASK) == VIDEO_STD_AUTO_SWITCH_BIT) {
+ 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(decoder->client,
- REG_VIDEO_STD_STATUS);
- } else
+ std_status = tvp514x_read_reg(sd, REG_VIDEO_STD_STATUS);
+ else
std_status = std; /* use the standard register itself */
switch (std_status & VIDEO_STD_MASK) {
@@ -369,70 +354,71 @@ static enum tvp514x_std tvp514x_get_current_std(struct tvp514x_decoder
/*
* TVP5146/47 register dump function
*/
-static void tvp514x_reg_dump(struct tvp514x_decoder *decoder)
+static void tvp514x_reg_dump(struct v4l2_subdev *sd)
{
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);
+ dump_reg(sd, REG_INPUT_SEL, value);
+ dump_reg(sd, REG_AFE_GAIN_CTRL, value);
+ dump_reg(sd, REG_VIDEO_STD, value);
+ dump_reg(sd, REG_OPERATION_MODE, value);
+ dump_reg(sd, REG_COLOR_KILLER, value);
+ dump_reg(sd, REG_LUMA_CONTROL1, value);
+ dump_reg(sd, REG_LUMA_CONTROL2, value);
+ dump_reg(sd, REG_LUMA_CONTROL3, value);
+ dump_reg(sd, REG_BRIGHTNESS, value);
+ dump_reg(sd, REG_CONTRAST, value);
+ dump_reg(sd, REG_SATURATION, value);
+ dump_reg(sd, REG_HUE, value);
+ dump_reg(sd, REG_CHROMA_CONTROL1, value);
+ dump_reg(sd, REG_CHROMA_CONTROL2, value);
+ dump_reg(sd, REG_COMP_PR_SATURATION, value);
+ dump_reg(sd, REG_COMP_Y_CONTRAST, value);
+ dump_reg(sd, REG_COMP_PB_SATURATION, value);
+ dump_reg(sd, REG_COMP_Y_BRIGHTNESS, value);
+ dump_reg(sd, REG_AVID_START_PIXEL_LSB, value);
+ dump_reg(sd, REG_AVID_START_PIXEL_MSB, value);
+ dump_reg(sd, REG_AVID_STOP_PIXEL_LSB, value);
+ dump_reg(sd, REG_AVID_STOP_PIXEL_MSB, value);
+ dump_reg(sd, REG_HSYNC_START_PIXEL_LSB, value);
+ dump_reg(sd, REG_HSYNC_START_PIXEL_MSB, value);
+ dump_reg(sd, REG_HSYNC_STOP_PIXEL_LSB, value);
+ dump_reg(sd, REG_HSYNC_STOP_PIXEL_MSB, value);
+ dump_reg(sd, REG_VSYNC_START_LINE_LSB, value);
+ dump_reg(sd, REG_VSYNC_START_LINE_MSB, value);
+ dump_reg(sd, REG_VSYNC_STOP_LINE_LSB, value);
+ dump_reg(sd, REG_VSYNC_STOP_LINE_MSB, value);
+ dump_reg(sd, REG_VBLK_START_LINE_LSB, value);
+ dump_reg(sd, REG_VBLK_START_LINE_MSB, value);
+ dump_reg(sd, REG_VBLK_STOP_LINE_LSB, value);
+ dump_reg(sd, REG_VBLK_STOP_LINE_MSB, value);
+ dump_reg(sd, REG_SYNC_CONTROL, value);
+ dump_reg(sd, REG_OUTPUT_FORMATTER1, value);
+ dump_reg(sd, REG_OUTPUT_FORMATTER2, value);
+ dump_reg(sd, REG_OUTPUT_FORMATTER3, value);
+ dump_reg(sd, REG_OUTPUT_FORMATTER4, value);
+ dump_reg(sd, REG_OUTPUT_FORMATTER5, value);
+ dump_reg(sd, REG_OUTPUT_FORMATTER6, value);
+ dump_reg(sd, REG_CLEAR_LOST_LOCK, value);
}
/*
* 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)
+static int tvp514x_configure(struct v4l2_subdev *sd,
+ struct tvp514x_decoder *decoder)
{
int err;
/* common register initialization */
err =
- tvp514x_write_regs(decoder->client, decoder->tvp514x_regs);
+ tvp514x_write_regs(sd, decoder->tvp514x_regs);
if (err)
return err;
if (debug)
- tvp514x_reg_dump(decoder);
+ tvp514x_reg_dump(sd);
return 0;
}
@@ -445,15 +431,17 @@ static int tvp514x_configure(struct tvp514x_decoder *decoder)
* Returns ENODEV error number if no device is detected, or zero
* if a device is detected.
*/
-static int tvp514x_detect(struct tvp514x_decoder *decoder)
+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(decoder->client, REG_CHIP_ID_MSB);
- chip_id_lsb = tvp514x_read_reg(decoder->client, REG_CHIP_ID_LSB);
- rom_ver = tvp514x_read_reg(decoder->client, REG_ROM_VERSION);
+ 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);
- v4l_dbg(1, debug, decoder->client,
+ 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)
@@ -462,19 +450,16 @@ static int tvp514x_detect(struct tvp514x_decoder *decoder)
/* We didn't read the values we expected, so this must not be
* an TVP5146/47.
*/
- v4l_err(decoder->client,
- "chip id mismatch msb:0x%x lsb:0x%x\n",
- chip_id_msb, chip_id_lsb);
+ 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;
- decoder->state = STATE_DETECTED;
- v4l_info(decoder->client,
- "%s found at 0x%x (%s)\n", decoder->client->name,
- decoder->client->addr << 1,
- decoder->client->adapter->name);
+ 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;
}
@@ -483,17 +468,17 @@ static int tvp514x_detect(struct tvp514x_decoder *decoder)
* TVP5146/47 decoder driver.
*/
-/**
- * ioctl_querystd - V4L2 decoder interface handler for VIDIOC_QUERYSTD ioctl
- * @s: pointer to standard V4L2 device structure
+/*
+ * tvp514x_querystd - V4L2 decoder interface handler for VIDIOC_QUERYSTD ioctl
+ * @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, returns -EINVAL
*/
-static int ioctl_querystd(struct v4l2_int_device *s, v4l2_std_id *std_id)
+static int tvp514x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std_id)
{
- struct tvp514x_decoder *decoder = s->priv;
+ struct tvp514x_decoder *decoder = to_decoder(sd);
enum tvp514x_std current_std;
enum tvp514x_input input_sel;
u8 sync_lock_status, lock_mask;
@@ -502,11 +487,11 @@ static int ioctl_querystd(struct v4l2_int_device *s, v4l2_std_id *std_id)
return -EINVAL;
/* get the current standard */
- current_std = tvp514x_get_current_std(decoder);
+ current_std = tvp514x_get_current_std(sd);
if (current_std == STD_INVALID)
return -EINVAL;
- input_sel = decoder->route.input;
+ input_sel = decoder->input;
switch (input_sel) {
case INPUT_CVBS_VI1A:
@@ -544,42 +529,39 @@ static int ioctl_querystd(struct v4l2_int_device *s, v4l2_std_id *std_id)
return -EINVAL;
}
/* check whether signal is locked */
- sync_lock_status = tvp514x_read_reg(decoder->client, REG_STATUS1);
+ sync_lock_status = tvp514x_read_reg(sd, REG_STATUS1);
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;
- v4l_dbg(1, debug, decoder->client, "Current STD: %s",
+ v4l2_dbg(1, debug, sd, "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
+/*
+ * tvp514x_s_std - V4L2 decoder interface handler for VIDIOC_S_STD ioctl
+ * @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 ioctl_s_std(struct v4l2_int_device *s, v4l2_std_id *std_id)
+static int tvp514x_s_std(struct v4l2_subdev *sd, v4l2_std_id std_id)
{
- struct tvp514x_decoder *decoder = s->priv;
+ struct tvp514x_decoder *decoder = to_decoder(sd);
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)
+ if (std_id & decoder->std_list[i].standard.id)
break;
if ((i == decoder->num_stds) || (i == STD_INVALID))
return -EINVAL;
- err = tvp514x_write_reg(decoder->client, REG_VIDEO_STD,
+ err = tvp514x_write_reg(sd, REG_VIDEO_STD,
decoder->std_list[i].video_std);
if (err)
return err;
@@ -588,24 +570,24 @@ static int ioctl_s_std(struct v4l2_int_device *s, v4l2_std_id *std_id)
decoder->tvp514x_regs[REG_VIDEO_STD].val =
decoder->std_list[i].video_std;
- v4l_dbg(1, debug, decoder->client, "Standard set to: %s",
+ v4l2_dbg(1, debug, sd, "Standard set to: %s",
decoder->std_list[i].standard.name);
return 0;
}
-/**
- * ioctl_s_routing - V4L2 decoder interface handler for VIDIOC_S_INPUT ioctl
- * @s: pointer to standard V4L2 device structure
+/*
+ * tvp514x_s_routing - V4L2 decoder interface handler for VIDIOC_S_INPUT ioctl
+ * @sd: pointer to standard V4L2 sub-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.
*/
-static int ioctl_s_routing(struct v4l2_int_device *s,
- struct v4l2_routing *route)
+static int tvp514x_s_routing(struct v4l2_subdev *sd,
+ u32 input, u32 output, u32 config)
{
- struct tvp514x_decoder *decoder = s->priv;
+ struct tvp514x_decoder *decoder = to_decoder(sd);
int err;
enum tvp514x_input input_sel;
enum tvp514x_output output_sel;
@@ -613,20 +595,20 @@ static int ioctl_s_routing(struct v4l2_int_device *s,
u8 sync_lock_status, lock_mask;
int try_count = LOCK_RETRY_COUNT;
- if ((!route) || (route->input >= INPUT_INVALID) ||
- (route->output >= OUTPUT_INVALID))
+ if ((input >= INPUT_INVALID) ||
+ (output >= OUTPUT_INVALID))
return -EINVAL; /* Index out of bound */
- input_sel = route->input;
- output_sel = route->output;
+ input_sel = input;
+ output_sel = output;
- err = tvp514x_write_reg(decoder->client, REG_INPUT_SEL, input_sel);
+ err = tvp514x_write_reg(sd, REG_INPUT_SEL, input_sel);
if (err)
return err;
- output_sel |= tvp514x_read_reg(decoder->client,
+ output_sel |= tvp514x_read_reg(sd,
REG_OUTPUT_FORMATTER1) & 0x7;
- err = tvp514x_write_reg(decoder->client, REG_OUTPUT_FORMATTER1,
+ err = tvp514x_write_reg(sd, REG_OUTPUT_FORMATTER1,
output_sel);
if (err)
return err;
@@ -637,7 +619,7 @@ static int ioctl_s_routing(struct v4l2_int_device *s,
/* Clear status */
msleep(LOCK_RETRY_DELAY);
err =
- tvp514x_write_reg(decoder->client, REG_CLEAR_LOST_LOCK, 0x01);
+ tvp514x_write_reg(sd, REG_CLEAR_LOST_LOCK, 0x01);
if (err)
return err;
@@ -682,11 +664,11 @@ static int ioctl_s_routing(struct v4l2_int_device *s,
msleep(LOCK_RETRY_DELAY);
/* get the current standard for future reference */
- current_std = tvp514x_get_current_std(decoder);
+ current_std = tvp514x_get_current_std(sd);
if (current_std == STD_INVALID)
continue;
- sync_lock_status = tvp514x_read_reg(decoder->client,
+ sync_lock_status = tvp514x_read_reg(sd,
REG_STATUS1);
if (lock_mask == (sync_lock_status & lock_mask))
break; /* Input detected */
@@ -696,28 +678,26 @@ static int ioctl_s_routing(struct v4l2_int_device *s,
return -EINVAL;
decoder->current_std = current_std;
- decoder->route.input = route->input;
- decoder->route.output = route->output;
+ decoder->input = input;
+ decoder->output = output;
- v4l_dbg(1, debug, decoder->client,
- "Input set to: %d, std : %d",
+ v4l2_dbg(1, debug, sd, "Input set to: %d, std : %d",
input_sel, current_std);
return 0;
}
-/**
- * ioctl_queryctrl - V4L2 decoder interface handler for VIDIOC_QUERYCTRL ioctl
- * @s: pointer to standard V4L2 device structure
+/*
+ * tvp514x_queryctrl - V4L2 decoder interface handler for VIDIOC_QUERYCTRL ioctl
+ * @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
-ioctl_queryctrl(struct v4l2_int_device *s, struct v4l2_queryctrl *qctrl)
+tvp514x_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qctrl)
{
- struct tvp514x_decoder *decoder = s->priv;
int err = -EINVAL;
if (qctrl == NULL)
@@ -744,30 +724,27 @@ ioctl_queryctrl(struct v4l2_int_device *s, struct v4l2_queryctrl *qctrl)
err = v4l2_ctrl_query_fill(qctrl, -180, 180, 180, 0);
break;
case V4L2_CID_AUTOGAIN:
- /* Autogain is either 0 or 1*/
- memcpy(qctrl, &tvp514x_autogain_ctrl,
- sizeof(struct v4l2_queryctrl));
- err = 0;
+ /*
+ * Auto Gain supported is -
+ * 0 - 1 (Default - 1)
+ */
+ err = v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 1);
break;
default:
- v4l_err(decoder->client,
- "invalid control id %d\n", qctrl->id);
+ v4l2_err(sd, "invalid control id %d\n", qctrl->id);
return err;
}
- v4l_dbg(1, debug, decoder->client,
- "Query Control: %s : Min - %d, Max - %d, Def - %d",
- qctrl->name,
- qctrl->minimum,
- qctrl->maximum,
+ v4l2_dbg(1, debug, sd, "Query Control:%s: Min - %d, Max - %d, Def - %d",
+ qctrl->name, qctrl->minimum, qctrl->maximum,
qctrl->default_value);
return err;
}
-/**
- * ioctl_g_ctrl - V4L2 decoder interface handler for VIDIOC_G_CTRL ioctl
- * @s: pointer to standard V4L2 device structure
+/*
+ * tvp514x_g_ctrl - V4L2 decoder interface handler for VIDIOC_G_CTRL ioctl
+ * @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
@@ -775,9 +752,9 @@ ioctl_queryctrl(struct v4l2_int_device *s, struct v4l2_queryctrl *qctrl)
* supported.
*/
static int
-ioctl_g_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl)
+tvp514x_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct tvp514x_decoder *decoder = s->priv;
+ struct tvp514x_decoder *decoder = to_decoder(sd);
if (ctrl == NULL)
return -EINVAL;
@@ -811,74 +788,70 @@ ioctl_g_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl)
break;
default:
- v4l_err(decoder->client,
- "invalid control id %d\n", ctrl->id);
+ v4l2_err(sd, "invalid control id %d\n", ctrl->id);
return -EINVAL;
}
- v4l_dbg(1, debug, decoder->client,
- "Get Control: ID - %d - %d",
+ v4l2_dbg(1, debug, sd, "Get Control: ID - %d - %d",
ctrl->id, ctrl->value);
return 0;
}
-/**
- * ioctl_s_ctrl - V4L2 decoder interface handler for VIDIOC_S_CTRL ioctl
- * @s: pointer to standard V4L2 device structure
+/*
+ * tvp514x_s_ctrl - V4L2 decoder interface handler for VIDIOC_S_CTRL ioctl
+ * @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
-ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl)
+tvp514x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct tvp514x_decoder *decoder = s->priv;
+ struct tvp514x_decoder *decoder = to_decoder(sd);
int err = -EINVAL, value;
if (ctrl == NULL)
return err;
- value = (__s32) ctrl->value;
+ value = ctrl->value;
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
if (ctrl->value < 0 || ctrl->value > 255) {
- v4l_err(decoder->client,
- "invalid brightness setting %d\n",
+ v4l2_err(sd, "invalid brightness setting %d\n",
ctrl->value);
return -ERANGE;
}
- err = tvp514x_write_reg(decoder->client, REG_BRIGHTNESS,
+ 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) {
- v4l_err(decoder->client,
- "invalid contrast setting %d\n",
+ v4l2_err(sd, "invalid contrast setting %d\n",
ctrl->value);
return -ERANGE;
}
- err = tvp514x_write_reg(decoder->client, REG_CONTRAST,
- value);
+ 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) {
- v4l_err(decoder->client,
- "invalid saturation setting %d\n",
+ v4l2_err(sd, "invalid saturation setting %d\n",
ctrl->value);
return -ERANGE;
}
- err = tvp514x_write_reg(decoder->client, REG_SATURATION,
- value);
+ err = tvp514x_write_reg(sd, REG_SATURATION, value);
if (err)
return err;
+
decoder->tvp514x_regs[REG_SATURATION].val = value;
break;
case V4L2_CID_HUE:
@@ -889,15 +862,13 @@ ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl)
else if (value == 0)
value = 0;
else {
- v4l_err(decoder->client,
- "invalid hue setting %d\n",
- ctrl->value);
+ v4l2_err(sd, "invalid hue setting %d\n", ctrl->value);
return -ERANGE;
}
- err = tvp514x_write_reg(decoder->client, REG_HUE,
- value);
+ err = tvp514x_write_reg(sd, REG_HUE, value);
if (err)
return err;
+
decoder->tvp514x_regs[REG_HUE].val = value;
break;
case V4L2_CID_AUTOGAIN:
@@ -906,41 +877,38 @@ ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl)
else if (value == 0)
value = 0x0C;
else {
- v4l_err(decoder->client,
- "invalid auto gain setting %d\n",
+ v4l2_err(sd, "invalid auto gain setting %d\n",
ctrl->value);
return -ERANGE;
}
- err = tvp514x_write_reg(decoder->client, REG_AFE_GAIN_CTRL,
- value);
+ 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:
- v4l_err(decoder->client,
- "invalid control id %d\n", ctrl->id);
+ v4l2_err(sd, "invalid control id %d\n", ctrl->id);
return err;
}
- v4l_dbg(1, debug, decoder->client,
- "Set Control: ID - %d - %d",
+ v4l2_dbg(1, debug, sd, "Set Control: ID - %d - %d",
ctrl->id, ctrl->value);
return err;
}
-/**
- * ioctl_enum_fmt_cap - Implement the CAPTURE buffer VIDIOC_ENUM_FMT ioctl
- * @s: pointer to standard V4L2 device structure
+/*
+ * tvp514x_enum_fmt_cap - Implement the CAPTURE buffer VIDIOC_ENUM_FMT ioctl
+ * @sd: pointer to standard V4L2 sub-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)
+tvp514x_enum_fmt_cap(struct v4l2_subdev *sd, struct v4l2_fmtdesc *fmt)
{
- struct tvp514x_decoder *decoder = s->priv;
+ struct tvp514x_decoder *decoder = to_decoder(sd);
int index;
if (fmt == NULL)
@@ -956,16 +924,15 @@ ioctl_enum_fmt_cap(struct v4l2_int_device *s, struct v4l2_fmtdesc *fmt)
memcpy(fmt, &decoder->fmt_list[index],
sizeof(struct v4l2_fmtdesc));
- v4l_dbg(1, debug, decoder->client,
- "Current FMT: index - %d (%s)",
+ v4l2_dbg(1, debug, sd, "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
+/*
+ * tvp514x_try_fmt_cap - Implement the CAPTURE buffer VIDIOC_TRY_FMT ioctl
+ * @sd: pointer to standard V4L2 sub-device structure
* @f: pointer to standard V4L2 VIDIOC_TRY_FMT ioctl structure
*
* Implement the VIDIOC_TRY_FMT ioctl for the CAPTURE buffer type. This
@@ -973,9 +940,9 @@ ioctl_enum_fmt_cap(struct v4l2_int_device *s, struct v4l2_fmtdesc *fmt)
* without actually making it take effect.
*/
static int
-ioctl_try_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)
+tvp514x_try_fmt_cap(struct v4l2_subdev *sd, struct v4l2_format *f)
{
- struct tvp514x_decoder *decoder = s->priv;
+ struct tvp514x_decoder *decoder = to_decoder(sd);
int ifmt;
struct v4l2_pix_format *pix;
enum tvp514x_std current_std;
@@ -989,7 +956,7 @@ ioctl_try_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)
pix = &f->fmt.pix;
/* Calculate height and width based on current standard */
- current_std = tvp514x_get_current_std(decoder);
+ current_std = tvp514x_get_current_std(sd);
if (current_std == STD_INVALID)
return -EINVAL;
@@ -1012,17 +979,16 @@ ioctl_try_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)
pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
pix->priv = 0;
- v4l_dbg(1, debug, decoder->client,
- "Try FMT: pixelformat - %s, bytesperline - %d"
+ v4l2_dbg(1, debug, sd, "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
+/*
+ * tvp514x_s_fmt_cap - V4L2 decoder interface handler for VIDIOC_S_FMT ioctl
+ * @sd: pointer to standard V4L2 sub-device structure
* @f: pointer to standard V4L2 VIDIOC_S_FMT ioctl structure
*
* If the requested format is supported, configures the HW to use that
@@ -1030,9 +996,9 @@ ioctl_try_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)
* correctly configured.
*/
static int
-ioctl_s_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)
+tvp514x_s_fmt_cap(struct v4l2_subdev *sd, struct v4l2_format *f)
{
- struct tvp514x_decoder *decoder = s->priv;
+ struct tvp514x_decoder *decoder = to_decoder(sd);
struct v4l2_pix_format *pix;
int rval;
@@ -1043,7 +1009,7 @@ ioctl_s_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)
return -EINVAL; /* only capture is supported */
pix = &f->fmt.pix;
- rval = ioctl_try_fmt_cap(s, f);
+ rval = tvp514x_try_fmt_cap(sd, f);
if (rval)
return rval;
@@ -1052,18 +1018,18 @@ ioctl_s_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)
return rval;
}
-/**
- * ioctl_g_fmt_cap - V4L2 decoder interface handler for ioctl_g_fmt_cap
- * @s: pointer to standard V4L2 device structure
+/*
+ * tvp514x_g_fmt_cap - V4L2 decoder interface handler for tvp514x_g_fmt_cap
+ * @sd: pointer to standard V4L2 sub-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)
+tvp514x_g_fmt_cap(struct v4l2_subdev *sd, struct v4l2_format *f)
{
- struct tvp514x_decoder *decoder = s->priv;
+ struct tvp514x_decoder *decoder = to_decoder(sd);
if (f == NULL)
return -EINVAL;
@@ -1073,25 +1039,24 @@ ioctl_g_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)
f->fmt.pix = decoder->pix;
- v4l_dbg(1, debug, decoder->client,
- "Current FMT: bytesperline - %d"
+ v4l2_dbg(1, debug, sd, "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
+/*
+ * tvp514x_g_parm - V4L2 decoder interface handler for VIDIOC_G_PARM ioctl
+ * @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
-ioctl_g_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a)
+tvp514x_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
{
- struct tvp514x_decoder *decoder = s->priv;
+ struct tvp514x_decoder *decoder = to_decoder(sd);
struct v4l2_captureparm *cparm;
enum tvp514x_std current_std;
@@ -1105,7 +1070,7 @@ ioctl_g_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a)
a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
/* get the current standard */
- current_std = tvp514x_get_current_std(decoder);
+ current_std = tvp514x_get_current_std(sd);
if (current_std == STD_INVALID)
return -EINVAL;
@@ -1119,18 +1084,18 @@ ioctl_g_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a)
return 0;
}
-/**
- * ioctl_s_parm - V4L2 decoder interface handler for VIDIOC_S_PARM ioctl
- * @s: pointer to standard V4L2 device structure
+/*
+ * tvp514x_s_parm - V4L2 decoder interface handler for VIDIOC_S_PARM ioctl
+ * @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
-ioctl_s_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a)
+tvp514x_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
{
- struct tvp514x_decoder *decoder = s->priv;
+ struct tvp514x_decoder *decoder = to_decoder(sd);
struct v4l2_fract *timeperframe;
enum tvp514x_std current_std;
@@ -1143,7 +1108,7 @@ ioctl_s_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a)
timeperframe = &a->parm.capture.timeperframe;
/* get the current standard */
- current_std = tvp514x_get_current_std(decoder);
+ current_std = tvp514x_get_current_std(sd);
if (current_std == STD_INVALID)
return -EINVAL;
@@ -1155,112 +1120,59 @@ ioctl_s_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a)
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) {
- v4l_err(decoder->client, "g_ifparm.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
+/*
+ * tvp514x_s_stream - V4L2 decoder interface handler for vidioc_int_s_power_num
+ * @sd: pointer to standard V4L2 sub-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)
+static int tvp514x_s_stream(struct v4l2_subdev *sd, int enable)
{
- struct tvp514x_decoder *decoder = s->priv;
int err = 0;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct tvp514x_decoder *decoder = to_decoder(sd);
- 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);
- decoder->state = STATE_NOT_DETECTED;
- break;
+ if (decoder->state == enable)
+ return 0;
- case V4L2_POWER_STANDBY:
- if (decoder->pdata->power_set)
- err = decoder->pdata->power_set(on);
+ 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->state = enable;
break;
+ }
+ case 1:
+ {
+ struct tvp514x_reg *int_seq = (struct tvp514x_reg *)
+ client->driver->id_table->driver_data;
- case V4L2_POWER_ON:
- /* Enable mux for TVP5146/47 decoder data path */
- if ((decoder->pdata->power_set) &&
- (decoder->state == STATE_NOT_DETECTED)) {
- int i;
- struct tvp514x_init_seq *int_seq =
- (struct tvp514x_init_seq *)
- decoder->id->driver_data;
-
- err = decoder->pdata->power_set(on);
-
- /* Power Up Sequence */
- for (i = 0; i < int_seq->no_regs; i++) {
- err |= tvp514x_write_reg(decoder->client,
- int_seq->init_reg_seq[i].reg,
- int_seq->init_reg_seq[i].val);
- }
- /* Detect the sensor is not already detected */
- err |= tvp514x_detect(decoder);
- if (err) {
- v4l_err(decoder->client,
- "Unable to detect decoder\n");
- return err;
- }
+ /* Power Up Sequence */
+ err = tvp514x_write_regs(sd, int_seq);
+ if (err) {
+ v4l2_err(sd, "Unable to turn on decoder\n");
+ return err;
+ }
+ /* Detect the sensor is 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;
}
- err |= tvp514x_configure(decoder);
+ decoder->state = enable;
break;
-
+ }
default:
err = -ENODEV;
break;
@@ -1269,93 +1181,37 @@ static int ioctl_s_power(struct v4l2_int_device *s, enum v4l2_power on)
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 */
- decoder->tvp514x_regs[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) {
- v4l_err(decoder->client,
- "Unable to detect decoder\n");
- return err;
- }
-
- v4l_info(decoder->client,
- "chip version 0x%.2x detected\n", decoder->ver);
+static const struct v4l2_subdev_core_ops tvp514x_core_ops = {
+ .queryctrl = tvp514x_queryctrl,
+ .g_ctrl = tvp514x_g_ctrl,
+ .s_ctrl = tvp514x_s_ctrl,
+ .s_std = tvp514x_s_std,
+};
- return 0;
-}
+static const struct v4l2_subdev_video_ops tvp514x_video_ops = {
+ .s_routing = tvp514x_s_routing,
+ .querystd = tvp514x_querystd,
+ .enum_fmt = tvp514x_enum_fmt_cap,
+ .g_fmt = tvp514x_g_fmt_cap,
+ .try_fmt = tvp514x_try_fmt_cap,
+ .s_fmt = tvp514x_s_fmt_cap,
+ .g_parm = tvp514x_g_parm,
+ .s_parm = tvp514x_s_parm,
+ .s_stream = tvp514x_s_stream,
+};
-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_s_video_routing_num,
- (v4l2_int_ioctl_func *) ioctl_s_routing},
+static const struct v4l2_subdev_ops tvp514x_ops = {
+ .core = &tvp514x_core_ops,
+ .video = &tvp514x_video_ops,
};
static struct tvp514x_decoder tvp514x_dev = {
- .state = STATE_NOT_DETECTED,
+ .state = 0,
.fmt_list = tvp514x_fmt_list,
.num_fmts = ARRAY_SIZE(tvp514x_fmt_list),
- .pix = { /* Default to NTSC 8-bit YUV 422 */
+ .pix = {/* Default to NTSC 8-bit YUV 422 */
.width = NTSC_NUM_ACTIVE_PIXELS,
.height = NTSC_NUM_ACTIVE_LINES,
.pixelformat = V4L2_PIX_FMT_UYVY,
@@ -1369,20 +1225,13 @@ static struct tvp514x_decoder tvp514x_dev = {
.current_std = STD_NTSC_MJ,
.std_list = tvp514x_std_list,
.num_stds = ARRAY_SIZE(tvp514x_std_list),
- .v4l2_int_device = {
- .module = THIS_MODULE,
- .name = TVP514X_MODULE_NAME,
- .type = v4l2_int_type_slave,
- },
- .tvp514x_slave = {
- .ioctls = tvp514x_ioctl_desc,
- .num_ioctls = ARRAY_SIZE(tvp514x_ioctl_desc),
- },
+
};
-/**
+/*
* 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.
@@ -1391,67 +1240,59 @@ static int
tvp514x_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
struct tvp514x_decoder *decoder;
- int err;
+ struct v4l2_subdev *sd;
/* 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;
- if (!client->dev.platform_data) {
- v4l_err(client, "No platform data!!\n");
- err = -ENODEV;
- goto out_free;
- }
-
+ /*
+ * Initialize the tvp514x_decoder with default configuration
+ */
*decoder = tvp514x_dev;
- decoder->v4l2_int_device.priv = decoder;
- decoder->pdata = client->dev.platform_data;
- decoder->v4l2_int_device.u.slave = &decoder->tvp514x_slave;
+ /* 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->pdata->clk_polarity << 1);
decoder->tvp514x_regs[REG_SYNC_CONTROL].val |=
- ((decoder->pdata->hs_polarity << 2) |
- (decoder->pdata->vs_polarity << 3));
- /*
- * Save the id data, required for power up sequence
- */
- decoder->id = (struct i2c_device_id *)id;
- /* Attach to Master */
- strcpy(decoder->v4l2_int_device.u.slave->attach_to,
- decoder->pdata->master);
- decoder->client = client;
- i2c_set_clientdata(client, decoder);
+ ((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 */
- err = v4l2_int_device_register(&decoder->v4l2_int_device);
- if (err) {
- i2c_set_clientdata(client, NULL);
- v4l_err(client,
- "Unable to register to v4l2. Err[%d]\n", err);
- goto out_free;
-
- } else
- v4l_info(client, "Registered to v4l2 master %s!!\n",
- decoder->pdata->master);
+ sd = &decoder->sd;
+ v4l2_i2c_subdev_init(sd, client, &tvp514x_ops);
+
+ v4l2_info(sd, "%s decoder driver registered !!\n", sd->name);
+
return 0;
-out_free:
- kfree(decoder);
- return err;
}
-/**
+/*
* tvp514x_remove - decoder driver i2c remove handler
* @client: i2c driver client device structure
*
@@ -1460,13 +1301,10 @@ out_free:
*/
static int __exit tvp514x_remove(struct i2c_client *client)
{
- struct tvp514x_decoder *decoder = i2c_get_clientdata(client);
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct tvp514x_decoder *decoder = to_decoder(sd);
- if (!client->adapter)
- return -ENODEV; /* our client isn't attached */
-
- v4l2_int_device_unregister(&decoder->v4l2_int_device);
- i2c_set_clientdata(client, NULL);
+ v4l2_device_unregister_subdev(sd);
kfree(decoder);
return 0;
}
@@ -1485,11 +1323,9 @@ static const struct tvp514x_reg tvp5146_init_reg_seq[] = {
{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},
};
-static const struct tvp514x_init_seq tvp5146_init = {
- .no_regs = ARRAY_SIZE(tvp5146_init_reg_seq),
- .init_reg_seq = tvp5146_init_reg_seq,
-};
+
/*
* TVP5147 Init/Power on Sequence
*/
@@ -1512,22 +1348,18 @@ static const struct tvp514x_reg tvp5147_init_reg_seq[] = {
{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},
};
-static const struct tvp514x_init_seq tvp5147_init = {
- .no_regs = ARRAY_SIZE(tvp5147_init_reg_seq),
- .init_reg_seq = tvp5147_init_reg_seq,
-};
+
/*
* 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},
};
-static const struct tvp514x_init_seq tvp514xm_init = {
- .no_regs = ARRAY_SIZE(tvp514xm_init_reg_seq),
- .init_reg_seq = tvp514xm_init_reg_seq,
-};
+
/*
* I2C Device Table -
*
@@ -1535,48 +1367,22 @@ static const struct tvp514x_init_seq tvp514xm_init = {
* driver_data - Driver data
*/
static const struct i2c_device_id tvp514x_id[] = {
- {"tvp5146", (unsigned long)&tvp5146_init},
- {"tvp5146m2", (unsigned long)&tvp514xm_init},
- {"tvp5147", (unsigned long)&tvp5147_init},
- {"tvp5147m1", (unsigned long)&tvp514xm_init},
+ {"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_i2c_driver = {
- .driver = {
- .name = TVP514X_MODULE_NAME,
- .owner = THIS_MODULE,
- },
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = TVP514X_MODULE_NAME,
.probe = tvp514x_probe,
.remove = __exit_p(tvp514x_remove),
.id_table = tvp514x_id,
};
-/**
- * tvp514x_init
- *
- * Module init function
- */
-static int __init tvp514x_init(void)
-{
- return i2c_add_driver(&tvp514x_i2c_driver);
-}
-
-/**
- * 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/drivers/media/video/tvp514x_regs.h b/drivers/media/video/tvp514x_regs.h
index 351620a..18f29ad 100644
--- a/drivers/media/video/tvp514x_regs.h
+++ b/drivers/media/video/tvp514x_regs.h
@@ -284,14 +284,4 @@ struct tvp514x_reg {
u32 val;
};
-/**
- * struct tvp514x_init_seq - Structure for TVP5146/47/46M2/47M1 power up
- * Sequence.
- * @ no_regs - Number of registers to write for power up sequence.
- * @ init_reg_seq - Array of registers and respective value to write.
- */
-struct tvp514x_init_seq {
- unsigned int no_regs;
- const struct tvp514x_reg *init_reg_seq;
-};
#endif /* ifndef _TVP514X_REGS_H */
diff --git a/include/media/tvp514x.h b/include/media/tvp514x.h
index 5e7ee96..74387e8 100644
--- a/include/media/tvp514x.h
+++ b/include/media/tvp514x.h
@@ -104,10 +104,6 @@ enum tvp514x_output {
* @ vs_polarity: VSYNC Polarity configuration for current interface.
*/
struct tvp514x_platform_data {
- char *master;
- int (*power_set) (enum v4l2_power on);
- int (*ifparm) (struct v4l2_ifparm *p);
- int (*priv_data_set) (void *);
/* Interface control params */
bool clk_polarity;
bool hs_polarity;
--
1.6.2.4
^ permalink raw reply related [flat|nested] 28+ messages in thread
* Re: [PATCH (V2)] TVP514x: Migration to sub-device framework
2009-05-06 18:31 ` [PATCH (V2)] TVP514x: Migration to sub-device framework hvaibhav
@ 2009-06-14 10:14 ` Hans Verkuil
2009-06-14 12:44 ` Hans Verkuil
[not found] ` <200906141214.38355.hverkuil-qWit8jRvyhVmR6Xm/wNWPw@public.gmane.org>
0 siblings, 2 replies; 28+ messages in thread
From: Hans Verkuil @ 2009-06-14 10:14 UTC (permalink / raw)
To: hvaibhav
Cc: linux-media, linux-omap, davinci-linux-open-source, Brijesh Jadav,
Hardik Shah
On Wednesday 06 May 2009 20:31:33 hvaibhav@ti.com wrote:
> From: Vaibhav Hiremath <hvaibhav@ti.com>
>
> This patch converts TVP514x driver to sub-device framework
> from V4L2-int framework.
>
> NOTE: Please note that this patch has not been tested on any board,
> only compilation/build tested.
>
> Changes (From Previous post):
> - Added static function to_decoder which will replace all
> container_of instances.
> - "unsigned int" replaced with "u32".
> - Cleaned up for line indentation.
> - pdata initialized, was missing in earlier patch.
>
> TODO:
> - Add support for some basic video/core functionality like,
> .g_chip_ident
> .reset
> .g_input_status
> - Migration master driver to validate this driver.
> - validate on Davinci and OMAP boards.
>
> Reviewed By "Hans Verkuil".
>
> Signed-off-by: Brijesh Jadav <brijesh.j@ti.com>
> Signed-off-by: Hardik Shah <hardik.shah@ti.com>
> Signed-off-by: Vaibhav Hiremath <hvaibhav@ti.com>
> ---
> drivers/media/video/tvp514x.c | 854 ++++++++++++++----------------------
> drivers/media/video/tvp514x_regs.h | 10 -
> include/media/tvp514x.h | 4 -
> 3 files changed, 330 insertions(+), 538 deletions(-)
>
> diff --git a/drivers/media/video/tvp514x.c b/drivers/media/video/tvp514x.c
> index 4262e60..12b49ad 100644
> --- a/drivers/media/video/tvp514x.c
> +++ b/drivers/media/video/tvp514x.c
> @@ -31,7 +31,11 @@
> #include <linux/i2c.h>
> #include <linux/delay.h>
> #include <linux/videodev2.h>
> -#include <media/v4l2-int-device.h>
> +
> +#include <media/v4l2-device.h>
> +#include <media/v4l2-common.h>
> +#include <media/v4l2-chip-ident.h>
> +#include <media/v4l2-i2c-drv.h>
> #include <media/tvp514x.h>
>
> #include "tvp514x_regs.h"
> @@ -49,13 +53,13 @@ static int debug;
> module_param(debug, bool, 0644);
> MODULE_PARM_DESC(debug, "Debug level (0-1)");
>
> -#define dump_reg(client, reg, val) \
> +#define dump_reg(sd, reg, val) \
> do { \
> - val = tvp514x_read_reg(client, reg); \
> - v4l_info(client, "Reg(0x%.2X): 0x%.2X\n", reg, val); \
> + val = tvp514x_read_reg(sd, reg); \
> + v4l2_info(sd, "Reg(0x%.2X): 0x%.2X\n", reg, val); \
> } while (0)
Why not turn this into a static inline function? Much better than a macro.
>
> -/**
> +/*
> * enum tvp514x_std - enum for supported standards
> */
> enum tvp514x_std {
> @@ -64,15 +68,7 @@ enum tvp514x_std {
> STD_INVALID
> };
>
> -/**
> - * enum tvp514x_state - enum for different decoder states
> - */
> -enum tvp514x_state {
> - STATE_NOT_DETECTED,
> - STATE_DETECTED
> -};
> -
> -/**
> +/*
> * struct tvp514x_std_info - Structure to store standard informations
> * @width: Line width in pixels
> * @height:Number of active lines
> @@ -87,35 +83,29 @@ struct tvp514x_std_info {
> };
>
> static struct tvp514x_reg tvp514x_reg_list_default[0x40];
> -/**
> +/*
> * struct tvp514x_decoder - TVP5146/47 decoder object
> - * @v4l2_int_device: Slave handle
> - * @tvp514x_slave: Slave pointer which is used by @v4l2_int_device
> + * @sd: Subdevice Slave handle
> * @tvp514x_regs: copy of hw's regs with preset values.
> * @pdata: Board specific
> - * @client: I2C client data
> - * @id: Entry from I2C table
> * @ver: Chip version
> - * @state: TVP5146/47 decoder state - detected or not-detected
> + * @state: TVP5146/47 decoder state - enabled or disabled.
> * @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
> - * @route: input and output routing at chip level
> + * @input: Input routing at chip level
> + * @output: Output routing at chip level
> */
> struct tvp514x_decoder {
> - struct v4l2_int_device v4l2_int_device;
> - struct v4l2_int_slave tvp514x_slave;
> + struct v4l2_subdev sd;
> struct tvp514x_reg tvp514x_regs[ARRAY_SIZE(tvp514x_reg_list_default)];
> const struct tvp514x_platform_data *pdata;
> - struct i2c_client *client;
> -
> - struct i2c_device_id *id;
>
> int ver;
> - enum tvp514x_state state;
> + int state;
>
> struct v4l2_pix_format pix;
> int num_fmts;
> @@ -124,8 +114,11 @@ struct tvp514x_decoder {
> enum tvp514x_std current_std;
> int num_stds;
> struct tvp514x_std_info *std_list;
> -
> - struct v4l2_routing route;
> + /*
> + * Input and Output Routing parameters
> + */
> + u32 input;
> + u32 output;
> };
>
> /* TVP514x default register values */
> @@ -191,7 +184,8 @@ static struct tvp514x_reg tvp514x_reg_list_default[] = {
> {TOK_TERM, 0, 0},
> };
>
> -/* List of image formats supported by TVP5146/47 decoder
> +/*
> + * 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.
> */
> @@ -240,35 +234,27 @@ static struct tvp514x_std_info tvp514x_std_list[] = {
> },
> /* Standard: need to add for additional standard */
> };
> -/*
> - * Control structure for Auto Gain
> - * This is temporary data, will get replaced once
> - * v4l2_ctrl_query_fill supports it.
> - */
> -static const struct v4l2_queryctrl tvp514x_autogain_ctrl = {
> - .id = V4L2_CID_AUTOGAIN,
> - .name = "Gain, Automatic",
> - .type = V4L2_CTRL_TYPE_BOOLEAN,
> - .minimum = 0,
> - .maximum = 1,
> - .step = 1,
> - .default_value = 1,
> -};
>
> +
> +static inline struct tvp514x_decoder *to_decoder(struct v4l2_subdev *sd)
> +{
> + return container_of(sd, struct tvp514x_decoder, sd);
> +}
> /*
> * Read a value from a register in an TVP5146/47 decoder device.
> * Returns value read if successful, or non-zero (-1) otherwise.
> */
> -static int tvp514x_read_reg(struct i2c_client *client, u8 reg)
> +static int tvp514x_read_reg(struct v4l2_subdev *sd, u8 reg)
> {
> - int err;
> - int retry = 0;
> + int err, retry = 0;
> + struct i2c_client *client = v4l2_get_subdevdata(sd);
> +
> read_again:
>
> err = i2c_smbus_read_byte_data(client, reg);
> if (err == -1) {
> if (retry <= I2C_RETRY_COUNT) {
> - v4l_warn(client, "Read: retry ... %d\n", retry);
> + v4l2_warn(sd, "Read: retry ... %d\n", retry);
> retry++;
> msleep_interruptible(10);
> goto read_again;
> @@ -282,16 +268,17 @@ read_again:
> * 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)
> +static int tvp514x_write_reg(struct v4l2_subdev *sd, u8 reg, u8 val)
> {
> - int err;
> - int retry = 0;
> + int err, retry = 0;
> + struct i2c_client *client = v4l2_get_subdevdata(sd);
> +
> write_again:
>
> err = i2c_smbus_write_byte_data(client, reg, val);
> if (err) {
> if (retry <= I2C_RETRY_COUNT) {
> - v4l_warn(client, "Write: retry ... %d\n", retry);
> + v4l2_warn(sd, "Write: retry ... %d\n", retry);
> retry++;
> msleep_interruptible(10);
> goto write_again;
> @@ -311,7 +298,7 @@ write_again:
> * reglist - list of registers to be written
> * Returns zero if successful, or non-zero otherwise.
> */
> -static int tvp514x_write_regs(struct i2c_client *client,
> +static int tvp514x_write_regs(struct v4l2_subdev *sd,
> const struct tvp514x_reg reglist[])
> {
> int err;
> @@ -326,9 +313,9 @@ static int tvp514x_write_regs(struct i2c_client *client,
> if (next->token == TOK_SKIP)
> continue;
>
> - err = tvp514x_write_reg(client, next->reg, (u8) next->val);
> + err = tvp514x_write_reg(sd, next->reg, (u8) next->val);
> if (err) {
> - v4l_err(client, "Write failed. Err[%d]\n", err);
> + v4l2_err(sd, "Write failed. Err[%d]\n", err);
> return err;
> }
> }
> @@ -339,17 +326,15 @@ static int tvp514x_write_regs(struct i2c_client *client,
> * tvp514x_get_current_std:
> * Returns the current standard detected by TVP5146/47
> */
> -static enum tvp514x_std tvp514x_get_current_std(struct tvp514x_decoder
> - *decoder)
> +static enum tvp514x_std tvp514x_get_current_std(struct v4l2_subdev *sd)
> {
> u8 std, std_status;
>
> - std = tvp514x_read_reg(decoder->client, REG_VIDEO_STD);
> - if ((std & VIDEO_STD_MASK) == VIDEO_STD_AUTO_SWITCH_BIT) {
> + 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(decoder->client,
> - REG_VIDEO_STD_STATUS);
> - } else
> + std_status = tvp514x_read_reg(sd, REG_VIDEO_STD_STATUS);
> + else
> std_status = std; /* use the standard register itself */
>
> switch (std_status & VIDEO_STD_MASK) {
> @@ -369,70 +354,71 @@ static enum tvp514x_std tvp514x_get_current_std(struct tvp514x_decoder
> /*
> * TVP5146/47 register dump function
> */
> -static void tvp514x_reg_dump(struct tvp514x_decoder *decoder)
> +static void tvp514x_reg_dump(struct v4l2_subdev *sd)
> {
> 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);
> + dump_reg(sd, REG_INPUT_SEL, value);
> + dump_reg(sd, REG_AFE_GAIN_CTRL, value);
> + dump_reg(sd, REG_VIDEO_STD, value);
> + dump_reg(sd, REG_OPERATION_MODE, value);
> + dump_reg(sd, REG_COLOR_KILLER, value);
> + dump_reg(sd, REG_LUMA_CONTROL1, value);
> + dump_reg(sd, REG_LUMA_CONTROL2, value);
> + dump_reg(sd, REG_LUMA_CONTROL3, value);
> + dump_reg(sd, REG_BRIGHTNESS, value);
> + dump_reg(sd, REG_CONTRAST, value);
> + dump_reg(sd, REG_SATURATION, value);
> + dump_reg(sd, REG_HUE, value);
> + dump_reg(sd, REG_CHROMA_CONTROL1, value);
> + dump_reg(sd, REG_CHROMA_CONTROL2, value);
> + dump_reg(sd, REG_COMP_PR_SATURATION, value);
> + dump_reg(sd, REG_COMP_Y_CONTRAST, value);
> + dump_reg(sd, REG_COMP_PB_SATURATION, value);
> + dump_reg(sd, REG_COMP_Y_BRIGHTNESS, value);
> + dump_reg(sd, REG_AVID_START_PIXEL_LSB, value);
> + dump_reg(sd, REG_AVID_START_PIXEL_MSB, value);
> + dump_reg(sd, REG_AVID_STOP_PIXEL_LSB, value);
> + dump_reg(sd, REG_AVID_STOP_PIXEL_MSB, value);
> + dump_reg(sd, REG_HSYNC_START_PIXEL_LSB, value);
> + dump_reg(sd, REG_HSYNC_START_PIXEL_MSB, value);
> + dump_reg(sd, REG_HSYNC_STOP_PIXEL_LSB, value);
> + dump_reg(sd, REG_HSYNC_STOP_PIXEL_MSB, value);
> + dump_reg(sd, REG_VSYNC_START_LINE_LSB, value);
> + dump_reg(sd, REG_VSYNC_START_LINE_MSB, value);
> + dump_reg(sd, REG_VSYNC_STOP_LINE_LSB, value);
> + dump_reg(sd, REG_VSYNC_STOP_LINE_MSB, value);
> + dump_reg(sd, REG_VBLK_START_LINE_LSB, value);
> + dump_reg(sd, REG_VBLK_START_LINE_MSB, value);
> + dump_reg(sd, REG_VBLK_STOP_LINE_LSB, value);
> + dump_reg(sd, REG_VBLK_STOP_LINE_MSB, value);
> + dump_reg(sd, REG_SYNC_CONTROL, value);
> + dump_reg(sd, REG_OUTPUT_FORMATTER1, value);
> + dump_reg(sd, REG_OUTPUT_FORMATTER2, value);
> + dump_reg(sd, REG_OUTPUT_FORMATTER3, value);
> + dump_reg(sd, REG_OUTPUT_FORMATTER4, value);
> + dump_reg(sd, REG_OUTPUT_FORMATTER5, value);
> + dump_reg(sd, REG_OUTPUT_FORMATTER6, value);
> + dump_reg(sd, REG_CLEAR_LOST_LOCK, value);
> }
>
> /*
> * 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)
> +static int tvp514x_configure(struct v4l2_subdev *sd,
> + struct tvp514x_decoder *decoder)
> {
> int err;
>
> /* common register initialization */
> err =
> - tvp514x_write_regs(decoder->client, decoder->tvp514x_regs);
> + tvp514x_write_regs(sd, decoder->tvp514x_regs);
> if (err)
> return err;
>
> if (debug)
> - tvp514x_reg_dump(decoder);
> + tvp514x_reg_dump(sd);
>
> return 0;
> }
> @@ -445,15 +431,17 @@ static int tvp514x_configure(struct tvp514x_decoder *decoder)
> * Returns ENODEV error number if no device is detected, or zero
> * if a device is detected.
> */
> -static int tvp514x_detect(struct tvp514x_decoder *decoder)
> +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(decoder->client, REG_CHIP_ID_MSB);
> - chip_id_lsb = tvp514x_read_reg(decoder->client, REG_CHIP_ID_LSB);
> - rom_ver = tvp514x_read_reg(decoder->client, REG_ROM_VERSION);
> + 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);
>
> - v4l_dbg(1, debug, decoder->client,
> + 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)
> @@ -462,19 +450,16 @@ static int tvp514x_detect(struct tvp514x_decoder *decoder)
> /* We didn't read the values we expected, so this must not be
> * an TVP5146/47.
> */
> - v4l_err(decoder->client,
> - "chip id mismatch msb:0x%x lsb:0x%x\n",
> - chip_id_msb, chip_id_lsb);
> + 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;
> - decoder->state = STATE_DETECTED;
>
> - v4l_info(decoder->client,
> - "%s found at 0x%x (%s)\n", decoder->client->name,
> - decoder->client->addr << 1,
> - decoder->client->adapter->name);
> + 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;
> }
>
> @@ -483,17 +468,17 @@ static int tvp514x_detect(struct tvp514x_decoder *decoder)
> * TVP5146/47 decoder driver.
> */
>
> -/**
> - * ioctl_querystd - V4L2 decoder interface handler for VIDIOC_QUERYSTD ioctl
> - * @s: pointer to standard V4L2 device structure
> +/*
> + * tvp514x_querystd - V4L2 decoder interface handler for VIDIOC_QUERYSTD ioctl
> + * @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, returns -EINVAL
> */
> -static int ioctl_querystd(struct v4l2_int_device *s, v4l2_std_id *std_id)
> +static int tvp514x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std_id)
> {
> - struct tvp514x_decoder *decoder = s->priv;
> + struct tvp514x_decoder *decoder = to_decoder(sd);
> enum tvp514x_std current_std;
> enum tvp514x_input input_sel;
> u8 sync_lock_status, lock_mask;
> @@ -502,11 +487,11 @@ static int ioctl_querystd(struct v4l2_int_device *s, v4l2_std_id *std_id)
> return -EINVAL;
>
> /* get the current standard */
> - current_std = tvp514x_get_current_std(decoder);
> + current_std = tvp514x_get_current_std(sd);
> if (current_std == STD_INVALID)
> return -EINVAL;
>
> - input_sel = decoder->route.input;
> + input_sel = decoder->input;
>
> switch (input_sel) {
> case INPUT_CVBS_VI1A:
> @@ -544,42 +529,39 @@ static int ioctl_querystd(struct v4l2_int_device *s, v4l2_std_id *std_id)
> return -EINVAL;
> }
> /* check whether signal is locked */
> - sync_lock_status = tvp514x_read_reg(decoder->client, REG_STATUS1);
> + sync_lock_status = tvp514x_read_reg(sd, REG_STATUS1);
> 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;
>
> - v4l_dbg(1, debug, decoder->client, "Current STD: %s",
> + v4l2_dbg(1, debug, sd, "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
> +/*
> + * tvp514x_s_std - V4L2 decoder interface handler for VIDIOC_S_STD ioctl
> + * @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 ioctl_s_std(struct v4l2_int_device *s, v4l2_std_id *std_id)
> +static int tvp514x_s_std(struct v4l2_subdev *sd, v4l2_std_id std_id)
> {
> - struct tvp514x_decoder *decoder = s->priv;
> + struct tvp514x_decoder *decoder = to_decoder(sd);
> 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)
> + if (std_id & decoder->std_list[i].standard.id)
> break;
>
> if ((i == decoder->num_stds) || (i == STD_INVALID))
> return -EINVAL;
>
> - err = tvp514x_write_reg(decoder->client, REG_VIDEO_STD,
> + err = tvp514x_write_reg(sd, REG_VIDEO_STD,
> decoder->std_list[i].video_std);
> if (err)
> return err;
> @@ -588,24 +570,24 @@ static int ioctl_s_std(struct v4l2_int_device *s, v4l2_std_id *std_id)
> decoder->tvp514x_regs[REG_VIDEO_STD].val =
> decoder->std_list[i].video_std;
>
> - v4l_dbg(1, debug, decoder->client, "Standard set to: %s",
> + v4l2_dbg(1, debug, sd, "Standard set to: %s",
> decoder->std_list[i].standard.name);
> return 0;
> }
>
> -/**
> - * ioctl_s_routing - V4L2 decoder interface handler for VIDIOC_S_INPUT ioctl
> - * @s: pointer to standard V4L2 device structure
> +/*
> + * tvp514x_s_routing - V4L2 decoder interface handler for VIDIOC_S_INPUT ioctl
> + * @sd: pointer to standard V4L2 sub-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.
> */
> -static int ioctl_s_routing(struct v4l2_int_device *s,
> - struct v4l2_routing *route)
> +static int tvp514x_s_routing(struct v4l2_subdev *sd,
> + u32 input, u32 output, u32 config)
> {
> - struct tvp514x_decoder *decoder = s->priv;
> + struct tvp514x_decoder *decoder = to_decoder(sd);
> int err;
> enum tvp514x_input input_sel;
> enum tvp514x_output output_sel;
> @@ -613,20 +595,20 @@ static int ioctl_s_routing(struct v4l2_int_device *s,
> u8 sync_lock_status, lock_mask;
> int try_count = LOCK_RETRY_COUNT;
>
> - if ((!route) || (route->input >= INPUT_INVALID) ||
> - (route->output >= OUTPUT_INVALID))
> + if ((input >= INPUT_INVALID) ||
> + (output >= OUTPUT_INVALID))
> return -EINVAL; /* Index out of bound */
>
> - input_sel = route->input;
> - output_sel = route->output;
> + input_sel = input;
> + output_sel = output;
>
> - err = tvp514x_write_reg(decoder->client, REG_INPUT_SEL, input_sel);
> + err = tvp514x_write_reg(sd, REG_INPUT_SEL, input_sel);
> if (err)
> return err;
>
> - output_sel |= tvp514x_read_reg(decoder->client,
> + output_sel |= tvp514x_read_reg(sd,
> REG_OUTPUT_FORMATTER1) & 0x7;
> - err = tvp514x_write_reg(decoder->client, REG_OUTPUT_FORMATTER1,
> + err = tvp514x_write_reg(sd, REG_OUTPUT_FORMATTER1,
> output_sel);
> if (err)
> return err;
> @@ -637,7 +619,7 @@ static int ioctl_s_routing(struct v4l2_int_device *s,
> /* Clear status */
> msleep(LOCK_RETRY_DELAY);
> err =
> - tvp514x_write_reg(decoder->client, REG_CLEAR_LOST_LOCK, 0x01);
> + tvp514x_write_reg(sd, REG_CLEAR_LOST_LOCK, 0x01);
> if (err)
> return err;
>
> @@ -682,11 +664,11 @@ static int ioctl_s_routing(struct v4l2_int_device *s,
> msleep(LOCK_RETRY_DELAY);
>
> /* get the current standard for future reference */
> - current_std = tvp514x_get_current_std(decoder);
> + current_std = tvp514x_get_current_std(sd);
> if (current_std == STD_INVALID)
> continue;
>
> - sync_lock_status = tvp514x_read_reg(decoder->client,
> + sync_lock_status = tvp514x_read_reg(sd,
> REG_STATUS1);
> if (lock_mask == (sync_lock_status & lock_mask))
> break; /* Input detected */
> @@ -696,28 +678,26 @@ static int ioctl_s_routing(struct v4l2_int_device *s,
> return -EINVAL;
>
> decoder->current_std = current_std;
> - decoder->route.input = route->input;
> - decoder->route.output = route->output;
> + decoder->input = input;
> + decoder->output = output;
>
> - v4l_dbg(1, debug, decoder->client,
> - "Input set to: %d, std : %d",
> + v4l2_dbg(1, debug, sd, "Input set to: %d, std : %d",
> input_sel, current_std);
>
> return 0;
> }
>
> -/**
> - * ioctl_queryctrl - V4L2 decoder interface handler for VIDIOC_QUERYCTRL ioctl
> - * @s: pointer to standard V4L2 device structure
> +/*
> + * tvp514x_queryctrl - V4L2 decoder interface handler for VIDIOC_QUERYCTRL ioctl
> + * @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
> -ioctl_queryctrl(struct v4l2_int_device *s, struct v4l2_queryctrl *qctrl)
> +tvp514x_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qctrl)
> {
> - struct tvp514x_decoder *decoder = s->priv;
> int err = -EINVAL;
>
> if (qctrl == NULL)
> @@ -744,30 +724,27 @@ ioctl_queryctrl(struct v4l2_int_device *s, struct v4l2_queryctrl *qctrl)
> err = v4l2_ctrl_query_fill(qctrl, -180, 180, 180, 0);
> break;
> case V4L2_CID_AUTOGAIN:
> - /* Autogain is either 0 or 1*/
> - memcpy(qctrl, &tvp514x_autogain_ctrl,
> - sizeof(struct v4l2_queryctrl));
> - err = 0;
> + /*
> + * Auto Gain supported is -
> + * 0 - 1 (Default - 1)
> + */
> + err = v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 1);
> break;
> default:
> - v4l_err(decoder->client,
> - "invalid control id %d\n", qctrl->id);
> + v4l2_err(sd, "invalid control id %d\n", qctrl->id);
> return err;
> }
>
> - v4l_dbg(1, debug, decoder->client,
> - "Query Control: %s : Min - %d, Max - %d, Def - %d",
> - qctrl->name,
> - qctrl->minimum,
> - qctrl->maximum,
> + v4l2_dbg(1, debug, sd, "Query Control:%s: Min - %d, Max - %d, Def - %d",
> + qctrl->name, qctrl->minimum, qctrl->maximum,
> qctrl->default_value);
>
> return err;
> }
>
> -/**
> - * ioctl_g_ctrl - V4L2 decoder interface handler for VIDIOC_G_CTRL ioctl
> - * @s: pointer to standard V4L2 device structure
> +/*
> + * tvp514x_g_ctrl - V4L2 decoder interface handler for VIDIOC_G_CTRL ioctl
> + * @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
> @@ -775,9 +752,9 @@ ioctl_queryctrl(struct v4l2_int_device *s, struct v4l2_queryctrl *qctrl)
> * supported.
> */
> static int
> -ioctl_g_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl)
> +tvp514x_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
> {
> - struct tvp514x_decoder *decoder = s->priv;
> + struct tvp514x_decoder *decoder = to_decoder(sd);
>
> if (ctrl == NULL)
> return -EINVAL;
> @@ -811,74 +788,70 @@ ioctl_g_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl)
>
> break;
> default:
> - v4l_err(decoder->client,
> - "invalid control id %d\n", ctrl->id);
> + v4l2_err(sd, "invalid control id %d\n", ctrl->id);
> return -EINVAL;
> }
>
> - v4l_dbg(1, debug, decoder->client,
> - "Get Control: ID - %d - %d",
> + v4l2_dbg(1, debug, sd, "Get Control: ID - %d - %d",
> ctrl->id, ctrl->value);
> return 0;
> }
>
> -/**
> - * ioctl_s_ctrl - V4L2 decoder interface handler for VIDIOC_S_CTRL ioctl
> - * @s: pointer to standard V4L2 device structure
> +/*
> + * tvp514x_s_ctrl - V4L2 decoder interface handler for VIDIOC_S_CTRL ioctl
> + * @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
> -ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl)
> +tvp514x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
> {
> - struct tvp514x_decoder *decoder = s->priv;
> + struct tvp514x_decoder *decoder = to_decoder(sd);
> int err = -EINVAL, value;
>
> if (ctrl == NULL)
> return err;
>
> - value = (__s32) ctrl->value;
> + value = ctrl->value;
>
> switch (ctrl->id) {
> case V4L2_CID_BRIGHTNESS:
> if (ctrl->value < 0 || ctrl->value > 255) {
> - v4l_err(decoder->client,
> - "invalid brightness setting %d\n",
> + v4l2_err(sd, "invalid brightness setting %d\n",
> ctrl->value);
> return -ERANGE;
> }
> - err = tvp514x_write_reg(decoder->client, REG_BRIGHTNESS,
> + 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) {
> - v4l_err(decoder->client,
> - "invalid contrast setting %d\n",
> + v4l2_err(sd, "invalid contrast setting %d\n",
> ctrl->value);
> return -ERANGE;
> }
> - err = tvp514x_write_reg(decoder->client, REG_CONTRAST,
> - value);
> + 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) {
> - v4l_err(decoder->client,
> - "invalid saturation setting %d\n",
> + v4l2_err(sd, "invalid saturation setting %d\n",
> ctrl->value);
> return -ERANGE;
> }
> - err = tvp514x_write_reg(decoder->client, REG_SATURATION,
> - value);
> + err = tvp514x_write_reg(sd, REG_SATURATION, value);
> if (err)
> return err;
> +
> decoder->tvp514x_regs[REG_SATURATION].val = value;
> break;
> case V4L2_CID_HUE:
> @@ -889,15 +862,13 @@ ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl)
> else if (value == 0)
> value = 0;
> else {
> - v4l_err(decoder->client,
> - "invalid hue setting %d\n",
> - ctrl->value);
> + v4l2_err(sd, "invalid hue setting %d\n", ctrl->value);
> return -ERANGE;
> }
> - err = tvp514x_write_reg(decoder->client, REG_HUE,
> - value);
> + err = tvp514x_write_reg(sd, REG_HUE, value);
> if (err)
> return err;
> +
> decoder->tvp514x_regs[REG_HUE].val = value;
> break;
> case V4L2_CID_AUTOGAIN:
> @@ -906,41 +877,38 @@ ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl)
> else if (value == 0)
> value = 0x0C;
> else {
> - v4l_err(decoder->client,
> - "invalid auto gain setting %d\n",
> + v4l2_err(sd, "invalid auto gain setting %d\n",
> ctrl->value);
> return -ERANGE;
> }
> - err = tvp514x_write_reg(decoder->client, REG_AFE_GAIN_CTRL,
> - value);
> + 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:
> - v4l_err(decoder->client,
> - "invalid control id %d\n", ctrl->id);
> + v4l2_err(sd, "invalid control id %d\n", ctrl->id);
> return err;
> }
>
> - v4l_dbg(1, debug, decoder->client,
> - "Set Control: ID - %d - %d",
> + v4l2_dbg(1, debug, sd, "Set Control: ID - %d - %d",
> ctrl->id, ctrl->value);
>
> return err;
> }
>
> -/**
> - * ioctl_enum_fmt_cap - Implement the CAPTURE buffer VIDIOC_ENUM_FMT ioctl
> - * @s: pointer to standard V4L2 device structure
> +/*
> + * tvp514x_enum_fmt_cap - Implement the CAPTURE buffer VIDIOC_ENUM_FMT ioctl
> + * @sd: pointer to standard V4L2 sub-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)
> +tvp514x_enum_fmt_cap(struct v4l2_subdev *sd, struct v4l2_fmtdesc *fmt)
> {
> - struct tvp514x_decoder *decoder = s->priv;
> + struct tvp514x_decoder *decoder = to_decoder(sd);
> int index;
>
> if (fmt == NULL)
> @@ -956,16 +924,15 @@ ioctl_enum_fmt_cap(struct v4l2_int_device *s, struct v4l2_fmtdesc *fmt)
> memcpy(fmt, &decoder->fmt_list[index],
> sizeof(struct v4l2_fmtdesc));
>
> - v4l_dbg(1, debug, decoder->client,
> - "Current FMT: index - %d (%s)",
> + v4l2_dbg(1, debug, sd, "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
> +/*
> + * tvp514x_try_fmt_cap - Implement the CAPTURE buffer VIDIOC_TRY_FMT ioctl
> + * @sd: pointer to standard V4L2 sub-device structure
> * @f: pointer to standard V4L2 VIDIOC_TRY_FMT ioctl structure
> *
> * Implement the VIDIOC_TRY_FMT ioctl for the CAPTURE buffer type. This
> @@ -973,9 +940,9 @@ ioctl_enum_fmt_cap(struct v4l2_int_device *s, struct v4l2_fmtdesc *fmt)
> * without actually making it take effect.
> */
> static int
> -ioctl_try_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)
> +tvp514x_try_fmt_cap(struct v4l2_subdev *sd, struct v4l2_format *f)
> {
> - struct tvp514x_decoder *decoder = s->priv;
> + struct tvp514x_decoder *decoder = to_decoder(sd);
> int ifmt;
> struct v4l2_pix_format *pix;
> enum tvp514x_std current_std;
> @@ -989,7 +956,7 @@ ioctl_try_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)
> pix = &f->fmt.pix;
>
> /* Calculate height and width based on current standard */
> - current_std = tvp514x_get_current_std(decoder);
> + current_std = tvp514x_get_current_std(sd);
> if (current_std == STD_INVALID)
> return -EINVAL;
>
> @@ -1012,17 +979,16 @@ ioctl_try_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)
> pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
> pix->priv = 0;
>
> - v4l_dbg(1, debug, decoder->client,
> - "Try FMT: pixelformat - %s, bytesperline - %d"
> + v4l2_dbg(1, debug, sd, "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
> +/*
> + * tvp514x_s_fmt_cap - V4L2 decoder interface handler for VIDIOC_S_FMT ioctl
> + * @sd: pointer to standard V4L2 sub-device structure
> * @f: pointer to standard V4L2 VIDIOC_S_FMT ioctl structure
> *
> * If the requested format is supported, configures the HW to use that
> @@ -1030,9 +996,9 @@ ioctl_try_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)
> * correctly configured.
> */
> static int
> -ioctl_s_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)
> +tvp514x_s_fmt_cap(struct v4l2_subdev *sd, struct v4l2_format *f)
> {
> - struct tvp514x_decoder *decoder = s->priv;
> + struct tvp514x_decoder *decoder = to_decoder(sd);
> struct v4l2_pix_format *pix;
> int rval;
>
> @@ -1043,7 +1009,7 @@ ioctl_s_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)
> return -EINVAL; /* only capture is supported */
>
> pix = &f->fmt.pix;
> - rval = ioctl_try_fmt_cap(s, f);
> + rval = tvp514x_try_fmt_cap(sd, f);
> if (rval)
> return rval;
>
> @@ -1052,18 +1018,18 @@ ioctl_s_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)
> return rval;
> }
>
> -/**
> - * ioctl_g_fmt_cap - V4L2 decoder interface handler for ioctl_g_fmt_cap
> - * @s: pointer to standard V4L2 device structure
> +/*
> + * tvp514x_g_fmt_cap - V4L2 decoder interface handler for tvp514x_g_fmt_cap
> + * @sd: pointer to standard V4L2 sub-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)
> +tvp514x_g_fmt_cap(struct v4l2_subdev *sd, struct v4l2_format *f)
> {
> - struct tvp514x_decoder *decoder = s->priv;
> + struct tvp514x_decoder *decoder = to_decoder(sd);
>
> if (f == NULL)
> return -EINVAL;
> @@ -1073,25 +1039,24 @@ ioctl_g_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)
>
> f->fmt.pix = decoder->pix;
>
> - v4l_dbg(1, debug, decoder->client,
> - "Current FMT: bytesperline - %d"
> + v4l2_dbg(1, debug, sd, "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
> +/*
> + * tvp514x_g_parm - V4L2 decoder interface handler for VIDIOC_G_PARM ioctl
> + * @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
> -ioctl_g_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a)
> +tvp514x_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
> {
> - struct tvp514x_decoder *decoder = s->priv;
> + struct tvp514x_decoder *decoder = to_decoder(sd);
> struct v4l2_captureparm *cparm;
> enum tvp514x_std current_std;
>
> @@ -1105,7 +1070,7 @@ ioctl_g_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a)
> a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
>
> /* get the current standard */
> - current_std = tvp514x_get_current_std(decoder);
> + current_std = tvp514x_get_current_std(sd);
> if (current_std == STD_INVALID)
> return -EINVAL;
>
> @@ -1119,18 +1084,18 @@ ioctl_g_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a)
> return 0;
> }
>
> -/**
> - * ioctl_s_parm - V4L2 decoder interface handler for VIDIOC_S_PARM ioctl
> - * @s: pointer to standard V4L2 device structure
> +/*
> + * tvp514x_s_parm - V4L2 decoder interface handler for VIDIOC_S_PARM ioctl
> + * @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
> -ioctl_s_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a)
> +tvp514x_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
> {
> - struct tvp514x_decoder *decoder = s->priv;
> + struct tvp514x_decoder *decoder = to_decoder(sd);
> struct v4l2_fract *timeperframe;
> enum tvp514x_std current_std;
>
> @@ -1143,7 +1108,7 @@ ioctl_s_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a)
> timeperframe = &a->parm.capture.timeperframe;
>
> /* get the current standard */
> - current_std = tvp514x_get_current_std(decoder);
> + current_std = tvp514x_get_current_std(sd);
> if (current_std == STD_INVALID)
> return -EINVAL;
>
> @@ -1155,112 +1120,59 @@ ioctl_s_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a)
> 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) {
> - v4l_err(decoder->client, "g_ifparm.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
> +/*
> + * tvp514x_s_stream - V4L2 decoder interface handler for vidioc_int_s_power_num
> + * @sd: pointer to standard V4L2 sub-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)
> +static int tvp514x_s_stream(struct v4l2_subdev *sd, int enable)
> {
> - struct tvp514x_decoder *decoder = s->priv;
> int err = 0;
> + struct i2c_client *client = v4l2_get_subdevdata(sd);
> + struct tvp514x_decoder *decoder = to_decoder(sd);
>
> - 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);
> - decoder->state = STATE_NOT_DETECTED;
> - break;
> + if (decoder->state == enable)
> + return 0;
>
> - case V4L2_POWER_STANDBY:
> - if (decoder->pdata->power_set)
> - err = decoder->pdata->power_set(on);
> + 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->state = enable;
I suggest renaming 'state' to 'streaming'. The name 'state' is too generic:
I didn't understand what it meant until I saw this assignment.
> break;
> + }
> + case 1:
> + {
> + struct tvp514x_reg *int_seq = (struct tvp514x_reg *)
> + client->driver->id_table->driver_data;
>
> - case V4L2_POWER_ON:
> - /* Enable mux for TVP5146/47 decoder data path */
> - if ((decoder->pdata->power_set) &&
> - (decoder->state == STATE_NOT_DETECTED)) {
> - int i;
> - struct tvp514x_init_seq *int_seq =
> - (struct tvp514x_init_seq *)
> - decoder->id->driver_data;
> -
> - err = decoder->pdata->power_set(on);
> -
> - /* Power Up Sequence */
> - for (i = 0; i < int_seq->no_regs; i++) {
> - err |= tvp514x_write_reg(decoder->client,
> - int_seq->init_reg_seq[i].reg,
> - int_seq->init_reg_seq[i].val);
> - }
> - /* Detect the sensor is not already detected */
> - err |= tvp514x_detect(decoder);
> - if (err) {
> - v4l_err(decoder->client,
> - "Unable to detect decoder\n");
> - return err;
> - }
> + /* Power Up Sequence */
> + err = tvp514x_write_regs(sd, int_seq);
> + if (err) {
> + v4l2_err(sd, "Unable to turn on decoder\n");
> + return err;
> + }
> + /* Detect the sensor is not already detected */
'sensor'??? And the comment is confusing in any case: '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;
> }
> - err |= tvp514x_configure(decoder);
> + decoder->state = enable;
> break;
> -
> + }
> default:
> err = -ENODEV;
> break;
> @@ -1269,93 +1181,37 @@ static int ioctl_s_power(struct v4l2_int_device *s, enum v4l2_power on)
> 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 */
> - decoder->tvp514x_regs[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) {
> - v4l_err(decoder->client,
> - "Unable to detect decoder\n");
> - return err;
> - }
> -
> - v4l_info(decoder->client,
> - "chip version 0x%.2x detected\n", decoder->ver);
> +static const struct v4l2_subdev_core_ops tvp514x_core_ops = {
> + .queryctrl = tvp514x_queryctrl,
> + .g_ctrl = tvp514x_g_ctrl,
> + .s_ctrl = tvp514x_s_ctrl,
> + .s_std = tvp514x_s_std,
> +};
>
> - return 0;
> -}
> +static const struct v4l2_subdev_video_ops tvp514x_video_ops = {
> + .s_routing = tvp514x_s_routing,
> + .querystd = tvp514x_querystd,
> + .enum_fmt = tvp514x_enum_fmt_cap,
> + .g_fmt = tvp514x_g_fmt_cap,
> + .try_fmt = tvp514x_try_fmt_cap,
> + .s_fmt = tvp514x_s_fmt_cap,
> + .g_parm = tvp514x_g_parm,
> + .s_parm = tvp514x_s_parm,
> + .s_stream = tvp514x_s_stream,
> +};
>
> -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_s_video_routing_num,
> - (v4l2_int_ioctl_func *) ioctl_s_routing},
> +static const struct v4l2_subdev_ops tvp514x_ops = {
> + .core = &tvp514x_core_ops,
> + .video = &tvp514x_video_ops,
> };
>
> static struct tvp514x_decoder tvp514x_dev = {
> - .state = STATE_NOT_DETECTED,
> + .state = 0,
>
> .fmt_list = tvp514x_fmt_list,
> .num_fmts = ARRAY_SIZE(tvp514x_fmt_list),
>
> - .pix = { /* Default to NTSC 8-bit YUV 422 */
> + .pix = {/* Default to NTSC 8-bit YUV 422 */
> .width = NTSC_NUM_ACTIVE_PIXELS,
> .height = NTSC_NUM_ACTIVE_LINES,
> .pixelformat = V4L2_PIX_FMT_UYVY,
> @@ -1369,20 +1225,13 @@ static struct tvp514x_decoder tvp514x_dev = {
> .current_std = STD_NTSC_MJ,
> .std_list = tvp514x_std_list,
> .num_stds = ARRAY_SIZE(tvp514x_std_list),
> - .v4l2_int_device = {
> - .module = THIS_MODULE,
> - .name = TVP514X_MODULE_NAME,
> - .type = v4l2_int_type_slave,
> - },
> - .tvp514x_slave = {
> - .ioctls = tvp514x_ioctl_desc,
> - .num_ioctls = ARRAY_SIZE(tvp514x_ioctl_desc),
> - },
> +
> };
>
> -/**
> +/*
> * 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.
> @@ -1391,67 +1240,59 @@ static int
> tvp514x_probe(struct i2c_client *client, const struct i2c_device_id *id)
> {
> struct tvp514x_decoder *decoder;
> - int err;
> + struct v4l2_subdev *sd;
>
> /* 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;
>
> - if (!client->dev.platform_data) {
> - v4l_err(client, "No platform data!!\n");
> - err = -ENODEV;
> - goto out_free;
> - }
> -
> + /*
> + * Initialize the tvp514x_decoder with default configuration
> + */
> *decoder = tvp514x_dev;
> - decoder->v4l2_int_device.priv = decoder;
> - decoder->pdata = client->dev.platform_data;
> - decoder->v4l2_int_device.u.slave = &decoder->tvp514x_slave;
> + /* 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->pdata->clk_polarity << 1);
> decoder->tvp514x_regs[REG_SYNC_CONTROL].val |=
> - ((decoder->pdata->hs_polarity << 2) |
> - (decoder->pdata->vs_polarity << 3));
> - /*
> - * Save the id data, required for power up sequence
> - */
> - decoder->id = (struct i2c_device_id *)id;
> - /* Attach to Master */
> - strcpy(decoder->v4l2_int_device.u.slave->attach_to,
> - decoder->pdata->master);
> - decoder->client = client;
> - i2c_set_clientdata(client, decoder);
> + ((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 */
> - err = v4l2_int_device_register(&decoder->v4l2_int_device);
> - if (err) {
> - i2c_set_clientdata(client, NULL);
> - v4l_err(client,
> - "Unable to register to v4l2. Err[%d]\n", err);
> - goto out_free;
> -
> - } else
> - v4l_info(client, "Registered to v4l2 master %s!!\n",
> - decoder->pdata->master);
> + sd = &decoder->sd;
> + v4l2_i2c_subdev_init(sd, client, &tvp514x_ops);
> +
> + v4l2_info(sd, "%s decoder driver registered !!\n", sd->name);
> +
> return 0;
>
> -out_free:
> - kfree(decoder);
> - return err;
> }
>
> -/**
> +/*
> * tvp514x_remove - decoder driver i2c remove handler
> * @client: i2c driver client device structure
> *
> @@ -1460,13 +1301,10 @@ out_free:
> */
> static int __exit tvp514x_remove(struct i2c_client *client)
> {
> - struct tvp514x_decoder *decoder = i2c_get_clientdata(client);
> + struct v4l2_subdev *sd = i2c_get_clientdata(client);
> + struct tvp514x_decoder *decoder = to_decoder(sd);
>
> - if (!client->adapter)
> - return -ENODEV; /* our client isn't attached */
> -
> - v4l2_int_device_unregister(&decoder->v4l2_int_device);
> - i2c_set_clientdata(client, NULL);
> + v4l2_device_unregister_subdev(sd);
> kfree(decoder);
> return 0;
> }
> @@ -1485,11 +1323,9 @@ static const struct tvp514x_reg tvp5146_init_reg_seq[] = {
> {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},
> };
> -static const struct tvp514x_init_seq tvp5146_init = {
> - .no_regs = ARRAY_SIZE(tvp5146_init_reg_seq),
> - .init_reg_seq = tvp5146_init_reg_seq,
> -};
> +
> /*
> * TVP5147 Init/Power on Sequence
> */
> @@ -1512,22 +1348,18 @@ static const struct tvp514x_reg tvp5147_init_reg_seq[] = {
> {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},
> };
> -static const struct tvp514x_init_seq tvp5147_init = {
> - .no_regs = ARRAY_SIZE(tvp5147_init_reg_seq),
> - .init_reg_seq = tvp5147_init_reg_seq,
> -};
> +
> /*
> * 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},
> };
> -static const struct tvp514x_init_seq tvp514xm_init = {
> - .no_regs = ARRAY_SIZE(tvp514xm_init_reg_seq),
> - .init_reg_seq = tvp514xm_init_reg_seq,
> -};
> +
> /*
> * I2C Device Table -
> *
> @@ -1535,48 +1367,22 @@ static const struct tvp514x_init_seq tvp514xm_init = {
> * driver_data - Driver data
> */
> static const struct i2c_device_id tvp514x_id[] = {
> - {"tvp5146", (unsigned long)&tvp5146_init},
> - {"tvp5146m2", (unsigned long)&tvp514xm_init},
> - {"tvp5147", (unsigned long)&tvp5147_init},
> - {"tvp5147m1", (unsigned long)&tvp514xm_init},
> + {"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_i2c_driver = {
> - .driver = {
> - .name = TVP514X_MODULE_NAME,
> - .owner = THIS_MODULE,
> - },
> +static struct v4l2_i2c_driver_data v4l2_i2c_data = {
> + .name = TVP514X_MODULE_NAME,
Please don't use v4l2_i2c_driver_data. That is only necessary if this module
has to support pre-2.6.26 kernels. Since this driver will never be built for
such older kernels there is also no need to use this struct. Do it the same
as was done in the ths7303 driver, i.e. as a regular i2c driver.
Don't forget to remove the media/v4l2-i2c-drv.h include!
> .probe = tvp514x_probe,
> .remove = __exit_p(tvp514x_remove),
> .id_table = tvp514x_id,
> };
>
> -/**
> - * tvp514x_init
> - *
> - * Module init function
> - */
> -static int __init tvp514x_init(void)
> -{
> - return i2c_add_driver(&tvp514x_i2c_driver);
> -}
> -
> -/**
> - * 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/drivers/media/video/tvp514x_regs.h b/drivers/media/video/tvp514x_regs.h
> index 351620a..18f29ad 100644
> --- a/drivers/media/video/tvp514x_regs.h
> +++ b/drivers/media/video/tvp514x_regs.h
> @@ -284,14 +284,4 @@ struct tvp514x_reg {
> u32 val;
> };
>
> -/**
> - * struct tvp514x_init_seq - Structure for TVP5146/47/46M2/47M1 power up
> - * Sequence.
> - * @ no_regs - Number of registers to write for power up sequence.
> - * @ init_reg_seq - Array of registers and respective value to write.
> - */
> -struct tvp514x_init_seq {
> - unsigned int no_regs;
> - const struct tvp514x_reg *init_reg_seq;
> -};
> #endif /* ifndef _TVP514X_REGS_H */
> diff --git a/include/media/tvp514x.h b/include/media/tvp514x.h
> index 5e7ee96..74387e8 100644
> --- a/include/media/tvp514x.h
> +++ b/include/media/tvp514x.h
> @@ -104,10 +104,6 @@ enum tvp514x_output {
> * @ vs_polarity: VSYNC Polarity configuration for current interface.
> */
> struct tvp514x_platform_data {
> - char *master;
> - int (*power_set) (enum v4l2_power on);
> - int (*ifparm) (struct v4l2_ifparm *p);
> - int (*priv_data_set) (void *);
> /* Interface control params */
> bool clk_polarity;
> bool hs_polarity;
> --
> 1.6.2.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-media" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
Other than the four small points I mentioned it is OK. Just fix those and
I'm happy with it.
Reviewed-by: Hans Verkuil <hverkuil@xs4all.nl>
Regards,
Hans
--
Hans Verkuil - video4linux developer - sponsored by TANDBERG Telecom
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH (V2)] TVP514x: Migration to sub-device framework
2009-06-14 10:14 ` Hans Verkuil
@ 2009-06-14 12:44 ` Hans Verkuil
2009-06-14 14:32 ` tcm825x.c: migrating to sub-device framework? (was: TVP514x: Migration to sub-device framework) Hans Verkuil
[not found] ` <200906141214.38355.hverkuil-qWit8jRvyhVmR6Xm/wNWPw@public.gmane.org>
1 sibling, 1 reply; 28+ messages in thread
From: Hans Verkuil @ 2009-06-14 12:44 UTC (permalink / raw)
To: hvaibhav
Cc: linux-media, linux-omap, davinci-linux-open-source, Brijesh Jadav,
Hardik Shah
On Sunday 14 June 2009 12:14:38 Hans Verkuil wrote:
> On Wednesday 06 May 2009 20:31:33 hvaibhav@ti.com wrote:
> > From: Vaibhav Hiremath <hvaibhav@ti.com>
> >
> > This patch converts TVP514x driver to sub-device framework
> > from V4L2-int framework.
> >
> > NOTE: Please note that this patch has not been tested on any board,
> > only compilation/build tested.
> >
> > Changes (From Previous post):
> > - Added static function to_decoder which will replace all
> > container_of instances.
> > - "unsigned int" replaced with "u32".
> > - Cleaned up for line indentation.
> > - pdata initialized, was missing in earlier patch.
> >
> > TODO:
> > - Add support for some basic video/core functionality like,
> > .g_chip_ident
> > .reset
> > .g_input_status
> > - Migration master driver to validate this driver.
> > - validate on Davinci and OMAP boards.
> >
> > Reviewed By "Hans Verkuil".
> >
> > Signed-off-by: Brijesh Jadav <brijesh.j@ti.com>
> > Signed-off-by: Hardik Shah <hardik.shah@ti.com>
> > Signed-off-by: Vaibhav Hiremath <hvaibhav@ti.com>
> > ---
> > drivers/media/video/tvp514x.c | 854 ++++++++++++++----------------------
> > drivers/media/video/tvp514x_regs.h | 10 -
> > include/media/tvp514x.h | 4 -
> > 3 files changed, 330 insertions(+), 538 deletions(-)
> >
> > diff --git a/drivers/media/video/tvp514x.c b/drivers/media/video/tvp514x.c
> > index 4262e60..12b49ad 100644
> > --- a/drivers/media/video/tvp514x.c
> > +++ b/drivers/media/video/tvp514x.c
<snip>
> > +/*
> > * tvp514x_remove - decoder driver i2c remove handler
> > * @client: i2c driver client device structure
> > *
> > @@ -1460,13 +1301,10 @@ out_free:
> > */
> > static int __exit tvp514x_remove(struct i2c_client *client)
This can't be __exit since it is called when the adapter is removed, not when
the driver is removed. And that's perfectly valid even if this driver is
compiled in the kernel instead of as a module.
> > {
> > - struct tvp514x_decoder *decoder = i2c_get_clientdata(client);
> > + struct v4l2_subdev *sd = i2c_get_clientdata(client);
> > + struct tvp514x_decoder *decoder = to_decoder(sd);
> >
> > - if (!client->adapter)
> > - return -ENODEV; /* our client isn't attached */
> > -
> > - v4l2_int_device_unregister(&decoder->v4l2_int_device);
> > - i2c_set_clientdata(client, NULL);
> > + v4l2_device_unregister_subdev(sd);
> > kfree(decoder);
> > return 0;
> > }
> > @@ -1485,11 +1323,9 @@ static const struct tvp514x_reg tvp5146_init_reg_seq[] = {
> > {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},
> > };
> > -static const struct tvp514x_init_seq tvp5146_init = {
> > - .no_regs = ARRAY_SIZE(tvp5146_init_reg_seq),
> > - .init_reg_seq = tvp5146_init_reg_seq,
> > -};
> > +
> > /*
> > * TVP5147 Init/Power on Sequence
> > */
> > @@ -1512,22 +1348,18 @@ static const struct tvp514x_reg tvp5147_init_reg_seq[] = {
> > {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},
> > };
> > -static const struct tvp514x_init_seq tvp5147_init = {
> > - .no_regs = ARRAY_SIZE(tvp5147_init_reg_seq),
> > - .init_reg_seq = tvp5147_init_reg_seq,
> > -};
> > +
> > /*
> > * 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},
> > };
> > -static const struct tvp514x_init_seq tvp514xm_init = {
> > - .no_regs = ARRAY_SIZE(tvp514xm_init_reg_seq),
> > - .init_reg_seq = tvp514xm_init_reg_seq,
> > -};
> > +
> > /*
> > * I2C Device Table -
> > *
> > @@ -1535,48 +1367,22 @@ static const struct tvp514x_init_seq tvp514xm_init = {
> > * driver_data - Driver data
> > */
> > static const struct i2c_device_id tvp514x_id[] = {
> > - {"tvp5146", (unsigned long)&tvp5146_init},
> > - {"tvp5146m2", (unsigned long)&tvp514xm_init},
> > - {"tvp5147", (unsigned long)&tvp5147_init},
> > - {"tvp5147m1", (unsigned long)&tvp514xm_init},
> > + {"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_i2c_driver = {
> > - .driver = {
> > - .name = TVP514X_MODULE_NAME,
> > - .owner = THIS_MODULE,
> > - },
> > +static struct v4l2_i2c_driver_data v4l2_i2c_data = {
> > + .name = TVP514X_MODULE_NAME,
>
> Please don't use v4l2_i2c_driver_data. That is only necessary if this module
> has to support pre-2.6.26 kernels. Since this driver will never be built for
> such older kernels there is also no need to use this struct. Do it the same
> as was done in the ths7303 driver, i.e. as a regular i2c driver.
>
> Don't forget to remove the media/v4l2-i2c-drv.h include!
>
> > .probe = tvp514x_probe,
> > .remove = __exit_p(tvp514x_remove),
__exit_p should not be used.
> > .id_table = tvp514x_id,
> > };
Regards,
Hans
--
Hans Verkuil - video4linux developer - sponsored by TANDBERG Telecom
^ permalink raw reply [flat|nested] 28+ messages in thread
* tcm825x.c: migrating to sub-device framework? (was: TVP514x: Migration to sub-device framework)
2009-06-14 12:44 ` Hans Verkuil
@ 2009-06-14 14:32 ` Hans Verkuil
2009-06-15 8:45 ` tcm825x.c: migrating to sub-device framework? Sakari Ailus
0 siblings, 1 reply; 28+ messages in thread
From: Hans Verkuil @ 2009-06-14 14:32 UTC (permalink / raw)
To: hvaibhav
Cc: linux-media, linux-omap, davinci-linux-open-source, Brijesh Jadav,
Hardik Shah, Sakari Ailus
On Sunday 14 June 2009 14:44:53 Hans Verkuil wrote:
> On Sunday 14 June 2009 12:14:38 Hans Verkuil wrote:
> > On Wednesday 06 May 2009 20:31:33 hvaibhav@ti.com wrote:
> > > From: Vaibhav Hiremath <hvaibhav@ti.com>
> > >
> > > This patch converts TVP514x driver to sub-device framework
> > > from V4L2-int framework.
Now that tvp514x is converted to using v4l2_subdev (pending a few small final
tweaks) there is only one driver left that uses the v4l2-int-device.h API:
tcm825x.c.
What is involved in converting this driver as well? And who can do this?
Regards,
Hans
--
Hans Verkuil - video4linux developer - sponsored by TANDBERG Telecom
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH (V2)] TVP514x: Migration to sub-device framework
[not found] ` <200906141214.38355.hverkuil-qWit8jRvyhVmR6Xm/wNWPw@public.gmane.org>
@ 2009-06-14 19:50 ` David Brownell
0 siblings, 0 replies; 28+ messages in thread
From: David Brownell @ 2009-06-14 19:50 UTC (permalink / raw)
To: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/
Cc: linux-omap-u79uwXL29TY76Z2rM5mHXA,
linux-media-u79uwXL29TY76Z2rM5mHXA
On Sunday 14 June 2009, Hans Verkuil wrote:
> > +#define dump_reg(sd, reg, val) \
> > do { \
> > - val = tvp514x_read_reg(client, reg); \
> > - v4l_info(client, "Reg(0x%.2X): 0x%.2X\n", reg, val); \
> > + val = tvp514x_read_reg(sd, reg); \
> > + v4l2_info(sd, "Reg(0x%.2X): 0x%.2X\n", reg, val); \
> > } while (0)
>
> Why not turn this into a static inline function? Much better than a macro.
IMO, too big for either. Make it a real function.
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: tcm825x.c: migrating to sub-device framework?
2009-06-14 14:32 ` tcm825x.c: migrating to sub-device framework? (was: TVP514x: Migration to sub-device framework) Hans Verkuil
@ 2009-06-15 8:45 ` Sakari Ailus
0 siblings, 0 replies; 28+ messages in thread
From: Sakari Ailus @ 2009-06-15 8:45 UTC (permalink / raw)
To: Hans Verkuil
Cc: hvaibhav, linux-media, linux-omap, davinci-linux-open-source,
Brijesh Jadav, Hardik Shah
Hans Verkuil wrote:
> On Sunday 14 June 2009 14:44:53 Hans Verkuil wrote:
>> On Sunday 14 June 2009 12:14:38 Hans Verkuil wrote:
>>> On Wednesday 06 May 2009 20:31:33 hvaibhav@ti.com wrote:
>>>> From: Vaibhav Hiremath <hvaibhav@ti.com>
>>>>
>>>> This patch converts TVP514x driver to sub-device framework
>>>> from V4L2-int framework.
>
> Now that tvp514x is converted to using v4l2_subdev (pending a few small final
> tweaks) there is only one driver left that uses the v4l2-int-device.h API:
> tcm825x.c.
There's also the OMAP 2 camera driver (master),
drivers/media/video/omap24xxcam.c. The tcm825x is the slave driver that
is used in conjunction with omap24xxcam on N800 and N810.
--
Sakari Ailus
sakari.ailus@maxwell.research.nokia.com
^ permalink raw reply [flat|nested] 28+ messages in thread
end of thread, other threads:[~2009-06-15 8:45 UTC | newest]
Thread overview: 28+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <hvaibhav@ti.com>
2008-11-21 15:22 ` [PATCH 2/2] TVP514x V4L int device driver support hvaibhav
2008-11-21 16:16 ` Hans Verkuil
2008-11-21 18:12 ` Trilok Soni
2008-11-21 19:07 ` Hiremath, Vaibhav
2008-11-21 19:11 ` David Brownell
2008-11-23 22:00 ` Hans Verkuil
2008-11-23 22:04 ` Koen Kooi
2008-11-24 6:16 ` Trilok Soni
2008-11-24 6:32 ` David Brownell
2008-11-24 7:53 ` Hans Verkuil
2008-11-24 8:53 ` Hiremath, Vaibhav
2008-11-24 8:04 ` Hans Verkuil
2008-11-24 8:43 ` Trilok Soni
2008-11-24 8:59 ` Hiremath, Vaibhav
2008-11-24 10:06 ` David Brownell
2008-11-26 17:05 ` [PATCH 2/2] TVP514x Driver with Review comments fixed hvaibhav
2008-11-26 17:48 ` Hans Verkuil
2008-12-02 15:35 ` [PATCH 2/2] TVP514x Driver with Review comments fixed [V4] hvaibhav
2008-12-02 17:20 ` Hans Verkuil
2008-12-03 3:58 ` Hiremath, Vaibhav
2008-12-02 19:29 ` David Brownell
2008-12-02 19:44 ` David Brownell
2009-05-06 18:31 ` [PATCH (V2)] TVP514x: Migration to sub-device framework hvaibhav
2009-06-14 10:14 ` Hans Verkuil
2009-06-14 12:44 ` Hans Verkuil
2009-06-14 14:32 ` tcm825x.c: migrating to sub-device framework? (was: TVP514x: Migration to sub-device framework) Hans Verkuil
2009-06-15 8:45 ` tcm825x.c: migrating to sub-device framework? Sakari Ailus
[not found] ` <200906141214.38355.hverkuil-qWit8jRvyhVmR6Xm/wNWPw@public.gmane.org>
2009-06-14 19:50 ` [PATCH (V2)] TVP514x: Migration to sub-device framework David Brownell
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox