From a857465243afa77deb67371a0613c4dedb75d9b9 Mon Sep 17 00:00:00 2001 From: Vladimir Barinov Date: Mon, 28 Aug 2017 03:20:46 +0300 Subject: Add AR0132 LVDS camera support --- .../linux-renesas/0030-Gen3-LVDS-cameras.patch | 975 ++++++++++++++++++++- 1 file 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 --- 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 ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#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, }, @@ -6440,19 +7325,28 @@ index 74fb005..f5c2528 100644 + .packing = SOC_MBUS_PACKING_NONE, + .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) { -- cgit 1.2.3-korg