| From 16c7aadce4a1626a11f392e2ab14d66998475034 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Mon, 26 Jul 2021 09:35:15 +0200 |
| Subject: media: mt9p031: Fix corrupted frame after restarting stream |
| |
| From: Dirk Bender <d.bender@phytec.de> |
| |
| [ Upstream commit 0961ba6dd211a4a52d1dd4c2d59be60ac2dc08c7 ] |
| |
| To prevent corrupted frames after starting and stopping the sensor its |
| datasheet specifies a specific pause sequence to follow: |
| |
| Stopping: |
| Set Pause_Restart Bit -> Set Restart Bit -> Set Chip_Enable Off |
| |
| Restarting: |
| Set Chip_Enable On -> Clear Pause_Restart Bit |
| |
| The Restart Bit is cleared automatically and must not be cleared |
| manually as this would cause undefined behavior. |
| |
| Signed-off-by: Dirk Bender <d.bender@phytec.de> |
| Signed-off-by: Stefan Riedmueller <s.riedmueller@phytec.de> |
| Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com> |
| Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/media/i2c/mt9p031.c | 28 +++++++++++++++++++++++++++- |
| 1 file changed, 27 insertions(+), 1 deletion(-) |
| |
| diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c |
| index dc23b9ed510a4..18440c5104ad9 100644 |
| --- a/drivers/media/i2c/mt9p031.c |
| +++ b/drivers/media/i2c/mt9p031.c |
| @@ -78,7 +78,9 @@ |
| #define MT9P031_PIXEL_CLOCK_INVERT (1 << 15) |
| #define MT9P031_PIXEL_CLOCK_SHIFT(n) ((n) << 8) |
| #define MT9P031_PIXEL_CLOCK_DIVIDE(n) ((n) << 0) |
| -#define MT9P031_FRAME_RESTART 0x0b |
| +#define MT9P031_RESTART 0x0b |
| +#define MT9P031_FRAME_PAUSE_RESTART (1 << 1) |
| +#define MT9P031_FRAME_RESTART (1 << 0) |
| #define MT9P031_SHUTTER_DELAY 0x0c |
| #define MT9P031_RST 0x0d |
| #define MT9P031_RST_ENABLE 1 |
| @@ -445,9 +447,23 @@ static int mt9p031_set_params(struct mt9p031 *mt9p031) |
| static int mt9p031_s_stream(struct v4l2_subdev *subdev, int enable) |
| { |
| struct mt9p031 *mt9p031 = to_mt9p031(subdev); |
| + struct i2c_client *client = v4l2_get_subdevdata(subdev); |
| + int val; |
| int ret; |
| |
| if (!enable) { |
| + /* enable pause restart */ |
| + val = MT9P031_FRAME_PAUSE_RESTART; |
| + ret = mt9p031_write(client, MT9P031_RESTART, val); |
| + if (ret < 0) |
| + return ret; |
| + |
| + /* enable restart + keep pause restart set */ |
| + val |= MT9P031_FRAME_RESTART; |
| + ret = mt9p031_write(client, MT9P031_RESTART, val); |
| + if (ret < 0) |
| + return ret; |
| + |
| /* Stop sensor readout */ |
| ret = mt9p031_set_output_control(mt9p031, |
| MT9P031_OUTPUT_CONTROL_CEN, 0); |
| @@ -467,6 +483,16 @@ static int mt9p031_s_stream(struct v4l2_subdev *subdev, int enable) |
| if (ret < 0) |
| return ret; |
| |
| + /* |
| + * - clear pause restart |
| + * - don't clear restart as clearing restart manually can cause |
| + * undefined behavior |
| + */ |
| + val = MT9P031_FRAME_RESTART; |
| + ret = mt9p031_write(client, MT9P031_RESTART, val); |
| + if (ret < 0) |
| + return ret; |
| + |
| return mt9p031_pll_enable(mt9p031); |
| } |
| |
| -- |
| 2.33.0 |
| |