All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/3] V4L: mt9m111: clean up and fix .s_crop() / .s_fmt()
@ 2011-12-21 15:53 Guennadi Liakhovetski
  2011-12-21 15:53 ` [PATCH 1/3] V4L: mt9m111: cleanly separate register contexts Guennadi Liakhovetski
                   ` (4 more replies)
  0 siblings, 5 replies; 7+ messages in thread
From: Guennadi Liakhovetski @ 2011-12-21 15:53 UTC (permalink / raw)
  To: Linux Media Mailing List; +Cc: Robert Jarzmik

Hi all

While working on a context-switching test, I've cleaned up the mt9m111 
driver a bit and fixed its cropping and scaling functions. These are 
planned for 3.3.

Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 1/3] V4L: mt9m111: cleanly separate register contexts
  2011-12-21 15:53 [PATCH 0/3] V4L: mt9m111: clean up and fix .s_crop() / .s_fmt() Guennadi Liakhovetski
@ 2011-12-21 15:53 ` Guennadi Liakhovetski
  2011-12-21 15:53 ` [PATCH 2/3] V4L: mt9m111: power down most circuits when suspended Guennadi Liakhovetski
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 7+ messages in thread
From: Guennadi Liakhovetski @ 2011-12-21 15:53 UTC (permalink / raw)
  To: Linux Media Mailing List; +Cc: Robert Jarzmik

Cleanly separating register contexts A and B will allow us to configure
the contexts independently.

Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
---
 drivers/media/video/mt9m111.c |  137 +++++++++++++++++++++++------------------
 1 files changed, 76 insertions(+), 61 deletions(-)

diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c
index 258adfd..54edb6b4 100644
--- a/drivers/media/video/mt9m111.c
+++ b/drivers/media/video/mt9m111.c
@@ -139,6 +139,46 @@
 #define MT9M111_MAX_HEIGHT	1024
 #define MT9M111_MAX_WIDTH	1280
 
