Show a patch.

GET /api/1.1/patches/4160/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 4160,
    "url": "https://patchwork.libcamera.org/api/1.1/patches/4160/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/4160/",
    "project": {
        "id": 1,
        "url": "https://patchwork.libcamera.org/api/1.1/projects/1/?format=api",
        "name": "libcamera",
        "link_name": "libcamera",
        "list_id": "libcamera_core",
        "list_email": "libcamera-devel@lists.libcamera.org",
        "web_url": "",
        "scm_url": "",
        "webscm_url": ""
    },
    "msgid": "<20200623164224.44476-3-jacopo@jmondi.org>",
    "date": "2020-06-23T16:42:22",
    "name": "[libcamera-devel,13/25] media: ov5647: Support gain, exposure and AWB controls",
    "commit_ref": null,
    "pull_url": null,
    "state": "not-applicable",
    "archived": false,
    "hash": "03cdf4f8e81e28b9e69918c559a1b84bdd4c7fb4",
    "submitter": {
        "id": 3,
        "url": "https://patchwork.libcamera.org/api/1.1/people/3/?format=api",
        "name": "Jacopo Mondi",
        "email": "jacopo@jmondi.org"
    },
    "delegate": {
        "id": 15,
        "url": "https://patchwork.libcamera.org/api/1.1/users/15/?format=api",
        "username": "jmondi",
        "first_name": "Jacopo",
        "last_name": "Mondi",
        "email": "jacopo@jmondi.org"
    },
    "mbox": "https://patchwork.libcamera.org/patch/4160/mbox/",
    "series": [
        {
            "id": 1030,
            "url": "https://patchwork.libcamera.org/api/1.1/series/1030/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=1030",
            "date": "2020-06-23T10:07:50",
            "name": "media: ov5647: Support RaspberryPi Camera Module v1",
            "version": 1,
            "mbox": "https://patchwork.libcamera.org/series/1030/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/4160/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/4160/checks/",
    "tags": {},
    "headers": {
        "Return-Path": "<jacopo@jmondi.org>",
        "Received": [
            "from relay3-d.mail.gandi.net (relay3-d.mail.gandi.net\n\t[217.70.183.195])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 4A903609A5\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 23 Jun 2020 18:39:18 +0200 (CEST)",
            "from uno.lan (93-34-118-233.ip49.fastwebnet.it [93.34.118.233])\n\t(Authenticated sender: jacopo@jmondi.org)\n\tby relay3-d.mail.gandi.net (Postfix) with ESMTPSA id D938460009;\n\tTue, 23 Jun 2020 16:39:14 +0000 (UTC)"
        ],
        "X-Originating-IP": "93.34.118.233",
        "From": "Jacopo Mondi <jacopo@jmondi.org>",
        "To": "mchehab@kernel.org, sakari.ailus@linux.intel.com, hverkuil@xs4all.nl,\n\tlaurent.pinchart@ideasonboard.com, roman.kovalivskyi@globallogic.com, \n\tdave.stevenson@raspberrypi.org, naush@raspberrypi.com",
        "Cc": "mrodin@de.adit-jv.com, hugues.fruchet@st.com, mripard@kernel.org,\n\taford173@gmail.com, sudipi@jp.adit-jv.com, andrew_gabbasov@mentor.com,\n\terosca@de.adit-jv.com, linux-media@vger.kernel.org,\n\tlibcamera-devel@lists.libcamera.org,\n\tDavid Plowman <david.plowman@raspberrypi.com>,\n\tJacopo Mondi <jacopo@jmondi.org>",
        "Date": "Tue, 23 Jun 2020 18:42:22 +0200",
        "Message-Id": "<20200623164224.44476-3-jacopo@jmondi.org>",
        "X-Mailer": "git-send-email 2.27.0",
        "In-Reply-To": "<20200623100815.10674-1-jacopo@jmondi.org>",
        "References": "<20200623100815.10674-1-jacopo@jmondi.org>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "Subject": "[libcamera-devel] [PATCH 13/25] media: ov5647: Support gain,\n\texposure and AWB controls",
        "X-BeenThere": "libcamera-devel@lists.libcamera.org",
        "X-Mailman-Version": "2.1.29",
        "Precedence": "list",
        "List-Id": "<libcamera-devel.lists.libcamera.org>",
        "List-Unsubscribe": "<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>",
        "List-Archive": "<https://lists.libcamera.org/pipermail/libcamera-devel/>",
        "List-Post": "<mailto:libcamera-devel@lists.libcamera.org>",
        "List-Help": "<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>",
        "List-Subscribe": "<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>",
        "X-List-Received-Date": "Tue, 23 Jun 2020 16:39:18 -0000"
    },
    "content": "From: David Plowman <david.plowman@raspberrypi.com>\n\nAdd controls to support AWB, AEC and AGC. Also add control support to\nset exposure (in lines) and analogue gain (as a register code).\n\nSigned-off-by: David Plowman <david.plowman@raspberrypi.com>\nSigned-off-by: Naushir Patuck <naush@raspberrypi.com>\nSigned-off-by: Jacopo Mondi <jacopo@jmondi.org>\n---\n drivers/media/i2c/ov5647.c | 170 ++++++++++++++++++++++++++++++++++++-\n 1 file changed, 168 insertions(+), 2 deletions(-)",
    "diff": "diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c\nindex 2d2829f934c3c..8cfe315cfd00b 100644\n--- a/drivers/media/i2c/ov5647.c\n+++ b/drivers/media/i2c/ov5647.c\n@@ -21,6 +21,7 @@\n #include <linux/of_graph.h>\n #include <linux/slab.h>\n #include <linux/videodev2.h>\n+#include <media/v4l2-ctrls.h>\n #include <media/v4l2-device.h>\n #include <media/v4l2-fwnode.h>\n #include <media/v4l2-image-sizes.h>\n@@ -43,9 +44,16 @@\n #define OV5647_REG_CHIPID_H\t\t0x300a\n #define OV5647_REG_CHIPID_L\t\t0x300b\n #define OV5640_REG_PAD_OUT\t\t0x300d\n+#define OV5647_REG_EXP_HI\t\t0x3500\n+#define OV5647_REG_EXP_MID\t\t0x3501\n+#define OV5647_REG_EXP_LO\t\t0x3502\n+#define OV5647_REG_AEC_AGC\t\t0x3503\n+#define OV5647_REG_GAIN_HI\t\t0x350a\n+#define OV5647_REG_GAIN_LO\t\t0x350b\n #define OV5647_REG_FRAME_OFF_NUMBER\t0x4202\n #define OV5647_REG_MIPI_CTRL00\t\t0x4800\n #define OV5647_REG_MIPI_CTRL14\t\t0x4814\n+#define OV5647_REG_AWB\t\t\t0x5001\n \n #define REG_TERM 0xfffe\n #define VAL_TERM 0xfe\n@@ -87,6 +95,7 @@ struct ov5647 {\n \tstruct clk\t\t\t*xclk;\n \tstruct gpio_desc\t\t*pwdn;\n \tbool\t\t\t\tclock_ncont;\n+\tstruct v4l2_ctrl_handler\tctrls;\n };\n \n static inline struct ov5647 *to_state(struct v4l2_subdev *sd)\n@@ -121,7 +130,6 @@ static struct regval_list ov5647_640x480[] = {\n \t{0x3612, 0x59},\n \t{0x3618, 0x00},\n \t{0x5000, 0x06},\n-\t{0x5001, 0x01},\n \t{0x5002, 0x41},\n \t{0x5003, 0x08},\n \t{0x5a00, 0x08},\n@@ -312,6 +320,11 @@ static int ov5647_stream_on(struct v4l2_subdev *sd)\n \t\treturn ret;\n \t}\n \n+\t/* Apply customized values from user when stream starts. */\n+\tret =  __v4l2_ctrl_handler_setup(sd->ctrl_handler);\n+\tif (ret)\n+\t\treturn ret;\n+\n \tif (ov5647->clock_ncont)\n \t\tval |= MIPI_CTRL00_CLOCK_LANE_GATE |\n \t\t       MIPI_CTRL00_LINE_SYNC_ENABLE;\n@@ -591,6 +604,152 @@ static const struct v4l2_subdev_internal_ops ov5647_subdev_internal_ops = {\n \t.open = ov5647_open,\n };\n \n+static int ov5647_s_auto_white_balance(struct v4l2_subdev *sd, u32 val)\n+{\n+\treturn ov5647_write(sd, OV5647_REG_AWB, val ? 1 : 0);\n+}\n+\n+static int ov5647_s_autogain(struct v4l2_subdev *sd, u32 val)\n+{\n+\tint ret;\n+\tu8 reg;\n+\n+\t/* Non-zero turns on AGC by clearing bit 1.*/\n+\tret = ov5647_read(sd, OV5647_REG_AEC_AGC, &reg);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\treturn ov5647_write(sd, OV5647_REG_AEC_AGC, val ? reg & ~BIT(1)\n+\t\t\t\t\t\t\t: reg | BIT(1));\n+}\n+\n+static int ov5647_s_exposure_auto(struct v4l2_subdev *sd, u32 val)\n+{\n+\tint ret;\n+\tu8 reg;\n+\n+\t/*\n+\t * Everything except V4L2_EXPOSURE_MANUAL turns on AEC by\n+\t * clearing bit 0.\n+\t */\n+\tret = ov5647_read(sd, OV5647_REG_AEC_AGC, &reg);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\treturn ov5647_write(sd, OV5647_REG_AEC_AGC, val == V4L2_EXPOSURE_MANUAL ?\n+\t\t\t\t\t\t    reg | BIT(0) : reg & ~BIT(0));\n+}\n+\n+static int ov5647_s_analogue_gain(struct v4l2_subdev *sd, u32 val)\n+{\n+\tint ret;\n+\n+\t/* 10 bits of gain, 2 in the high register. */\n+\tret = ov5647_write(sd, OV5647_REG_GAIN_HI, (val >> 8) & 3);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\treturn ov5647_write(sd, OV5647_REG_GAIN_LO, val & 0xff);\n+}\n+\n+static int ov5647_s_exposure(struct v4l2_subdev *sd, u32 val)\n+{\n+\tint ret;\n+\n+\t/*\n+\t * Sensor has 20 bits, but the bottom 4 bits are fractions of a line\n+\t * which we leave as zero (and don't receive in \"val\").\n+\t */\n+\tret = ov5647_write(sd, OV5647_REG_EXP_HI, (val >> 12) & 0xf);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = ov5647_write(sd, OV5647_REG_EXP_MID, (val >> 4) & 0xff);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\treturn ov5647_write(sd, OV5647_REG_EXP_LO, (val & 0xf) << 4);\n+}\n+\n+static int ov5647_s_ctrl(struct v4l2_ctrl *ctrl)\n+{\n+\tstruct ov5647 *sensor = container_of(ctrl->handler,\n+\t\t\t\t\t    struct ov5647, ctrls);\n+\tstruct v4l2_subdev *sd = &sensor->sd;\n+\tstruct i2c_client *client = v4l2_get_subdevdata(sd);\n+\n+\t/* v4l2_ctrl_lock() locks our own mutex */\n+\n+\t/*\n+\t * If the device is not powered up by the host driver do\n+\t * not apply any controls to H/W at this time. Instead\n+\t * the controls will be restored at s_stream(1) time.\n+\t */\n+\tif (!sensor->power_count)\n+\t\treturn 0;\n+\n+\tswitch (ctrl->id) {\n+\tcase V4L2_CID_AUTO_WHITE_BALANCE:\n+\t\treturn ov5647_s_auto_white_balance(sd, ctrl->val);\n+\tcase V4L2_CID_AUTOGAIN:\n+\t\treturn ov5647_s_autogain(sd, ctrl->val);\n+\tcase V4L2_CID_EXPOSURE_AUTO:\n+\t\treturn ov5647_s_exposure_auto(sd, ctrl->val);\n+\tcase V4L2_CID_ANALOGUE_GAIN:\n+\t\treturn  ov5647_s_analogue_gain(sd, ctrl->val);\n+\tcase V4L2_CID_EXPOSURE:\n+\t\treturn ov5647_s_exposure(sd, ctrl->val);\n+\tdefault:\n+\t\tdev_info(&client->dev,\n+\t\t\t \"Control (id:0x%x, val:0x%x) not supported\\n\",\n+\t\t\t ctrl->id, ctrl->val);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static const struct v4l2_ctrl_ops ov5647_ctrl_ops = {\n+\t.s_ctrl = ov5647_s_ctrl,\n+};\n+\n+static int ov5647_init_controls(struct ov5647 *sensor)\n+{\n+\tstruct i2c_client *client = v4l2_get_subdevdata(&sensor->sd);\n+\n+\tv4l2_ctrl_handler_init(&sensor->ctrls, 5);\n+\n+\tv4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,\n+\t\t\t  V4L2_CID_AUTOGAIN, 0, 1, 1, 0);\n+\n+\tv4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,\n+\t\t\t  V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 0);\n+\n+\tv4l2_ctrl_new_std_menu(&sensor->ctrls, &ov5647_ctrl_ops,\n+\t\t\t       V4L2_CID_EXPOSURE_AUTO, V4L2_EXPOSURE_MANUAL,\n+\t\t\t       0, V4L2_EXPOSURE_MANUAL);\n+\n+\t/* min: 4 lines; max: 0xffff lines; default: 1000 lines. */\n+\tv4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,\n+\t\t\t  V4L2_CID_EXPOSURE, 4, 65535, 1, 1000);\n+\n+\t/* min: 16 = 1.0x; max (10 bits); default: 32 = 2.0x. */\n+\tv4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,\n+\t\t\t  V4L2_CID_ANALOGUE_GAIN, 16, 1023, 1, 32);\n+\n+\tif (sensor->ctrls.error) {\n+\t\tdev_err(&client->dev, \"%s Controls initialization failed (%d)\\n\",\n+\t\t\t__func__, sensor->ctrls.error);\n+\t\tv4l2_ctrl_handler_free(&sensor->ctrls);\n+\n+\t\treturn sensor->ctrls.error;\n+\t}\n+\n+\tsensor->sd.ctrl_handler = &sensor->ctrls;\n+\n+\treturn 0;\n+}\n+\n static int ov5647_parse_dt(struct ov5647 *sensor, struct device_node *np)\n {\n \tstruct v4l2_fwnode_endpoint bus_cfg = {\n@@ -654,6 +813,10 @@ static int ov5647_probe(struct i2c_client *client)\n \n \tmutex_init(&sensor->lock);\n \n+\tret = ov5647_init_controls(sensor);\n+\tif (ret)\n+\t\tgoto mutex_destroy;\n+\n \tsd = &sensor->sd;\n \tv4l2_i2c_subdev_init(sd, client, &ov5647_subdev_ops);\n \tsd->internal_ops = &ov5647_subdev_internal_ops;\n@@ -663,7 +826,7 @@ static int ov5647_probe(struct i2c_client *client)\n \tsd->entity.function = MEDIA_ENT_F_CAM_SENSOR;\n \tret = media_entity_pads_init(&sd->entity, 1, &sensor->pad);\n \tif (ret < 0)\n-\t\tgoto mutex_destroy;\n+\t\tgoto ctrl_handler_free;\n \n \tif (sensor->pwdn) {\n \t\tgpiod_set_value_cansleep(sensor->pwdn, 0);\n@@ -685,6 +848,8 @@ static int ov5647_probe(struct i2c_client *client)\n \n entity_cleanup:\n \tmedia_entity_cleanup(&sd->entity);\n+ctrl_handler_free:\n+\tv4l2_ctrl_handler_free(&sensor->ctrls);\n mutex_destroy:\n \tmutex_destroy(&sensor->lock);\n \n@@ -698,6 +863,7 @@ static int ov5647_remove(struct i2c_client *client)\n \n \tv4l2_async_unregister_subdev(&ov5647->sd);\n \tmedia_entity_cleanup(&ov5647->sd.entity);\n+\tv4l2_ctrl_handler_free(&ov5647->ctrls);\n \tv4l2_device_unregister_subdev(sd);\n \tmutex_destroy(&ov5647->lock);\n \n",
    "prefixes": [
        "libcamera-devel",
        "13/25"
    ]
}