139bc6b434b8f60bd6bbf8cd4435bbc672d1b341
[openwrt/staging/ldir.git] /
1 From 621a1194ac97d166b4bf747c5fedabdbfb01620c Mon Sep 17 00:00:00 2001
2 From: Naushir Patuck <naush@raspberrypi.com>
3 Date: Tue, 14 Mar 2023 11:00:48 +0000
4 Subject: [PATCH] media: i2c: imx296: Add horizontal/vertical flip
5 support
6
7 Add support for setting horizontal and/or vertial flips in the IMX296
8 sensor through the V4L2_CID_HFLIP and V4L2_CID_VFLIP controls.
9
10 Add a new helper function to return the media bus format code that
11 depends on the sensor flips.
12
13 Grab the V4L2_CID_HFLIP and V4L2_CID_VFLIP controls on stream on, and
14 release on stream off to ensure flips cannot be changed while the sensor
15 is streaming.
16
17 Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
18 ---
19 drivers/media/i2c/imx296.c | 64 +++++++++++++++++++++++++++++++++++---
20 1 file changed, 59 insertions(+), 5 deletions(-)
21
22 --- a/drivers/media/i2c/imx296.c
23 +++ b/drivers/media/i2c/imx296.c
24 @@ -210,6 +210,8 @@ struct imx296 {
25 struct v4l2_ctrl_handler ctrls;
26 struct v4l2_ctrl *hblank;
27 struct v4l2_ctrl *vblank;
28 + struct v4l2_ctrl *vflip;
29 + struct v4l2_ctrl *hflip;
30 };
31
32 static inline struct imx296 *to_imx296(struct v4l2_subdev *sd)
33 @@ -251,6 +253,36 @@ static int imx296_write(struct imx296 *s
34 return ret;
35 }
36
37 +/*
38 + * The supported formats.
39 + * This table MUST contain 4 entries per format, to cover the various flip
40 + * combinations in the order
41 + * - no flip
42 + * - h flip
43 + * - v flip
44 + * - h&v flips
45 + */
46 +static const u32 mbus_codes[] = {
47 + /* 10-bit modes. */
48 + MEDIA_BUS_FMT_SRGGB10_1X10,
49 + MEDIA_BUS_FMT_SGRBG10_1X10,
50 + MEDIA_BUS_FMT_SGBRG10_1X10,
51 + MEDIA_BUS_FMT_SBGGR10_1X10,
52 +};
53 +
54 +static u32 imx296_mbus_code(const struct imx296 *sensor)
55 +{
56 + unsigned int i = 0;
57 +
58 + if (sensor->mono)
59 + return MEDIA_BUS_FMT_Y10_1X10;
60 +
61 + if (sensor->vflip && sensor->hflip)
62 + i = (sensor->vflip->val ? 2 : 0) | (sensor->hflip->val ? 1 : 0);
63 +
64 + return mbus_codes[i];
65 +}
66 +
67 static int imx296_power_on(struct imx296 *sensor)
68 {
69 int ret;
70 @@ -345,6 +377,13 @@ static int imx296_s_ctrl(struct v4l2_ctr
71 &ret);
72 break;
73
74 + case V4L2_CID_HFLIP:
75 + case V4L2_CID_VFLIP:
76 + imx296_write(sensor, IMX296_CTRL0E,
77 + sensor->vflip->val | (sensor->hflip->val << 1),
78 + &ret);
79 + break;
80 +
81 case V4L2_CID_TEST_PATTERN:
82 if (ctrl->val) {
83 imx296_write(sensor, IMX296_PGHPOS, 8, &ret);
84 @@ -428,6 +467,16 @@ static int imx296_ctrls_init(struct imx2
85 V4L2_CID_ANALOGUE_GAIN, IMX296_GAIN_MIN,
86 IMX296_GAIN_MAX, 1, IMX296_GAIN_MIN);
87
88 + sensor->hflip = v4l2_ctrl_new_std(&sensor->ctrls, &imx296_ctrl_ops,
89 + V4L2_CID_HFLIP, 0, 1, 1, 0);
90 + if (sensor->hflip && !sensor->mono)
91 + sensor->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
92 +
93 + sensor->vflip = v4l2_ctrl_new_std(&sensor->ctrls, &imx296_ctrl_ops,
94 + V4L2_CID_VFLIP, 0, 1, 1, 0);
95 + if (sensor->vflip && !sensor->mono)
96 + sensor->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
97 +
98 imx296_setup_hblank(sensor, IMX296_PIXEL_ARRAY_WIDTH);
99
100 sensor->vblank = v4l2_ctrl_new_std(&sensor->ctrls, &imx296_ctrl_ops,
101 @@ -598,6 +647,10 @@ static int imx296_stream_on(struct imx29
102 usleep_range(2000, 5000);
103 imx296_write(sensor, IMX296_CTRL0A, 0, &ret);
104
105 + /* vflip and hflip cannot change during streaming */
106 + __v4l2_ctrl_grab(sensor->vflip, 1);
107 + __v4l2_ctrl_grab(sensor->hflip, 1);
108 +
109 return ret;
110 }
111
112 @@ -608,6 +661,9 @@ static int imx296_stream_off(struct imx2
113 imx296_write(sensor, IMX296_CTRL0A, IMX296_CTRL0A_XMSTA, &ret);
114 imx296_write(sensor, IMX296_CTRL00, IMX296_CTRL00_STANDBY, &ret);
115
116 + __v4l2_ctrl_grab(sensor->vflip, 0);
117 + __v4l2_ctrl_grab(sensor->hflip, 0);
118 +
119 return ret;
120 }
121
122 @@ -678,8 +734,7 @@ static int imx296_enum_mbus_code(struct
123 if (code->index != 0)
124 return -EINVAL;
125
126 - code->code = sensor->mono ? MEDIA_BUS_FMT_Y10_1X10
127 - : MEDIA_BUS_FMT_SBGGR10_1X10;
128 + code->code = imx296_mbus_code(sensor);
129
130 return 0;
131 }
132 @@ -695,7 +750,7 @@ static int imx296_enum_frame_size(struct
133
134 format = v4l2_subdev_get_pad_format(sd, state, fse->pad);
135
136 - if (fse->index >= max_index || fse->code != format->code)
137 + if (fse->index >= max_index || fse->code != imx296_mbus_code(sensor))
138 return -EINVAL;
139
140 fse->min_width = IMX296_PIXEL_ARRAY_WIDTH / (fse->index + 1);
141 @@ -755,8 +810,7 @@ static int imx296_set_format(struct v4l2
142
143 imx296_setup_hblank(sensor, format->width);
144
145 - format->code = sensor->mono ? MEDIA_BUS_FMT_Y10_1X10
146 - : MEDIA_BUS_FMT_SBGGR10_1X10;
147 + format->code = imx296_mbus_code(sensor);
148 format->field = V4L2_FIELD_NONE;
149 format->colorspace = V4L2_COLORSPACE_RAW;
150 format->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;