]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - android-sdk/kernel-video.git/commitdiff
i2c: tvp5158: Analog camera decoder driver
authorSathishkumar S <sathish.omap@gmail.com>
Sat, 31 Jan 2015 13:40:48 +0000 (19:10 +0530)
committerGerrit Code Review <gerrit2@DLEZVX23.itg.ti.com>
Wed, 27 May 2015 12:13:15 +0000 (07:13 -0500)
Add support for TVP5158 video decoder. This driver
does the default initialization for single channel
NTSC decode. It is tested with NTSC camera source.

Change-Id: Ia5f6bd038a5bcd5e7571afdc5447acbf575a97ef
Signed-off-by: Sathishkumar S <sathish.omap@gmail.com>
[Added multi channel support]
Signed-off-by: Nikhil Devshatwar <nikhil.nd@ti.com>
Documentation/devicetree/bindings/media/i2c/tvp5158.txt [new file with mode: 0644]
drivers/media/i2c/Kconfig
drivers/media/i2c/Makefile
drivers/media/i2c/tvp5158.c [new file with mode: 0644]

diff --git a/Documentation/devicetree/bindings/media/i2c/tvp5158.txt b/Documentation/devicetree/bindings/media/i2c/tvp5158.txt
new file mode 100644 (file)
index 0000000..833dbcd
--- /dev/null
@@ -0,0 +1,34 @@
+* Texas Instruments TVP5158 video decoder
+
+The TVP5158 device is high quality, single-chip
+digital video decoder that digitizes and decodes all popular baseband analog
+video formats into digital video component. The tvp5158 decoder supports
+decoding of NTSC, PAL and SECAM composite and S-video.
+
+TVP5158 generates output in BT656 format with embedded sync.
+
+Required Properties :
+- compatible : Must be "ti,tvp5158"
+
+Optional Properties :
+  There are no custom optional properties although the driver supports
+  standard endpoint properties as documented in
+  Documentation/devicetree/bindings/media/video-interfaces.txt
+
+Example:
+
+       &i2c2 {
+               ...
+               ...
+               tvp5158@5c {
+                       compatible = "ti,tvp5158";
+                       reg = <0x58>;
+
+                       port {
+                               tvp_decoder: endpoint {
+                                       /* No properties for BT 656 */
+                               };
+                       };
+               };
+               ...
+       };
index 70a36cfe43a65f39c8ab6add0f015e0099f7a566..47a4282c706cbb9f307b7a8c8913dbc860c85533 100644 (file)
@@ -313,6 +313,17 @@ config VIDEO_TVP5150
          To compile this driver as a module, choose M here: the
          module will be called tvp5150.
 
+config VIDEO_TVP5158
+       tristate "Analog video decoder TVP5158 support NTSC/PAL"
+       depends on I2C && VIDEO_V4L2
+       depends on MEDIA_CAMERA_SUPPORT
+       ---help---
+       This is a Video4Linux2 subdevice driver for the TVP5158
+       NTSC/PAL video decoder.
+
+       To compile this driver as a module, choose M here: the
+       module will be called tvp5158.
+
 config VIDEO_TVP7002
        tristate "Texas Instruments TVP7002 video decoder"
        depends on VIDEO_V4L2 && I2C
index cd17c1fdaad87965a4f81083f0c631c06c20b08d..e7e1975016a6876ea583efa73114a005b2aafdfb 100644 (file)
@@ -40,6 +40,7 @@ obj-$(CONFIG_VIDEO_THS7303) += ths7303.o
 obj-$(CONFIG_VIDEO_THS8200) += ths8200.o
 obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o
 obj-$(CONFIG_VIDEO_TVP514X) += tvp514x.o
+obj-$(CONFIG_VIDEO_TVP5158) += tvp5158.o
 obj-$(CONFIG_VIDEO_TVP7002) += tvp7002.o
 obj-$(CONFIG_VIDEO_TW2804) += tw2804.o
 obj-$(CONFIG_VIDEO_TW9903) += tw9903.o