+struct mt9m111_context {
+	u16 read_mode;
+	u16 blanking_h;
+	u16 blanking_v;
+	u16 reducer_xzoom;
+	u16 reducer_yzoom;
+	u16 reducer_xsize;
+	u16 reducer_ysize;
+	u16 output_fmt_ctrl2;
+	u16 control;
+};
+
+static struct mt9m111_context context_a = {
+	.read_mode		= MT9M111_READ_MODE_A,
+	.blanking_h		= MT9M111_HORIZONTAL_BLANKING_A,
+	.blanking_v		= MT9M111_VERTICAL_BLANKING_A,
+	.reducer_xzoom		= MT9M111_REDUCER_XZOOM_A,
+	.reducer_yzoom		= MT9M111_REDUCER_YZOOM_A,
+	.reducer_xsize		= MT9M111_REDUCER_XSIZE_A,
+	.reducer_ysize		= MT9M111_REDUCER_YSIZE_A,
+	.output_fmt_ctrl2	= MT9M111_OUTPUT_FORMAT_CTRL2_A,
+	.control		= MT9M111_CTXT_CTRL_RESTART,
+};
+
+static struct mt9m111_context context_b = {
+	.read_mode		= MT9M111_READ_MODE_B,
+	.blanking_h		= MT9M111_HORIZONTAL_BLANKING_B,
+	.blanking_v		= MT9M111_VERTICAL_BLANKING_B,
+	.reducer_xzoom		= MT9M111_REDUCER_XZOOM_B,
+	.reducer_yzoom		= MT9M111_REDUCER_YZOOM_B,
+	.reducer_xsize		= MT9M111_REDUCER_XSIZE_B,
+	.reducer_ysize		= MT9M111_REDUCER_YSIZE_B,
+	.output_fmt_ctrl2	= MT9M111_OUTPUT_FORMAT_CTRL2_B,
+	.control		= MT9M111_CTXT_CTRL_RESTART |
+		MT9M111_CTXT_CTRL_DEFECTCOR_B | MT9M111_CTXT_CTRL_RESIZE_B |
+		MT9M111_CTXT_CTRL_CTRL2_B | MT9M111_CTXT_CTRL_GAMMA_B |
+		MT9M111_CTXT_CTRL_READ_MODE_B | MT9M111_CTXT_CTRL_VBLANK_SEL_B |
+		MT9M111_CTXT_CTRL_HBLANK_SEL_B,
+};
+
 /* MT9M111 has only one fixed colorspace per pixelcode */
 struct mt9m111_datafmt {
 	enum v4l2_mbus_pixelcode	code;
@@ -173,18 +213,13 @@ static const struct mt9m111_datafmt mt9m111_colour_fmts[] = {
 	{V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB},
 };
 
-enum mt9m111_context {
-	HIGHPOWER = 0,
-	LOWPOWER,
-};
-
 struct mt9m111 {
 	struct v4l2_subdev subdev;
 	struct v4l2_ctrl_handler hdl;
 	struct v4l2_ctrl *gain;
 	int model;	/* V4L2_IDENT_MT9M111 or V4L2_IDENT_MT9M112 code
 			 * from v4l2-chip-ident.h */
-	enum mt9m111_context context;
+	struct mt9m111_context *ctx;
 	struct v4l2_rect rect;
 	struct mutex power_lock; /* lock to protect power_count */
 	int power_count;
@@ -275,35 +310,33 @@ static int mt9m111_reg_mask(struct i2c_client *client, const u16 reg,
 }
 
 static int mt9m111_set_context(struct mt9m111 *mt9m111,
-			       enum mt9m111_context ctxt)
+			       struct mt9m111_context *ctx)
 {
 	struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
-	int valB = MT9M111_CTXT_CTRL_RESTART | MT9M111_CTXT_CTRL_DEFECTCOR_B
-		| MT9M111_CTXT_CTRL_RESIZE_B | MT9M111_CTXT_CTRL_CTRL2_B
-		| MT9M111_CTXT_CTRL_GAMMA_B | MT9M111_CTXT_CTRL_READ_MODE_B
-		| MT9M111_CTXT_CTRL_VBLANK_SEL_B
-		| MT9M111_CTXT_CTRL_HBLANK_SEL_B;
-	int valA = MT9M111_CTXT_CTRL_RESTART;
-
-	if (ctxt == HIGHPOWER)
-		return reg_write(CONTEXT_CONTROL, valB);
-	else
-		return reg_write(CONTEXT_CONTROL, valA);
+	return reg_write(CONTEXT_CONTROL, ctx->control);
+}
+
+static int mt9m111_setup_rect_ctx(struct mt9m111 *mt9m111,
+			struct v4l2_rect *rect, struct mt9m111_context *ctx)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
+	int ret = mt9m111_reg_write(client, ctx->reducer_xzoom, MT9M111_MAX_WIDTH);
+	if (!ret)
+		ret = mt9m111_reg_write(client, ctx->reducer_yzoom, MT9M111_MAX_HEIGHT);
+	if (!ret)
+		ret = mt9m111_reg_write(client, ctx->reducer_xsize, rect->width);
+	if (!ret)
+		ret = mt9m111_reg_write(client, ctx->reducer_ysize, rect->height);
+	return ret;
 }
 
 static int mt9m111_setup_rect(struct mt9m111 *mt9m111,
 			      struct v4l2_rect *rect)
 {
 	struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
-	int ret, is_raw_format;
-	int width = rect->width;
-	int height = rect->height;
-
-	if (mt9m111->fmt->code == V4L2_MBUS_FMT_SBGGR8_1X8 ||
-	    mt9m111->fmt->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE)
-		is_raw_format = 1;
-	else
-		is_raw_format = 0;
+	int ret;
+	bool is_raw_format = mt9m111->fmt->code == V4L2_MBUS_FMT_SBGGR8_1X8 ||
+		mt9m111->fmt->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE;
 
 	ret = reg_write(COLUMN_START, rect->left);
 	if (!ret)
@@ -311,26 +344,14 @@ static int mt9m111_setup_rect(struct mt9m111 *mt9m111,
 
 	if (is_raw_format) {
 		if (!ret)
-			ret = reg_write(WINDOW_WIDTH, width);
+			ret = reg_write(WINDOW_WIDTH, rect->width);
 		if (!ret)
-			ret = reg_write(WINDOW_HEIGHT, height);
+			ret = reg_write(WINDOW_HEIGHT, rect->height);
 	} else {
 		if (!ret)
-			ret = reg_write(REDUCER_XZOOM_B, MT9M111_MAX_WIDTH);
-		if (!ret)
-			ret = reg_write(REDUCER_YZOOM_B, MT9M111_MAX_HEIGHT);
-		if (!ret)
-			ret = reg_write(REDUCER_XSIZE_B, width);
+			ret = mt9m111_setup_rect_ctx(mt9m111, rect, &context_b);
 		if (!ret)
-			ret = reg_write(REDUCER_YSIZE_B, height);
-		if (!ret)
-			ret = reg_write(REDUCER_XZOOM_A, MT9M111_MAX_WIDTH);
-		if (!ret)
-			ret = reg_write(REDUCER_YZOOM_A, MT9M111_MAX_HEIGHT);
-		if (!ret)
-			ret = reg_write(REDUCER_XSIZE_A, width);
-		if (!ret)
-			ret = reg_write(REDUCER_YSIZE_A, height);
+			ret = mt9m111_setup_rect_ctx(mt9m111, rect, &context_a);
 	}
 
 	return ret;
@@ -503,11 +524,11 @@ static int mt9m111_set_pixfmt(struct mt9m111 *mt9m111,
 		return -EINVAL;
 	}
 
-	ret = reg_mask(OUTPUT_FORMAT_CTRL2_A, data_outfmt2,
-		       mask_outfmt2);
+	ret = mt9m111_reg_mask(client, context_a.output_fmt_ctrl2,
+			       data_outfmt2, mask_outfmt2);
 	if (!ret)
-		ret = reg_mask(OUTPUT_FORMAT_CTRL2_B, data_outfmt2,
-			       mask_outfmt2);
+		ret = mt9m111_reg_mask(client, context_b.output_fmt_ctrl2,
+				       data_outfmt2, mask_outfmt2);
 
 	return ret;
 }
@@ -649,17 +670,10 @@ static int mt9m111_set_flip(struct mt9m111 *mt9m111, int flip, int mask)
 	struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
 	int ret;
 
-	if (mt9m111->context == HIGHPOWER) {
-		if (flip)
-			ret = reg_set(READ_MODE_B, mask);
-		else
-			ret = reg_clear(READ_MODE_B, mask);
-	} else {
-		if (flip)
-			ret = reg_set(READ_MODE_A, mask);
-		else
-			ret = reg_clear(READ_MODE_A, mask);
-	}
+	if (flip)
+		ret = mt9m111_reg_set(client, mt9m111->ctx->read_mode, mask);
+	else
+		ret = mt9m111_reg_clear(client, mt9m111->ctx->read_mode, mask);
 
 	return ret;
 }
