diff options
Diffstat (limited to 'bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0520-media-i2c-soc_camera-add-dummy-lvds-sensor.patch')
-rw-r--r-- | bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0520-media-i2c-soc_camera-add-dummy-lvds-sensor.patch | 620 |
1 files changed, 620 insertions, 0 deletions
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0520-media-i2c-soc_camera-add-dummy-lvds-sensor.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0520-media-i2c-soc_camera-add-dummy-lvds-sensor.patch new file mode 100644 index 00000000..84a7e44e --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0520-media-i2c-soc_camera-add-dummy-lvds-sensor.patch @@ -0,0 +1,620 @@ +From 0368ffc88e6aec7655d9b63c7ddc50c57714dd58 Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Sat, 30 May 2020 00:48:18 +0300 +Subject: [PATCH] media: i2c: soc_camera: add dummy lvds sensor + +This adds sensor that is not detectable behind serializer + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/dummy.c | 539 +++++++++++++++++++++++++++++++++ + drivers/media/i2c/soc_camera/max9286.h | 3 + + drivers/media/i2c/soc_camera/ov106xx.c | 11 + + 3 files changed, 553 insertions(+) + create mode 100644 drivers/media/i2c/soc_camera/dummy.c + +diff --git a/drivers/media/i2c/soc_camera/dummy.c b/drivers/media/i2c/soc_camera/dummy.c +new file mode 100644 +index 0000000..346b5dd +--- /dev/null ++++ b/drivers/media/i2c/soc_camera/dummy.c +@@ -0,0 +1,539 @@ ++/* ++ * Dummy sensor camera driver ++ * ++ * Copyright (C) 2019-2020 Cogent Embedded, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++#include <linux/delay.h> ++#include <linux/init.h> ++#include <linux/i2c.h> ++#include <linux/module.h> ++#include <linux/of_graph.h> ++#include <linux/videodev2.h> ++ ++#include <media/soc_camera.h> ++#include <media/v4l2-common.h> ++#include <media/v4l2-ctrls.h> ++ ++struct dummy_priv { ++ struct v4l2_subdev sd; ++ struct v4l2_ctrl_handler hdl; ++ struct media_pad pad; ++ struct v4l2_rect rect; ++ u8 id[6]; ++ int max_width; ++ int max_height; ++ const char * media_bus_format; ++ int mbus_format; ++ int dummy; ++ /* serializers */ ++ int ti9x4_addr; ++ int ti9x3_addr; ++ int port; ++}; ++ ++static int width = 1920; ++module_param(width, int, 0644); ++MODULE_PARM_DESC(width, " width (default: 1920)"); ++ ++static int height = 1080; ++module_param(height, int, 0644); ++MODULE_PARM_DESC(height, " height (default: 1080)"); ++ ++static char *fmt = "yuyv"; ++module_param(fmt, charp, 0644); ++MODULE_PARM_DESC(fmt, " MEDIA_BUS_FORMAT (default: YUYV)"); ++ ++static int dummy = 0; ++module_param(dummy, int, 0644); ++MODULE_PARM_DESC(dummy, " dummy force (0 - dummy imager disabled)"); ++ ++static inline struct dummy_priv *to_dummy(const struct i2c_client *client) ++{ ++ return container_of(i2c_get_clientdata(client), struct dummy_priv, sd); ++} ++ ++static inline struct v4l2_subdev *dummy_to_sd(struct v4l2_ctrl *ctrl) ++{ ++ return &container_of(ctrl->handler, struct dummy_priv, hdl)->sd; ++} ++ ++static int dummy_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ return 0; ++} ++ ++static int dummy_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct v4l2_mbus_framefmt *mf = &format->format; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct dummy_priv *priv = to_dummy(client); ++ ++ if (format->pad) ++ return -EINVAL; ++ ++ mf->width = priv->rect.width; ++ mf->height = priv->rect.height; ++ mf->code = priv->mbus_format; ++ mf->colorspace = V4L2_COLORSPACE_SMPTE170M; ++ mf->field = V4L2_FIELD_NONE; ++ ++ return 0; ++} ++ ++static int dummy_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct v4l2_mbus_framefmt *mf = &format->format; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct dummy_priv *priv = to_dummy(client); ++ ++ mf->code = priv->mbus_format; ++ mf->colorspace = V4L2_COLORSPACE_SMPTE170M; ++ mf->field = V4L2_FIELD_NONE; ++ ++ if (format->which == V4L2_SUBDEV_FORMAT_TRY) ++ cfg->try_fmt = *mf; ++ ++ return 0; ++} ++ ++static int dummy_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct dummy_priv *priv = to_dummy(client); ++ ++ if (code->pad || code->index > 0) ++ return -EINVAL; ++ ++ code->code = priv->mbus_format; ++ ++ return 0; ++} ++ ++static int dummy_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct dummy_priv *priv = to_dummy(client); ++ ++ memcpy(edid->edid, priv->id, 6); ++ ++ edid->edid[6] = 0xff; ++ edid->edid[7] = client->addr; ++ edid->edid[8] = 'D' >> 8; ++ edid->edid[9] = 'Y' & 0xff; ++ ++ return 0; ++} ++ ++static int dummy_set_selection(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_selection *sel) ++{ ++ struct v4l2_rect *rect = &sel->r; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct dummy_priv *priv = to_dummy(client); ++ ++ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE || ++ sel->target != V4L2_SEL_TGT_CROP) ++ return -EINVAL; ++ ++ rect->left = ALIGN(rect->left, 2); ++ rect->top = ALIGN(rect->top, 2); ++ rect->width = ALIGN(rect->width, 2); ++ rect->height = ALIGN(rect->height, 2); ++ ++ if ((rect->left + rect->width > priv->max_width) || ++ (rect->top + rect->height > priv->max_height)) ++ *rect = priv->rect; ++ ++ priv->rect.left = rect->left; ++ priv->rect.top = rect->top; ++ priv->rect.width = rect->width; ++ priv->rect.height = rect->height; ++ ++ return 0; ++} ++ ++static int dummy_get_selection(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_selection *sel) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct dummy_priv *priv = to_dummy(client); ++ ++ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) ++ return -EINVAL; ++ ++ switch (sel->target) { ++ case V4L2_SEL_TGT_CROP_BOUNDS: ++ sel->r.left = 0; ++ sel->r.top = 0; ++ sel->r.width = priv->max_width; ++ sel->r.height = priv->max_height; ++ return 0; ++ case V4L2_SEL_TGT_CROP_DEFAULT: ++ sel->r.left = 0; ++ sel->r.top = 0; ++ sel->r.width = priv->max_width; ++ sel->r.height = priv->max_height; ++ return 0; ++ case V4L2_SEL_TGT_CROP: ++ sel->r = priv->rect; ++ return 0; ++ default: ++ return -EINVAL; ++ } ++} ++ ++static int dummy_g_mbus_config(struct v4l2_subdev *sd, ++ struct v4l2_mbus_config *cfg) ++{ ++ cfg->flags = V4L2_MBUS_CSI2_1_LANE | V4L2_MBUS_CSI2_CHANNEL_0 | ++ V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; ++ cfg->type = V4L2_MBUS_CSI2; ++ ++ return 0; ++} ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int dummy_g_register(struct v4l2_subdev *sd, ++ struct v4l2_dbg_register *reg) ++{ ++ reg->val = 0; ++ reg->size = sizeof(u16); ++ ++ return 0; ++} ++ ++static int dummy_s_register(struct v4l2_subdev *sd, ++ const struct v4l2_dbg_register *reg) ++{ ++ return 0; ++} ++#endif ++ ++static struct v4l2_subdev_core_ops dummy_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = dummy_g_register, ++ .s_register = dummy_s_register, ++#endif ++}; ++ ++static int dummy_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ switch (ctrl->id) { ++ case V4L2_CID_BRIGHTNESS: ++ case V4L2_CID_CONTRAST: ++ case V4L2_CID_SATURATION: ++ case V4L2_CID_HUE: ++ case V4L2_CID_GAMMA: ++ case V4L2_CID_SHARPNESS: ++ case V4L2_CID_AUTOGAIN: ++ case V4L2_CID_GAIN: ++ case V4L2_CID_ANALOGUE_GAIN: ++ case V4L2_CID_EXPOSURE: ++ case V4L2_CID_HFLIP: ++ case V4L2_CID_VFLIP: ++ case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE: ++ break; ++ } ++ ++ return 0; ++} ++ ++static const struct v4l2_ctrl_ops dummy_ctrl_ops = { ++ .s_ctrl = dummy_s_ctrl, ++}; ++ ++static struct v4l2_subdev_video_ops dummy_video_ops = { ++ .s_stream = dummy_s_stream, ++ .g_mbus_config = dummy_g_mbus_config, ++}; ++ ++static const struct v4l2_subdev_pad_ops dummy_subdev_pad_ops = { ++ .get_edid = dummy_get_edid, ++ .enum_mbus_code = dummy_enum_mbus_code, ++ .get_selection = dummy_get_selection, ++ .set_selection = dummy_set_selection, ++ .get_fmt = dummy_get_fmt, ++ .set_fmt = dummy_set_fmt, ++}; ++ ++static struct v4l2_subdev_ops dummy_subdev_ops = { ++ .core = &dummy_core_ops, ++ .video = &dummy_video_ops, ++ .pad = &dummy_subdev_pad_ops, ++}; ++ ++static void dummy_otp_id_read(struct i2c_client *client) ++{ ++ struct dummy_priv *priv = to_dummy(client); ++ ++ /* dummy camera id */ ++ priv->id[0] = 'd'; ++ priv->id[1] = 'u'; ++ priv->id[2] = 'm'; ++ priv->id[3] = 'm'; ++ priv->id[4] = 'y'; ++ priv->id[5] = '.'; ++} ++ ++static ssize_t dummy_otp_id_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(to_i2c_client(dev)); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct dummy_priv *priv = to_dummy(client); ++ ++ dummy_otp_id_read(client); ++ ++ return snprintf(buf, 32, "%02x:%02x:%02x:%02x:%02x:%02x\n", ++ priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]); ++} ++ ++static DEVICE_ATTR(otp_id_dummy, S_IRUGO, dummy_otp_id_show, NULL); ++ ++static int dummy_initialize(struct i2c_client *client) ++{ ++ struct dummy_priv *priv = to_dummy(client); ++ u8 pid = 0xff; ++ int tmp_addr; ++ ++ tmp_addr = client->addr; ++ do { ++ if (priv->ti9x4_addr) { ++ client->addr = priv->ti9x3_addr; ++ /* check if UB953 ID */ ++ reg8_read(client, 0xf1, &pid); ++ if (pid == 'U') ++ break; ++ /* check if UB913 ID */ ++ reg8_read(client, 0x00, &pid); ++ if (pid == (TI913_ID << 1)) ++ break; ++ ++ dev_dbg(&client->dev, "Product ID error %x\n", pid); ++ client->addr = tmp_addr; ++ return -ENODEV; ++ } ++ } while(0); ++ client->addr = tmp_addr; ++ ++ if (strcmp(priv->media_bus_format, "yuyv") == 0) ++ priv->mbus_format = MEDIA_BUS_FMT_YUYV8_2X8; ++ else if (strcmp(priv->media_bus_format, "uyvy") == 0) ++ priv->mbus_format = MEDIA_BUS_FMT_UYVY8_2X8; ++ else if (strcmp(priv->media_bus_format, "grey") == 0) ++ priv->mbus_format = MEDIA_BUS_FMT_Y8_1X8; ++ else if (strcmp(priv->media_bus_format, "rggb8") == 0) ++ priv->mbus_format = MEDIA_BUS_FMT_SRGGB8_1X8; ++ else if (strcmp(priv->media_bus_format, "bggr8") == 0) ++ priv->mbus_format = MEDIA_BUS_FMT_SBGGR8_1X8; ++ else if (strcmp(priv->media_bus_format, "grbg8") == 0) ++ priv->mbus_format = MEDIA_BUS_FMT_SGRBG8_1X8; ++ else if (strcmp(priv->media_bus_format, "rggb12") == 0) ++ priv->mbus_format = MEDIA_BUS_FMT_SRGGB12_1X12; ++ else if (strcmp(priv->media_bus_format, "bggr12") == 0) ++ priv->mbus_format = MEDIA_BUS_FMT_SBGGR12_1X12; ++ else if (strcmp(priv->media_bus_format, "grbg12") == 0) ++ priv->mbus_format = MEDIA_BUS_FMT_SGRBG12_1X12; ++ else if (strcmp(priv->media_bus_format, "rggb14") == 0) ++ priv->mbus_format = MEDIA_BUS_FMT_SRGGB14_1X14; ++ else if (strcmp(priv->media_bus_format, "bggr14") == 0) ++ priv->mbus_format = MEDIA_BUS_FMT_SBGGR14_1X14; ++ else if (strcmp(priv->media_bus_format, "grbg14") == 0) ++ priv->mbus_format = MEDIA_BUS_FMT_SGRBG14_1X14; ++ else if (strcmp(priv->media_bus_format, "rggb16") == 0) ++ priv->mbus_format = MEDIA_BUS_FMT_SRGGB16_1X16; ++ else if (strcmp(priv->media_bus_format, "bggr16") == 0) ++ priv->mbus_format = MEDIA_BUS_FMT_SBGGR16_1X16; ++ else if (strcmp(priv->media_bus_format, "grbg16") == 0) ++ priv->mbus_format = MEDIA_BUS_FMT_SGRBG16_1X16; ++ else { ++ v4l_err(client, "failed to parse mbus format (%s)\n", priv->media_bus_format); ++ return -EINVAL; ++ } ++ ++ /* Read OTP IDs */ ++ dummy_otp_id_read(client); ++ ++ dev_info(&client->dev, "Dummy camera PID %x, res %dx%d, fmt %s, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n", ++ pid, priv->max_width, priv->max_height, priv->media_bus_format, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]); ++ ++ return 0; ++} ++ ++static int dummy_parse_dt(struct device_node *np, struct dummy_priv *priv) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&priv->sd); ++ int i; ++ struct device_node *endpoint = NULL, *rendpoint = NULL; ++ int tmp_addr = 0; ++ ++ for (i = 0; ; i++) { ++ endpoint = of_graph_get_next_endpoint(np, endpoint); ++ if (!endpoint) ++ break; ++ ++ of_property_read_u32(endpoint, "dummy", &priv->dummy); ++ ++ if (of_property_read_u32(np, "dummy,width", &priv->max_width)) ++ priv->max_width = width; ++ if (of_property_read_u32(np, "dummy,height", &priv->max_height)) ++ priv->max_height = height; ++ if (of_property_read_string(np, "dummy,fmt", &priv->media_bus_format)) ++ priv->media_bus_format = fmt; ++ ++ rendpoint = of_parse_phandle(endpoint, "remote-endpoint", 0); ++ if (!rendpoint) ++ continue; ++ ++ if (!of_property_read_u32(rendpoint, "ti9x3-addr", &priv->ti9x3_addr) && ++ !of_property_match_string(rendpoint->parent->parent, "compatible", "ti,ti9x4") && ++ !of_property_read_u32(rendpoint->parent->parent, "reg", &priv->ti9x4_addr) && ++ !kstrtouint(strrchr(rendpoint->full_name, '@') + 1, 0, &priv->port)) ++ break; ++ } ++ ++ of_node_put(endpoint); ++ ++ if (!priv->ti9x4_addr) { ++ dev_dbg(&client->dev, "deserializer does not present\n"); ++ return -EINVAL; ++ } ++ ++ /* setup I2C translator address */ ++ tmp_addr = client->addr; ++ if (priv->ti9x4_addr) { ++ client->addr = priv->ti9x4_addr; /* Deserializer I2C address */ ++ ++ reg8_write(client, 0x4c, (priv->port << 4) | (1 << priv->port)); /* Select RX port number */ ++ usleep_range(2000, 2500); /* wait 2ms */ ++ reg8_write(client, 0x65, tmp_addr << 1); /* Sensor translated I2C address */ ++ } ++ client->addr = tmp_addr; ++ ++ /* module params override dts */ ++ if (strcmp(fmt, "yuyv")) ++ priv->media_bus_format = fmt; ++ if (width != 1920) ++ priv->max_width = width; ++ if (height != 1080) ++ priv->max_height = height; ++ if (dummy) ++ priv->dummy = dummy; ++ ++ if (!priv->dummy) ++ return -ENODEV; ++ ++ return 0; ++} ++ ++static int dummy_probe(struct i2c_client *client, ++ const struct i2c_device_id *did) ++{ ++ struct dummy_priv *priv; ++ int ret; ++ ++ priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ v4l2_i2c_subdev_init(&priv->sd, client, &dummy_subdev_ops); ++ priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; ++ ++ v4l2_ctrl_handler_init(&priv->hdl, 4); ++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops, ++ V4L2_CID_BRIGHTNESS, 0, 16, 1, 7); ++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops, ++ V4L2_CID_CONTRAST, 0, 16, 1, 7); ++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops, ++ V4L2_CID_SATURATION, 0, 7, 1, 2); ++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops, ++ V4L2_CID_HUE, 0, 23, 1, 12); ++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops, ++ V4L2_CID_GAMMA, -128, 128, 1, 0); ++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops, ++ V4L2_CID_SHARPNESS, 0, 10, 1, 3); ++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops, ++ V4L2_CID_AUTOGAIN, 0, 1, 1, 0); ++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops, ++ V4L2_CID_GAIN, 1, 0x7ff, 1, 0x200); ++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops, ++ V4L2_CID_ANALOGUE_GAIN, 1, 0xe, 1, 0xa); ++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops, ++ V4L2_CID_EXPOSURE, 1, 0x600, 1, 0x144); ++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ priv->sd.ctrl_handler = &priv->hdl; ++ ++ ret = priv->hdl.error; ++ if (ret) ++ goto cleanup; ++ ++ v4l2_ctrl_handler_setup(&priv->hdl); ++ ++ priv->pad.flags = MEDIA_PAD_FL_SOURCE; ++ priv->sd.entity.flags |= MEDIA_ENT_F_CAM_SENSOR; ++ ret = media_entity_pads_init(&priv->sd.entity, 1, &priv->pad); ++ if (ret < 0) ++ goto cleanup; ++ ++ ret = dummy_parse_dt(client->dev.of_node, priv); ++ if (ret) ++ goto cleanup; ++ ++ ret = dummy_initialize(client); ++ if (ret < 0) ++ goto cleanup; ++ ++ priv->rect.left = 0; ++ priv->rect.top = 0; ++ priv->rect.width = priv->max_width; ++ priv->rect.height = priv->max_height; ++ ++ ret = v4l2_async_register_subdev(&priv->sd); ++ if (ret) ++ goto cleanup; ++ ++ if (device_create_file(&client->dev, &dev_attr_otp_id_dummy) != 0) { ++ dev_err(&client->dev, "sysfs otp_id entry creation failed\n"); ++ goto cleanup; ++ } ++ ++ return 0; ++ ++cleanup: ++ media_entity_cleanup(&priv->sd.entity); ++ v4l2_ctrl_handler_free(&priv->hdl); ++ v4l2_device_unregister_subdev(&priv->sd); ++ v4l_err(client, "failed to probe @ 0x%02x (%s)\n", ++ client->addr, client->adapter->name); ++ return ret; ++} ++ ++static int dummy_remove(struct i2c_client *client) ++{ ++ struct dummy_priv *priv = i2c_get_clientdata(client); ++ ++ device_remove_file(&client->dev, &dev_attr_otp_id_dummy); ++ v4l2_async_unregister_subdev(&priv->sd); ++ media_entity_cleanup(&priv->sd.entity); ++ v4l2_ctrl_handler_free(&priv->hdl); ++ v4l2_device_unregister_subdev(&priv->sd); ++ ++ return 0; ++} +diff --git a/drivers/media/i2c/soc_camera/max9286.h b/drivers/media/i2c/soc_camera/max9286.h +index 3fe713f..48233e2 100644 +--- a/drivers/media/i2c/soc_camera/max9286.h ++++ b/drivers/media/i2c/soc_camera/max9286.h +@@ -30,6 +30,9 @@ + #define MAX9290_ID 0x2C + #define BROADCAST 0x6f + ++#define TI913_ID 0x58 ++#define TI953_ID 0x30 ++ + static inline int reg8_read(struct i2c_client *client, u8 reg, u8 *val) + { + int ret, retries; +diff --git a/drivers/media/i2c/soc_camera/ov106xx.c b/drivers/media/i2c/soc_camera/ov106xx.c +index cf97f28..b3d84a6 100644 +--- a/drivers/media/i2c/soc_camera/ov106xx.c ++++ b/drivers/media/i2c/soc_camera/ov106xx.c +@@ -32,6 +32,7 @@ static enum { + ID_ISX016, + ID_ISX019, + ID_OV2311, ++ ID_DUMMY, + } chip_id; + + #include "ov10635.c" +@@ -55,6 +56,7 @@ static enum { + #include "isx019.c" + #include "ov2311.c" + #include "ar0147.c" ++#include "dummy.c" + + static int ov106xx_probe(struct i2c_client *client, + const struct i2c_device_id *did) +@@ -62,6 +64,12 @@ static int ov106xx_probe(struct i2c_client *client, + int ret = -1; + chip_id = -EINVAL; + ++ ret = dummy_probe(client, did); ++ if (!ret) { ++ chip_id = ID_DUMMY; ++ goto out; ++ } ++ + ret = gw5200_probe(client, did); + if (!ret) { + chip_id = ID_GW5200_IMX390; +@@ -258,6 +266,9 @@ static int ov106xx_remove(struct i2c_client *client) + case ID_OV2311: + ov2311_remove(client); + break; ++ case ID_DUMMY: ++ dummy_remove(client); ++ break; + default: + break; + }; +-- +2.7.4 + |