diff --git a/drivers/media/i2c/tvp5158.c b/drivers/media/i2c/tvp5158.c
new file mode 100644 (file)
index 0000000..0a37a48
--- /dev/null
@@ -0,0 +1,676 @@
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/videodev2.h>
+
+#include <media/soc_camera.h>
+#include <media/v4l2-async.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ctrls.h>
+
+#include <linux/pm_runtime.h>
+
+#include <linux/of_gpio.h>
+#include <linux/of_device.h>
+
+/* Debug functions */
+static bool debug;
+module_param(debug, bool, 0644);
+MODULE_PARM_DESC(debug, "Debug level (0-2)");
+
+/* VBUS Register Address (24-bit), VBUS Register value (8-bit) */
+struct vbus_addr_value {
+       unsigned int addr;
+       unsigned char val;
+};
+
+struct vbus_addr_value vbus_addr_value_set[] = {
+       {0x00403E50, 0x40},
+       {0x00403E51, 0x00},
+       {0x00403E52, 0x40},
+       {0x00403E53, 0x00},
+       {0x00403E54, 0x44},
+       {0x00403E55, 0x23},
+       {0x00403E56, 0x38},
+       {0x00403E57, 0x10},
+       {0x00403E58, 0x53},
+       {0x00403E59, 0x23},
+       {0x00403E5A, 0x02},
+       {0x00403E5B, 0x00},
+       {0x00403E5C, 0x20},
+       {0x00403E5D, 0x00},
+       {0x00403E5E, 0x04},
+       {0x00403E5F, 0x04},
+       {0x00403E60, 0x04},
+       {0x00403E61, 0x04},
+       {0x00403E62, 0x10},
+       {0x00403E63, 0xF8},
+       {0x00403E64, 0x30},
+       {0x00403E65, 0x20},
+       {0x00403E66, 0x30},
+       {0x00403E67, 0x3F},
+       {0x00403E68, 0x3F},
+       {0x00403E69, 0x3F},
+       {0x00403E6A, 0x0C},
+       {0x00403E6B, 0x0C},
+       {0x00403E6C, 0x80},
+       {0x00403E6D, 0x80},
+       {0x00403E6E, 0x08},
+       {0x00403E6F, 0x08},
+       {0x00403E70, 0x08},
+       {0x00403E71, 0x30},
+       {0x00403E72, 0x08},
+       {0x00403E73, 0x04},
+       {0x00403E74, 0x00},
+       {0x00403E75, 0x10},
+       {0x00403E76, 0x00},
+       {0x00403E77, 0x00},
+       {0x00403E78, 0x38},
+       {0x00403E79, 0x00},
+       {0x00403E7A, 0x55},
+       {0x00403E7B, 0x03},
+       {0x00403E7C, 0x03},
+       {0x00403E7D, 0x00},
+       {0x00403E7E, 0x03},
+       {0x00403E7F, 0x00},
+       {0x00403E80, 0x30},
+       {0x00403E81, 0x30},
+       {0x00403E82, 0x18},
+       {0x00403E83, 0x0C},
+       {0x00403E95, 0x00},
+       {0x00403E96, 0x00},
+       {0x00403E9B, 0x3F},
+       {0x00403EA2, 0x0C},
+       {0x00403EA3, 0x10},
+       {0x00403EA6, 0x0C},
+       {0x00403EA7, 0x10},
+       {0x00403EA8, 0x44},
+       {0x00403EA9, 0x00},
+};
+static bool vbus_prog = 1;
+static int
+tvp5158_get_gpios(struct device_node *node, struct i2c_client *client);
+static int tvp5158_set_gpios(struct i2c_client *client);
+static int
+tvp5158_set_default(struct i2c_client *client, unsigned char core);
+static enum tvp5158_std
+tvp5158_get_video_std(struct i2c_client *client, unsigned char core);
+static void
+tvp5158_start_streaming(struct i2c_client *client, unsigned char core);
+static int
+tvp5158_set_int_regs(struct i2c_client *client, struct vbus_addr_value *reg,
+                       int cnt);
+
+#define REG_STAUS_1    0x00
+#define REG_STAUS_2    0x01
+#define REG_VID_STAND  0x0C
+#define REG_CHIPID_MSB 0x08
+#define REG_CHIPID_LSB 0x09
+#define REG_AVD_CTRL_1 0xB0
+#define REG_AVD_CTRL_2 0xB1
+#define REG_OFM_CTRL   0xB2
+#define REG_DEC_RD_EN  0xFF
+#define REG_DEC_WR_EN  0xFE
+#define REG_VBUS_1     0xE8
+#define REG_VBUS_2     0xE9
+#define REG_VBUS_3     0xEA
+#define REG_VBUS_DATA  0xE0
+
+#define TVP_CORE_ALL           0x0F
+#define TVP_DECODER_1          (1<<0)
+/* Non interleaved */
+#define TVP_INTERLEAVE_MODE_NON                (0<<6)
+#define TVP_INTERLEAVE_MODE_PIX                (1<<6)
+#define TVP_INTERLEAVE_MODE_LINE       (2<<6)
+/* Number of time multiplexed channels = 0 */
+#define TVP_CH_MUX_NUMBER      (2<<4)
+/* ITU BT 656 8 bit */
+#define TVP_OUTPUT_TYPE                (0<<3)
+/* Single stage */
+#define TVP_VCS_ID             (0<<2)
+/* D1 */
+#define TVP_VID_RES            (0<<0)
+
+#define TVP_ENABLE_DITHERING   (1<<4)
+#define TVP_VID_DET_SAVEAV_EN  (1<<0)
+
+#define TVP_VIDEO_PORT_ENABLE  (1<<0)
+#define TVP_OUT_CLK_P_EN       (1<<2)
+#define TVP_FIELD_RATE         (1<<5)
+#define TVP_SIGNAL_PRESENT     (1<<7)
+#define TVP_VIDEO_STANDARD_MASK        (0x07)
+
+/* Number of pixels and number of lines per frame for different standards */
+#define NTSC_NUM_ACTIVE_PIXELS  (720)
+#define NTSC_NUM_ACTIVE_LINES   (480)
+
+struct tvp5158_color_format {
+       enum v4l2_mbus_pixelcode code;
+       enum v4l2_colorspace colorspace;
+};
+
+static const struct tvp5158_color_format tvp5158_cfmts[] = {
+       {
+               .code           = V4L2_MBUS_FMT_YUYV8_2X8,
+               .colorspace     = V4L2_COLORSPACE_SMPTE170M,
+       },
+       {
+               .code           = V4L2_MBUS_FMT_YUYV10_2X10,
+               .colorspace     = V4L2_COLORSPACE_SMPTE170M,
+       },
+};
+
+/* enum tvp5158_std - enum for supported standards */
+enum tvp5158_std {
+       STD_NTSC_MJ = 0,
+       STD_PAL_BDGHIN,
+       STD_INVALID
+};
+
+/**
+ * struct tvp5158_std_info - Structure to store standard informations
+ * @width: Line width in pixels
+ * @height:Number of active lines
+ * @standard: v4l2 standard structure information
+ */
+struct tvp5158_std_info {
+       unsigned long width;
+       unsigned long height;
+       struct v4l2_standard standard;
+};
+
+enum tvp5158_signal_present {
+       TVP5158_SIGNAL_DEAD = 0,
+       TVP5158_SIGNAL_PRESENT
+};
+struct tvp5158_priv {
+       struct v4l2_subdev              subdev;
+       struct v4l2_async_subdev        asd;
+       struct v4l2_ctrl_handler        hdl;
+       int                             power;
+       int                             model;
+       int                             revision;
+       int                             width;
+       int                             height;
+       const char                      *sensor_name;
+       int                             cam_fpd_mux_s0_gpio;
+       int                             sel_tvp_fpd_s0;
+       enum                            tvp5158_std current_std;
+       enum                            tvp5158_signal_present signal_present;
+       const struct                    tvp5158_std_info *std_list;
+       const struct tvp5158_color_format       *cfmt;
+};
+
+static const struct tvp5158_std_info tvp5158_std_list[] = {
+/* Standard: STD_NTSC_MJ */
+[STD_NTSC_MJ] = {
+       .width = NTSC_NUM_ACTIVE_PIXELS,
+       .height = NTSC_NUM_ACTIVE_LINES,
+       .standard = {
+               .index = 0,
+               .id = V4L2_STD_NTSC,
+               .name = "NTSC",
+               .frameperiod = {1001, 30000},
+               .framelines = 525
+               },
+       },
+       /* Standard: need to add for additional standard */
+};
+
+static struct tvp5158_priv *to_tvp5158(const struct i2c_client *client)
+{
+       return container_of(i2c_get_clientdata(client), struct tvp5158_priv,
+                       subdev);
+}
+
+
+static int tvp5158_read(struct i2c_client *client, unsigned char addr)
+{
+       unsigned char buffer[1];
+       int rc;
+
+       buffer[0] = addr;
+
+       rc = i2c_master_send(client, buffer, 1);
+       if (rc < 0) {
+               dev_err(&client->dev, "i2c i/o error: rc == %d (should be 1)\n"
+               , rc);
+               return rc;
+       }
+
+       rc = i2c_master_recv(client, buffer, 1);
+       if (rc < 0) {
+               dev_err(&client->dev, "i2c i/o error: rc == %d (should be 1)\n"
+               , rc);
+               return rc;
+       }
+
+       return buffer[0];
+}
+static inline void tvp5158_write(struct i2c_client *client, unsigned char addr,
+                       unsigned char value)
+{
+       unsigned char buffer[2];
+       int rc;
+
+       buffer[0] = addr;
+       buffer[1] = value;
+       rc = i2c_master_send(client, buffer, 2);
+       if (rc != 2)
+               dev_err(&client->dev, "i2c i/o error: rc == %d (should be 2)\n"
+               , rc);
+}
+
+/**
+ * tvp5158_s_stream() - V4L2 decoder i/f handler for s_stream
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @enable: streaming enable or disable
+ *
+ * Sets streaming to enable or disable.
+ */
+static int tvp5158_s_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       if (enable) {
+               if (vbus_prog == 1)
+                       /* VBUS address value setting */
+                       tvp5158_set_int_regs(client, vbus_addr_value_set,
+                                       ARRAY_SIZE(vbus_addr_value_set));
+               tvp5158_start_streaming(client, TVP_CORE_ALL);
+       } else {
+               tvp5158_write(client, REG_OFM_CTRL, 0x0);
+       }
+
+       return 0;
+}
+
+/**
+ * tvp5158_querystd() - V4L2 decoder interface handler for querystd
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @std_id: standard V4L2 std_id ioctl enum
+ *
+ * Returns the current standard detected by TVP5146/47. If no active input is
+ * detected then *std_id is set to 0 and the function returns 0.
+ */
+static int tvp5158_querystd(struct v4l2_subdev *sd, v4l2_std_id *std_id)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct tvp5158_priv *priv = to_tvp5158(client);
+
+       if (std_id == NULL)
+               return -EINVAL;
+       *std_id = V4L2_STD_UNKNOWN;
+
+       tvp5158_get_video_std(client, TVP_CORE_ALL);
+       if (priv->current_std == STD_INVALID)
+               return -EINVAL;
+       *std_id = priv->std_list[0].standard.id;
+
+return 0;
+}
+
+/**
+ * tvp5158_g_parm() - V4L2 decoder interface handler for g_parm
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure
+ *
+ * Returns the decoder's video CAPTURE parameters.
+ */
+static int tvp5158_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct tvp5158_priv *priv = to_tvp5158(client);
+       struct v4l2_captureparm *cparm;
+       enum tvp5158_std current_std;
+
+       if (parms == NULL)
+               return -EINVAL;
+
+       if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               /* only capture is supported */
+               return -EINVAL;
+       if (priv->current_std == STD_INVALID)
+               return -EINVAL;
+       /* get the current standard */
+       current_std = priv->current_std;
+       cparm = &parms->parm.capture;
+       cparm->capability = V4L2_CAP_TIMEPERFRAME;
+       cparm->timeperframe =
+               priv->std_list[current_std].standard.frameperiod;
+
+       return 0;
+}
+
+/**
+ * tvp5158_s_parm() - V4L2 decoder interface handler for s_parm
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @a: pointer to standard V4L2 VIDIOC_S_PARM ioctl structure
+ *
+ * Configures the decoder to use the input parameters, if possible. If
+ * not possible, returns the appropriate error code.
+ */
+static int tvp5158_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct tvp5158_priv *priv = to_tvp5158(client);
+       struct v4l2_fract *timeperframe;
+       enum tvp5158_std current_std;
+
+       if (parms == NULL)
+               return -EINVAL;
+
+       if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               /* only capture is supported */
+               return -EINVAL;
+
+       timeperframe = &parms->parm.capture.timeperframe;
+
+       /* get the current standard */
+       current_std = priv->current_std;
+
+       *timeperframe =
+           priv->std_list[current_std].standard.frameperiod;
+
+       return 0;
+}
+
+/* set the format we will capture in */
+static int tvp5158_s_fmt(struct v4l2_subdev *sd,
+               struct v4l2_mbus_framefmt *mf)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct tvp5158_priv *priv = to_tvp5158(client);
+
+       tvp5158_set_gpios(client);
+       v4l2_info(&priv->subdev, "Currently only D1 resolution is supported\n");
+
+       return 0;
+}
+
+static int tvp5158_g_fmt(struct v4l2_subdev *sd,
+               struct v4l2_mbus_framefmt *mf)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct tvp5158_priv *priv = to_tvp5158(client);
+       enum tvp5158_std current_std;
+
+       if (priv->current_std == STD_INVALID)
+               return -EINVAL;
+       /* Calculate height and width based on current standard */
+       current_std = priv->current_std;
+       /* both fields alternating into separate buffers */
+       mf->field = V4L2_FIELD_ALTERNATE;
+       mf->code = tvp5158_cfmts[0].code;
+       mf->width = priv->std_list[current_std].width;
+       mf->height = priv->std_list[current_std].height;
+       mf->colorspace = tvp5158_cfmts[0].colorspace;
+
+       return 0;
+}
+
+static int tvp5158_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+                       enum v4l2_mbus_pixelcode *code)
+{
+       if (index >= ARRAY_SIZE(tvp5158_cfmts))
+               return -EINVAL;
+
+       *code = tvp5158_cfmts[0].code;
+
+       return 0;
+}
+
+static int tvp5158_get_gpios(struct device_node *node,
+                       struct i2c_client *client)
+{
+
+       struct tvp5158_priv *priv = to_tvp5158(client);
+       int gpio;
+
+       gpio = of_get_gpio(node, 0);
+       if (gpio_is_valid(gpio)) {
+               priv->cam_fpd_mux_s0_gpio = gpio;
+       } else {
+               dev_err(&client->dev, "failed to parse CAM_FPD_MUX_S0 gpio\n");
+               return -EINVAL;
+       }
+       gpio = of_get_gpio(node, 1);
+       if (gpio_is_valid(gpio)) {
+               priv->sel_tvp_fpd_s0 = gpio;
+       } else {
+               dev_err(&client->dev, "failed to parse TVP_FPD_MUX_S0 gpio\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int tvp5158_set_gpios(struct i2c_client *client)
+{
+
+       struct tvp5158_priv *priv = to_tvp5158(client);
+       struct gpio gpios[] = {
+               { priv->sel_tvp_fpd_s0, GPIOF_OUT_INIT_LOW,
+                       "tvp_fpd_mux_s0" },
+               { priv->cam_fpd_mux_s0_gpio, GPIOF_OUT_INIT_HIGH,
+                       "cam_fpd_mux_s0" },
+       };
+       int ret = -1;
+
+       ret = gpio_request_array(gpios, ARRAY_SIZE(gpios));
+       if (ret)
+               return ret;
+
+       gpio_free_array(gpios, ARRAY_SIZE(gpios));
+
+       return 0;
+}
+
+static struct v4l2_subdev_video_ops tvp5158_video_ops = {
+       .querystd       = tvp5158_querystd,
+       .enum_mbus_fmt  = tvp5158_enum_fmt,
+       .g_parm         = tvp5158_g_parm,
+       .s_parm         = tvp5158_s_parm,
+       .s_stream       = tvp5158_s_stream,
+       .g_mbus_fmt     = tvp5158_g_fmt,
+       .s_mbus_fmt     = tvp5158_s_fmt,
+       .try_mbus_fmt   = tvp5158_g_fmt,
+};
+
+static struct v4l2_subdev_ops tvp5158_subdev_ops = {
+       .video          = &tvp5158_video_ops,
+};
+
+static const struct i2c_device_id tvp5158_id[] = {
+       { "ti,tvp5158", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, tvp5158_id);
+
+static const struct of_device_id tvp5158_dt_id[] = {
+       {
+       .compatible   = "ti,tvp5158", .data = "tvp5158"
+       },
+       {
+       }
+};
+
+static int tvp5158_set_int_regs(struct i2c_client *client,
+                       struct vbus_addr_value *reg, int cnt)
+{
+       int i = 0;
+       /* Core Write enable*/
+       tvp5158_write(client, REG_DEC_WR_EN, TVP_CORE_ALL);
+       for (i = 0; i < cnt; i++) {
+               tvp5158_write(client, REG_VBUS_1, ((reg[i].addr >> 0) & 0xFF));
+               tvp5158_write(client, REG_VBUS_2, ((reg[i].addr >> 8) & 0xFF));
+               tvp5158_write(client, REG_VBUS_3, ((reg[i].addr >> 16) & 0xFF));
+               tvp5158_write(client, REG_VBUS_DATA, reg[i].val);
+       }
+       vbus_prog = 0;
+       return 0;
+}
+
+static int
+tvp5158_set_default(struct i2c_client *client, unsigned char core)
+{
+       unsigned char tvp_reg_val = 0;
+       /* Core Write enable*/
+       tvp5158_write(client, REG_DEC_WR_EN, core);
+       /* Set Video format */
+       tvp_reg_val = TVP_INTERLEAVE_MODE_LINE | TVP_CH_MUX_NUMBER
+                       | TVP_OUTPUT_TYPE | TVP_VCS_ID | TVP_VID_RES;
+       tvp5158_write(client, REG_AVD_CTRL_1, tvp_reg_val);
+       tvp_reg_val = 0;
+       tvp_reg_val = TVP_ENABLE_DITHERING | TVP_VID_DET_SAVEAV_EN;
+       tvp5158_write(client, REG_AVD_CTRL_2, tvp_reg_val);
+
+       return 0;
+}
+
+static enum tvp5158_std
+tvp5158_get_video_std(struct i2c_client *client, unsigned char core)
+{
+       struct tvp5158_priv *priv       = to_tvp5158(client);
+       int i2c_read = 0, ret = 0;
+
+       /* Core Read Enable */
+       tvp5158_write(client, REG_DEC_RD_EN, core);
+       /* Get Video Status */
+       i2c_read = tvp5158_read(client, REG_STAUS_2);
+       v4l2_dbg(1, debug, &priv->subdev, "%s\n",
+               (i2c_read & TVP_SIGNAL_PRESENT) ?
+               "Signal Present" : "Signal not present");
+       if (i2c_read & TVP_SIGNAL_PRESENT)
+               priv->signal_present = TVP5158_SIGNAL_PRESENT;
+       else {
+               priv->current_std = STD_INVALID;
+               return priv->current_std;
+       }
+       /* Get Video Standard */
+       ret = tvp5158_read(client, REG_VID_STAND);
+       i2c_read = tvp5158_read(client, REG_STAUS_1);
+       v4l2_dbg(1, debug, &priv->subdev, "Video Standard : %s %dHz\n",
+               (ret & TVP_VIDEO_STANDARD_MASK) == 1 ?
+               "NTSC 720x240 @" : "Unknown",
+               (i2c_read & TVP_FIELD_RATE) ? 50 : 60);
+       if (ret & TVP_VIDEO_STANDARD_MASK) {
+               priv->std_list = tvp5158_std_list;
+               priv->current_std = STD_NTSC_MJ;
+       } else
+               priv->current_std = STD_INVALID;
+
+       return priv->current_std;
+}
+
+static void
+tvp5158_start_streaming(struct i2c_client *client, unsigned char core)
+{
+       unsigned char tvp_reg_val = 0;
+
+       /* Decoder Write Enable */
+       tvp5158_write(client, REG_DEC_WR_EN, core);
+       /* Enable output stream on */
+       tvp_reg_val = TVP_VIDEO_PORT_ENABLE | TVP_OUT_CLK_P_EN;
+       tvp5158_write(client, REG_OFM_CTRL, tvp_reg_val);
+
+}
+
+static int tvp5158_probe(struct i2c_client *client,
+                        const struct i2c_device_id *did)
+{
+       struct tvp5158_priv *priv;
+       struct v4l2_subdev *sd;
+       struct device_node *node = client->dev.of_node;
+       int ret = -1;
+       int i2c_read;
+       union {
+               char buff[4];
+               int buffer;
+       } u_i2cbuf;
+
+       priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+       i2c_set_clientdata(client, priv);
+
+       priv->cfmt = &tvp5158_cfmts[0];
+
+       sd = &priv->subdev;
+
+       v4l2_i2c_subdev_init(sd, client, &tvp5158_subdev_ops);
+
+       ret = tvp5158_get_gpios(node, client);
+       if (ret) {
+               dev_err(&client->dev, "Unable to get gpios\n");
+               return ret;
+       }
+
+       ret = tvp5158_set_gpios(client);
+       if (ret) {
+               dev_err(&client->dev, "failed to set gpios ERR %d\n", ret);
+               return ret;
+       }
+
+       priv->signal_present = TVP5158_SIGNAL_DEAD;
+       priv->current_std = STD_INVALID;
+       /* Get Chip ID and register with v4l2*/
+       i2c_read = tvp5158_read(client, REG_CHIPID_MSB);
+       u_i2cbuf.buffer = i2c_read << 8;
+       i2c_read = tvp5158_read(client, REG_CHIPID_LSB);
+       u_i2cbuf.buffer |= i2c_read;
+       if (u_i2cbuf.buffer == 0x5158) {
+               v4l2_dbg(1, debug, sd, "Chip id : %x\n", u_i2cbuf.buffer);
+               tvp5158_write(client, REG_DEC_WR_EN, TVP_CORE_ALL);
+               tvp5158_write(client, REG_OFM_CTRL,
+               (TVP_VIDEO_PORT_ENABLE | TVP_OUT_CLK_P_EN));
+       } else {
+               dev_err(&client->dev, "ERROR: Chip id is not TVP5158");
+               return -ENODEV;
+       }
+
+       tvp5158_set_default(client, TVP_CORE_ALL);
+       tvp5158_get_video_std(client, TVP_CORE_ALL);
+
+       /* V4l2 asyn subdev register */
+       sd->dev = &client->dev;
+       ret = v4l2_async_register_subdev(sd);
+       if (!ret)
+               v4l2_info(&priv->subdev, "Camera sensor driver registered\n");
+       else
+               return ret;
+
+       pm_runtime_enable(&client->dev);
+
+       return ret;
+}
+
+static int tvp5158_remove(struct i2c_client *client)
+{
+       struct tvp5158_priv *priv = i2c_get_clientdata(client);
+
+       v4l2_device_unregister_subdev(&priv->subdev);
+       return 0;
+}
+
+static struct i2c_driver tvp5158_i2c_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "tvp5158",
+               .of_match_table = tvp5158_dt_id,
+       },
+       .probe    = tvp5158_probe,
+       .remove   = tvp5158_remove,
+       .id_table = tvp5158_id,
+};
+
+module_i2c_driver(tvp5158_i2c_driver);
+
+MODULE_DESCRIPTION("Video Decoder driver");
+MODULE_AUTHOR("Sathishkumar S");
+MODULE_LICENSE("GPL v2");