summaryrefslogtreecommitdiffstats
path: root/meta-rcar-gen3-adas/recipes-kernel/linux
diff options
context:
space:
mode:
authorVladimir Barinov <vladimir.barinov@cogentembedded.com>2017-08-28 03:20:46 +0300
committerVladimir Barinov <vladimir.barinov@cogentembedded.com>2017-08-28 03:20:46 +0300
commita857465243afa77deb67371a0613c4dedb75d9b9 (patch)
tree19506e9e4ff0a345b7197390125b2b093712986c /meta-rcar-gen3-adas/recipes-kernel/linux
parentcfdd0eca26a38b0ea452ea8c65bc3e246528b04d (diff)
Add AR0132 LVDS camera support
Diffstat (limited to 'meta-rcar-gen3-adas/recipes-kernel/linux')
-rw-r--r--meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0030-Gen3-LVDS-cameras.patch975
1 files changed, 935 insertions, 40 deletions
diff --git a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0030-Gen3-LVDS-cameras.patch b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0030-Gen3-LVDS-cameras.patch
index 461b2c7..7a15d6c 100644
--- a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0030-Gen3-LVDS-cameras.patch
+++ b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0030-Gen3-LVDS-cameras.patch
@@ -5,32 +5,36 @@ Subject: [PATCH] Gen3: LVDS cameras
This add Gen3 LVDS cameras support:
- deserializers: MAX9286, TI964, TI954, TI960
-- cameras: ov10635, ov490+ov10640, ov495+OV2775
+- cameras: ov10635, ov490+ov10640, ov495+OV2775, ar0132
Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
---
drivers/media/i2c/soc_camera/Kconfig | 47 +
drivers/media/i2c/soc_camera/Makefile | 7 +
+ drivers/media/i2c/soc_camera/ar0132.c | 548 +++++++++++
+ drivers/media/i2c/soc_camera/ar0132.h | 213 ++++
drivers/media/i2c/soc_camera/max9286_max9271.c | 567 +++++++++++
- drivers/media/i2c/soc_camera/max9286_max9271.h | 196 ++++
+ drivers/media/i2c/soc_camera/max9286_max9271.h | 243 +++++
drivers/media/i2c/soc_camera/ov10635.c | 759 ++++++++++++++
drivers/media/i2c/soc_camera/ov10635.h | 1139 ++++++++++++++++++++++
drivers/media/i2c/soc_camera/ov10635_debug.h | 54 +
- drivers/media/i2c/soc_camera/ov106xx.c | 95 ++
+ drivers/media/i2c/soc_camera/ov106xx.c | 106 ++
drivers/media/i2c/soc_camera/ov490_ov10640.c | 1046 ++++++++++++++++++++
drivers/media/i2c/soc_camera/ov490_ov10640.h | 88 ++
drivers/media/i2c/soc_camera/ov495_ov2775.c | 658 +++++++++++++
drivers/media/i2c/soc_camera/ov495_ov2775.h | 23 +
drivers/media/i2c/soc_camera/ti954_ti9x3.c | 417 ++++++++
drivers/media/i2c/soc_camera/ti964_ti9x3.c | 385 ++++++++
- drivers/media/i2c/soc_camera/ti9x4_ti9x3.h | 108 ++
+ drivers/media/i2c/soc_camera/ti9x4_ti9x3.h | 153 +++
drivers/media/platform/soc_camera/rcar_csi2.c | 297 ++++--
- drivers/media/platform/soc_camera/rcar_vin.c | 159 ++-
+ drivers/media/platform/soc_camera/rcar_vin.c | 174 +++-
drivers/media/platform/soc_camera/soc_camera.c | 17 +-
drivers/media/platform/soc_camera/soc_mediabus.c | 16 +
include/media/drv-intf/soc_mediabus.h | 3 +
include/media/soc_camera.h | 1 +
- 21 files changed, 5973 insertions(+), 109 deletions(-)
+ 23 files changed, 6852 insertions(+), 109 deletions(-)
+ create mode 100644 drivers/media/i2c/soc_camera/ar0132.c
+ create mode 100644 drivers/media/i2c/soc_camera/ar0132.h
create mode 100644 drivers/media/i2c/soc_camera/max9286_max9271.c
create mode 100644 drivers/media/i2c/soc_camera/max9286_max9271.h
create mode 100644 drivers/media/i2c/soc_camera/ov10635.c
@@ -123,6 +127,779 @@ index 6f994f9..7d4c1ab 100644
obj-$(CONFIG_SOC_CAMERA_OV2640) += ov2640.o
obj-$(CONFIG_SOC_CAMERA_OV5642) += ov5642.o
obj-$(CONFIG_SOC_CAMERA_OV6650) += ov6650.o
+diff --git a/drivers/media/i2c/soc_camera/ar0132.c b/drivers/media/i2c/soc_camera/ar0132.c
+new file mode 100644
+index 0000000..284c522
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/ar0132.c
+@@ -0,0 +1,548 @@
++/*
++ * Aptina AR0132 sensor camera driver
++ *
++ * Copyright (C) 2017 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/videodev2.h>
++
++#include <media/soc_camera.h>
++#include <media/v4l2-common.h>
++#include <media/v4l2-ctrls.h>
++#include <media/v4l2-of.h>
++
++#include "ar0132.h"
++
++#define AR0132_I2C_ADDR 0x18
++//#define AR0132_I2C_ADDR 0x50 // eeprom
++
++#define AR0132_PID 0x3000
++#define AR0132_VERSION_REG 0x2400
++
++#define AR0132_MEDIA_BUS_FMT MEDIA_BUS_FMT_SBGGR12_1X12
++
++struct ar0132_priv {
++ struct v4l2_subdev sd;
++ struct v4l2_ctrl_handler hdl;
++ struct media_pad pad;
++ struct v4l2_rect rect;
++ int init_complete;
++ u8 id[6];
++ int exposure;
++ int gain;
++ int autogain;
++ int dvp_order;
++ /* serializers */
++ int ti964_addr;
++ int ti954_addr;
++ int ti9x3_addr;
++ int port;
++ int gpio_resetb;
++ int gpio_fsin;
++
++};
++
++static inline struct ar0132_priv *to_ar0132(const struct i2c_client *client)
++{
++ return container_of(i2c_get_clientdata(client), struct ar0132_priv, sd);
++}
++
++static int ar0132_set_regs(struct i2c_client *client,
++ const struct ar0132_reg *regs, int nr_regs)
++{
++ int i;
++
++ for (i = 0; i < nr_regs; i++) {
++ if (regs[i].reg == AR0132_DELAY) {
++ mdelay(regs[i].val);
++ continue;
++ }
++
++ reg16_write16(client, regs[i].reg, regs[i].val);
++ }
++
++ return 0;
++}
++
++static int ar0132_s_stream(struct v4l2_subdev *sd, int enable)
++{
++ return 0;
++}
++
++static int ar0132_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 ar0132_priv *priv = to_ar0132(client);
++
++ if (format->pad)
++ return -EINVAL;
++
++ mf->width = priv->rect.width;
++ mf->height = priv->rect.height;
++ mf->code = AR0132_MEDIA_BUS_FMT;
++ mf->colorspace = V4L2_COLORSPACE_SMPTE170M;
++ mf->field = V4L2_FIELD_NONE;
++
++ return 0;
++}
++
++static int ar0132_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 = AR0132_MEDIA_BUS_FMT;
++ 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 ar0132_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 = AR0132_MEDIA_BUS_FMT;
++
++ return 0;
++}
++
++static int ar0132_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ar0132_priv *priv = to_ar0132(client);
++
++ memcpy(edid->edid, priv->id, 6);
++
++ edid->edid[6] = 0xff;
++ edid->edid[7] = client->addr;
++ edid->edid[8] = AR0132_VERSION_REG >> 8;
++ edid->edid[9] = AR0132_VERSION_REG & 0xff;
++
++ return 0;
++}
++
++static int ar0132_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 ar0132_priv *priv = to_ar0132(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 > AR0132_MAX_WIDTH) ||
++ (rect->top + rect->height > AR0132_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 ar0132_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 ar0132_priv *priv = to_ar0132(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 = AR0132_MAX_WIDTH;
++ sel->r.height = AR0132_MAX_HEIGHT;
++ return 0;
++ case V4L2_SEL_TGT_CROP_DEFAULT:
++ sel->r.left = 0;
++ sel->r.top = 0;
++ sel->r.width = AR0132_MAX_WIDTH;
++ sel->r.height = AR0132_MAX_HEIGHT;
++ return 0;
++ case V4L2_SEL_TGT_CROP:
++ sel->r = priv->rect;
++ return 0;
++ default:
++ return -EINVAL;
++ }
++}
++
++static int ar0132_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 ar0132_g_register(struct v4l2_subdev *sd,
++ struct v4l2_dbg_register *reg)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ int ret;
++ u16 val = 0;
++
++ ret = reg16_read16(client, (u16)reg->reg, &val);
++ if (ret < 0)
++ return ret;
++
++ reg->val = val;
++ reg->size = sizeof(u16);
++
++ return 0;
++}
++
++static int ar0132_s_register(struct v4l2_subdev *sd,
++ const struct v4l2_dbg_register *reg)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++
++ return reg16_write16(client, (u16)reg->reg, (u16)reg->val);
++}
++#endif
++
++static struct v4l2_subdev_core_ops ar0132_core_ops = {
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++ .g_register = ar0132_g_register,
++ .s_register = ar0132_s_register,
++#endif
++};
++
++static int ar0132_s_ctrl(struct v4l2_ctrl *ctrl)
++{
++ struct v4l2_subdev *sd = to_sd(ctrl);
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ar0132_priv *priv = to_ar0132(client);
++ int ret = -EINVAL;
++
++ if (!priv->init_complete)
++ return 0;
++
++ 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_EXPOSURE:
++ case V4L2_CID_HFLIP:
++ case V4L2_CID_VFLIP:
++ break;
++ }
++
++ return ret;
++}
++
++static const struct v4l2_ctrl_ops ar0132_ctrl_ops = {
++ .s_ctrl = ar0132_s_ctrl,
++};
++
++static struct v4l2_subdev_video_ops ar0132_video_ops = {
++ .s_stream = ar0132_s_stream,
++ .g_mbus_config = ar0132_g_mbus_config,
++};
++
++static const struct v4l2_subdev_pad_ops ar0132_subdev_pad_ops = {
++ .get_edid = ar0132_get_edid,
++ .enum_mbus_code = ar0132_enum_mbus_code,
++ .get_selection = ar0132_get_selection,
++ .set_selection = ar0132_set_selection,
++ .get_fmt = ar0132_get_fmt,
++ .set_fmt = ar0132_set_fmt,
++};
++
++static struct v4l2_subdev_ops ar0132_subdev_ops = {
++ .core = &ar0132_core_ops,
++ .video = &ar0132_video_ops,
++ .pad = &ar0132_subdev_pad_ops,
++};
++
++static void ar0132_otp_id_read(struct i2c_client *client)
++{
++}
++
++static ssize_t ar0132_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 ar0132_priv *priv = to_ar0132(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_ar0132, S_IRUGO, ar0132_otp_id_show, NULL);
++
++static int ar0132_initialize(struct i2c_client *client)
++{
++ struct ar0132_priv *priv = to_ar0132(client);
++ u16 val = 0;
++ u16 pid = 0;
++ int ret = 0;
++
++ /* check and show model ID */
++ reg16_read16(client, AR0132_PID, &pid);
++
++ if (pid != AR0132_VERSION_REG) {
++ dev_dbg(&client->dev, "Product ID error %x\n", pid);
++ ret = -ENODEV;
++ goto err;
++ }
++
++ /* Program wizard registers */
++ ar0132_set_regs(client, ar0132_regs_wizard, ARRAY_SIZE(ar0132_regs_wizard));
++
++ /* Enable stream */
++ reg16_read16(client, 0x301a, &val); // read inital reset_register value
++ val |= (1 << 2); // Set streamOn bit
++ reg16_write16(client, 0x301a, val); // Start Streaming
++
++ /* Read OTP IDs */
++ ar0132_otp_id_read(client);
++
++ dev_info(&client->dev, "ar0132 PID %x, res %dx%d, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n",
++ pid, AR0132_MAX_WIDTH, AR0132_MAX_HEIGHT, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]);
++err:
++ return ret;
++}
++
++static int ar0132_parse_dt(struct device_node *np, struct ar0132_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_node_put(endpoint);
++
++ of_property_read_u32(endpoint, "dvp-order", &priv->dvp_order);
++
++ 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,ti964-ti9x3") &&
++ !of_property_read_u32(rendpoint->parent->parent, "reg", &priv->ti964_addr) &&
++ !kstrtouint(strrchr(rendpoint->full_name, '@') + 1, 0, &priv->port))
++ break;
++
++ if (!of_property_read_u32(rendpoint, "ti9x3-addr", &priv->ti9x3_addr) &&
++ !of_property_match_string(rendpoint->parent->parent, "compatible", "ti,ti954-ti9x3") &&
++ !of_property_read_u32(rendpoint->parent->parent, "reg", &priv->ti954_addr) &&
++ !kstrtouint(strrchr(rendpoint->full_name, '@') + 1, 0, &priv->port))
++ break;
++ }
++
++ if (!priv->ti964_addr && !priv->ti954_addr) {
++ dev_err(&client->dev, "deserializer does not present\n");
++ return -EINVAL;
++ }
++
++ /* setup I2C translator address */
++ tmp_addr = client->addr;
++ if (priv->ti964_addr) {
++ client->addr = priv->ti964_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 */
++ reg8_write(client, 0x5d, AR0132_I2C_ADDR << 1); /* Sensor native I2C address */
++
++ reg8_write(client, 0x6e, 0xa9); /* GPIO0 - reset, GPIO1 - fsin */
++ }
++ if (priv->ti954_addr) {
++ client->addr = priv->ti954_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 */
++ reg8_write(client, 0x5d, AR0132_I2C_ADDR << 1); /* Sensor native I2C address */
++
++ reg8_write(client, 0x6e, 0xa9); /* GPIO0 - reset, GPIO1 - fsin */
++ }
++ client->addr = tmp_addr;
++
++ mdelay(10);
++
++ return 0;
++}
++
++static int ar0132_probe(struct i2c_client *client,
++ const struct i2c_device_id *did)
++{
++ struct ar0132_priv *priv;
++ int ret;
++
++ priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
++ if (!priv)
++ return -ENOMEM;
++
++ v4l2_i2c_subdev_init(&priv->sd, client, &ar0132_subdev_ops);
++ priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
++
++ priv->exposure = 0x100;
++ priv->gain = 0x100;
++ priv->autogain = 1;
++ v4l2_ctrl_handler_init(&priv->hdl, 4);
++ v4l2_ctrl_new_std(&priv->hdl, &ar0132_ctrl_ops,
++ V4L2_CID_BRIGHTNESS, 0, 16, 1, 7);
++ v4l2_ctrl_new_std(&priv->hdl, &ar0132_ctrl_ops,
++ V4L2_CID_CONTRAST, 0, 16, 1, 7);
++ v4l2_ctrl_new_std(&priv->hdl, &ar0132_ctrl_ops,
++ V4L2_CID_SATURATION, 0, 7, 1, 2);
++ v4l2_ctrl_new_std(&priv->hdl, &ar0132_ctrl_ops,
++ V4L2_CID_HUE, 0, 23, 1, 12);
++ v4l2_ctrl_new_std(&priv->hdl, &ar0132_ctrl_ops,
++ V4L2_CID_GAMMA, -128, 128, 1, 0);
++ v4l2_ctrl_new_std(&priv->hdl, &ar0132_ctrl_ops,
++ V4L2_CID_SHARPNESS, 0, 10, 1, 3);
++ v4l2_ctrl_new_std(&priv->hdl, &ar0132_ctrl_ops,
++ V4L2_CID_AUTOGAIN, 0, 1, 1, priv->autogain);
++ v4l2_ctrl_new_std(&priv->hdl, &ar0132_ctrl_ops,
++ V4L2_CID_GAIN, 0, 0xffff, 1, priv->gain);
++ v4l2_ctrl_new_std(&priv->hdl, &ar0132_ctrl_ops,
++ V4L2_CID_EXPOSURE, 0, 0xffff, 1, priv->exposure);
++ v4l2_ctrl_new_std(&priv->hdl, &ar0132_ctrl_ops,
++ V4L2_CID_HFLIP, 0, 1, 1, 1);
++ v4l2_ctrl_new_std(&priv->hdl, &ar0132_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 = ar0132_parse_dt(client->dev.of_node, priv);
++ if (ret)
++ goto cleanup;
++
++ ret = ar0132_initialize(client);
++ if (ret < 0)
++ goto cleanup;
++
++ priv->rect.left = 0;
++ priv->rect.top = 0;
++ priv->rect.width = AR0132_MAX_WIDTH;
++ priv->rect.height = AR0132_MAX_HEIGHT;
++
++ ret = v4l2_async_register_subdev(&priv->sd);
++ if (ret)
++ goto cleanup;
++
++ if (device_create_file(&client->dev, &dev_attr_otp_id_ar0132) != 0) {
++ dev_err(&client->dev, "sysfs otp_id entry creation failed\n");
++ goto cleanup;
++ }
++
++ priv->init_complete = 1;
++
++ return 0;
++
++cleanup:
++ media_entity_cleanup(&priv->sd.entity);
++ v4l2_ctrl_handler_free(&priv->hdl);
++ v4l2_device_unregister_subdev(&priv->sd);
++#ifdef CONFIG_SOC_CAMERA_AR0132
++ v4l_err(client, "failed to probe @ 0x%02x (%s)\n",
++ client->addr, client->adapter->name);
++#endif
++ return ret;
++}
++
++static int ar0132_remove(struct i2c_client *client)
++{
++ struct ar0132_priv *priv = i2c_get_clientdata(client);
++
++ device_remove_file(&client->dev, &dev_attr_otp_id_ar0132);
++ 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;
++}
++
++#ifdef CONFIG_SOC_CAMERA_AR0132
++static const struct i2c_device_id ar0132_id[] = {
++ { "ar0132", 0 },
++ { }
++};
++MODULE_DEVICE_TABLE(i2c, ar0132_id);
++
++static const struct of_device_id ar0132_of_ids[] = {
++ { .compatible = "aptina,ar0132", },
++ { }
++};
++MODULE_DEVICE_TABLE(of, ar0132_of_ids);
++
++static struct i2c_driver ar0132_i2c_driver = {
++ .driver = {
++ .name = "ar0132",
++ .of_match_table = ar0132_of_ids,
++ },
++ .probe = ar0132_probe,
++ .remove = ar0132_remove,
++ .id_table = ar0132_id,
++};
++
++module_i2c_driver(ar0132_i2c_driver);
++
++MODULE_DESCRIPTION("SoC Camera driver for AR0132");
++MODULE_AUTHOR("Vladimir Barinov");
++MODULE_LICENSE("GPL");
++#endif
+diff --git a/drivers/media/i2c/soc_camera/ar0132.h b/drivers/media/i2c/soc_camera/ar0132.h
+new file mode 100644
+index 0000000..055841d
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/ar0132.h
+@@ -0,0 +1,213 @@
++/*
++ * OmniVision ar0132 sensor camera wizard 1110x620@30/BGGR/BT601/12bit
++ *
++ * Copyright (C) 2017 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.
++ */
++
++//#define AR0132_DISPLAY_PATTERN_FIXED
++//#define AR0132_DISPLAY_PATTERN_COLOR_BAR
++
++#define AR0132_EMBEDDED_LINE
++
++#define AR0132_MAX_WIDTH 1665 // (1110*3/2)
++#define AR0132_MAX_HEIGHT 624
++
++#define AR0132_DELAY 0xffff
++
++#define AR0132_MAX_ROI_DIM_X 1288
++#define AR0132_MAX_ROI_DIM_Y 968
++#define AR0132_InfoLines 4
++
++#define AR0132_ROI_DIM_X 1110 // 1104
++#define AR0132_ROI_DIM_Y 620 // AR0132_MAX_HEIGHT
++
++#define AR0132_ROI_Y_START 0x00AE
++#define AR0132_ROI_X_START 0x005C
++#define AR0132_ROI_Y_END AR0132_ROI_Y_START+AR0132_ROI_DIM_Y-1
++#define AR0132_ROI_X_END AR0132_ROI_X_START+AR0132_ROI_DIM_X-1
++
++#define AR0132_FrameLength_Lines 0x029E
++#define AR0132_LineLength_Ticks 0x06B6
++
++#define AR0132_PLL_VT_Pix_Clk_Div 0x0008
++#define AR0132_PLL_VT_Sys_Clk_Div 0x0001
++#define AR0132_PLL_Pre_Clk_Div 0x0004
++#define AR0132_PLL_Multiplier 0x003C
++
++#define AR0132_DigitalTest 0x2002
++
++struct ar0132_reg {
++ u16 reg;
++ u16 val;
++};
++
++static const struct ar0132_reg ar0132_regs_wizard[] = {
++{0x301A, 0x0001}, // reset
++{AR0132_DELAY, 100},
++{0x301A, 0x10D8}, // Stream off and setup parallel
++{0x3070, 0x0001},
++{0x3070, 0x0000}, // 1: Solid color test pattern,
++ // 2: Full color bar test pattern,
++ // 3: Fade to grey color bar test pattern,
++ //256: Walking 1 test pattern (12 bit)
++#ifdef AR0132_DISPLAY_PATTERN_FIXED
++{0x3070, 0x0001},
++{0x3072, 0x0123}, // R
++{0x3074, 0x0456}, // G(GR row)
++{0x3076, 0x0abc}, // B
++{0x3078, 0x0def}, // G(GB row)
++#endif
++#ifdef AR0132_DISPLAY_PATTERN_COLOR_BAR
++{0x3070, 0x0002},
++#endif
++{AR0132_DELAY, 250},
++// patch begin
++{0x3088, 0x8000},
++{0x3086, 0x0025}, {0x3086, 0x5050}, {0x3086, 0x2D26}, {0x3086, 0x0828}, {0x3086, 0x0D17}, {0x3086, 0x0926}, {0x3086, 0x0028}, {0x3086, 0x0526},
++{0x3086, 0xA728}, {0x3086, 0x0725}, {0x3086, 0x8080}, {0x3086, 0x2925}, {0x3086, 0x0040}, {0x3086, 0x2702}, {0x3086, 0x1616}, {0x3086, 0x2706},
++{0x3086, 0x1736}, {0x3086, 0x26A6}, {0x3086, 0x1703}, {0x3086, 0x26A4}, {0x3086, 0x171F}, {0x3086, 0x2805}, {0x3086, 0x2620}, {0x3086, 0x2804},
++{0x3086, 0x2520}, {0x3086, 0x2027}, {0x3086, 0x0017}, {0x3086, 0x1D25}, {0x3086, 0x0020}, {0x3086, 0x1F17}, {0x3086, 0x1028}, {0x3086, 0x0519},
++{0x3086, 0x1703}, {0x3086, 0x2706}, {0x3086, 0x1703}, {0x3086, 0x1741}, {0x3086, 0x2660}, {0x3086, 0x17AE}, {0x3086, 0x2500}, {0x3086, 0x9027},
++{0x3086, 0x0026}, {0x3086, 0x1828}, {0x3086, 0x002E}, {0x3086, 0x2A28}, {0x3086, 0x081C}, {0x3086, 0x1470}, {0x3086, 0x7003}, {0x3086, 0x1470},
++{0x3086, 0x7004}, {0x3086, 0x1470}, {0x3086, 0x7005}, {0x3086, 0x1470}, {0x3086, 0x7009}, {0x3086, 0x170C}, {0x3086, 0x0014}, {0x3086, 0x0020},
++{0x3086, 0x2300}, {0x3086, 0x1400}, {0x3086, 0x5003}, {0x3086, 0x1400}, {0x3086, 0x2003}, {0x3086, 0x1400}, {0x3086, 0x5022}, {0x3086, 0x0414},
++{0x3086, 0x0020}, {0x3086, 0x0414}, {0x3086, 0x0050}, {0x3086, 0x0514}, {0x3086, 0x0020}, {0x3086, 0x2405}, {0x3086, 0x1400}, {0x3086, 0x5001},
++{0x3086, 0x2550}, {0x3086, 0x502D}, {0x3086, 0x2608}, {0x3086, 0x280D}, {0x3086, 0x1709}, {0x3086, 0x2600}, {0x3086, 0x2805}, {0x3086, 0x26A7},
++{0x3086, 0x2807}, {0x3086, 0x2580}, {0x3086, 0x8029}, {0x3086, 0x2500}, {0x3086, 0x4027}, {0x3086, 0x0216}, {0x3086, 0x1627}, {0x3086, 0x0617},
++{0x3086, 0x3626}, {0x3086, 0xA617}, {0x3086, 0x0326}, {0x3086, 0xA417}, {0x3086, 0x1F28}, {0x3086, 0x0526}, {0x3086, 0x2028}, {0x3086, 0x0425},
++{0x3086, 0x2020}, {0x3086, 0x2700}, {0x3086, 0x171D}, {0x3086, 0x2500}, {0x3086, 0x2020}, {0x3086, 0x1710}, {0x3086, 0x2805}, {0x3086, 0x1A17},
++{0x3086, 0x0327}, {0x3086, 0x0617}, {0x3086, 0x0317}, {0x3086, 0x4126}, {0x3086, 0x6017}, {0x3086, 0xAE25}, {0x3086, 0x0090}, {0x3086, 0x2700},
++{0x3086, 0x2618}, {0x3086, 0x2800}, {0x3086, 0x2E2A}, {0x3086, 0x2808}, {0x3086, 0x1D05}, {0x3086, 0x1470}, {0x3086, 0x7009}, {0x3086, 0x1720},
++{0x3086, 0x1400}, {0x3086, 0x2024}, {0x3086, 0x1400}, {0x3086, 0x5002}, {0x3086, 0x2550}, {0x3086, 0x502D}, {0x3086, 0x2608}, {0x3086, 0x280D},
++{0x3086, 0x1709}, {0x3086, 0x2600}, {0x3086, 0x2805}, {0x3086, 0x26A7}, {0x3086, 0x2807}, {0x3086, 0x2580}, {0x3086, 0x8029}, {0x3086, 0x2500},
++{0x3086, 0x4027}, {0x3086, 0x0216}, {0x3086, 0x1627}, {0x3086, 0x0617}, {0x3086, 0x3626}, {0x3086, 0xA617}, {0x3086, 0x0326}, {0x3086, 0xA417},
++{0x3086, 0x1F28}, {0x3086, 0x0526}, {0x3086, 0x2028}, {0x3086, 0x0425}, {0x3086, 0x2020}, {0x3086, 0x2700}, {0x3086, 0x171D}, {0x3086, 0x2500},
++{0x3086, 0x2021}, {0x3086, 0x1710}, {0x3086, 0x2805}, {0x3086, 0x1B17}, {0x3086, 0x0327}, {0x3086, 0x0617}, {0x3086, 0x0317}, {0x3086, 0x4126},
++{0x3086, 0x6017}, {0x3086, 0xAE25}, {0x3086, 0x0090}, {0x3086, 0x2700}, {0x3086, 0x2618}, {0x3086, 0x2800}, {0x3086, 0x2E2A}, {0x3086, 0x2808},
++{0x3086, 0x1E17}, {0x3086, 0x0A05}, {0x3086, 0x1470}, {0x3086, 0x7009}, {0x3086, 0x1616}, {0x3086, 0x1616}, {0x3086, 0x1616}, {0x3086, 0x1616},
++{0x3086, 0x1616}, {0x3086, 0x1616}, {0x3086, 0x1616}, {0x3086, 0x1616}, {0x3086, 0x1616}, {0x3086, 0x1616}, {0x3086, 0x1616}, {0x3086, 0x1616},
++{0x3086, 0x1616}, {0x3086, 0x1616}, {0x3086, 0x1616}, {0x3086, 0x1616}, {0x3086, 0x1400}, {0x3086, 0x2024}, {0x3086, 0x1400}, {0x3086, 0x502B},
++{0x3086, 0x302C}, {0x3086, 0x2C2C}, {0x3086, 0x2C00}, {0x3086, 0x0225}, {0x3086, 0x5050}, {0x3086, 0x2D26}, {0x3086, 0x0828}, {0x3086, 0x0D17},
++{0x3086, 0x0926}, {0x3086, 0x0028}, {0x3086, 0x0526}, {0x3086, 0xA728}, {0x3086, 0x0725}, {0x3086, 0x8080}, {0x3086, 0x2917}, {0x3086, 0x0525},
++{0x3086, 0x0040}, {0x3086, 0x2702}, {0x3086, 0x1616}, {0x3086, 0x2706}, {0x3086, 0x1736}, {0x3086, 0x26A6}, {0x3086, 0x1703}, {0x3086, 0x26A4},
++{0x3086, 0x171F}, {0x3086, 0x2805}, {0x3086, 0x2620}, {0x3086, 0x2804}, {0x3086, 0x2520}, {0x3086, 0x2027}, {0x3086, 0x0017}, {0x3086, 0x1E25},
++{0x3086, 0x0020}, {0x3086, 0x2117}, {0x3086, 0x1028}, {0x3086, 0x051B}, {0x3086, 0x1703}, {0x3086, 0x2706}, {0x3086, 0x1703}, {0x3086, 0x1747},
++{0x3086, 0x2660}, {0x3086, 0x17AE}, {0x3086, 0x2500}, {0x3086, 0x9027}, {0x3086, 0x0026}, {0x3086, 0x1828}, {0x3086, 0x002E}, {0x3086, 0x2A28},
++{0x3086, 0x081E}, {0x3086, 0x0831}, {0x3086, 0x1440}, {0x3086, 0x4014}, {0x3086, 0x2020}, {0x3086, 0x1410}, {0x3086, 0x1034}, {0x3086, 0x1400},
++{0x3086, 0x1014}, {0x3086, 0x0020}, {0x3086, 0x1400}, {0x3086, 0x4013}, {0x3086, 0x1802}, {0x3086, 0x1470}, {0x3086, 0x7004}, {0x3086, 0x1470},
++{0x3086, 0x7003}, {0x3086, 0x1470}, {0x3086, 0x7017}, {0x3086, 0x2002}, {0x3086, 0x1400}, {0x3086, 0x2002}, {0x3086, 0x1400}, {0x3086, 0x5004},
++{0x3086, 0x1400}, {0x3086, 0x2004}, {0x3086, 0x1400}, {0x3086, 0x5022}, {0x3086, 0x0314}, {0x3086, 0x0020}, {0x3086, 0x0314}, {0x3086, 0x0050},
++{0x3086, 0x2C2C}, {0x3086, 0x2C2C},
++{0x309E, 0x0186},
++{0x309E, 0x0186},
++// patch end
++{AR0132_DELAY, 250},
++{0x301A, 0x10D8}, // WR= RESET_REGISTER, 0x10D8 - stop streaming
++{0x3082, 0x0028}, // Set HiDy OPERATION_MODE_CTRL(A) Requested integration time ratio (T2 to T3): 8 & (T1 t0 T2): 16
++{0x3084, 0x0028}, // Set HiDy OPERATION_MODE_CTRL(B) Requested integration time ratio (T2 to T3): 16 & (T1 t0 T2): 16
++{0x301E, 0x00C8}, // set datapedestal to 200 to avoid clipping near saturation
++{0x3EDA, 0x0F03}, // Set vln_dac to 0x3 as recommended by Sergey
++{0x3EDE, 0xC007},
++{0x3ED8, 0x01EF}, // Vrst_low = +1
++{0x3EE2, 0xA46B},
++{0x3EE0, 0x067D}, // enable anti eclipse and adjust setting for high conversion gain
++{0x3EDC, 0x0070}, // adjust anti eclipse setting for low conversion gain
++{0x3044, 0x0404}, // disable digital row noise correction and cancels TX during column correction
++{0x3EE6, 0x4303}, // Helps with column noise at low light
++{0x3EE4, 0xD208}, // enable analog row noise correction
++{0x3ED6, 0x00BD},
++{0x3EE6, 0x8303}, // improves low light FPN
++{0x30E4, 0x6372}, // ADC settings to improve noise performance
++{0x30E2, 0x7253},
++{0x30E0, 0x5470},
++{0x30E6, 0xC4CC},
++{0x30E8, 0x8050},
++{AR0132_DELAY, 250},
++{0x3058, 0x003F}, // WR= BLUE_GAIN, 0x003F
++{0x3014, 0}, // Fine_IT_Time(A)
++{0x3002, AR0132_ROI_Y_START}, // WR= Y_ADDR_START_(A)
++{0x3004, AR0132_ROI_X_START}, // WR= X_ADDR_START_(A)
++{0x3006, AR0132_ROI_Y_END}, // WR= Y_ADDR_END_(A)
++{0x3008, AR0132_ROI_X_END}, // WR= X_ADDR_END_(A)
++{0x300A, AR0132_FrameLength_Lines}, // WR= FRAME_LENGTH_LINES_(A)
++{0x3018, 0}, // Fine_IT_Time(B)
++{0x308C, AR0132_ROI_Y_START}, // Y_ADDR_START_(B)
++{0x308A, AR0132_ROI_X_START}, // X_ADDR_START_(B)
++{0x3090, AR0132_ROI_Y_END}, // Y_ADDR_END_(B)
++{0x308E, AR0132_ROI_X_END}, // X_ADDR_END_(B)
++{0x30AA, AR0132_FrameLength_Lines}, // FRAME_LENGTH_LINES_(B)
++{0x300C, AR0132_LineLength_Ticks}, // Line Length
++{0x301A, 0x10D8}, // Disable Streaming and setup parallel
++{0x31D0, 0x0001}, // Set to 12 bits
++{0x3028, 0x0010}, // ROW_SPEED = 16
++{0x302A, AR0132_PLL_VT_Pix_Clk_Div},
++{0x302C, AR0132_PLL_VT_Sys_Clk_Div},
++{0x302E, AR0132_PLL_Pre_Clk_Div},
++{0x3030, AR0132_PLL_Multiplier},
++{0x3032, 0x0000}, // SCALING_MODE = 0
++{0x3040, 0xC000}, // READ_MODE = read_mode_vert_flip | read_mode_horiz_mirror
++{0x3044, 0x0404}, // Dark Control = 1028
++{0x30A6, 0x0001}, // Y Odd Inc. (A) = 1
++{0x30A8, 0x0001}, // Y Odd Inc. (B) = 1
++{0x30B0, AR0132_DigitalTest},
++{AR0132_DELAY, 100},
++#ifdef AR0132_EMBEDDED_LINE
++{0x3064, 0x1982}, // Embedded Data on
++#else
++{0x3064, 0x1802}, // Embedded Data off
++#endif
++{0x3100, 0x0084}, // WR= AECTRLREG,
++{0x3190, 0x6BA0},
++{0x3194, 0x0E74},
++{0x3196, 0x0ED8},
++{0x3198, 0x0FA0},
++{0x319E, 0x5040}, // resetvalue
++{0x31A2, 0x0FA0},
++//FrontCamera Specific Section
++//Common
++#ifdef AR0132_EMBEDDED_LINE
++{0x3064, 0x1982},
++#else
++{0x3064, 0x1802},
++#endif
++{0x30B4, 0x0011},
++{0x30ba, 0x0008},
++{0x3180, 0xE000},
++{0x3182, 0x012C},
++{0x3190, 0x6BA0},
++{0x3194, 0x0E74},
++{0x3196, 0x0ED8},
++{0x3198, 0x0FA0},
++{0x319E, 0x5040},
++{0x31A2, 0x0FA0},
++//Context A:0
++{0x3012, 0x0021},
++{0x3014, 0x0000},
++{0x30A6, 0x0001},
++{0x3056, 0x0008},
++{0x3058, 0x0008},
++{0x305A, 0x0008},
++{0x305C, 0x0008},
++{0x305E, 0x0008},
++{0x3082, 0x0014},
++//Context B:0
++{0x3016, 0x007F},
++{0x3018, 0x0000},
++{0x30A8, 0x0001},
++{0x30BC, 0x0020},
++{0x30BE, 0x0020},
++{0x30C0, 0x0020},
++{0x30C2, 0x0020},
++{0x30C4, 0x0020},
++{0x3084, 0x0028},
++//not covered
++{0x301E, 0x00C8},
++{0x3044, 0x0404},
++{0x31D0, 0x0001},
++{0x30B0, 0x2002},
++};
diff --git a/drivers/media/i2c/soc_camera/max9286_max9271.c b/drivers/media/i2c/soc_camera/max9286_max9271.c
new file mode 100644
index 0000000..9797d24
@@ -698,10 +1475,10 @@ index 0000000..9797d24
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/soc_camera/max9286_max9271.h b/drivers/media/i2c/soc_camera/max9286_max9271.h
new file mode 100644
-index 0000000..87c040b
+index 0000000..0016f28a
--- /dev/null
+++ b/drivers/media/i2c/soc_camera/max9286_max9271.h
-@@ -0,0 +1,196 @@
+@@ -0,0 +1,243 @@
+/*
+ * MAXIM max9286-max9271 GMSL driver include file
+ *
@@ -833,6 +1610,53 @@ index 0000000..87c040b
+ return ret < 0 ? ret : 0;
+}
+
++
++static inline int reg16_read16(struct i2c_client *client, u16 reg, u16 *val)
++{
++ int ret, retries;
++ u8 buf[2] = {reg >> 8, reg & 0xff};
++
++ for (retries = REG8_NUM_RETRIES; retries; retries--) {
++ ret = i2c_master_send(client, buf, 2);
++ if (ret == 2) {
++ ret = i2c_master_recv(client, buf, 2);
++ if (ret == 2)
++ break;
++ }
++ }
++
++ if (ret < 0) {
++ dev_err(&client->dev,
++ "read fail: chip 0x%x register 0x%x: %d\n",
++ client->addr, reg, ret);
++ } else {
++ *val = ((u16)buf[0] << 8) | buf[1];
++ }
++
++ return ret < 0 ? ret : 0;
++}
++
++static inline int reg16_write16(struct i2c_client *client, u16 reg, u16 val)
++{
++ int ret, retries;
++ u8 buf[4] = {reg >> 8, reg & 0xff, val >> 8, val & 0xff};
++
++ for (retries = REG8_NUM_RETRIES; retries; retries--) {
++ ret = i2c_master_send(client, buf, 4);
++ if (ret == 4)
++ break;
++ }
++
++ if (ret < 0) {
++ dev_err(&client->dev,
++ "write fail: chip 0x%x register 0x%x: %d\n",
++ client->addr, reg, ret);
++ }
++
++ return ret < 0 ? ret : 0;
++}
++
++
+#ifdef MAXIM_DUMP
+static void maxim_ovsensor_dump_regs(struct i2c_client *client)
+{
@@ -2870,10 +3694,10 @@ index 0000000..4c3515a
+#endif
diff --git a/drivers/media/i2c/soc_camera/ov106xx.c b/drivers/media/i2c/soc_camera/ov106xx.c
new file mode 100644
-index 0000000..0079bb2
+index 0000000..f2bb706
--- /dev/null
+++ b/drivers/media/i2c/soc_camera/ov106xx.c
-@@ -0,0 +1,95 @@
+@@ -0,0 +1,106 @@
+/*
+ * OmniVision ov10635/ov490-ov10640/ov495-ov2775 sensor camera driver
+ *
@@ -2888,11 +3712,13 @@ index 0000000..0079bb2
+#include "ov10635.c"
+#include "ov490_ov10640.c"
+#include "ov495_ov2775.c"
++#include "ar0132.c"
+
+static enum {
+ ID_OV10635,
+ ID_OV490_OV10640,
+ ID_OV495_OV2775,
++ ID_AR0132,
+} chip_id;
+
+static int ov106xx_probe(struct i2c_client *client,
@@ -2919,6 +3745,12 @@ index 0000000..0079bb2
+ goto out;
+ }
+
++ ret = ar0132_probe(client, did);
++ if (!ret) {
++ chip_id = ID_AR0132;
++ goto out;
++ }
++
+ v4l_err(client, "failed to probe @ 0x%02x (%s)\n",
+ client->addr, client->adapter->name);
+out:
@@ -2937,6 +3769,9 @@ index 0000000..0079bb2
+ case ID_OV495_OV2775:
+ ov495_remove(client);
+ break;
++ case ID_AR0132:
++ ar0132_remove(client);
++ break;
+ };
+
+ return 0;
@@ -2966,7 +3801,7 @@ index 0000000..0079bb2
+
+module_i2c_driver(ov106xx_i2c_driver);
+
-+MODULE_DESCRIPTION("SoC Camera driver for OV10635 or OV490/OV10640 or OV495/OV2775");
++MODULE_DESCRIPTION("SoC Camera driver for OV10635 or OV490/OV10640 or OV495/OV2775 or AR0132");
+MODULE_AUTHOR("Vladimir Barinov");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/soc_camera/ov490_ov10640.c b/drivers/media/i2c/soc_camera/ov490_ov10640.c
@@ -5624,10 +6459,10 @@ index 0000000..8dd0f99
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/soc_camera/ti9x4_ti9x3.h b/drivers/media/i2c/soc_camera/ti9x4_ti9x3.h
new file mode 100644
-index 0000000..0cee5f1
+index 0000000..69d3728
--- /dev/null
+++ b/drivers/media/i2c/soc_camera/ti9x4_ti9x3.h
-@@ -0,0 +1,108 @@
+@@ -0,0 +1,153 @@
+/*
+ * TI FPDLinkIII driver include file
+ *
@@ -5735,6 +6570,51 @@ index 0000000..0cee5f1
+
+ return ret < 0 ? ret : 0;
+}
++
++static inline int reg16_read16(struct i2c_client *client, u16 reg, u16 *val)
++{
++ int ret, retries;
++ u8 buf[2] = {reg >> 8, reg & 0xff};
++
++ for (retries = MAXIM_NUM_RETRIES; retries; retries--) {
++ ret = i2c_master_send(client, buf, 2);
++ if (ret == 2) {
++ ret = i2c_master_recv(client, buf, 2);
++ if (ret == 2)
++ break;
++ }
++ }
++
++ if (ret < 0) {
++ dev_err(&client->dev,
++ "read fail: chip 0x%x register 0x%x: %d\n",
++ client->addr, reg, ret);
++ } else {
++ *val = ((u16)buf[0] << 8) | buf[1];
++ }
++
++ return ret < 0 ? ret : 0;
++}
++
++static inline int reg16_write16(struct i2c_client *client, u16 reg, u16 val)
++{
++ int ret, retries;
++ u8 buf[4] = {reg >> 8, reg & 0xff, val >> 8, val & 0xff};
++
++ for (retries = MAXIM_NUM_RETRIES; retries; retries--) {
++ ret = i2c_master_send(client, buf, 4);
++ if (ret == 4)
++ break;
++ }
++
++ if (ret < 0) {
++ dev_err(&client->dev,
++ "write fail: chip 0x%x register 0x%x: %d\n",
++ client->addr, reg, ret);
++ }
++
++ return ret < 0 ? ret : 0;
++}
+#endif /* _TI9X4_H */
diff --git a/drivers/media/platform/soc_camera/rcar_csi2.c b/drivers/media/platform/soc_camera/rcar_csi2.c
index 4d95da6..2ef27e8 100644
@@ -6223,7 +7103,7 @@ index 4d95da6..2ef27e8 100644
return 0;
diff --git a/drivers/media/platform/soc_camera/rcar_vin.c b/drivers/media/platform/soc_camera/rcar_vin.c
-index 74fb005..f5c2528 100644
+index 74fb005..496a8bd 100644
--- a/drivers/media/platform/soc_camera/rcar_vin.c
+++ b/drivers/media/platform/soc_camera/rcar_vin.c
@@ -106,6 +106,7 @@
@@ -6264,17 +7144,18 @@ index 74fb005..f5c2528 100644
/* Synchronous probing compatibility */
struct platform_device *csi2_pdev;
-@@ -989,6 +995,9 @@ static int rcar_vin_setup(struct rcar_vin_priv *priv)
+@@ -989,6 +995,10 @@ static int rcar_vin_setup(struct rcar_vin_priv *priv)
VNMC_INF_YUV10_BT656 : VNMC_INF_YUV10_BT601;
input_is_yuv = true;
break;
+ case MEDIA_BUS_FMT_SBGGR8_1X8:
++ case MEDIA_BUS_FMT_SBGGR12_1X12:
+ vnmc |= VNMC_INF_RAW8 | VNMC_BPS;
+ break;
default:
break;
}
-@@ -1021,6 +1030,10 @@ static int rcar_vin_setup(struct rcar_vin_priv *priv)
+@@ -1021,6 +1031,10 @@ static int rcar_vin_setup(struct rcar_vin_priv *priv)
dmr = 0;
output_is_yuv = true;
break;
@@ -6285,27 +7166,29 @@ index 74fb005..f5c2528 100644
case V4L2_PIX_FMT_ARGB555:
dmr = VNDMR_DTMD_ARGB;
break;
-@@ -1043,6 +1056,9 @@ static int rcar_vin_setup(struct rcar_vin_priv *priv)
+@@ -1043,6 +1057,10 @@ static int rcar_vin_setup(struct rcar_vin_priv *priv)
dmr = VNDMR_EXRGB | VNDMR_DTMD_ARGB;
break;
+ case V4L2_PIX_FMT_SBGGR8:
++ case V4L2_PIX_FMT_SBGGR12:
+ dmr = 0;
+ break;
default:
goto e_format;
}
-@@ -1061,7 +1077,8 @@ static int rcar_vin_setup(struct rcar_vin_priv *priv)
+@@ -1061,7 +1079,9 @@ static int rcar_vin_setup(struct rcar_vin_priv *priv)
else
vnmc |= VNMC_DPINE;
- if ((icd->current_fmt->host_fmt->fourcc != V4L2_PIX_FMT_NV12)
+ if ((icd->current_fmt->host_fmt->fourcc != V4L2_PIX_FMT_NV12) &&
-+ (icd->current_fmt->host_fmt->fourcc != V4L2_PIX_FMT_SBGGR8)
++ (icd->current_fmt->host_fmt->fourcc != V4L2_PIX_FMT_SBGGR8) &&
++ (icd->current_fmt->host_fmt->fourcc != V4L2_PIX_FMT_SBGGR12)
&& is_scaling(cam))
vnmc |= VNMC_SCLE;
}
-@@ -1211,6 +1228,10 @@ static void rcar_vin_videobuf_queue(struct vb2_buffer *vb)
+@@ -1211,6 +1231,10 @@ static void rcar_vin_videobuf_queue(struct vb2_buffer *vb)
*/
static void rcar_vin_wait_stop_streaming(struct rcar_vin_priv *priv)
{
@@ -6316,7 +7199,7 @@ index 74fb005..f5c2528 100644
while (priv->state != STOPPED) {
/* issue stop if running */
if (priv->state == RUNNING)
-@@ -1361,6 +1382,31 @@ static struct v4l2_subdev *find_csi2(struct rcar_vin_priv *pcdev)
+@@ -1361,6 +1385,31 @@ static struct v4l2_subdev *find_csi2(struct rcar_vin_priv *pcdev)
return NULL;
}
@@ -6348,7 +7231,7 @@ index 74fb005..f5c2528 100644
static int rcar_vin_add_device(struct soc_camera_device *icd)
{
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
-@@ -1375,7 +1421,8 @@ static int rcar_vin_add_device(struct soc_camera_device *icd)
+@@ -1375,7 +1424,8 @@ static int rcar_vin_add_device(struct soc_camera_device *icd)
if (priv->chip == RCAR_H3 || priv->chip == RCAR_M3 ||
priv->chip == RCAR_V3M) {
struct v4l2_subdev *csi2_sd = find_csi2(priv);
@@ -6358,7 +7241,7 @@ index 74fb005..f5c2528 100644
if (csi2_sd) {
csi2_sd->grp_id = soc_camera_grp_id(icd);
-@@ -1390,6 +1437,18 @@ static int rcar_vin_add_device(struct soc_camera_device *icd)
+@@ -1390,6 +1440,18 @@ static int rcar_vin_add_device(struct soc_camera_device *icd)
if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV)
return ret;
}
@@ -6377,7 +7260,7 @@ index 74fb005..f5c2528 100644
/*
* -ENODEV is special:
* either csi2_sd == NULL or the CSI-2 driver
-@@ -1417,6 +1476,7 @@ static void rcar_vin_remove_device(struct soc_camera_device *icd)
+@@ -1417,6 +1479,7 @@ static void rcar_vin_remove_device(struct soc_camera_device *icd)
struct rcar_vin_priv *priv = ici->priv;
struct vb2_v4l2_buffer *vbuf;
struct v4l2_subdev *csi2_sd = find_csi2(priv);
@@ -6385,7 +7268,7 @@ index 74fb005..f5c2528 100644
int i;
/* disable capture, disable interrupts */
-@@ -1443,6 +1503,8 @@ static void rcar_vin_remove_device(struct soc_camera_device *icd)
+@@ -1443,6 +1506,8 @@ static void rcar_vin_remove_device(struct soc_camera_device *icd)
if ((csi2_sd) && (priv->csi_sync))
v4l2_subdev_call(csi2_sd, core, s_power, 0);
@@ -6394,27 +7277,29 @@ index 74fb005..f5c2528 100644
dev_dbg(icd->parent, "R-Car VIN driver detached from camera %d\n",
icd->devnum);
-@@ -1621,13 +1683,17 @@ static int rcar_vin_set_rect(struct soc_camera_device *icd)
+@@ -1621,13 +1686,19 @@ static int rcar_vin_set_rect(struct soc_camera_device *icd)
if (priv->chip == RCAR_H3 || priv->chip == RCAR_M3 ||
priv->chip == RCAR_V3M) {
- if ((icd->current_fmt->host_fmt->fourcc != V4L2_PIX_FMT_NV12)
+ if ((icd->current_fmt->host_fmt->fourcc != V4L2_PIX_FMT_NV12) &&
-+ (icd->current_fmt->host_fmt->fourcc != V4L2_PIX_FMT_SBGGR8)
++ (icd->current_fmt->host_fmt->fourcc != V4L2_PIX_FMT_SBGGR8) &&
++ (icd->current_fmt->host_fmt->fourcc != V4L2_PIX_FMT_SBGGR12)
&& is_scaling(cam)) {
ret = rcar_vin_uds_set(priv, cam);
if (ret < 0)
return ret;
}
- if (is_scaling(cam) ||
-+ if (icd->current_fmt->host_fmt->fourcc == V4L2_PIX_FMT_SBGGR8)
++ if ((icd->current_fmt->host_fmt->fourcc == V4L2_PIX_FMT_SBGGR8) ||
++ (icd->current_fmt->host_fmt->fourcc == V4L2_PIX_FMT_SBGGR12))
+ iowrite32(ALIGN(cam->out_width / 2, 0x10),
+ priv->base + VNIS_REG);
+ else if (is_scaling(cam) ||
(icd->current_fmt->host_fmt->fourcc == V4L2_PIX_FMT_NV16) ||
(icd->current_fmt->host_fmt->fourcc == V4L2_PIX_FMT_NV12))
iowrite32(ALIGN(cam->out_width, 0x20),
-@@ -1868,6 +1934,14 @@ static bool rcar_vin_packing_supported(const struct soc_mbus_pixelfmt *fmt)
+@@ -1868,6 +1939,14 @@ static bool rcar_vin_packing_supported(const struct soc_mbus_pixelfmt *fmt)
.layout = SOC_MBUS_LAYOUT_PACKED,
},
{
@@ -6429,7 +7314,7 @@ index 74fb005..f5c2528 100644
.fourcc = V4L2_PIX_FMT_RGB565,
.name = "RGB565",
.bits_per_sample = 16,
-@@ -1899,6 +1973,14 @@ static bool rcar_vin_packing_supported(const struct soc_mbus_pixelfmt *fmt)
+@@ -1899,6 +1978,22 @@ static bool rcar_vin_packing_supported(const struct soc_mbus_pixelfmt *fmt)
.order = SOC_MBUS_ORDER_LE,
.layout = SOC_MBUS_LAYOUT_PACKED,
},
@@ -6441,18 +7326,27 @@ index 74fb005..f5c2528 100644
+ .order = SOC_MBUS_ORDER_LE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
+ },
++ {
++ .fourcc = V4L2_PIX_FMT_SBGGR12,
++ .name = "Bayer 12 BGGR",
++ .bits_per_sample = 8,
++ .packing = SOC_MBUS_PACKING_NONE,
++ .order = SOC_MBUS_ORDER_LE,
++ .layout = SOC_MBUS_LAYOUT_PACKED,
++ },
};
static int rcar_vin_get_formats(struct soc_camera_device *icd, unsigned int idx,
-@@ -2012,6 +2094,7 @@ static int rcar_vin_get_formats(struct soc_camera_device *icd, unsigned int idx,
+@@ -2012,6 +2107,8 @@ static int rcar_vin_get_formats(struct soc_camera_device *icd, unsigned int idx,
case MEDIA_BUS_FMT_YUYV8_2X8:
case MEDIA_BUS_FMT_YUYV10_2X10:
case MEDIA_BUS_FMT_RGB888_1X24:
+ case MEDIA_BUS_FMT_SBGGR8_1X8:
++ case MEDIA_BUS_FMT_SBGGR12_1X12:
if (cam->extra_fmt)
break;
-@@ -2218,12 +2301,14 @@ static int rcar_vin_set_fmt(struct soc_camera_device *icd,
+@@ -2218,12 +2315,15 @@ static int rcar_vin_set_fmt(struct soc_camera_device *icd,
case V4L2_PIX_FMT_ABGR32:
case V4L2_PIX_FMT_UYVY:
case V4L2_PIX_FMT_YUYV:
@@ -6464,10 +7358,11 @@ index 74fb005..f5c2528 100644
break;
case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_SBGGR8:
++ case V4L2_PIX_FMT_SBGGR12:
default:
can_scale = false;
break;
-@@ -2316,7 +2401,8 @@ static int rcar_vin_try_fmt(struct soc_camera_device *icd,
+@@ -2316,7 +2416,8 @@ static int rcar_vin_try_fmt(struct soc_camera_device *icd,
/* odd number clipping by pixel post clip processing, */
/* it is outputted to a memory per even pixels. */
if ((pixfmt == V4L2_PIX_FMT_NV16) || (pixfmt == V4L2_PIX_FMT_NV12) ||
@@ -6477,7 +7372,7 @@ index 74fb005..f5c2528 100644
v4l_bound_align_image(&pix->width, 5, priv->max_width, 1,
&pix->height, 2, priv->max_height, 0, 0);
else
-@@ -2486,6 +2572,19 @@ static int rcar_vin_cropcap(struct soc_camera_device *icd,
+@@ -2486,6 +2587,19 @@ static int rcar_vin_cropcap(struct soc_camera_device *icd,
}
#endif
@@ -6497,7 +7392,7 @@ index 74fb005..f5c2528 100644
static struct soc_camera_host_ops rcar_vin_host_ops = {
.owner = THIS_MODULE,
.add = rcar_vin_add_device,
-@@ -2504,6 +2603,7 @@ static int rcar_vin_cropcap(struct soc_camera_device *icd,
+@@ -2504,6 +2618,7 @@ static int rcar_vin_cropcap(struct soc_camera_device *icd,
.get_selection = rcar_vin_get_selection,
.cropcap = rcar_vin_cropcap,
#endif
@@ -6505,7 +7400,7 @@ index 74fb005..f5c2528 100644
};
#ifdef CONFIG_OF
-@@ -2524,7 +2624,7 @@ static int rcar_vin_cropcap(struct soc_camera_device *icd,
+@@ -2524,7 +2639,7 @@ static int rcar_vin_cropcap(struct soc_camera_device *icd,
MODULE_DEVICE_TABLE(of, rcar_vin_of_table);
#endif
@@ -6514,7 +7409,7 @@ index 74fb005..f5c2528 100644
static DECLARE_BITMAP(device_map, MAP_MAX_NUM);
static DEFINE_MUTEX(list_lock);
-@@ -2714,7 +2814,11 @@ static int rcar_vin_probe(struct platform_device *pdev)
+@@ -2714,7 +2829,11 @@ static int rcar_vin_probe(struct platform_device *pdev)
const char *str;
unsigned int i;
struct device_node *epn = NULL, *ren = NULL;
@@ -6526,7 +7421,7 @@ index 74fb005..f5c2528 100644
match = of_match_device(of_match_ptr(rcar_vin_of_table), &pdev->dev);
-@@ -2741,13 +2845,27 @@ static int rcar_vin_probe(struct platform_device *pdev)
+@@ -2741,13 +2860,27 @@ static int rcar_vin_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "node name:%s\n",
of_node_full_name(ren->parent));
@@ -6558,7 +7453,7 @@ index 74fb005..f5c2528 100644
}
ret = v4l2_of_parse_endpoint(np, &ep);
-@@ -2799,6 +2917,7 @@ static int rcar_vin_probe(struct platform_device *pdev)
+@@ -2799,6 +2932,7 @@ static int rcar_vin_probe(struct platform_device *pdev)
priv->ici.drv_name = dev_name(&pdev->dev);
priv->ici.ops = &rcar_vin_host_ops;
priv->csi_sync = false;
@@ -6566,7 +7461,7 @@ index 74fb005..f5c2528 100644
priv->pdata_flags = pdata_flags;
if (!match) {
-@@ -2983,7 +3102,25 @@ static int rcar_vin_probe(struct platform_device *pdev)
+@@ -2983,7 +3117,25 @@ static int rcar_vin_probe(struct platform_device *pdev)
goto cleanup;
if (csi_use) {