openwrt/target/linux/bcm27xx/patches-6.6/950-0463-media-i2c-imx258-Make-HFLIP-and-VFLIP-controls-writa.patch

241 lines
7.7 KiB
Diff
Raw Normal View History

From e9b26efc223784f72ec43cc64b4c485c6798be42 Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
Date: Tue, 15 Jun 2021 18:29:52 +0100
Subject: [PATCH 0463/1085] media: i2c: imx258: Make HFLIP and VFLIP controls
writable
The sensor supports H & V flips, but the controls were READ_ONLY.
Note that the Bayer order changes with these flips, therefore
they set the V4L2_CTRL_FLAG_MODIFY_LAYOUT property.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
drivers/media/i2c/imx258.c | 98 +++++++++++++++++++++++++-------------
1 file changed, 64 insertions(+), 34 deletions(-)
--- a/drivers/media/i2c/imx258.c
+++ b/drivers/media/i2c/imx258.c
@@ -82,7 +82,8 @@
/* Orientation */
#define REG_MIRROR_FLIP_CONTROL 0x0101
-#define REG_CONFIG_MIRROR_FLIP 0x03
+#define REG_CONFIG_MIRROR_HFLIP 0x01
+#define REG_CONFIG_MIRROR_VFLIP 0x02
#define REG_CONFIG_FLIP_TEST_PATTERN 0x02
/* IMX258 native and active pixel array size. */
@@ -672,6 +673,23 @@ static const struct imx258_variant_cfg i
.num_regs = ARRAY_SIZE(imx258_pdaf_cfg_regs),
};
+/*
+ * The supported formats.
+ * This table MUST contain 4 entries per format, to cover the various flip
+ * combinations in the order
+ * - no flip
+ * - h flip
+ * - v flip
+ * - h&v flips
+ */
+static const u32 codes[] = {
+ /* 10-bit modes. */
+ MEDIA_BUS_FMT_SRGGB10_1X10,
+ MEDIA_BUS_FMT_SGRBG10_1X10,
+ MEDIA_BUS_FMT_SGBRG10_1X10,
+ MEDIA_BUS_FMT_SBGGR10_1X10
+};
+
static const char * const imx258_test_pattern_menu[] = {
"Disabled",
"Solid Colour",
@@ -865,6 +883,8 @@ struct imx258 {
struct v4l2_ctrl *vblank;
struct v4l2_ctrl *hblank;
struct v4l2_ctrl *exposure;
+ struct v4l2_ctrl *hflip;
+ struct v4l2_ctrl *vflip;
/* Current long exposure factor in use. Set through V4L2_CID_VBLANK */
unsigned int long_exp_shift;
@@ -968,9 +988,22 @@ static int imx258_write_regs(struct imx2
return 0;
}
+/* Get bayer order based on flip setting. */
+static u32 imx258_get_format_code(struct imx258 *imx258)
+{
+ unsigned int i;
+
+ lockdep_assert_held(&imx258->mutex);
+
+ i = (imx258->vflip->val ? 2 : 0) |
+ (imx258->hflip->val ? 1 : 0);
+
+ return codes[i];
+}
/* Open sub-device */
static int imx258_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
+ struct imx258 *imx258 = to_imx258(sd);
struct v4l2_mbus_framefmt *try_fmt =
v4l2_subdev_get_try_format(sd, fh->state, 0);
struct v4l2_rect *try_crop;
@@ -978,7 +1011,7 @@ static int imx258_open(struct v4l2_subde
/* Initialize try_fmt */
try_fmt->width = supported_modes[0].width;
try_fmt->height = supported_modes[0].height;
- try_fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
+ try_fmt->code = imx258_get_format_code(imx258);
try_fmt->field = V4L2_FIELD_NONE;
/* Initialize try_crop */
@@ -1091,10 +1124,6 @@ static int imx258_set_ctrl(struct v4l2_c
ret = imx258_write_reg(imx258, IMX258_REG_TEST_PATTERN,
IMX258_REG_VALUE_16BIT,
ctrl->val);
- ret = imx258_write_reg(imx258, REG_MIRROR_FLIP_CONTROL,
- IMX258_REG_VALUE_08BIT,
- !ctrl->val ? REG_CONFIG_MIRROR_FLIP :
- REG_CONFIG_FLIP_TEST_PATTERN);
break;
case V4L2_CID_WIDE_DYNAMIC_RANGE:
if (!ctrl->val) {
@@ -1116,6 +1145,15 @@ static int imx258_set_ctrl(struct v4l2_c
ret = imx258_set_frame_length(imx258,
imx258->cur_mode->height + ctrl->val);
break;
+ case V4L2_CID_VFLIP:
+ case V4L2_CID_HFLIP:
+ ret = imx258_write_reg(imx258, REG_MIRROR_FLIP_CONTROL,
+ IMX258_REG_VALUE_08BIT,
+ (imx258->hflip->val ?
+ REG_CONFIG_MIRROR_HFLIP : 0) |
+ (imx258->vflip->val ?
+ REG_CONFIG_MIRROR_VFLIP : 0));
+ break;
default:
dev_info(&client->dev,
"ctrl(id:0x%x,val:0x%x) is not handled\n",
@@ -1137,11 +1175,13 @@ static int imx258_enum_mbus_code(struct
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
- /* Only one bayer order(GRBG) is supported */
+ struct imx258 *imx258 = to_imx258(sd);
+
+ /* Only one bayer format (10 bit) is supported */
if (code->index > 0)
return -EINVAL;
- code->code = MEDIA_BUS_FMT_SBGGR10_1X10;
+ code->code = imx258_get_format_code(imx258);
return 0;
}
@@ -1150,10 +1190,11 @@ static int imx258_enum_frame_size(struct
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
+ struct imx258 *imx258 = to_imx258(sd);
if (fse->index >= ARRAY_SIZE(supported_modes))
return -EINVAL;
- if (fse->code != MEDIA_BUS_FMT_SBGGR10_1X10)
+ if (fse->code != imx258_get_format_code(imx258))
return -EINVAL;
fse->min_width = supported_modes[fse->index].width;
@@ -1164,12 +1205,13 @@ static int imx258_enum_frame_size(struct
return 0;
}
-static void imx258_update_pad_format(const struct imx258_mode *mode,
+static void imx258_update_pad_format(struct imx258 *imx258,
+ const struct imx258_mode *mode,
struct v4l2_subdev_format *fmt)
{
fmt->format.width = mode->width;
fmt->format.height = mode->height;
- fmt->format.code = MEDIA_BUS_FMT_SBGGR10_1X10;
+ fmt->format.code = imx258_get_format_code(imx258);
fmt->format.field = V4L2_FIELD_NONE;
}
@@ -1182,7 +1224,7 @@ static int __imx258_get_pad_format(struc
sd_state,
fmt->pad);
else
- imx258_update_pad_format(imx258->cur_mode, fmt);
+ imx258_update_pad_format(imx258, imx258->cur_mode, fmt);
return 0;
}
@@ -1218,13 +1260,12 @@ static int imx258_set_pad_format(struct
mutex_lock(&imx258->mutex);
- /* Only one raw bayer(GBRG) order is supported */
- fmt->format.code = MEDIA_BUS_FMT_SBGGR10_1X10;
+ fmt->format.code = imx258_get_format_code(imx258);
mode = v4l2_find_nearest_size(supported_modes,
ARRAY_SIZE(supported_modes), width, height,
fmt->format.width, fmt->format.height);
- imx258_update_pad_format(mode, fmt);
+ imx258_update_pad_format(imx258, mode, fmt);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
*framefmt = fmt->format;
@@ -1367,15 +1408,6 @@ static int imx258_start_streaming(struct
return ret;
}
- /* Set Orientation be 180 degree */
- ret = imx258_write_reg(imx258, REG_MIRROR_FLIP_CONTROL,
- IMX258_REG_VALUE_08BIT, REG_CONFIG_MIRROR_FLIP);
- if (ret) {
- dev_err(&client->dev, "%s failed to set orientation\n",
- __func__);
- return ret;
- }
-
/* Apply customized values from user */
ret = __v4l2_ctrl_handler_setup(imx258->sd.ctrl_handler);
if (ret)
@@ -1564,7 +1596,6 @@ static int imx258_init_controls(struct i
struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd);
const struct imx258_link_freq_config *link_freq_cfgs;
struct v4l2_fwnode_device_properties props;
- struct v4l2_ctrl *vflip, *hflip;
struct v4l2_ctrl_handler *ctrl_hdlr;
const struct imx258_link_cfg *link_cfg;
s64 vblank_def;
@@ -1589,16 +1620,15 @@ static int imx258_init_controls(struct i
if (imx258->link_freq)
imx258->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
- /* The driver only supports one bayer order and flips by default. */
- hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops,
- V4L2_CID_HFLIP, 1, 1, 1, 1);
- if (hflip)
- hflip->flags |= V4L2_CTRL_FLAG_READ_ONLY;
-
- vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops,
- V4L2_CID_VFLIP, 1, 1, 1, 1);
- if (vflip)
- vflip->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+ imx258->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 1);
+ if (imx258->hflip)
+ imx258->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
+
+ imx258->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 1);
+ if (imx258->vflip)
+ imx258->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
link_freq_cfgs = &imx258->link_freq_configs[0];
link_cfg = link_freq_cfgs[imx258->lane_mode_idx].link_cfg;