mirror of
				https://github.com/Ysurac/openmptcprouter.git
				synced 2025-03-09 15:40:20 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			176 lines
		
	
	
	
		
			5.7 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			176 lines
		
	
	
	
		
			5.7 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| From 2175fc381be0ec0817071ca23550be35bd7fbb03 Mon Sep 17 00:00:00 2001
 | |
| From: Dave Stevenson <dave.stevenson@raspberrypi.com>
 | |
| Date: Thu, 16 Feb 2023 00:30:02 +0200
 | |
| Subject: [PATCH] media: i2c: imx290: Add support for H & V Flips
 | |
| 
 | |
| Should be upstream commit 42765b80f8c6
 | |
| 
 | |
| The sensor supports H & V flips, so add the relevant hooks for
 | |
| V4L2_CID_HFLIP and V4L2_CID_VFLIP to configure them.
 | |
| 
 | |
| Note that the Bayer order is maintained as the readout area
 | |
| shifts by 1 pixel in the appropriate direction (note the
 | |
| comment about the top margin being 8 pixels whilst the bottom
 | |
| margin is 9). The V4L2_SEL_TGT_CROP region is therefore
 | |
| adjusted appropriately.
 | |
| 
 | |
| Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
 | |
| Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
 | |
| Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
 | |
| Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
 | |
| ---
 | |
|  drivers/media/i2c/imx290.c | 51 ++++++++++++++++++++++++++++++++++----
 | |
|  1 file changed, 46 insertions(+), 5 deletions(-)
 | |
| 
 | |
| --- a/drivers/media/i2c/imx290.c
 | |
| +++ b/drivers/media/i2c/imx290.c
 | |