@@ -744,7 +758,7 @@ static int mt9m111_suspend(struct mt9m111 *mt9m111)
 
 static void mt9m111_restore_state(struct mt9m111 *mt9m111)
 {
-	mt9m111_set_context(mt9m111, mt9m111->context);
+	mt9m111_set_context(mt9m111, mt9m111->ctx);
 	mt9m111_set_pixfmt(mt9m111, mt9m111->fmt->code);
 	mt9m111_setup_rect(mt9m111, &mt9m111->rect);
 	v4l2_ctrl_handler_setup(&mt9m111->hdl);
@@ -769,12 +783,13 @@ static int mt9m111_init(struct mt9m111 *mt9m111)
 	struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
 	int ret;
 
-	mt9m111->context = HIGHPOWER;
+	/* Default HIGHPOWER context */
+	mt9m111->ctx = &context_b;
 	ret = mt9m111_enable(mt9m111);
 	if (!ret)
 		ret = mt9m111_reset(mt9m111);
 	if (!ret)
-		ret = mt9m111_set_context(mt9m111, mt9m111->context);
+		ret = mt9m111_set_context(mt9m111, mt9m111->ctx);
 	if (ret)
 		dev_err(&client->dev, "mt9m111 init failed: %d\n", ret);
 	return ret;
-- 
1.7.2.5


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 2/3] V4L: mt9m111: power down most circuits when suspended
  2011-12-21 15:53 [PATCH 0/3] V4L: mt9m111: clean up and fix .s_crop() / .s_fmt() Guennadi Liakhovetski
  2011-12-21 15:53 ` [PATCH 1/3] V4L: mt9m111: cleanly separate register contexts Guennadi Liakhovetski
@ 2011-12-21 15:53 ` Guennadi Liakhovetski
  2011-12-21 15:53 ` [PATCH 3/3] V4L: mt9m111: properly implement .s_crop and .s_fmt(), reset on STREAMON Guennadi Liakhovetski
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 7+ messages in thread
From: Guennadi Liakhovetski @ 2011-12-21 15:53 UTC (permalink / raw)
  To: Linux Media Mailing List; +Cc: Robert Jarzmik

Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
---
 drivers/media/video/mt9m111.c |   34 ++++++++++++++++++----------------
 1 files changed, 18 insertions(+), 16 deletions(-)

diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c
index 54edb6b4..797660b 100644
--- a/drivers/media/video/mt9m111.c
+++ b/drivers/media/video/mt9m111.c
@@ -226,7 +226,6 @@ struct mt9m111 {
 	const struct mt9m111_datafmt *fmt;
 	int lastpage;	/* PageMap cache value */
 	unsigned char datawidth;
-	unsigned int powered:1;
 };
 
 static struct mt9m111 *to_mt9m111(const struct i2c_client *client)
@@ -360,12 +359,7 @@ static int mt9m111_setup_rect(struct mt9m111 *mt9m111,
 static int mt9m111_enable(struct mt9m111 *mt9m111)
 {
 	struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
-	int ret;
-
-	ret = reg_set(RESET, MT9M111_RESET_CHIP_ENABLE);
-	if (!ret)
-		mt9m111->powered = 1;
-	return ret;
+	return reg_write(RESET, MT9M111_RESET_CHIP_ENABLE);
 }
 
 static int mt9m111_reset(struct mt9m111 *mt9m111)
@@ -751,9 +745,20 @@ static int mt9m111_s_ctrl(struct v4l2_ctrl *ctrl)
 
 static int mt9m111_suspend(struct mt9m111 *mt9m111)
 {
+	struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
+	int ret;
+
 	v4l2_ctrl_s_ctrl(mt9m111->gain, mt9m111_get_global_gain(mt9m111));
 
-	return 0;
+	ret = reg_set(RESET, MT9M111_RESET_RESET_MODE);
+	if (!ret)
+		ret = reg_set(RESET, MT9M111_RESET_RESET_SOC |
+			      MT9M111_RESET_OUTPUT_DISABLE |
+			      MT9M111_RESET_ANALOG_STANDBY);
+	if (!ret)
+		ret = reg_clear(RESET, MT9M111_RESET_CHIP_ENABLE);
+
+	return ret;
 }
 
 static void mt9m111_restore_state(struct mt9m111 *mt9m111)
@@ -766,15 +771,12 @@ static void mt9m111_restore_state(struct mt9m111 *mt9m111)
 
 static int mt9m111_resume(struct mt9m111 *mt9m111)
 {
-	int ret = 0;
+	int ret = mt9m111_enable(mt9m111);
+	if (!ret)
+		ret = mt9m111_reset(mt9m111);
+	if (!ret)
+		mt9m111_restore_state(mt9m111);
 
-	if (mt9m111->powered) {
-		ret = mt9m111_enable(mt9m111);
-		if (!ret)
-			ret = mt9m111_reset(mt9m111);
-		if (!ret)
-			mt9m111_restore_state(mt9m111);
-	}
 	return ret;
 }
 
-- 
1.7.2.5


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 3/3] V4L: mt9m111: properly implement .s_crop and .s_fmt(), reset on STREAMON
  2011-12-21 15:53 [PATCH 0/3] V4L: mt9m111: clean up and fix .s_crop() / .s_fmt() Guennadi Liakhovetski
  2011-12-21 15:53 ` [PATCH 1/3] V4L: mt9m111: cleanly separate register contexts Guennadi Liakhovetski
  2011-12-21 15:53 ` [PATCH 2/3] V4L: mt9m111: power down most circuits when suspended Guennadi Liakhovetski
@ 2011-12-21 15:53 ` Guennadi Liakhovetski
  2012-01-04 20:09 ` [PATCH 0/3] V4L: mt9m111: clean up and fix .s_crop() / .s_fmt() Robert Jarzmik
  2012-01-08 15:08 ` Robert Jarzmik
  4 siblings, 0 replies; 7+ messages in thread
