diff options
Diffstat (limited to 'bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0146-lvds-add-dummy-imager-driver.patch')
-rw-r--r-- | bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0146-lvds-add-dummy-imager-driver.patch | 350 |
1 files changed, 350 insertions, 0 deletions
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0146-lvds-add-dummy-imager-driver.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0146-lvds-add-dummy-imager-driver.patch new file mode 100644 index 00000000..34b35bb6 --- /dev/null +++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0146-lvds-add-dummy-imager-driver.patch @@ -0,0 +1,350 @@ +From f44ff8e351a4c5447f3bcf7e0138e2373793a55a Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Thu, 17 Jan 2019 10:41:34 +0300 +Subject: [PATCH 095/122] lvds: add dummy imager driver + +Dummy imager glue driver + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + drivers/media/i2c/soc_camera/Makefile | 1 + + drivers/media/i2c/soc_camera/dummy.c | 317 ++++++++++++++++++++++++++++++++++ + 2 files changed, 318 insertions(+) + create mode 100644 drivers/media/i2c/soc_camera/dummy.c + +diff --git a/drivers/media/i2c/soc_camera/Makefile b/drivers/media/i2c/soc_camera/Makefile +index eed6e24..4aa5046 100644 +--- a/drivers/media/i2c/soc_camera/Makefile ++++ b/drivers/media/i2c/soc_camera/Makefile +@@ -15,4 +15,5 @@ obj-$(CONFIG_SOC_CAMERA_MAX9286) += max9286.o + obj-$(CONFIG_SOC_CAMERA_TI9X4) += ti9x4.o + obj-$(CONFIG_SOC_CAMERA_OV106XX) += ov106xx.o + obj-$(CONFIG_SOC_CAMERA_IMX219) += imx219.o ++obj-y += dummy.o + +diff --git a/drivers/media/i2c/soc_camera/dummy.c b/drivers/media/i2c/soc_camera/dummy.c +new file mode 100644 +index 0000000..a38d7c4 +--- /dev/null ++++ b/drivers/media/i2c/soc_camera/dummy.c +@@ -0,0 +1,317 @@ ++/* ++ * Dummy sensor camera driver ++ * ++ * Copyright (C) 2019 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> ++ ++#define MEDIA_BUS_FORMAT MEDIA_BUS_FMT_YUYV8_2X8 ++ ++struct dummy_priv { ++ struct v4l2_subdev sd; ++ struct v4l2_ctrl_handler hdl; ++ struct media_pad pad; ++ struct v4l2_rect rect; ++ int max_width; ++ int max_height; ++}; ++ ++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 *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 = MEDIA_BUS_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; ++ ++ mf->code = MEDIA_BUS_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) ++{ ++ if (code->pad || code->index > 0) ++ return -EINVAL; ++ ++ code->code = MEDIA_BUS_FORMAT; ++ ++ 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; ++} ++ ++static int dummy_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ return -EINVAL; ++} ++ ++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 = { ++ .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 = { ++ .video = &dummy_video_ops, ++ .pad = &dummy_subdev_pad_ops, ++}; ++ ++static int dummy_initialize(struct i2c_client *client) ++{ ++ struct dummy_priv *priv = to_dummy(client); ++ ++ dev_info(&client->dev, "Dummy sensor res %dx%d\n", priv->max_width, priv->max_height); ++ ++ 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 err; ++ ++ err = of_property_read_u32(np, "dummy,width", &priv->max_width); ++ if (err) { ++ dev_err(&client->dev, "dummy,width must be defined\n"); ++ goto out; ++ } ++ ++ err = of_property_read_u32(np, "dummy,height", &priv->max_height); ++ if (err) { ++ dev_err(&client->dev, "dummy,height must be defined\n"); ++ goto out; ++ } ++ ++out: ++ return err; ++} ++ ++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); ++ 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; ++ ++ 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); ++ ++ 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; ++} ++ ++static const struct i2c_device_id dummy_id[] = { ++ { "dummy-camera", 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, dummy_id); ++ ++static const struct of_device_id dummy_of_ids[] = { ++ { .compatible = "dummy-camera", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, dummy_of_ids); ++ ++static struct i2c_driver dummy_i2c_driver = { ++ .driver = { ++ .name = "dummy-camera", ++ .of_match_table = dummy_of_ids, ++ }, ++ .probe = dummy_probe, ++ .remove = dummy_remove, ++ .id_table = dummy_id, ++}; ++module_i2c_driver(dummy_i2c_driver); ++ ++MODULE_DESCRIPTION("Dummy SoC camera driver"); ++MODULE_AUTHOR("Vladimir Barinov"); ++MODULE_LICENSE("GPL"); +-- +2.7.4 + |