| @@ -211,6 +211,7 @@ struct imx290_mode {
 | |
|  	u32 hmax_min;
 | |
|  	u32 vmax_min;
 | |
|  	u8 link_freq_index;
 | |
| +	u8 ctrl_07;
 | |
|  
 | |
|  	const struct imx290_regval *data;
 | |
|  	u32 data_size;
 | |
| @@ -251,6 +252,10 @@ struct imx290 {
 | |
|  	struct v4l2_ctrl *hblank;
 | |
|  	struct v4l2_ctrl *vblank;
 | |
|  	struct v4l2_ctrl *exposure;
 | |
| +	struct {
 | |
| +		struct v4l2_ctrl *hflip;
 | |
| +		struct v4l2_ctrl *vflip;
 | |
| +	};
 | |
|  };
 | |
|  
 | |
|  static inline struct imx290 *to_imx290(struct v4l2_subdev *_sd)
 | |
| @@ -328,7 +333,6 @@ static const struct imx290_regval xclk_r
 | |
|  
 | |
|  static const struct imx290_regval imx290_1080p_settings[] = {
 | |
|  	/* mode settings */
 | |
| -	{ IMX290_CTRL_07, IMX290_WINMODE_1080P },
 | |
|  	{ IMX290_WINWV_OB, 12 },
 | |
|  	{ IMX290_OPB_SIZE_V, 10 },
 | |
|  	{ IMX290_X_OUT_SIZE, 1920 },
 | |
| @@ -337,7 +341,6 @@ static const struct imx290_regval imx290
 | |
|  
 | |
|  static const struct imx290_regval imx290_720p_settings[] = {
 | |
|  	/* mode settings */
 | |
| -	{ IMX290_CTRL_07, IMX290_WINMODE_720P },
 | |
|  	{ IMX290_WINWV_OB, 6 },
 | |
|  	{ IMX290_OPB_SIZE_V, 4 },
 | |
|  	{ IMX290_X_OUT_SIZE, 1280 },
 | |
| @@ -497,6 +500,7 @@ static const struct imx290_mode imx290_m
 | |
|  		.hmax_min = 2200,
 | |
|  		.vmax_min = 1125,
 | |
|  		.link_freq_index = FREQ_INDEX_1080P,
 | |
| +		.ctrl_07 = IMX290_WINMODE_1080P,
 | |
|  		.data = imx290_1080p_settings,
 | |
|  		.data_size = ARRAY_SIZE(imx290_1080p_settings),
 | |
|  		.clk_cfg = imx290_1080p_clock_config,
 | |
| @@ -507,6 +511,7 @@ static const struct imx290_mode imx290_m
 | |
|  		.hmax_min = 3300,
 | |
|  		.vmax_min = 750,
 | |
|  		.link_freq_index = FREQ_INDEX_720P,
 | |
| +		.ctrl_07 = IMX290_WINMODE_720P,
 | |
|  		.data = imx290_720p_settings,
 | |
|  		.data_size = ARRAY_SIZE(imx290_720p_settings),
 | |
|  		.clk_cfg = imx290_720p_clock_config,
 | |
| @@ -520,6 +525,7 @@ static const struct imx290_mode imx290_m
 | |
|  		.hmax_min = 2200,
 | |
|  		.vmax_min = 1125,
 | |
|  		.link_freq_index = FREQ_INDEX_1080P,
 | |
| +		.ctrl_07 = IMX290_WINMODE_1080P,
 | |
|  		.data = imx290_1080p_settings,
 | |
|  		.data_size = ARRAY_SIZE(imx290_1080p_settings),
 | |
|  		.clk_cfg = imx290_1080p_clock_config,
 | |
| @@ -530,6 +536,7 @@ static const struct imx290_mode imx290_m
 | |
|  		.hmax_min = 3300,
 | |
|  		.vmax_min = 750,
 | |
|  		.link_freq_index = FREQ_INDEX_720P,
 | |
| +		.ctrl_07 = IMX290_WINMODE_720P,
 | |
|  		.data = imx290_720p_settings,
 | |
|  		.data_size = ARRAY_SIZE(imx290_720p_settings),
 | |
|  		.clk_cfg = imx290_720p_clock_config,
 | |
| @@ -840,6 +847,20 @@ static int imx290_set_ctrl(struct v4l2_c
 | |
|  				   NULL);
 | |
|  		break;
 | |
|  
 | |
| +	case V4L2_CID_HFLIP:
 | |
| +	case V4L2_CID_VFLIP:
 | |
| +	{
 | |
| +		u32 reg;
 | |
| +
 | |
| +		reg = imx290->current_mode->ctrl_07;
 | |
| +		if (imx290->hflip->val)
 | |
| +			reg |= IMX290_HREVERSE;
 | |
| +		if (imx290->vflip->val)
 | |
| +			reg |= IMX290_VREVERSE;
 | |
| +		ret = imx290_write(imx290, IMX290_CTRL_07, reg, NULL);
 | |
| +		break;
 | |
| +	}
 | |
| +
 | |
|  	default:
 | |
|  		ret = -EINVAL;
 | |
|  		break;
 | |
| @@ -892,7 +913,7 @@ static int imx290_ctrl_init(struct imx29
 | |
|  	if (ret < 0)
 | |
|  		return ret;
 | |
|  
 | |
| -	v4l2_ctrl_handler_init(&imx290->ctrls, 9);
 | |
| +	v4l2_ctrl_handler_init(&imx290->ctrls, 11);
 | |
|  
 | |
|  	/*
 | |
|  	 * The sensor has an analog gain and a digital gain, both controlled
 | |
| @@ -949,6 +970,12 @@ static int imx290_ctrl_init(struct imx29
 | |
|  	imx290->vblank = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
 | |
|  					   V4L2_CID_VBLANK, 1, 1, 1, 1);
 | |
|  
 | |
| +	imx290->hflip = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
 | |
| +					  V4L2_CID_HFLIP, 0, 1, 1, 0);
 | |
| +	imx290->vflip = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
 | |
| +					  V4L2_CID_VFLIP, 0, 1, 1, 0);
 | |
| +	v4l2_ctrl_cluster(2, &imx290->hflip);
 | |
| +
 | |
|  	v4l2_ctrl_new_fwnode_properties(&imx290->ctrls, &imx290_ctrl_ops,
 | |
|  					&props);
 | |
|  
 | |
| @@ -1070,6 +1097,13 @@ static int imx290_set_stream(struct v4l2
 | |
|  		pm_runtime_put_autosuspend(imx290->dev);
 | |
|  	}
 | |
|  
 | |
| +	/*
 | |
| +	 * vflip and hflip should not be changed during streaming as the sensor
 | |
| +	 * will produce an invalid frame.
 | |
| +	 */
 | |
| +	__v4l2_ctrl_grab(imx290->vflip, enable);
 | |
| +	__v4l2_ctrl_grab(imx290->hflip, enable);
 | |
| +
 | |
|  unlock:
 | |
|  	v4l2_subdev_unlock_state(state);
 | |
|  	return ret;
 | |
| @@ -1152,16 +1186,23 @@ static int imx290_get_selection(struct v
 | |
|  				struct v4l2_subdev_state *sd_state,
 | |
|  				struct v4l2_subdev_selection *sel)
 | |
|  {
 | |
| +	struct imx290 *imx290 = to_imx290(sd);
 | |
|  	struct v4l2_mbus_framefmt *format;
 | |
|  
 | |
|  	switch (sel->target) {
 | |
|  	case V4L2_SEL_TGT_CROP: {
 | |
|  		format = v4l2_subdev_get_pad_format(sd, sd_state, 0);
 | |
|  
 | |
| +		/*
 | |
| +		 * The sensor moves the readout by 1 pixel based on flips to
 | |
| +		 * keep the Bayer order the same.
 | |
| +		 */
 | |
|  		sel->r.top = IMX920_PIXEL_ARRAY_MARGIN_TOP
 | |
| -			   + (IMX290_PIXEL_ARRAY_RECORDING_HEIGHT - format->height) / 2;
 | |
| +			   + (IMX290_PIXEL_ARRAY_RECORDING_HEIGHT - format->height) / 2
 | |
| +			   + imx290->vflip->val;
 | |
|  		sel->r.left = IMX920_PIXEL_ARRAY_MARGIN_LEFT
 | |
| -			    + (IMX290_PIXEL_ARRAY_RECORDING_WIDTH - format->width) / 2;
 | |
| +			    + (IMX290_PIXEL_ARRAY_RECORDING_WIDTH - format->width) / 2
 | |
| +			    + imx290->hflip->val;
 | |
|  		sel->r.width = format->width;
 | |
|  		sel->r.height = format->height;
 | |
|  
 |