mirror of
				https://github.com/Ysurac/openmptcprouter.git
				synced 2025-03-09 15:40:20 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			149 lines
		
	
	
	
		
			4.4 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			149 lines
		
	
	
	
		
			4.4 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| From 30812fd35d6f0181b24acad5a94d3a94d999568e 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;
 |