From: Guennadi Liakhovetski @ 2011-12-21 15:53 UTC (permalink / raw)
  To: Linux Media Mailing List; +Cc: Robert Jarzmik

mt9m111 camera sensors support cropping and scaling. The current
implementation is broken. For example, .s_crop() sets output frame sizes
instead of the input cropping window. This patch adds a proper implementation
of these methods. Besides it adds a sensor-disable and -enable operations
on first open() and last close() respectively, to save power while closed and
to return the camera to the default power-on state.

Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
---
 drivers/media/video/mt9m111.c |  226 ++++++++++++++++++++--------------------
 1 files changed, 113 insertions(+), 113 deletions(-)

diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c
index 797660b..ba1ea8c 100644
--- a/drivers/media/video/mt9m111.c
+++ b/drivers/media/video/mt9m111.c
@@ -185,19 +185,6 @@ struct mt9m111_datafmt {
 	enum v4l2_colorspace		colorspace;
 };
 
-/* Find a data format by a pixel code in an array */
-static const struct mt9m111_datafmt *mt9m111_find_datafmt(
-	enum v4l2_mbus_pixelcode code, const struct mt9m111_datafmt *fmt,
-	int n)
-{
-	int i;
-	for (i = 0; i < n; i++)
-		if (fmt[i].code == code)
-			return fmt + i;
-
-	return NULL;
-}
-
 static const struct mt9m111_datafmt mt9m111_colour_fmts[] = {
 	{V4L2_MBUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG},
 	{V4L2_MBUS_FMT_YVYU8_2X8, V4L2_COLORSPACE_JPEG},
@@ -220,7 +207,9 @@ struct mt9m111 {
 	int model;	/* V4L2_IDENT_MT9M111 or V4L2_IDENT_MT9M112 code
 			 * from v4l2-chip-ident.h */
 	struct mt9m111_context *ctx;
-	struct v4l2_rect rect;
+	struct v4l2_rect rect;	/* cropping rectangle */
+	int width;		/* output */
+	int height;		/* sizes */
 	struct mutex power_lock; /* lock to protect power_count */
 	int power_count;
 	const struct mt9m111_datafmt *fmt;
@@ -228,6 +217,18 @@ struct mt9m111 {
 	unsigned char datawidth;
 };
 
+/* Find a data format by a pixel code */
+static const struct mt9m111_datafmt *mt9m111_find_datafmt(struct mt9m111 *mt9m111,
+						enum v4l2_mbus_pixelcode code)
+{
+	int i;
+	for (i = 0; i < ARRAY_SIZE(mt9m111_colour_fmts); i++)
+		if (mt9m111_colour_fmts[i].code == code)
+			return mt9m111_colour_fmts + i;
+
+	return mt9m111->fmt;
+}
+
 static struct mt9m111 *to_mt9m111(const struct i2c_client *client)
 {
 	return container_of(i2c_get_clientdata(client), struct mt9m111, subdev);
@@ -316,43 +317,49 @@ static int mt9m111_set_context(struct mt9m111 *mt9m111,
 }
 
 static int mt9m111_setup_rect_ctx(struct mt9m111 *mt9m111,
-			struct v4l2_rect *rect, struct mt9m111_context *ctx)
+			struct mt9m111_context *ctx, struct v4l2_rect *rect,
+			unsigned int width, unsigned int height)
 {
 	struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
-	int ret = mt9m111_reg_write(client, ctx->reducer_xzoom, MT9M111_MAX_WIDTH);
+	int ret = mt9m111_reg_write(client, ctx->reducer_xzoom, rect->width);
 	if (!ret)
-		ret = mt9m111_reg_write(client, ctx->reducer_yzoom, MT9M111_MAX_HEIGHT);
+		ret = mt9m111_reg_write(client, ctx->reducer_yzoom, rect->height);
 	if (!ret)
-		ret = mt9m111_reg_write(client, ctx->reducer_xsize, rect->width);
+		ret = mt9m111_reg_write(client, ctx->reducer_xsize, width);
 	if (!ret)
-		ret = mt9m111_reg_write(client, ctx->reducer_ysize, rect->height);
+		ret = mt9m111_reg_write(client, ctx->reducer_ysize, height);
 	return ret;
 }
 
-static int mt9m111_setup_rect(struct mt9m111 *mt9m111,
-			      struct v4l2_rect *rect)
+static int mt9m111_setup_geometry(struct mt9m111 *mt9m111, struct v4l2_rect *rect,
+			int width, int height, enum v4l2_mbus_pixelcode code)
 {
 	struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
 	int ret;
-	bool is_raw_format = mt9m111->fmt->code == V4L2_MBUS_FMT_SBGGR8_1X8 ||
-		mt9m111->fmt->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE;
 
 	ret = reg_write(COLUMN_START, rect->left);
 	if (!ret)
 		ret = reg_write(ROW_START, rect->top);
 
-	if (is_raw_format) {
-		if (!ret)
-			ret = reg_write(WINDOW_WIDTH, rect->width);
-		if (!ret)
-			ret = reg_write(WINDOW_HEIGHT, rect->height);
-	} else {
+	if (!ret)
+		ret = reg_write(WINDOW_WIDTH, rect->width);
+	if (!ret)
+		ret = reg_write(WINDOW_HEIGHT, rect->height);
+
+	if (code != V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE) {
+		/* IFP in use, down-scaling possible */
 		if (!ret)
-			ret = mt9m111_setup_rect_ctx(mt9m111, rect, &context_b);
+			ret = mt9m111_setup_rect_ctx(mt9m111, &context_b,
+						     rect, width, height);
 		if (!ret)
-			ret = mt9m111_setup_rect_ctx(mt9m111, rect, &context_a);
+			ret = mt9m111_setup_rect_ctx(mt9m111, &context_a,
+						     rect, width, height);
 	}
 
+	dev_dbg(&client->dev, "%s(%x): %ux%u@%u:%u -> %ux%u = %d\n",
+		__func__, code, rect->width, rect->height, rect->left, rect->top,
+		width, height, ret);
+
 	return ret;
 }
 
@@ -377,43 +384,41 @@ static int mt9m111_reset(struct mt9m111 *mt9m111)
 	return ret;
 }
 
-static int mt9m111_make_rect(struct mt9m111 *mt9m111,
-			     struct v4l2_rect *rect)
+static int mt9m111_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
 {
+	struct v4l2_rect rect = a->c;
+	struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
+	int width, height;
+	int ret;
+
+	if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
 	if (mt9m111->fmt->code == V4L2_MBUS_FMT_SBGGR8_1X8 ||
 	    mt9m111->fmt->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE) {
 		/* Bayer format - even size lengths */
-		rect->width	= ALIGN(rect->width, 2);
-		rect->height	= ALIGN(rect->height, 2);
+		rect.width	= ALIGN(rect.width, 2);
+		rect.height	= ALIGN(rect.height, 2);
 		/* Let the user play with the starting pixel */
 	}
 
 	/* FIXME: the datasheet doesn't specify minimum sizes */
-	soc_camera_limit_side(&rect->left, &rect->width,
+	soc_camera_limit_side(&rect.left, &rect.width,
 		     MT9M111_MIN_DARK_COLS, 2, MT9M111_MAX_WIDTH);
 
-	soc_camera_limit_side(&rect->top, &rect->height,
+	soc_camera_limit_side(&rect.top, &rect.height,
 		     MT9M111_MIN_DARK_ROWS, 2, MT9M111_MAX_HEIGHT);
 
-	return mt9m111_setup_rect(mt9m111, rect);
-}
-
-static int mt9m111_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
-{
-	struct v4l2_rect rect = a->c;
-	struct i2c_client *client = v4l2_get_subdevdata(sd);
-	struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
-	int ret;
+	width = min(mt9m111->width, rect.width);
+	height = min(mt9m111->height, rect.height);
 
-	dev_dbg(&client->dev, "%s left=%d, top=%d, width=%d, height=%d\n",
-		__func__, rect.left, rect.top, rect.width, rect.height);
-
-	if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-		return -EINVAL;
-
-	ret = mt9m111_make_rect(mt9m111, &rect);
-	if (!ret)
+	ret = mt9m111_setup_geometry(mt9m111, &rect, width, height, mt9m111->fmt->code);
+	if (!ret) {
 		mt9m111->rect = rect;
+		mt9m111->width = width;
+		mt9m111->height = height;
+	}
+
 	return ret;
 }
 
@@ -448,8 +453,8 @@ static int mt9m111_g_fmt(struct v4l2_subdev *sd,
 {
 	struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
 
-	mf->width	= mt9m111->rect.width;
-	mf->height	= mt9m111->rect.height;
+	mf->width	= mt9m111->width;
+	mf->height	= mt9m111->height;
 	mf->code	= mt9m111->fmt->code;
 	mf->colorspace	= mt9m111->fmt->colorspace;
 	mf->field	= V4L2_FIELD_NONE;
@@ -527,80 +532,74 @@ static int mt9m111_set_pixfmt(struct mt9m111 *mt9m111,
 	return ret;
 }
 
-static int mt9m111_s_fmt(struct v4l2_subdev *sd,
-			 struct v4l2_mbus_framefmt *mf)
-{
-	struct i2c_client *client = v4l2_get_subdevdata(sd);
-	const struct mt9m111_datafmt *fmt;
-	struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
-	struct v4l2_rect rect = {
-		.left	= mt9m111->rect.left,
-		.top	= mt9m111->rect.top,
-		.width	= mf->width,
-		.height	= mf->height,
-	};
-	int ret;
-
-	fmt = mt9m111_find_datafmt(mf->code, mt9m111_colour_fmts,
-				   ARRAY_SIZE(mt9m111_colour_fmts));
-	if (!fmt)
-		return -EINVAL;
-
-	dev_dbg(&client->dev,
-		"%s code=%x left=%d, top=%d, width=%d, height=%d\n", __func__,
-		mf->code, rect.left, rect.top, rect.width, rect.height);
-
-	ret = mt9m111_make_rect(mt9m111, &rect);
-	if (!ret)
-		ret = mt9m111_set_pixfmt(mt9m111, mf->code);
-	if (!ret) {
-		mt9m111->rect	= rect;
-		mt9m111->fmt	= fmt;
-		mf->colorspace	= fmt->colorspace;
-	}
-
-	return ret;
-}
-
 static int mt9m111_try_fmt(struct v4l2_subdev *sd,
 			   struct v4l2_mbus_framefmt *mf)
 {
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
 	struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
 	const struct mt9m111_datafmt *fmt;
-	bool bayer = mf->code == V4L2_MBUS_FMT_SBGGR8_1X8 ||
-		mf->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE;
-
-	fmt = mt9m111_find_datafmt(mf->code, mt9m111_colour_fmts,
-				   ARRAY_SIZE(mt9m111_colour_fmts));
-	if (!fmt) {
-		fmt = mt9m111->fmt;
-		mf->code = fmt->code;
-	}
+	struct v4l2_rect *rect = &mt9m111->rect;
+	bool bayer;
+
+	fmt = mt9m111_find_datafmt(mt9m111, mf->code);
+
+	bayer = fmt->code == V4L2_MBUS_FMT_SBGGR8_1X8 ||
+		fmt->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE;
 
 	/*
 	 * With Bayer format enforce even side lengths, but let the user play
 	 * with the starting pixel
 	 */
+	if (bayer) {
+		rect->width = ALIGN(rect->width, 2);
+		rect->height = ALIGN(rect->height, 2);
+	}
 
-	if (mf->height > MT9M111_MAX_HEIGHT)
-		mf->height = MT9M111_MAX_HEIGHT;
-	else if (mf->height < 2)
-		mf->height = 2;
-	else if (bayer)
-		mf->height = ALIGN(mf->height, 2);
+	if (fmt->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE) {
+		/* IFP bypass mode, no scaling */
+		mf->width = rect->width;
+		mf->height = rect->height;
+	} else {
+		/* No upscaling */
+		if (mf->width > rect->width)
+			mf->width = rect->width;
+		if (mf->height > rect->height)
+			mf->height = rect->height;
+	}
 
-	if (mf->width > MT9M111_MAX_WIDTH)
-		mf->width = MT9M111_MAX_WIDTH;
-	else if (mf->width < 2)
-		mf->width = 2;
-	else if (bayer)
-		mf->width = ALIGN(mf->width, 2);
+	dev_dbg(&client->dev, "%s(): %ux%u, code=%x\n", __func__,
+		mf->width, mf->height, fmt->code);
 
+	mf->code = fmt->code;
 	mf->colorspace = fmt->colorspace;
 
 	return 0;
 }
 
+static int mt9m111_s_fmt(struct v4l2_subdev *sd,
+			 struct v4l2_mbus_framefmt *mf)
+{
+	const struct mt9m111_datafmt *fmt;
+	struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
+	struct v4l2_rect *rect = &mt9m111->rect;
+	int ret;
+
+	mt9m111_try_fmt(sd, mf);
+	fmt = mt9m111_find_datafmt(mt9m111, mf->code);
+	/* try_fmt() guarantees fmt != NULL && fmt->code == mf->code */
+
+	ret = mt9m111_setup_geometry(mt9m111, rect, mf->width, mf->height, mf->code);
+	if (!ret)
+		ret = mt9m111_set_pixfmt(mt9m111, mf->code);
+	if (!ret) {
+		mt9m111->width	= mf->width;
+		mt9m111->height	= mf->height;
+		mt9m111->fmt	= fmt;
+	}
+
+	return ret;
+}
+
 static int mt9m111_g_chip_ident(struct v4l2_subdev *sd,
 				struct v4l2_dbg_chip_ident *id)
 {
@@ -765,7 +764,8 @@ static void mt9m111_restore_state(struct mt9m111 *mt9m111)
 {
 	mt9m111_set_context(mt9m111, mt9m111->ctx);
 	mt9m111_set_pixfmt(mt9m111, mt9m111->fmt->code);
-	mt9m111_setup_rect(mt9m111, &mt9m111->rect);
+	mt9m111_setup_geometry(mt9m111, &mt9m111->rect,
+			mt9m111->width, mt9m111->height, mt9m111->fmt->code);
 	v4l2_ctrl_handler_setup(&mt9m111->hdl);
 }
 
-- 
1.7.2.5


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH 0/3] V4L: mt9m111: clean up and fix .s_crop() / .s_fmt()
  2011-12-21 15:53 [PATCH 0/3] V4L: mt9m111: clean up and fix .s_crop() / .s_fmt() Guennadi Liakhovetski
                   ` (2 preceding siblings ...)
  2011-12-21 15:53 ` [PATCH 3/3] V4L: mt9m111: properly implement .s_crop and .s_fmt(), reset on STREAMON Guennadi Liakhovetski
@ 2012-01-04 20:09 ` Robert Jarzmik
  2012-01-08 15:08 ` Robert Jarzmik
  4 siblings, 0 replies; 7+ messages in thread
From: Robert Jarzmik @ 2012-01-04 20:09 UTC (permalink / raw)
  To: Guennadi Liakhovetski; +Cc: Linux Media Mailing List

Guennadi Liakhovetski <g.liakhovetski@gmx.de> writes:

> Hi all
>
> While working on a context-switching test, I've cleaned up the mt9m111 
> driver a bit and fixed its cropping and scaling functions. These are 
> planned for 3.3.

Hi Guennadi,

I've been on holidays ... so I've not dived into your changes.
>From a quick glance, it looks good. Did you test your changes on real hardware
(I'm thinking of the suspend power cut part) ?

Cheers.

-- 
Robert

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 0/3] V4L: mt9m111: clean up and fix .s_crop() / .s_fmt()
  2011-12-21 15:53 [PATCH 0/3] V4L: mt9m111: clean up and fix .s_crop() / .s_fmt() Guennadi Liakhovetski
                   ` (3 preceding siblings ...)
  2012-01-04 20:09 ` [PATCH 0/3] V4L: mt9m111: clean up and fix .s_crop() / .s_fmt() Robert Jarzmik
@ 2012-01-08 15:08 ` Robert Jarzmik
  2012-01-08 15:48   ` Guennadi Liakhovetski
  4 siblings, 1 reply; 7+ messages in thread
From: Robert Jarzmik @ 2012-01-08 15:08 UTC (permalink / raw)
  To: Guennadi Liakhovetski; +Cc: Linux Media Mailing List

Guennadi Liakhovetski <g.liakhovetski@gmx.de> writes:

> Hi all
>
> While working on a context-switching test, I've cleaned up the mt9m111 
> driver a bit and fixed its cropping and scaling functions. These are 
> planned for 3.3.

Hi Guennadi,

I've looked more deeply into the patchset, and I have no comment, it all looks
good. I've not been able to test it due to a ill tempered board, but I reviewed
patches 1 and 2 with my manual, and patch 3 a bit, and checked compilation
versus kernel 3.2.

So please find my:
Acked-by: Robert Jarzmik <robert.jarzmik@free.fr>

Cheers.

-- 
Robert

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 0/3] V4L: mt9m111: clean up and fix .s_crop() / .s_fmt()
  2012-01-08 15:08 ` Robert Jarzmik
@ 2012-01-08 15:48   ` Guennadi Liakhovetski
  0 siblings, 0 replies; 7+ messages in thread
From: Guennadi Liakhovetski @ 2012-01-08 15:48 UTC (permalink / raw)
  To: Robert Jarzmik; +Cc: Linux Media Mailing List

Hi Robert

On Sun, 8 Jan 2012, Robert Jarzmik wrote:

> Guennadi Liakhovetski <g.liakhovetski@gmx.de> writes:
> 
> > Hi all
> >
> > While working on a context-switching test, I've cleaned up the mt9m111 
> > driver a bit and fixed its cropping and scaling functions. These are 
> > planned for 3.3.
> 
> Hi Guennadi,
> 
> I've looked more deeply into the patchset, and I have no comment, it all looks
> good. I've not been able to test it due to a ill tempered board, but I reviewed
> patches 1 and 2 with my manual, and patch 3 a bit, and checked compilation
> versus kernel 3.2.
> 
> So please find my:
> Acked-by: Robert Jarzmik <robert.jarzmik@free.fr>

Thanks for the review and the ack, but I'm afraid it's a bit too late - 
the patches are already in next.

Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2012-01-08 15:48 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-12-21 15:53 [PATCH 0/3] V4L: mt9m111: clean up and fix .s_crop() / .s_fmt() Guennadi Liakhovetski
2011-12-21 15:53 ` [PATCH 1/3] V4L: mt9m111: cleanly separate register contexts Guennadi Liakhovetski
2011-12-21 15:53 ` [PATCH 2/3] V4L: mt9m111: power down most circuits when suspended Guennadi Liakhovetski
2011-12-21 15:53 ` [PATCH 3/3] V4L: mt9m111: properly implement .s_crop and .s_fmt(), reset on STREAMON Guennadi Liakhovetski
2012-01-04 20:09 ` [PATCH 0/3] V4L: mt9m111: clean up and fix .s_crop() / .s_fmt() Robert Jarzmik
2012-01-08 15:08 ` Robert Jarzmik
2012-01-08 15:48   ` Guennadi Liakhovetski

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.