aboutsummaryrefslogtreecommitdiff
path: root/target/linux/bcm27xx/patches-6.1/950-0599-media-i2c-imx296-Add-horizontal-vertical-flip-suppor.patch
blob: 139bc6b434b8f60bd6bbf8cd4435bbc672d1b341 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
From 621a1194ac97d166b4bf747c5fedabdbfb01620c Mon Sep 17 00:00:00 2001
From: Naushir Patuck <naush@raspberrypi.com>
Date: Tue, 14 Mar 2023 11:00:48 +0000
Subject: [PATCH] media: i2c: imx296: Add horizontal/vertical flip
 support

Add support for setting horizontal and/or vertial flips in the IMX296
sensor through the V4L2_CID_HFLIP and V4L2_CID_VFLIP controls.

Add a new helper function to return the media bus format code that
depends on the sensor flips.

Grab the V4L2_CID_HFLIP and V4L2_CID_VFLIP controls on stream on, and
release on stream off to ensure flips cannot be changed while the sensor
is streaming.

Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
---
 drivers/media/i2c/imx296.c | 64 +++++++++++++++++++++++++++++++++++---
 1 file changed, 59 insertions(+), 5 deletions(-)

--- a/drivers/media/i2c/imx296.c
+++ b/drivers/media/i2c/imx296.c
@@ -210,6 +210,8 @@ struct imx296 {
 	struct v4l2_ctrl_handler ctrls;
 	struct v4l2_ctrl *hblank;
 	struct v4l2_ctrl *vblank;
+	struct v4l2_ctrl *vflip;
+	struct v4l2_ctrl *hflip;
 };
 
 static inline struct imx296 *to_imx296(struct v4l2_subdev *sd)
@@ -251,6 +253,36 @@ static int imx296_write(struct imx296 *s
 	return ret;
 }
 
+/*
+ * 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 mbus_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 u32 imx296_mbus_code(const struct imx296 *sensor)
+{
+	unsigned int i = 0;
+
+	if (sensor->mono)
+		return MEDIA_BUS_FMT_Y10_1X10;
+
+	if (sensor->vflip && sensor->hflip)
+		i = (sensor->vflip->val ? 2 : 0) | (sensor->hflip->val ? 1 : 0);
+
+	return mbus_codes[i];
+}
+
 static int imx296_power_on(struct imx296 *sensor)
 {
 	int ret;
@@ -345,6 +377,13 @@ static int imx296_s_ctrl(struct v4l2_ctr
 			     &ret);
 		break;
 
+	case V4L2_CID_HFLIP:
+	case V4L2_CID_VFLIP:
+		imx296_write(sensor, IMX296_CTRL0E,
+			     sensor->vflip->val | (sensor->hflip->val << 1),
+			     &ret);
+		break;
+
 	case V4L2_CID_TEST_PATTERN:
 		if (ctrl->val) {
 			imx296_write(sensor, IMX296_PGHPOS, 8, &ret);
@@ -428,6 +467,16 @@ static int imx296_ctrls_init(struct imx2
 			  V4L2_CID_ANALOGUE_GAIN, IMX296_GAIN_MIN,
 			  IMX296_GAIN_MAX, 1, IMX296_GAIN_MIN);
 
+	sensor->hflip = v4l2_ctrl_new_std(&sensor->ctrls, &imx296_ctrl_ops,
+					  V4L2_CID_HFLIP, 0, 1, 1, 0);
+	if (sensor->hflip && !sensor->mono)
+		sensor->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
+
+	sensor->vflip = v4l2_ctrl_new_std(&sensor->ctrls, &imx296_ctrl_ops,
+					  V4L2_CID_VFLIP, 0, 1, 1, 0);
+	if (sensor->vflip && !sensor->mono)
+		sensor->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
+
 	imx296_setup_hblank(sensor, IMX296_PIXEL_ARRAY_WIDTH);
 
 	sensor->vblank = v4l2_ctrl_new_std(&sensor->ctrls, &imx296_ctrl_ops,
@@ -598,6 +647,10 @@ static int imx296_stream_on(struct imx29
 	usleep_range(2000, 5000);
 	imx296_write(sensor, IMX296_CTRL0A, 0, &ret);
 
+	/* vflip and hflip cannot change during streaming */
+	__v4l2_ctrl_grab(sensor->vflip, 1);
+	__v4l2_ctrl_grab(sensor->hflip, 1);
+
 	return ret;
 }
 
@@ -608,6 +661,9 @@ static int imx296_stream_off(struct imx2
 	imx296_write(sensor, IMX296_CTRL0A, IMX296_CTRL0A_XMSTA, &ret);
 	imx296_write(sensor, IMX296_CTRL00, IMX296_CTRL00_STANDBY, &ret);
 
+	__v4l2_ctrl_grab(sensor->vflip, 0);
+	__v4l2_ctrl_grab(sensor->hflip, 0);
+
 	return ret;
 }
 
@@ -678,8 +734,7 @@ static int imx296_enum_mbus_code(struct
 	if (code->index != 0)
 		return -EINVAL;
 
-	code->code = sensor->mono ? MEDIA_BUS_FMT_Y10_1X10
-		   : MEDIA_BUS_FMT_SBGGR10_1X10;
+	code->code = imx296_mbus_code(sensor);
 
 	return 0;
 }
@@ -695,7 +750,7 @@ static int imx296_enum_frame_size(struct
 
 	format = v4l2_subdev_get_pad_format(sd, state, fse->pad);
 
-	if (fse->index >= max_index || fse->code != format->code)
+	if (fse->index >= max_index || fse->code != imx296_mbus_code(sensor))
 		return -EINVAL;
 
 	fse->min_width = IMX296_PIXEL_ARRAY_WIDTH / (fse->index + 1);
@@ -755,8 +810,7 @@ static int imx296_set_format(struct v4l2
 
 	imx296_setup_hblank(sensor, format->width);
 
-	format->code = sensor->mono ? MEDIA_BUS_FMT_Y10_1X10
-		     : MEDIA_BUS_FMT_SBGGR10_1X10;
+	format->code = imx296_mbus_code(sensor);
 	format->field = V4L2_FIELD_NONE;
 	format->colorspace = V4L2_COLORSPACE_RAW;
 	format->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;