From 05529af92f509631f6a921dd6b43b9f9850c988a Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mar 17 2023 08:06:29 +0000 Subject: media: ov5640: Fix analogue gain control (bsc#1012628). --- diff --git a/patches.kernel.org/6.2.7-129-media-ov5640-Fix-analogue-gain-control.patch b/patches.kernel.org/6.2.7-129-media-ov5640-Fix-analogue-gain-control.patch new file mode 100644 index 0000000..0fcb6bc --- /dev/null +++ b/patches.kernel.org/6.2.7-129-media-ov5640-Fix-analogue-gain-control.patch @@ -0,0 +1,94 @@ +From: Paul Elder +Date: Mon, 28 Nov 2022 09:02:01 +0100 +Subject: [PATCH] media: ov5640: Fix analogue gain control +References: bsc#1012628 +Patch-mainline: 6.2.7 +Git-commit: afa4805799c1d332980ad23339fdb07b5e0cf7e0 + +[ Upstream commit afa4805799c1d332980ad23339fdb07b5e0cf7e0 ] + +Gain control is badly documented in publicly available (including +leaked) documentation. + +There is an AGC pre-gain in register 0x3a13, expressed as a 6-bit value +(plus an enable bit in bit 6). The driver hardcodes it to 0x43, which +one application note states is equal to x1.047. The documentation also +states that 0x40 is equel to x1.000. The pre-gain thus seems to be +expressed as in 1/64 increments, and thus ranges from x1.00 to x1.984. +What the pre-gain does is however unspecified. + +There is then an AGC gain limit, in registers 0x3a18 and 0x3a19, +expressed as a 10-bit "real gain format" value. One application note +sets it to 0x00f8 and states it is equal to x15.5, so it appears to be +expressed in 1/16 increments, up to x63.9375. + +The manual gain is stored in registers 0x350a and 0x350b, also as a +10-bit "real gain format" value. It is documented in the application +note as a Q6.4 values, up to x63.9375. + +One version of the datasheet indicates that the sensor supports a +digital gain: + + The OV5640 supports 1/2/4 digital gain. Normally, the gain is + controlled automatically by the automatic gain control (AGC) block. + +It isn't clear how that would be controlled manually. + +There appears to be no indication regarding whether the gain controlled +through registers 0x350a and 0x350b is an analogue gain only or also +includes digital gain. The words "real gain" don't necessarily mean +"combined analogue and digital gains". Some OmniVision sensors (such as +the OV8858) are documented as supoprting different formats for the gain +values, selectable through a register bit, and they are called "real +gain format" and "sensor gain format". For that sensor, we have (one of) +the gain registers documented as + + 0x3503[2]=0, gain[7:0] is real gain format, where low 4 bits are + fraction bits, for example, 0x10 is 1x gain, 0x28 is 2.5x gain + + If 0x3503[2]=1, gain[7:0] is sensor gain format, gain[7:4] is coarse + gain, 00000: 1x, 00001: 2x, 00011: 4x, 00111: 8x, gain[7] is 1, + gain[3:0] is fine gain. For example, 0x10 is 1x gain, 0x30 is 2x gain, + 0x70 is 4x gain + +(The second part of the text makes little sense) + +"Real gain" may thus refer to the combination of the coarse and fine +analogue gains as a single value. + +The OV5640 0x350a and 0x350b registers thus appear to control analogue +gain. The driver incorrectly uses V4L2_CID_GAIN as V4L2 has a specific +control for analogue gain, V4L2_CID_ANALOGUE_GAIN. Use it. + +If registers 0x350a and 0x350b are later found to control digital gain +as well, the driver could then restrict the range of the analogue gain +control value to lower than x64 and add a separate digital gain control. + +Signed-off-by: Paul Elder +Signed-off-by: Laurent Pinchart +Reviewed-by: Jacopo Mondi +Reviewed-by: Jai Luthra +Signed-off-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Sasha Levin +Signed-off-by: Jiri Slaby +--- + drivers/media/i2c/ov5640.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c +index c159f297..16ca9dbf 100644 +--- a/drivers/media/i2c/ov5640.c ++++ b/drivers/media/i2c/ov5640.c +@@ -3482,7 +3482,7 @@ static int ov5640_init_controls(struct ov5640_dev *sensor) + /* Auto/manual gain */ + ctrls->auto_gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTOGAIN, + 0, 1, 1, 1); +- ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN, ++ ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_ANALOGUE_GAIN, + 0, 1023, 1, 0); + + ctrls->saturation = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION, +-- +2.35.3 + diff --git a/series.conf b/series.conf index 6ff25ef..1343c07 100644 --- a/series.conf +++ b/series.conf @@ -1403,6 +1403,7 @@ patches.kernel.org/6.2.7-126-macintosh-windfarm-Use-unsigned-type-for-1-bit-.patch patches.kernel.org/6.2.7-127-PCI-Add-SolidRun-vendor-ID.patch patches.kernel.org/6.2.7-128-scripts-handle-BrokenPipeError-for-python-scrip.patch + patches.kernel.org/6.2.7-129-media-ov5640-Fix-analogue-gain-control.patch ######################################################## # Build fixes that apply to the vanilla kernel too.