[PATCH v5] media: i2c: imx471: return 0 from get_selection after filling crop

John Cronin <[email protected]>
Newsgroups org.kernel.vger.linux-media
Message-ID <[email protected]>
libcamera issues VIDIOC_SUBDEV_G_SELECTION with target CROP (rectangle
0) during CameraSensorLegacy bring-up. imx471_get_selection filled the
rectangle then fell out of the switch and returned -EINVAL.

Compute analog crop in set_pad_format: 2x binning, centered in the
native array, same idea as imx219. IMX471 2x2-binned 1928x1088 then
reports CROP as 3856x2176 centered in 4672x3512.

Tested on ThinkPad X9-15 Gen 1 (SONY471A / IPU7).

Link: https://bugzilla.redhat.com/show_bug.cgi?id=2454119
Signed-off-by: John Cronin <[email protected]>
Signed-off-by: John Cronin <[email protected]>
---
v5: drop extra braces; declare crop/bin vars at start of
    set_pad_format (sorted by line length); wrap to 80 cols;
    keep only the bug/feature in the commit log
v4: add Signed-off-by for [email protected]
v3: rebase on media-committers next
v2: compute analog crop in set_pad_format; return 0 after switch

 drivers/media/i2c/imx471.c | 23 ++++++++++++++++++++---
 1 file changed, 20 insertions(+), 3 deletions(-)

diff --git a/drivers/media/i2c/imx471.c b/drivers/media/i2c/imx471.c
index 4053aed84..0ea18fbb9 100644
--- a/drivers/media/i2c/imx471.c
+++ b/drivers/media/i2c/imx471.c
@@ -421,6 +421,8 @@ static int imx471_set_pad_format(struct v4l2_subdev *sd,
 {
 	struct imx471 *sensor = to_imx471(sd);
 	const struct imx471_mode *mode;
+	u8 bin_h, bin_v, binning;
+	struct v4l2_rect *crop;
 	int h_blank, ret;
 
 	mode = v4l2_find_nearest_size(imx471_modes, ARRAY_SIZE(imx471_modes),
@@ -431,6 +433,18 @@ static int imx471_set_pad_format(struct v4l2_subdev *sd,
 
 	*v4l2_subdev_state_get_format(sd_state, fmt->pad) = fmt->format;
 
+	/* Analog crop: 2x bin, centered in native array (imx219). */
+	crop = v4l2_subdev_state_get_crop(sd_state, fmt->pad);
+	bin_h = min_t(u32,
+		      IMX471_PIXEL_ARRAY_WIDTH / fmt->format.width, 2);
+	bin_v = min_t(u32,
+		      IMX471_PIXEL_ARRAY_HEIGHT / fmt->format.height, 2);
+	binning = min(bin_h, bin_v);
+	crop->width = fmt->format.width * binning;
+	crop->height = fmt->format.height * binning;
+	crop->left = (IMX471_NATIVE_WIDTH - crop->width) / 2;
+	crop->top = (IMX471_NATIVE_HEIGHT - crop->height) / 2;
+
 	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
 		return 0;
 
@@ -468,7 +482,7 @@ static int imx471_get_selection(struct v4l2_subdev *sd,
 		sel->r.left = 0;
 		sel->r.width = IMX471_NATIVE_WIDTH;
 		sel->r.height = IMX471_NATIVE_HEIGHT;
-		return 0;
+		break;
 
 	case V4L2_SEL_TGT_CROP_DEFAULT:
 	case V4L2_SEL_TGT_CROP_BOUNDS:
@@ -476,10 +490,13 @@ static int imx471_get_selection(struct v4l2_subdev *sd,
 		sel->r.left = IMX471_PIXEL_ARRAY_LEFT;
 		sel->r.width = IMX471_PIXEL_ARRAY_WIDTH;
 		sel->r.height = IMX471_PIXEL_ARRAY_HEIGHT;
-		return 0;
+		break;
+
+	default:
+		return -EINVAL;
 	}
 
-	return -EINVAL;
+	return 0;
 }
 
 static int imx471_init_state(struct v4l2_subdev *sd,
-- 
2.55.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.