[PATCH 14/14] media: ov6650: Fix stored crop rectangle not in sync with hardware

From: Janusz Krzysztofik
Date: Mon Apr 08 2019 - 17:43:36 EST

The driver stores crop rectangle settings supposed to be in line with
hardware state in a device private structure. Since the driver initial
submission, crop rectangle width and height settings are not updated
correctly when rectangle offset settings are applied on hardware. If
an error occurs while the device is updated, the stored settings my no
longer reflect hardware state and consecutive calls to .get_selection()
as well as .get_fmt() may return incorrect information. That in turn
may affect ability of a host device to use correct DMA transfer
settings if such incorrect informamtion on active frame format returned
by .get_fmt() is used.

Assuming a failed update of the device means its actual settings
haven't changed, update crop rectangle width and height settings stored
in the device private structure correctly while the rectangle offset is
successfully applied on hardware so the stored values always reflect
actual hardware state to the extent possible.

Fixes: 2f6e2404799a ("[media] SoC Camera: add driver for OV6650 sensor")
Signed-off-by: Janusz Krzysztofik <jmkrzyszt@xxxxxxxxx>
Cc: stable@xxxxxxxxxxxxxxx
drivers/media/i2c/ov6650.c | 2 ++
1 file changed, 2 insertions(+)

diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c
index 001457d39742..cffe6aa906b2 100644
--- a/drivers/media/i2c/ov6650.c
+++ b/drivers/media/i2c/ov6650.c
@@ -500,6 +500,7 @@ static int ov6650_set_selection(struct v4l2_subdev *sd,

ret = ov6650_reg_write(client, REG_HSTRT, sel->r.left >> 1);
if (!ret) {
+ priv->rect.width += priv->rect.left - sel->r.left;
priv->rect.left = sel->r.left;
ret = ov6650_reg_write(client, REG_HSTOP,
(sel->r.left + sel->r.width) >> 1);
@@ -509,6 +510,7 @@ static int ov6650_set_selection(struct v4l2_subdev *sd,
ret = ov6650_reg_write(client, REG_VSTRT, sel->r.top >> 1);
if (!ret) {
+ priv->rect.height += priv->rect.top - sel->r.top;
priv->rect.top = sel->r.top;
ret = ov6650_reg_write(client, REG_VSTOP,
(sel->r.top + sel->r.height) >> 1);