linux-media.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/21] imx258 improvements series
@ 2023-05-30 17:29 Dave Stevenson
  2023-05-30 17:29 ` [PATCH 01/21] media: i2c: imx258: Remove unused defines Dave Stevenson
                   ` (21 more replies)
  0 siblings, 22 replies; 54+ messages in thread
From: Dave Stevenson @ 2023-05-30 17:29 UTC (permalink / raw)
  To: Sakari Ailus, linux-media, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree
  Cc: Dave Stevenson

This is a set of patches for imx258 that allow it to work with alternate clock
frequencies, over either 2 or 4 lanes, and generally adding flexibility to the
driver.

Tested with an IMX258 module from Soho Enterprises that has a 24MHz oscillator.
Both 2 and 4 lane configurations work with correct link frequencies and pixel
rates.

Jacopo has tested on a PinePhone Pro which has an ~19.2MHz clock fed from the SoC,
He confirms that the two lower resolution modes work, but not the full res mode.
Comparing to the BSP it looks like they have some weird clock configuration in
the 4208x3120 mode (nominally 1224Mb/s/lane instead of 1267).
As it has never previously worked directly with the mainline driver this isn't a
regression but may indicate that there is a need for support of additional link
frequencies in the future.

The last patch that makes HFLIP and VFLIP configurable may be contentious as I've
retained the default configuration of inverted from the original driver. I know
this was discussed recently, but I can't recall the final outcome.

I am relying on someone from Intel testing this out, as correcting the cropping
and supporting flips has changed the Bayer order. Seeing as this is all above
board in V4L2 terms I really hope that the layers above it behave themselves.

Cheers
  Dave

Dave Stevenson (21):
  media: i2c: imx258: Remove unused defines
  media: i2c: imx258: Make image geometry meet sensor requirements
  media: i2c: imx258: Disable digital cropping on binned modes
  media: i2c: imx258: Remove redundant I2C writes.
  media: i2c: imx258: Add regulator control
  media: i2c: imx258: Make V4L2_CID_VBLANK configurable.
  media: i2c: imx258: Split out common registers from the mode based
    ones
  media: i2c: imx258: Add support for 24MHz clock
  media: i2c: imx258: Add support for running on 2 CSI data lanes
  media: i2c: imx258: Follow normal V4L2 behaviours for clipping
    exposure
  media: i2c: imx258: Add get_selection for pixel array information
  media: i2c: imx258: Allow configuration of clock lane behaviour
  media: i2c: imx258: Correct max FRM_LENGTH_LINES value
  media: i2c: imx258: Add support for long exposure modes
  media: i2c: imx258: Issue reset before starting streaming
  media: i2c: imx258: Set pixel_rate range to the same as the value
  media: i2c: imx258: Support faster pixel rate on binned modes
  dt-bindings: media: imx258: Rename to include vendor prefix
  dt-bindings: media: imx258: Add alternate compatible strings
  media: i2c: imx258: Change register settings for variants of the
    sensor
  media: i2c: imx258: Make HFLIP and VFLIP controls writable

 .../i2c/{imx258.yaml => sony,imx258.yaml}     |   9 +-
 MAINTAINERS                                   |   2 +-
 drivers/media/i2c/imx258.c                    | 994 ++++++++++++------
 3 files changed, 675 insertions(+), 330 deletions(-)
 rename Documentation/devicetree/bindings/media/i2c/{imx258.yaml => sony,imx258.yaml} (90%)

-- 
2.25.1


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

* [PATCH 01/21] media: i2c: imx258: Remove unused defines
  2023-05-30 17:29 [PATCH 00/21] imx258 improvements series Dave Stevenson
@ 2023-05-30 17:29 ` Dave Stevenson
  2023-05-31 15:08   ` Jacopo Mondi
  2023-05-30 17:29 ` [PATCH 02/21] media: i2c: imx258: Make image geometry meet sensor requirements Dave Stevenson
                   ` (20 subsequent siblings)
  21 siblings, 1 reply; 54+ messages in thread
From: Dave Stevenson @ 2023-05-30 17:29 UTC (permalink / raw)
  To: Sakari Ailus, linux-media, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree
  Cc: Dave Stevenson

The IMX258_FLL_* defines are unused. Remove them.

Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
 drivers/media/i2c/imx258.c | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
index 85d73b186111..6028579393b5 100644
--- a/drivers/media/i2c/imx258.c
+++ b/drivers/media/i2c/imx258.c
@@ -29,12 +29,6 @@
 #define IMX258_VTS_30FPS_VGA		0x034c
 #define IMX258_VTS_MAX			0xffff
 
-/*Frame Length Line*/
-#define IMX258_FLL_MIN			0x08a6
-#define IMX258_FLL_MAX			0xffff
-#define IMX258_FLL_STEP			1
-#define IMX258_FLL_DEFAULT		0x0c98
-
 /* HBLANK control - read only */
 #define IMX258_PPL_DEFAULT		5352
 
-- 
2.25.1


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

* [PATCH 02/21] media: i2c: imx258: Make image geometry meet sensor requirements
  2023-05-30 17:29 [PATCH 00/21] imx258 improvements series Dave Stevenson
  2023-05-30 17:29 ` [PATCH 01/21] media: i2c: imx258: Remove unused defines Dave Stevenson
@ 2023-05-30 17:29 ` Dave Stevenson
  2023-05-31 15:09   ` Jacopo Mondi
  2023-05-30 17:29 ` [PATCH 03/21] media: i2c: imx258: Disable digital cropping on binned modes Dave Stevenson
                   ` (19 subsequent siblings)
  21 siblings, 1 reply; 54+ messages in thread
From: Dave Stevenson @ 2023-05-30 17:29 UTC (permalink / raw)
  To: Sakari Ailus, linux-media, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree
  Cc: Dave Stevenson

The output image is defined as being 4208x3118 pixels in size.
Y_ADD_STA register was set to 0, and Y_ADD_END to 3118, giving
3119 lines total.

The datasheet lists a requirement for Y_ADD_STA to be a multiple
of a power of 2 depending on binning/scaling mode (2 for full pixel,
4 for x2-bin/scale, 8 for (x2-bin)+(x2-subsample) or x4-bin, or 16
for (x4-bin)+(x2-subsample)).
(Y_ADD_END – Y_ADD_STA + 1) also has to be a similar power of 2.

The current configuration for the full res modes breaks that second
requirement, and we can't increase Y_ADD_STA to 1 to retain exactly
the same field of view as that then breaks the first requirement.
For the binned modes, they are worse off as 3118 is not a multiple of
4.

Increase the main mode to 4208x3120 so that it is the same FOV as the
binned modes, with Y_ADD_STA at 0.
Fix Y_ADD_STA and Y_ADD_END for the binned modes so that they meet the
sensor requirements.

This does change the Bayer order as the default configuration is for
H&V flips to be enabled, so readout is from Y_STA_END to Y_ADD_STA,
and this patch has changed Y_STA_END.

Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
 drivers/media/i2c/imx258.c | 26 +++++++++++++-------------
 1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
index 6028579393b5..946b1a12971d 100644
--- a/drivers/media/i2c/imx258.c
+++ b/drivers/media/i2c/imx258.c
@@ -111,7 +111,7 @@ struct imx258_mode {
 	struct imx258_reg_list reg_list;
 };
 
-/* 4208x3118 needs 1267Mbps/lane, 4 lanes */
+/* 4208x3120 needs 1267Mbps/lane, 4 lanes */
 static const struct imx258_reg mipi_data_rate_1267mbps[] = {
 	{ 0x0301, 0x05 },
 	{ 0x0303, 0x02 },
@@ -148,7 +148,7 @@ static const struct imx258_reg mipi_data_rate_640mbps[] = {
 	{ 0x0823, 0x00 },
 };
 
-static const struct imx258_reg mode_4208x3118_regs[] = {
+static const struct imx258_reg mode_4208x3120_regs[] = {
 	{ 0x0136, 0x13 },
 	{ 0x0137, 0x33 },
 	{ 0x3051, 0x00 },
@@ -210,7 +210,7 @@ static const struct imx258_reg mode_4208x3118_regs[] = {
 	{ 0x0348, 0x10 },
 	{ 0x0349, 0x6F },
 	{ 0x034A, 0x0C },
-	{ 0x034B, 0x2E },
+	{ 0x034B, 0x2F },
 	{ 0x0381, 0x01 },
 	{ 0x0383, 0x01 },
 	{ 0x0385, 0x01 },
@@ -329,7 +329,7 @@ static const struct imx258_reg mode_2104_1560_regs[] = {
 	{ 0x0348, 0x10 },
 	{ 0x0349, 0x6F },
 	{ 0x034A, 0x0C },
-	{ 0x034B, 0x2E },
+	{ 0x034B, 0x2F },
 	{ 0x0381, 0x01 },
 	{ 0x0383, 0x01 },
 	{ 0x0385, 0x01 },
@@ -448,7 +448,7 @@ static const struct imx258_reg mode_1048_780_regs[] = {
 	{ 0x0348, 0x10 },
 	{ 0x0349, 0x6F },
 	{ 0x034A, 0x0C },
-	{ 0x034B, 0x2E },
+	{ 0x034B, 0x2F },
 	{ 0x0381, 0x01 },
 	{ 0x0383, 0x01 },
 	{ 0x0385, 0x01 },
@@ -562,12 +562,12 @@ static const struct imx258_link_freq_config link_freq_configs[] = {
 static const struct imx258_mode supported_modes[] = {
 	{
 		.width = 4208,
-		.height = 3118,
+		.height = 3120,
 		.vts_def = IMX258_VTS_30FPS,
 		.vts_min = IMX258_VTS_30FPS,
 		.reg_list = {
-			.num_of_regs = ARRAY_SIZE(mode_4208x3118_regs),
-			.regs = mode_4208x3118_regs,
+			.num_of_regs = ARRAY_SIZE(mode_4208x3120_regs),
+			.regs = mode_4208x3120_regs,
 		},
 		.link_freq_index = IMX258_LINK_FREQ_1267MBPS,
 	},
@@ -710,7 +710,7 @@ static int imx258_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 	/* Initialize try_fmt */
 	try_fmt->width = supported_modes[0].width;
 	try_fmt->height = supported_modes[0].height;
-	try_fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10;
+	try_fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
 	try_fmt->field = V4L2_FIELD_NONE;
 
 	return 0;
@@ -822,7 +822,7 @@ static int imx258_enum_mbus_code(struct v4l2_subdev *sd,
 	if (code->index > 0)
 		return -EINVAL;
 
-	code->code = MEDIA_BUS_FMT_SGRBG10_1X10;
+	code->code = MEDIA_BUS_FMT_SBGGR10_1X10;
 
 	return 0;
 }
@@ -834,7 +834,7 @@ static int imx258_enum_frame_size(struct v4l2_subdev *sd,
 	if (fse->index >= ARRAY_SIZE(supported_modes))
 		return -EINVAL;
 
-	if (fse->code != MEDIA_BUS_FMT_SGRBG10_1X10)
+	if (fse->code != MEDIA_BUS_FMT_SBGGR10_1X10)
 		return -EINVAL;
 
 	fse->min_width = supported_modes[fse->index].width;
@@ -850,7 +850,7 @@ static void imx258_update_pad_format(const struct imx258_mode *mode,
 {
 	fmt->format.width = mode->width;
 	fmt->format.height = mode->height;
-	fmt->format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
+	fmt->format.code = MEDIA_BUS_FMT_SBGGR10_1X10;
 	fmt->format.field = V4L2_FIELD_NONE;
 }
 
@@ -898,7 +898,7 @@ static int imx258_set_pad_format(struct v4l2_subdev *sd,
 	mutex_lock(&imx258->mutex);
 
 	/* Only one raw bayer(GBRG) order is supported */
-	fmt->format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
+	fmt->format.code = MEDIA_BUS_FMT_SBGGR10_1X10;
 
 	mode = v4l2_find_nearest_size(supported_modes,
 		ARRAY_SIZE(supported_modes), width, height,
-- 
2.25.1


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

* [PATCH 03/21] media: i2c: imx258: Disable digital cropping on binned modes
  2023-05-30 17:29 [PATCH 00/21] imx258 improvements series Dave Stevenson
  2023-05-30 17:29 ` [PATCH 01/21] media: i2c: imx258: Remove unused defines Dave Stevenson
  2023-05-30 17:29 ` [PATCH 02/21] media: i2c: imx258: Make image geometry meet sensor requirements Dave Stevenson
@ 2023-05-30 17:29 ` Dave Stevenson
  2023-05-31 15:02   ` Jacopo Mondi
  2023-05-30 17:29 ` [PATCH 04/21] media: i2c: imx258: Remove redundant I2C writes Dave Stevenson
                   ` (18 subsequent siblings)
  21 siblings, 1 reply; 54+ messages in thread
From: Dave Stevenson @ 2023-05-30 17:29 UTC (permalink / raw)
  To: Sakari Ailus, linux-media, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree
  Cc: Dave Stevenson

The binned modes set DIG_CROP_X_OFFSET and DIG_CROP_IMAGE_WIDTH
to less than the full image, even though the image being captured
is meant to be a scaled version of the full array size.

Reduce X_OFFSET to 0, and increase IMAGE_WIDTH to the full array.

Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
 drivers/media/i2c/imx258.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
index 946b1a12971d..aabd5c3e8af9 100644
--- a/drivers/media/i2c/imx258.c
+++ b/drivers/media/i2c/imx258.c
@@ -340,11 +340,11 @@ static const struct imx258_reg mode_2104_1560_regs[] = {
 	{ 0x0404, 0x00 },
 	{ 0x0405, 0x20 },
 	{ 0x0408, 0x00 },
-	{ 0x0409, 0x02 },
+	{ 0x0409, 0x00 },
 	{ 0x040A, 0x00 },
 	{ 0x040B, 0x00 },
 	{ 0x040C, 0x10 },
-	{ 0x040D, 0x6A },
+	{ 0x040D, 0x70 },
 	{ 0x040E, 0x06 },
 	{ 0x040F, 0x18 },
 	{ 0x3038, 0x00 },
@@ -459,11 +459,11 @@ static const struct imx258_reg mode_1048_780_regs[] = {
 	{ 0x0404, 0x00 },
 	{ 0x0405, 0x40 },
 	{ 0x0408, 0x00 },
-	{ 0x0409, 0x06 },
+	{ 0x0409, 0x00 },
 	{ 0x040A, 0x00 },
 	{ 0x040B, 0x00 },
 	{ 0x040C, 0x10 },
-	{ 0x040D, 0x64 },
+	{ 0x040D, 0x70 },
 	{ 0x040E, 0x03 },
 	{ 0x040F, 0x0C },
 	{ 0x3038, 0x00 },
-- 
2.25.1


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

* [PATCH 04/21] media: i2c: imx258: Remove redundant I2C writes.
  2023-05-30 17:29 [PATCH 00/21] imx258 improvements series Dave Stevenson
                   ` (2 preceding siblings ...)
  2023-05-30 17:29 ` [PATCH 03/21] media: i2c: imx258: Disable digital cropping on binned modes Dave Stevenson
@ 2023-05-30 17:29 ` Dave Stevenson
  2023-05-31 15:10   ` Jacopo Mondi
  2023-05-30 17:29 ` [PATCH 05/21] media: i2c: imx258: Add regulator control Dave Stevenson
                   ` (17 subsequent siblings)
  21 siblings, 1 reply; 54+ messages in thread
From: Dave Stevenson @ 2023-05-30 17:29 UTC (permalink / raw)
  To: Sakari Ailus, linux-media, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree
  Cc: Dave Stevenson

Registers 0x0202 and 0x0203 are written via the control handler
for V4L2_CID_EXPOSURE, so are not needed from the mode lists.

Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
 drivers/media/i2c/imx258.c | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
index aabd5c3e8af9..b695fd987b71 100644
--- a/drivers/media/i2c/imx258.c
+++ b/drivers/media/i2c/imx258.c
@@ -237,8 +237,6 @@ static const struct imx258_reg mode_4208x3120_regs[] = {
 	{ 0x034E, 0x0C },
 	{ 0x034F, 0x30 },
 	{ 0x0350, 0x01 },
-	{ 0x0202, 0x0C },
-	{ 0x0203, 0x46 },
 	{ 0x0204, 0x00 },
 	{ 0x0205, 0x00 },
 	{ 0x020E, 0x01 },
@@ -356,8 +354,6 @@ static const struct imx258_reg mode_2104_1560_regs[] = {
 	{ 0x034E, 0x06 },
 	{ 0x034F, 0x18 },
 	{ 0x0350, 0x01 },
-	{ 0x0202, 0x06 },
-	{ 0x0203, 0x2E },
 	{ 0x0204, 0x00 },
 	{ 0x0205, 0x00 },
 	{ 0x020E, 0x01 },
@@ -475,8 +471,6 @@ static const struct imx258_reg mode_1048_780_regs[] = {
 	{ 0x034E, 0x03 },
 	{ 0x034F, 0x0C },
 	{ 0x0350, 0x01 },
-	{ 0x0202, 0x03 },
-	{ 0x0203, 0x42 },
 	{ 0x0204, 0x00 },
 	{ 0x0205, 0x00 },
 	{ 0x020E, 0x01 },
-- 
2.25.1


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

* [PATCH 05/21] media: i2c: imx258: Add regulator control
  2023-05-30 17:29 [PATCH 00/21] imx258 improvements series Dave Stevenson
                   ` (3 preceding siblings ...)
  2023-05-30 17:29 ` [PATCH 04/21] media: i2c: imx258: Remove redundant I2C writes Dave Stevenson
@ 2023-05-30 17:29 ` Dave Stevenson
  2023-05-31 15:11   ` Jacopo Mondi
  2023-05-30 17:29 ` [PATCH 06/21] media: i2c: imx258: Make V4L2_CID_VBLANK configurable Dave Stevenson
                   ` (16 subsequent siblings)
  21 siblings, 1 reply; 54+ messages in thread
From: Dave Stevenson @ 2023-05-30 17:29 UTC (permalink / raw)
  To: Sakari Ailus, linux-media, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree
  Cc: Dave Stevenson

The device tree bindings define the relevant regulators for the
sensor, so update the driver to request the regulators and control
them at the appropriate times.

Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
 drivers/media/i2c/imx258.c | 42 +++++++++++++++++++++++++++++++++++++-
 1 file changed, 41 insertions(+), 1 deletion(-)

diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
index b695fd987b71..30bae7388c3a 100644
--- a/drivers/media/i2c/imx258.c
+++ b/drivers/media/i2c/imx258.c
@@ -7,6 +7,7 @@
 #include <linux/i2c.h>
 #include <linux/module.h>
 #include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-fwnode.h>
@@ -507,6 +508,16 @@ static const char * const imx258_test_pattern_menu[] = {
 	"Pseudorandom Sequence (PN9)",
 };
 
+/* regulator supplies */
+static const char * const imx258_supply_name[] = {
+	/* Supplies can be enabled in any order */
+	"vana",  /* Analog (2.8V) supply */
+	"vdig",  /* Digital Core (1.2V) supply */
+	"vif",  /* IF (1.8V) supply */
+};
+
+#define IMX258_NUM_SUPPLIES ARRAY_SIZE(imx258_supply_name)
+
 /* Configurations for supported link frequencies */
 #define IMX258_LINK_FREQ_634MHZ	633600000ULL
 #define IMX258_LINK_FREQ_320MHZ	320000000ULL
@@ -614,6 +625,7 @@ struct imx258 {
 	bool streaming;
 
 	struct clk *clk;
+	struct regulator_bulk_data supplies[IMX258_NUM_SUPPLIES];
 };
 
 static inline struct imx258 *to_imx258(struct v4l2_subdev *_sd)
@@ -999,9 +1011,19 @@ static int imx258_power_on(struct device *dev)
 	struct imx258 *imx258 = to_imx258(sd);
 	int ret;
 
+	ret = regulator_bulk_enable(IMX258_NUM_SUPPLIES,
+				    imx258->supplies);
+	if (ret) {
+		dev_err(dev, "%s: failed to enable regulators\n",
+			__func__);
+		return ret;
+	}
+
 	ret = clk_prepare_enable(imx258->clk);
-	if (ret)
+	if (ret) {
 		dev_err(dev, "failed to enable clock\n");
+		regulator_bulk_disable(IMX258_NUM_SUPPLIES, imx258->supplies);
+	}
 
 	return ret;
 }
@@ -1012,6 +1034,7 @@ static int imx258_power_off(struct device *dev)
 	struct imx258 *imx258 = to_imx258(sd);
 
 	clk_disable_unprepare(imx258->clk);
+	regulator_bulk_disable(IMX258_NUM_SUPPLIES, imx258->supplies);
 
 	return 0;
 }
@@ -1260,6 +1283,19 @@ static void imx258_free_controls(struct imx258 *imx258)
 	mutex_destroy(&imx258->mutex);
 }
 
+static int imx258_get_regulators(struct imx258 *imx258,
+				 struct i2c_client *client)
+{
+	unsigned int i;
+
+	for (i = 0; i < IMX258_NUM_SUPPLIES; i++)
+		imx258->supplies[i].supply = imx258_supply_name[i];
+
+	return devm_regulator_bulk_get(&client->dev,
+				       IMX258_NUM_SUPPLIES,
+				       imx258->supplies);
+}
+
 static int imx258_probe(struct i2c_client *client)
 {
 	struct imx258 *imx258;
@@ -1270,6 +1306,10 @@ static int imx258_probe(struct i2c_client *client)
 	if (!imx258)
 		return -ENOMEM;
 
+	ret = imx258_get_regulators(imx258, client);
+	if (ret)
+		return ret;
+
 	imx258->clk = devm_clk_get_optional(&client->dev, NULL);
 	if (IS_ERR(imx258->clk))
 		return dev_err_probe(&client->dev, PTR_ERR(imx258->clk),
-- 
2.25.1


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

* [PATCH 06/21] media: i2c: imx258: Make V4L2_CID_VBLANK configurable.
  2023-05-30 17:29 [PATCH 00/21] imx258 improvements series Dave Stevenson
                   ` (4 preceding siblings ...)
  2023-05-30 17:29 ` [PATCH 05/21] media: i2c: imx258: Add regulator control Dave Stevenson
@ 2023-05-30 17:29 ` Dave Stevenson
  2023-05-31 15:16   ` Jacopo Mondi
  2023-05-30 17:29 ` [PATCH 07/21] media: i2c: imx258: Split out common registers from the mode based ones Dave Stevenson
                   ` (15 subsequent siblings)
  21 siblings, 1 reply; 54+ messages in thread
From: Dave Stevenson @ 2023-05-30 17:29 UTC (permalink / raw)
  To: Sakari Ailus, linux-media, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree
  Cc: Dave Stevenson

The values and ranges of V4L2_CID_VBLANK are all computed,
so there is no reason for it to be a read only control.
Remove the register values from the mode lists, add the
handler, and remove the read only flag.

Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
 drivers/media/i2c/imx258.c | 16 +++++++---------
 1 file changed, 7 insertions(+), 9 deletions(-)

diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
index 30bae7388c3a..c6fb649abb95 100644
--- a/drivers/media/i2c/imx258.c
+++ b/drivers/media/i2c/imx258.c
@@ -30,6 +30,8 @@
 #define IMX258_VTS_30FPS_VGA		0x034c
 #define IMX258_VTS_MAX			0xffff
 
+#define IMX258_REG_VTS			0x0340
+
 /* HBLANK control - read only */
 #define IMX258_PPL_DEFAULT		5352
 
@@ -202,8 +204,6 @@ static const struct imx258_reg mode_4208x3120_regs[] = {
 	{ 0x0114, 0x03 },
 	{ 0x0342, 0x14 },
 	{ 0x0343, 0xE8 },
-	{ 0x0340, 0x0C },
-	{ 0x0341, 0x50 },
 	{ 0x0344, 0x00 },
 	{ 0x0345, 0x00 },
 	{ 0x0346, 0x00 },
@@ -319,8 +319,6 @@ static const struct imx258_reg mode_2104_1560_regs[] = {
 	{ 0x0114, 0x03 },
 	{ 0x0342, 0x14 },
 	{ 0x0343, 0xE8 },
-	{ 0x0340, 0x06 },
-	{ 0x0341, 0x38 },
 	{ 0x0344, 0x00 },
 	{ 0x0345, 0x00 },
 	{ 0x0346, 0x00 },
@@ -436,8 +434,6 @@ static const struct imx258_reg mode_1048_780_regs[] = {
 	{ 0x0114, 0x03 },
 	{ 0x0342, 0x14 },
 	{ 0x0343, 0xE8 },
-	{ 0x0340, 0x03 },
-	{ 0x0341, 0x4C },
 	{ 0x0344, 0x00 },
 	{ 0x0345, 0x00 },
 	{ 0x0346, 0x00 },
@@ -803,6 +799,11 @@ static int imx258_set_ctrl(struct v4l2_ctrl *ctrl)
 					       BIT(IMX258_HDR_RATIO_MAX));
 		}
 		break;
+	case V4L2_CID_VBLANK:
+		ret = imx258_write_reg(imx258, IMX258_REG_VTS,
+				       IMX258_REG_VALUE_16BIT,
+				       imx258->cur_mode->height + ctrl->val);
+		break;
 	default:
 		dev_info(&client->dev,
 			 "ctrl(id:0x%x,val:0x%x) is not handled\n",
@@ -1214,9 +1215,6 @@ static int imx258_init_controls(struct imx258 *imx258)
 				IMX258_VTS_MAX - imx258->cur_mode->height, 1,
 				vblank_def);
 
-	if (imx258->vblank)
-		imx258->vblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
-
 	imx258->hblank = v4l2_ctrl_new_std(
 				ctrl_hdlr, &imx258_ctrl_ops, V4L2_CID_HBLANK,
 				IMX258_PPL_DEFAULT - imx258->cur_mode->width,
-- 
2.25.1


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

* [PATCH 07/21] media: i2c: imx258: Split out common registers from the mode based ones
  2023-05-30 17:29 [PATCH 00/21] imx258 improvements series Dave Stevenson
                   ` (5 preceding siblings ...)
  2023-05-30 17:29 ` [PATCH 06/21] media: i2c: imx258: Make V4L2_CID_VBLANK configurable Dave Stevenson
@ 2023-05-30 17:29 ` Dave Stevenson
  2023-05-31 15:26   ` Jacopo Mondi
  2023-05-30 17:29 ` [PATCH 08/21] media: i2c: imx258: Add support for 24MHz clock Dave Stevenson
                   ` (14 subsequent siblings)
  21 siblings, 1 reply; 54+ messages in thread
From: Dave Stevenson @ 2023-05-30 17:29 UTC (permalink / raw)
  To: Sakari Ailus, linux-media, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree
  Cc: Dave Stevenson

Out of all the registers that are defined for each mode, only around
10 differ between the modes.

Split the table into common and mode specific ones.

Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
 drivers/media/i2c/imx258.c | 236 ++++---------------------------------
 1 file changed, 21 insertions(+), 215 deletions(-)

diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
index c6fb649abb95..5a57d0b5fcd8 100644
--- a/drivers/media/i2c/imx258.c
+++ b/drivers/media/i2c/imx258.c
@@ -151,7 +151,7 @@ static const struct imx258_reg mipi_data_rate_640mbps[] = {
 	{ 0x0823, 0x00 },
 };
 
-static const struct imx258_reg mode_4208x3120_regs[] = {
+static const struct imx258_reg mode_common_regs[] = {
 	{ 0x0136, 0x13 },
 	{ 0x0137, 0x33 },
 	{ 0x3051, 0x00 },
@@ -216,27 +216,17 @@ static const struct imx258_reg mode_4208x3120_regs[] = {
 	{ 0x0383, 0x01 },
 	{ 0x0385, 0x01 },
 	{ 0x0387, 0x01 },
-	{ 0x0900, 0x00 },
-	{ 0x0901, 0x11 },
-	{ 0x0401, 0x00 },
 	{ 0x0404, 0x00 },
-	{ 0x0405, 0x10 },
 	{ 0x0408, 0x00 },
 	{ 0x0409, 0x00 },
 	{ 0x040A, 0x00 },
 	{ 0x040B, 0x00 },
 	{ 0x040C, 0x10 },
 	{ 0x040D, 0x70 },
-	{ 0x040E, 0x0C },
-	{ 0x040F, 0x30 },
 	{ 0x3038, 0x00 },
 	{ 0x303A, 0x00 },
 	{ 0x303B, 0x10 },
 	{ 0x300D, 0x00 },
-	{ 0x034C, 0x10 },
-	{ 0x034D, 0x70 },
-	{ 0x034E, 0x0C },
-	{ 0x034F, 0x30 },
 	{ 0x0350, 0x01 },
 	{ 0x0204, 0x00 },
 	{ 0x0205, 0x00 },
@@ -266,234 +256,43 @@ static const struct imx258_reg mode_4208x3120_regs[] = {
 	{ 0x0220, 0x00 },
 };
 
+static const struct imx258_reg mode_4208x3120_regs[] = {
+	{ 0x0900, 0x00 },
+	{ 0x0901, 0x11 },
+	{ 0x0401, 0x00 },
+	{ 0x0405, 0x10 },
+	{ 0x040E, 0x0C },
+	{ 0x040F, 0x30 },
+	{ 0x034C, 0x10 },
+	{ 0x034D, 0x70 },
+	{ 0x034E, 0x0C },
+	{ 0x034F, 0x30 },
+};
+
 static const struct imx258_reg mode_2104_1560_regs[] = {
-	{ 0x0136, 0x13 },
-	{ 0x0137, 0x33 },
-	{ 0x3051, 0x00 },
-	{ 0x3052, 0x00 },
-	{ 0x4E21, 0x14 },
-	{ 0x6B11, 0xCF },
-	{ 0x7FF0, 0x08 },
-	{ 0x7FF1, 0x0F },
-	{ 0x7FF2, 0x08 },
-	{ 0x7FF3, 0x1B },
-	{ 0x7FF4, 0x23 },
-	{ 0x7FF5, 0x60 },
-	{ 0x7FF6, 0x00 },
-	{ 0x7FF7, 0x01 },
-	{ 0x7FF8, 0x00 },
-	{ 0x7FF9, 0x78 },
-	{ 0x7FFA, 0x00 },
-	{ 0x7FFB, 0x00 },
-	{ 0x7FFC, 0x00 },
-	{ 0x7FFD, 0x00 },
-	{ 0x7FFE, 0x00 },
-	{ 0x7FFF, 0x03 },
-	{ 0x7F76, 0x03 },
-	{ 0x7F77, 0xFE },
-	{ 0x7FA8, 0x03 },
-	{ 0x7FA9, 0xFE },
-	{ 0x7B24, 0x81 },
-	{ 0x7B25, 0x00 },
-	{ 0x6564, 0x07 },
-	{ 0x6B0D, 0x41 },
-	{ 0x653D, 0x04 },
-	{ 0x6B05, 0x8C },
-	{ 0x6B06, 0xF9 },
-	{ 0x6B08, 0x65 },
-	{ 0x6B09, 0xFC },
-	{ 0x6B0A, 0xCF },
-	{ 0x6B0B, 0xD2 },
-	{ 0x6700, 0x0E },
-	{ 0x6707, 0x0E },
-	{ 0x9104, 0x00 },
-	{ 0x4648, 0x7F },
-	{ 0x7420, 0x00 },
-	{ 0x7421, 0x1C },
-	{ 0x7422, 0x00 },
-	{ 0x7423, 0xD7 },
-	{ 0x5F04, 0x00 },
-	{ 0x5F05, 0xED },
-	{ 0x0112, 0x0A },
-	{ 0x0113, 0x0A },
-	{ 0x0114, 0x03 },
-	{ 0x0342, 0x14 },
-	{ 0x0343, 0xE8 },
-	{ 0x0344, 0x00 },
-	{ 0x0345, 0x00 },
-	{ 0x0346, 0x00 },
-	{ 0x0347, 0x00 },
-	{ 0x0348, 0x10 },
-	{ 0x0349, 0x6F },
-	{ 0x034A, 0x0C },
-	{ 0x034B, 0x2F },
-	{ 0x0381, 0x01 },
-	{ 0x0383, 0x01 },
-	{ 0x0385, 0x01 },
-	{ 0x0387, 0x01 },
 	{ 0x0900, 0x01 },
 	{ 0x0901, 0x12 },
 	{ 0x0401, 0x01 },
-	{ 0x0404, 0x00 },
 	{ 0x0405, 0x20 },
-	{ 0x0408, 0x00 },
-	{ 0x0409, 0x00 },
-	{ 0x040A, 0x00 },
-	{ 0x040B, 0x00 },
-	{ 0x040C, 0x10 },
-	{ 0x040D, 0x70 },
 	{ 0x040E, 0x06 },
 	{ 0x040F, 0x18 },
-	{ 0x3038, 0x00 },
-	{ 0x303A, 0x00 },
-	{ 0x303B, 0x10 },
-	{ 0x300D, 0x00 },
 	{ 0x034C, 0x08 },
 	{ 0x034D, 0x38 },
 	{ 0x034E, 0x06 },
 	{ 0x034F, 0x18 },
-	{ 0x0350, 0x01 },
-	{ 0x0204, 0x00 },
-	{ 0x0205, 0x00 },
-	{ 0x020E, 0x01 },
-	{ 0x020F, 0x00 },
-	{ 0x0210, 0x01 },
-	{ 0x0211, 0x00 },
-	{ 0x0212, 0x01 },
-	{ 0x0213, 0x00 },
-	{ 0x0214, 0x01 },
-	{ 0x0215, 0x00 },
-	{ 0x7BCD, 0x01 },
-	{ 0x94DC, 0x20 },
-	{ 0x94DD, 0x20 },
-	{ 0x94DE, 0x20 },
-	{ 0x95DC, 0x20 },
-	{ 0x95DD, 0x20 },
-	{ 0x95DE, 0x20 },
-	{ 0x7FB0, 0x00 },
-	{ 0x9010, 0x3E },
-	{ 0x9419, 0x50 },
-	{ 0x941B, 0x50 },
-	{ 0x9519, 0x50 },
-	{ 0x951B, 0x50 },
-	{ 0x3030, 0x00 },
-	{ 0x3032, 0x00 },
-	{ 0x0220, 0x00 },
 };
 
 static const struct imx258_reg mode_1048_780_regs[] = {
-	{ 0x0136, 0x13 },
-	{ 0x0137, 0x33 },
-	{ 0x3051, 0x00 },
-	{ 0x3052, 0x00 },
-	{ 0x4E21, 0x14 },
-	{ 0x6B11, 0xCF },
-	{ 0x7FF0, 0x08 },
-	{ 0x7FF1, 0x0F },
-	{ 0x7FF2, 0x08 },
-	{ 0x7FF3, 0x1B },
-	{ 0x7FF4, 0x23 },
-	{ 0x7FF5, 0x60 },
-	{ 0x7FF6, 0x00 },
-	{ 0x7FF7, 0x01 },
-	{ 0x7FF8, 0x00 },
-	{ 0x7FF9, 0x78 },
-	{ 0x7FFA, 0x00 },
-	{ 0x7FFB, 0x00 },
-	{ 0x7FFC, 0x00 },
-	{ 0x7FFD, 0x00 },
-	{ 0x7FFE, 0x00 },
-	{ 0x7FFF, 0x03 },
-	{ 0x7F76, 0x03 },
-	{ 0x7F77, 0xFE },
-	{ 0x7FA8, 0x03 },
-	{ 0x7FA9, 0xFE },
-	{ 0x7B24, 0x81 },
-	{ 0x7B25, 0x00 },
-	{ 0x6564, 0x07 },
-	{ 0x6B0D, 0x41 },
-	{ 0x653D, 0x04 },
-	{ 0x6B05, 0x8C },
-	{ 0x6B06, 0xF9 },
-	{ 0x6B08, 0x65 },
-	{ 0x6B09, 0xFC },
-	{ 0x6B0A, 0xCF },
-	{ 0x6B0B, 0xD2 },
-	{ 0x6700, 0x0E },
-	{ 0x6707, 0x0E },
-	{ 0x9104, 0x00 },
-	{ 0x4648, 0x7F },
-	{ 0x7420, 0x00 },
-	{ 0x7421, 0x1C },
-	{ 0x7422, 0x00 },
-	{ 0x7423, 0xD7 },
-	{ 0x5F04, 0x00 },
-	{ 0x5F05, 0xED },
-	{ 0x0112, 0x0A },
-	{ 0x0113, 0x0A },
-	{ 0x0114, 0x03 },
-	{ 0x0342, 0x14 },
-	{ 0x0343, 0xE8 },
-	{ 0x0344, 0x00 },
-	{ 0x0345, 0x00 },
-	{ 0x0346, 0x00 },
-	{ 0x0347, 0x00 },
-	{ 0x0348, 0x10 },
-	{ 0x0349, 0x6F },
-	{ 0x034A, 0x0C },
-	{ 0x034B, 0x2F },
-	{ 0x0381, 0x01 },
-	{ 0x0383, 0x01 },
-	{ 0x0385, 0x01 },
-	{ 0x0387, 0x01 },
 	{ 0x0900, 0x01 },
 	{ 0x0901, 0x14 },
 	{ 0x0401, 0x01 },
-	{ 0x0404, 0x00 },
 	{ 0x0405, 0x40 },
-	{ 0x0408, 0x00 },
-	{ 0x0409, 0x00 },
-	{ 0x040A, 0x00 },
-	{ 0x040B, 0x00 },
-	{ 0x040C, 0x10 },
-	{ 0x040D, 0x70 },
 	{ 0x040E, 0x03 },
 	{ 0x040F, 0x0C },
-	{ 0x3038, 0x00 },
-	{ 0x303A, 0x00 },
-	{ 0x303B, 0x10 },
-	{ 0x300D, 0x00 },
 	{ 0x034C, 0x04 },
 	{ 0x034D, 0x18 },
 	{ 0x034E, 0x03 },
 	{ 0x034F, 0x0C },
-	{ 0x0350, 0x01 },
-	{ 0x0204, 0x00 },
-	{ 0x0205, 0x00 },
-	{ 0x020E, 0x01 },
-	{ 0x020F, 0x00 },
-	{ 0x0210, 0x01 },
-	{ 0x0211, 0x00 },
-	{ 0x0212, 0x01 },
-	{ 0x0213, 0x00 },
-	{ 0x0214, 0x01 },
-	{ 0x0215, 0x00 },
-	{ 0x7BCD, 0x00 },
-	{ 0x94DC, 0x20 },
-	{ 0x94DD, 0x20 },
-	{ 0x94DE, 0x20 },
-	{ 0x95DC, 0x20 },
-	{ 0x95DD, 0x20 },
-	{ 0x95DE, 0x20 },
-	{ 0x7FB0, 0x00 },
-	{ 0x9010, 0x3E },
-	{ 0x9419, 0x50 },
-	{ 0x941B, 0x50 },
-	{ 0x9519, 0x50 },
-	{ 0x951B, 0x50 },
-	{ 0x3030, 0x00 },
-	{ 0x3032, 0x00 },
-	{ 0x0220, 0x00 },
 };
 
 static const char * const imx258_test_pattern_menu[] = {
@@ -959,6 +758,13 @@ static int imx258_start_streaming(struct imx258 *imx258)
 		return ret;
 	}
 
+	ret = imx258_write_regs(imx258, mode_common_regs,
+				ARRAY_SIZE(mode_common_regs));
+	if (ret) {
+		dev_err(&client->dev, "%s failed to set common regs\n", __func__);
+		return ret;
+	}
+
 	/* Apply default values of current mode */
 	reg_list = &imx258->cur_mode->reg_list;
 	ret = imx258_write_regs(imx258, reg_list->regs, reg_list->num_of_regs);
-- 
2.25.1


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

* [PATCH 08/21] media: i2c: imx258: Add support for 24MHz clock
  2023-05-30 17:29 [PATCH 00/21] imx258 improvements series Dave Stevenson
                   ` (6 preceding siblings ...)
  2023-05-30 17:29 ` [PATCH 07/21] media: i2c: imx258: Split out common registers from the mode based ones Dave Stevenson
@ 2023-05-30 17:29 ` Dave Stevenson
  2023-06-02 12:59   ` Jacopo Mondi
  2023-05-30 17:29 ` [PATCH 09/21] media: i2c: imx258: Add support for running on 2 CSI data lanes Dave Stevenson
                   ` (13 subsequent siblings)
  21 siblings, 1 reply; 54+ messages in thread
From: Dave Stevenson @ 2023-05-30 17:29 UTC (permalink / raw)
  To: Sakari Ailus, linux-media, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree
  Cc: Dave Stevenson

There's no reason why only a clock of 19.2MHz is supported.
Indeed this isn't even a frequency listed in the datasheet.

Add support for 24MHz as well.
The PLL settings result in slightly different link frequencies,
so parameterise those.

Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
 drivers/media/i2c/imx258.c | 137 ++++++++++++++++++++++++++++++-------
 1 file changed, 111 insertions(+), 26 deletions(-)

diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
index 5a57d0b5fcd8..d40521f9a3c6 100644
--- a/drivers/media/i2c/imx258.c
+++ b/drivers/media/i2c/imx258.c
@@ -76,9 +76,6 @@
 #define REG_CONFIG_MIRROR_FLIP		0x03
 #define REG_CONFIG_FLIP_TEST_PATTERN	0x02
 
-/* Input clock frequency in Hz */
-#define IMX258_INPUT_CLOCK_FREQ		19200000
-
 struct imx258_reg {
 	u16 address;
 	u8 val;
@@ -91,6 +88,7 @@ struct imx258_reg_list {
 
 /* Link frequency config */
 struct imx258_link_freq_config {
+	u64 link_frequency;
 	u32 pixels_per_line;
 
 	/* PLL registers for this link frequency */
@@ -115,7 +113,9 @@ struct imx258_mode {
 };
 
 /* 4208x3120 needs 1267Mbps/lane, 4 lanes */
-static const struct imx258_reg mipi_data_rate_1267mbps[] = {
+static const struct imx258_reg mipi_1267mbps_19_2mhz[] = {
+	{ 0x0136, 0x13 },
+	{ 0x0137, 0x33 },
 	{ 0x0301, 0x05 },
 	{ 0x0303, 0x02 },
 	{ 0x0305, 0x03 },
@@ -133,7 +133,29 @@ static const struct imx258_reg mipi_data_rate_1267mbps[] = {
 	{ 0x0823, 0xCC },
 };
 
-static const struct imx258_reg mipi_data_rate_640mbps[] = {
+static const struct imx258_reg mipi_1272mbps_24mhz[] = {
+	{ 0x0136, 0x18 },
+	{ 0x0137, 0x00 },
+	{ 0x0301, 0x05 },
+	{ 0x0303, 0x02 },
+	{ 0x0305, 0x04 },
+	{ 0x0306, 0x00 },
+	{ 0x0307, 0xD4 },
+	{ 0x0309, 0x0A },
+	{ 0x030B, 0x01 },
+	{ 0x030D, 0x02 },
+	{ 0x030E, 0x00 },
+	{ 0x030F, 0xD8 },
+	{ 0x0310, 0x00 },
+	{ 0x0820, 0x13 },
+	{ 0x0821, 0x4C },
+	{ 0x0822, 0xCC },
+	{ 0x0823, 0xCC },
+};
+
+static const struct imx258_reg mipi_640mbps_19_2mhz[] = {
+	{ 0x0136, 0x13 },
+	{ 0x0137, 0x33 },
 	{ 0x0301, 0x05 },
 	{ 0x0303, 0x02 },
 	{ 0x0305, 0x03 },
@@ -151,9 +173,27 @@ static const struct imx258_reg mipi_data_rate_640mbps[] = {
 	{ 0x0823, 0x00 },
 };
 
+static const struct imx258_reg mipi_642mbps_24mhz[] = {
+	{ 0x0136, 0x18 },
+	{ 0x0137, 0x00 },
+	{ 0x0301, 0x05 },
+	{ 0x0303, 0x02 },
+	{ 0x0305, 0x04 },
+	{ 0x0306, 0x00 },
+	{ 0x0307, 0x6B },
+	{ 0x0309, 0x0A },
+	{ 0x030B, 0x01 },
+	{ 0x030D, 0x02 },
+	{ 0x030E, 0x00 },
+	{ 0x030F, 0xD8 },
+	{ 0x0310, 0x00 },
+	{ 0x0820, 0x0A },
+	{ 0x0821, 0x00 },
+	{ 0x0822, 0x00 },
+	{ 0x0823, 0x00 },
+};
+
 static const struct imx258_reg mode_common_regs[] = {
-	{ 0x0136, 0x13 },
-	{ 0x0137, 0x33 },
 	{ 0x3051, 0x00 },
 	{ 0x3052, 0x00 },
 	{ 0x4E21, 0x14 },
@@ -313,10 +353,6 @@ static const char * const imx258_supply_name[] = {
 
 #define IMX258_NUM_SUPPLIES ARRAY_SIZE(imx258_supply_name)
 
-/* Configurations for supported link frequencies */
-#define IMX258_LINK_FREQ_634MHZ	633600000ULL
-#define IMX258_LINK_FREQ_320MHZ	320000000ULL
-
 enum {
 	IMX258_LINK_FREQ_1267MBPS,
 	IMX258_LINK_FREQ_640MBPS,
@@ -335,25 +371,55 @@ static u64 link_freq_to_pixel_rate(u64 f)
 }
 
 /* Menu items for LINK_FREQ V4L2 control */
-static const s64 link_freq_menu_items[] = {
+/* Configurations for supported link frequencies */
+#define IMX258_LINK_FREQ_634MHZ	633600000ULL
+#define IMX258_LINK_FREQ_320MHZ	320000000ULL
+
+static const s64 link_freq_menu_items_19_2[] = {
 	IMX258_LINK_FREQ_634MHZ,
 	IMX258_LINK_FREQ_320MHZ,
 };
 
+/* Configurations for supported link frequencies */
+#define IMX258_LINK_FREQ_636MHZ	636000000ULL
+#define IMX258_LINK_FREQ_321MHZ	321000000ULL
+
+static const s64 link_freq_menu_items_24[] = {
+	IMX258_LINK_FREQ_636MHZ,
+	IMX258_LINK_FREQ_321MHZ,
+};
+
 /* Link frequency configs */
-static const struct imx258_link_freq_config link_freq_configs[] = {
+static const struct imx258_link_freq_config link_freq_configs_19_2[] = {
+	[IMX258_LINK_FREQ_1267MBPS] = {
+		.pixels_per_line = IMX258_PPL_DEFAULT,
+		.reg_list = {
+			.num_of_regs = ARRAY_SIZE(mipi_1267mbps_19_2mhz),
+			.regs = mipi_1267mbps_19_2mhz,
+		}
+	},
+	[IMX258_LINK_FREQ_640MBPS] = {
+		.pixels_per_line = IMX258_PPL_DEFAULT,
+		.reg_list = {
+			.num_of_regs = ARRAY_SIZE(mipi_640mbps_19_2mhz),
+			.regs = mipi_640mbps_19_2mhz,
+		}
+	},
+};
+
+static const struct imx258_link_freq_config link_freq_configs_24[] = {
 	[IMX258_LINK_FREQ_1267MBPS] = {
 		.pixels_per_line = IMX258_PPL_DEFAULT,
 		.reg_list = {
-			.num_of_regs = ARRAY_SIZE(mipi_data_rate_1267mbps),
-			.regs = mipi_data_rate_1267mbps,
+			.num_of_regs = ARRAY_SIZE(mipi_1272mbps_24mhz),
+			.regs = mipi_1272mbps_24mhz,
 		}
 	},
 	[IMX258_LINK_FREQ_640MBPS] = {
 		.pixels_per_line = IMX258_PPL_DEFAULT,
 		.reg_list = {
-			.num_of_regs = ARRAY_SIZE(mipi_data_rate_640mbps),
-			.regs = mipi_data_rate_640mbps,
+			.num_of_regs = ARRAY_SIZE(mipi_642mbps_24mhz),
+			.regs = mipi_642mbps_24mhz,
 		}
 	},
 };
@@ -410,6 +476,9 @@ struct imx258 {
 	/* Current mode */
 	const struct imx258_mode *cur_mode;
 
+	const struct imx258_link_freq_config *link_freq_configs;
+	const s64 *link_freq_menu_items;
+
 	/*
 	 * Mutex for serialized access:
 	 * Protect sensor module set pad format and start/stop streaming safely.
@@ -717,7 +786,7 @@ static int imx258_set_pad_format(struct v4l2_subdev *sd,
 		imx258->cur_mode = mode;
 		__v4l2_ctrl_s_ctrl(imx258->link_freq, mode->link_freq_index);
 
-		link_freq = link_freq_menu_items[mode->link_freq_index];
+		link_freq = imx258->link_freq_menu_items[mode->link_freq_index];
 		pixel_rate = link_freq_to_pixel_rate(link_freq);
 		__v4l2_ctrl_s_ctrl_int64(imx258->pixel_rate, pixel_rate);
 		/* Update limits and set FPS to default */
@@ -731,7 +800,7 @@ static int imx258_set_pad_format(struct v4l2_subdev *sd,
 			vblank_def);
 		__v4l2_ctrl_s_ctrl(imx258->vblank, vblank_def);
 		h_blank =
-			link_freq_configs[mode->link_freq_index].pixels_per_line
+			imx258->link_freq_configs[mode->link_freq_index].pixels_per_line
 			 - imx258->cur_mode->width;
 		__v4l2_ctrl_modify_range(imx258->hblank, h_blank,
 					 h_blank, 1, h_blank);
@@ -751,7 +820,7 @@ static int imx258_start_streaming(struct imx258 *imx258)
 
 	/* Setup PLL */
 	link_freq_index = imx258->cur_mode->link_freq_index;
-	reg_list = &link_freq_configs[link_freq_index].reg_list;
+	reg_list = &imx258->link_freq_configs[link_freq_index].reg_list;
 	ret = imx258_write_regs(imx258, reg_list->regs, reg_list->num_of_regs);
 	if (ret) {
 		dev_err(&client->dev, "%s failed to set plls\n", __func__);
@@ -986,9 +1055,9 @@ static int imx258_init_controls(struct imx258 *imx258)
 	imx258->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr,
 				&imx258_ctrl_ops,
 				V4L2_CID_LINK_FREQ,
-				ARRAY_SIZE(link_freq_menu_items) - 1,
+				ARRAY_SIZE(link_freq_menu_items_19_2) - 1,
 				0,
-				link_freq_menu_items);
+				imx258->link_freq_menu_items);
 
 	if (imx258->link_freq)
 		imx258->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
@@ -1004,8 +1073,10 @@ static int imx258_init_controls(struct imx258 *imx258)
 	if (vflip)
 		vflip->flags |= V4L2_CTRL_FLAG_READ_ONLY;
 
-	pixel_rate_max = link_freq_to_pixel_rate(link_freq_menu_items[0]);
-	pixel_rate_min = link_freq_to_pixel_rate(link_freq_menu_items[1]);
+	pixel_rate_max =
+		link_freq_to_pixel_rate(imx258->link_freq_menu_items[0]);
+	pixel_rate_min =
+		link_freq_to_pixel_rate(imx258->link_freq_menu_items[1]);
 	/* By default, PIXEL_RATE is read only */
 	imx258->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops,
 				V4L2_CID_PIXEL_RATE,
@@ -1123,11 +1194,25 @@ static int imx258_probe(struct i2c_client *client)
 			"no clock provided, using clock-frequency property\n");
 
 		device_property_read_u32(&client->dev, "clock-frequency", &val);
+	} else if (IS_ERR(imx258->clk)) {
+		return dev_err_probe(&client->dev, PTR_ERR(imx258->clk),
+				     "error getting clock\n");
 	} else {
 		val = clk_get_rate(imx258->clk);
 	}
-	if (val != IMX258_INPUT_CLOCK_FREQ) {
-		dev_err(&client->dev, "input clock frequency not supported\n");
+
+	switch (val) {
+	case 19200000:
+		imx258->link_freq_configs = link_freq_configs_19_2;
+		imx258->link_freq_menu_items = link_freq_menu_items_19_2;
+		break;
+	case 24000000:
+		imx258->link_freq_configs = link_freq_configs_24;
+		imx258->link_freq_menu_items = link_freq_menu_items_24;
+		break;
+	default:
+		dev_err(&client->dev, "input clock frequency of %u not supported\n",
+			val);
 		return -EINVAL;
 	}
 
-- 
2.25.1


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

* [PATCH 09/21] media: i2c: imx258: Add support for running on 2 CSI data lanes
  2023-05-30 17:29 [PATCH 00/21] imx258 improvements series Dave Stevenson
                   ` (7 preceding siblings ...)
  2023-05-30 17:29 ` [PATCH 08/21] media: i2c: imx258: Add support for 24MHz clock Dave Stevenson
@ 2023-05-30 17:29 ` Dave Stevenson
  2023-05-30 17:37   ` Dave Stevenson
                     ` (2 more replies)
  2023-05-30 17:29 ` [PATCH 10/21] media: i2c: imx258: Follow normal V4L2 behaviours for clipping exposure Dave Stevenson
                   ` (12 subsequent siblings)
  21 siblings, 3 replies; 54+ messages in thread
From: Dave Stevenson @ 2023-05-30 17:29 UTC (permalink / raw)
  To: Sakari Ailus, linux-media, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree
  Cc: Dave Stevenson

Extends the driver to also support 2 data lanes.
Frame rates are obviously more restricted on 2 lanes, but some
hardware simply hasn't wired more up.

Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
 drivers/media/i2c/imx258.c | 211 ++++++++++++++++++++++++++++++++-----
 1 file changed, 187 insertions(+), 24 deletions(-)

diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
index d40521f9a3c6..433dff7f1fa0 100644
--- a/drivers/media/i2c/imx258.c
+++ b/drivers/media/i2c/imx258.c
@@ -86,13 +86,17 @@ struct imx258_reg_list {
 	const struct imx258_reg *regs;
 };
 
+#define IMX258_LANE_CONFIGS	2
+#define IMX258_2_LANE_MODE	0
+#define IMX258_4_LANE_MODE	1
+
 /* Link frequency config */
 struct imx258_link_freq_config {
 	u64 link_frequency;
 	u32 pixels_per_line;
 
 	/* PLL registers for this link frequency */
-	struct imx258_reg_list reg_list;
+	struct imx258_reg_list reg_list[IMX258_LANE_CONFIGS];
 };
 
 /* Mode : resolution and related config&values */
@@ -112,8 +116,30 @@ struct imx258_mode {
 	struct imx258_reg_list reg_list;
 };
 
-/* 4208x3120 needs 1267Mbps/lane, 4 lanes */
-static const struct imx258_reg mipi_1267mbps_19_2mhz[] = {
+/* 4208x3120 needs 1267Mbps/lane, 4 lanes. Use that rate on 2 lanes as well */
+static const struct imx258_reg mipi_1267mbps_19_2mhz_2l[] = {
+	{ 0x0136, 0x13 },
+	{ 0x0137, 0x33 },
+	{ 0x0301, 0x0A },
+	{ 0x0303, 0x02 },
+	{ 0x0305, 0x03 },
+	{ 0x0306, 0x00 },
+	{ 0x0307, 0xC6 },
+	{ 0x0309, 0x0A },
+	{ 0x030B, 0x01 },
+	{ 0x030D, 0x02 },
+	{ 0x030E, 0x00 },
+	{ 0x030F, 0xD8 },
+	{ 0x0310, 0x00 },
+
+	{ 0x0114, 0x01 },
+	{ 0x0820, 0x09 },
+	{ 0x0821, 0xa6 },
+	{ 0x0822, 0x66 },
+	{ 0x0823, 0x66 },
+};
+
+static const struct imx258_reg mipi_1267mbps_19_2mhz_4l[] = {
 	{ 0x0136, 0x13 },
 	{ 0x0137, 0x33 },
 	{ 0x0301, 0x05 },
@@ -127,16 +153,18 @@ static const struct imx258_reg mipi_1267mbps_19_2mhz[] = {
 	{ 0x030E, 0x00 },
 	{ 0x030F, 0xD8 },
 	{ 0x0310, 0x00 },
+
+	{ 0x0114, 0x03 },
 	{ 0x0820, 0x13 },
 	{ 0x0821, 0x4C },
 	{ 0x0822, 0xCC },
 	{ 0x0823, 0xCC },
 };
 
-static const struct imx258_reg mipi_1272mbps_24mhz[] = {
+static const struct imx258_reg mipi_1272mbps_24mhz_2l[] = {
 	{ 0x0136, 0x18 },
 	{ 0x0137, 0x00 },
-	{ 0x0301, 0x05 },
+	{ 0x0301, 0x0a },
 	{ 0x0303, 0x02 },
 	{ 0x0305, 0x04 },
 	{ 0x0306, 0x00 },
@@ -147,13 +175,59 @@ static const struct imx258_reg mipi_1272mbps_24mhz[] = {
 	{ 0x030E, 0x00 },
 	{ 0x030F, 0xD8 },
 	{ 0x0310, 0x00 },
+
+	{ 0x0114, 0x01 },
 	{ 0x0820, 0x13 },
 	{ 0x0821, 0x4C },
 	{ 0x0822, 0xCC },
 	{ 0x0823, 0xCC },
 };
 
-static const struct imx258_reg mipi_640mbps_19_2mhz[] = {
+static const struct imx258_reg mipi_1272mbps_24mhz_4l[] = {
+	{ 0x0136, 0x18 },
+	{ 0x0137, 0x00 },
+	{ 0x0301, 0x05 },
+	{ 0x0303, 0x02 },
+	{ 0x0305, 0x04 },
+	{ 0x0306, 0x00 },
+	{ 0x0307, 0xD4 },
+	{ 0x0309, 0x0A },
+	{ 0x030B, 0x01 },
+	{ 0x030D, 0x02 },
+	{ 0x030E, 0x00 },
+	{ 0x030F, 0xD8 },
+	{ 0x0310, 0x00 },
+
+	{ 0x0114, 0x03 },
+	{ 0x0820, 0x13 },
+	{ 0x0821, 0xE0 },
+	{ 0x0822, 0x00 },
+	{ 0x0823, 0x00 },
+};
+
+static const struct imx258_reg mipi_640mbps_19_2mhz_2l[] = {
+	{ 0x0136, 0x13 },
+	{ 0x0137, 0x33 },
+	{ 0x0301, 0x05 },
+	{ 0x0303, 0x02 },
+	{ 0x0305, 0x03 },
+	{ 0x0306, 0x00 },
+	{ 0x0307, 0x64 },
+	{ 0x0309, 0x0A },
+	{ 0x030B, 0x01 },
+	{ 0x030D, 0x02 },
+	{ 0x030E, 0x00 },
+	{ 0x030F, 0xD8 },
+	{ 0x0310, 0x00 },
+
+	{ 0x0114, 0x01 },
+	{ 0x0820, 0x05 },
+	{ 0x0821, 0x00 },
+	{ 0x0822, 0x00 },
+	{ 0x0823, 0x00 },
+};
+
+static const struct imx258_reg mipi_640mbps_19_2mhz_4l[] = {
 	{ 0x0136, 0x13 },
 	{ 0x0137, 0x33 },
 	{ 0x0301, 0x05 },
@@ -167,13 +241,37 @@ static const struct imx258_reg mipi_640mbps_19_2mhz[] = {
 	{ 0x030E, 0x00 },
 	{ 0x030F, 0xD8 },
 	{ 0x0310, 0x00 },
+
+	{ 0x0114, 0x03 },
 	{ 0x0820, 0x0A },
 	{ 0x0821, 0x00 },
 	{ 0x0822, 0x00 },
 	{ 0x0823, 0x00 },
 };
 
-static const struct imx258_reg mipi_642mbps_24mhz[] = {
+static const struct imx258_reg mipi_642mbps_24mhz_2l[] = {
+	{ 0x0136, 0x18 },
+	{ 0x0137, 0x00 },
+	{ 0x0301, 0x0A },
+	{ 0x0303, 0x02 },
+	{ 0x0305, 0x04 },
+	{ 0x0306, 0x00 },
+	{ 0x0307, 0x6B },
+	{ 0x0309, 0x0A },
+	{ 0x030B, 0x01 },
+	{ 0x030D, 0x02 },
+	{ 0x030E, 0x00 },
+	{ 0x030F, 0xD8 },
+	{ 0x0310, 0x00 },
+
+	{ 0x0114, 0x01 },
+	{ 0x0820, 0x0A },
+	{ 0x0821, 0x00 },
+	{ 0x0822, 0x00 },
+	{ 0x0823, 0x00 },
+};
+
+static const struct imx258_reg mipi_642mbps_24mhz_4l[] = {
 	{ 0x0136, 0x18 },
 	{ 0x0137, 0x00 },
 	{ 0x0301, 0x05 },
@@ -187,6 +285,8 @@ static const struct imx258_reg mipi_642mbps_24mhz[] = {
 	{ 0x030E, 0x00 },
 	{ 0x030F, 0xD8 },
 	{ 0x0310, 0x00 },
+
+	{ 0x0114, 0x03 },
 	{ 0x0820, 0x0A },
 	{ 0x0821, 0x00 },
 	{ 0x0822, 0x00 },
@@ -241,7 +341,6 @@ static const struct imx258_reg mode_common_regs[] = {
 	{ 0x5F05, 0xED },
 	{ 0x0112, 0x0A },
 	{ 0x0113, 0x0A },
-	{ 0x0114, 0x03 },
 	{ 0x0342, 0x14 },
 	{ 0x0343, 0xE8 },
 	{ 0x0344, 0x00 },
@@ -360,11 +459,13 @@ enum {
 
 /*
  * pixel_rate = link_freq * data-rate * nr_of_lanes / bits_per_sample
- * data rate => double data rate; number of lanes => 4; bits per pixel => 10
+ * data rate => double data rate;
+ * number of lanes => (configurable 2 or 4);
+ * bits per pixel => 10
  */
-static u64 link_freq_to_pixel_rate(u64 f)
+static u64 link_freq_to_pixel_rate(u64 f, unsigned int nlanes)
 {
-	f *= 2 * 4;
+	f *= 2 * nlanes;
 	do_div(f, 10);
 
 	return f;
@@ -394,15 +495,27 @@ static const struct imx258_link_freq_config link_freq_configs_19_2[] = {
 	[IMX258_LINK_FREQ_1267MBPS] = {
 		.pixels_per_line = IMX258_PPL_DEFAULT,
 		.reg_list = {
-			.num_of_regs = ARRAY_SIZE(mipi_1267mbps_19_2mhz),
-			.regs = mipi_1267mbps_19_2mhz,
+			[IMX258_2_LANE_MODE] = {
+				.num_of_regs = ARRAY_SIZE(mipi_1267mbps_19_2mhz_2l),
+				.regs = mipi_1267mbps_19_2mhz_2l,
+			},
+			[IMX258_4_LANE_MODE] = {
+				.num_of_regs = ARRAY_SIZE(mipi_1267mbps_19_2mhz_4l),
+				.regs = mipi_1267mbps_19_2mhz_4l,
+			},
 		}
 	},
 	[IMX258_LINK_FREQ_640MBPS] = {
 		.pixels_per_line = IMX258_PPL_DEFAULT,
 		.reg_list = {
-			.num_of_regs = ARRAY_SIZE(mipi_640mbps_19_2mhz),
-			.regs = mipi_640mbps_19_2mhz,
+			[IMX258_2_LANE_MODE] = {
+				.num_of_regs = ARRAY_SIZE(mipi_640mbps_19_2mhz_2l),
+				.regs = mipi_640mbps_19_2mhz_2l,
+			},
+			[IMX258_4_LANE_MODE] = {
+				.num_of_regs = ARRAY_SIZE(mipi_640mbps_19_2mhz_4l),
+				.regs = mipi_640mbps_19_2mhz_4l,
+			},
 		}
 	},
 };
@@ -411,15 +524,27 @@ static const struct imx258_link_freq_config link_freq_configs_24[] = {
 	[IMX258_LINK_FREQ_1267MBPS] = {
 		.pixels_per_line = IMX258_PPL_DEFAULT,
 		.reg_list = {
-			.num_of_regs = ARRAY_SIZE(mipi_1272mbps_24mhz),
-			.regs = mipi_1272mbps_24mhz,
+			[IMX258_2_LANE_MODE] = {
+				.num_of_regs = ARRAY_SIZE(mipi_1272mbps_24mhz_2l),
+				.regs = mipi_1272mbps_24mhz_2l,
+			},
+			[IMX258_4_LANE_MODE] = {
+				.num_of_regs = ARRAY_SIZE(mipi_1272mbps_24mhz_4l),
+				.regs = mipi_1272mbps_24mhz_4l,
+			},
 		}
 	},
 	[IMX258_LINK_FREQ_640MBPS] = {
 		.pixels_per_line = IMX258_PPL_DEFAULT,
 		.reg_list = {
-			.num_of_regs = ARRAY_SIZE(mipi_642mbps_24mhz),
-			.regs = mipi_642mbps_24mhz,
+			[IMX258_2_LANE_MODE] = {
+				.num_of_regs = ARRAY_SIZE(mipi_642mbps_24mhz_2l),
+				.regs = mipi_642mbps_24mhz_2l,
+			},
+			[IMX258_4_LANE_MODE] = {
+				.num_of_regs = ARRAY_SIZE(mipi_642mbps_24mhz_4l),
+				.regs = mipi_642mbps_24mhz_4l,
+			},
 		}
 	},
 };
@@ -478,6 +603,7 @@ struct imx258 {
 
 	const struct imx258_link_freq_config *link_freq_configs;
 	const s64 *link_freq_menu_items;
+	unsigned int nlanes;
 
 	/*
 	 * Mutex for serialized access:
@@ -787,7 +913,7 @@ static int imx258_set_pad_format(struct v4l2_subdev *sd,
 		__v4l2_ctrl_s_ctrl(imx258->link_freq, mode->link_freq_index);
 
 		link_freq = imx258->link_freq_menu_items[mode->link_freq_index];
-		pixel_rate = link_freq_to_pixel_rate(link_freq);
+		pixel_rate = link_freq_to_pixel_rate(link_freq, imx258->nlanes);
 		__v4l2_ctrl_s_ctrl_int64(imx258->pixel_rate, pixel_rate);
 		/* Update limits and set FPS to default */
 		vblank_def = imx258->cur_mode->vts_def -
@@ -816,11 +942,13 @@ static int imx258_start_streaming(struct imx258 *imx258)
 {
 	struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd);
 	const struct imx258_reg_list *reg_list;
+	const struct imx258_link_freq_config *link_freq_cfg;
 	int ret, link_freq_index;
 
 	/* Setup PLL */
 	link_freq_index = imx258->cur_mode->link_freq_index;
-	reg_list = &imx258->link_freq_configs[link_freq_index].reg_list;
+	link_freq_cfg = &imx258->link_freq_configs[link_freq_index];
+	reg_list = &link_freq_cfg->reg_list[imx258->nlanes == 2 ? 0 : 1];
 	ret = imx258_write_regs(imx258, reg_list->regs, reg_list->num_of_regs);
 	if (ret) {
 		dev_err(&client->dev, "%s failed to set plls\n", __func__);
@@ -1074,9 +1202,11 @@ static int imx258_init_controls(struct imx258 *imx258)
 		vflip->flags |= V4L2_CTRL_FLAG_READ_ONLY;
 
 	pixel_rate_max =
-		link_freq_to_pixel_rate(imx258->link_freq_menu_items[0]);
+		link_freq_to_pixel_rate(imx258->link_freq_menu_items[0],
+					imx258->nlanes);
 	pixel_rate_min =
-		link_freq_to_pixel_rate(imx258->link_freq_menu_items[1]);
+		link_freq_to_pixel_rate(imx258->link_freq_menu_items[1],
+					imx258->nlanes);
 	/* By default, PIXEL_RATE is read only */
 	imx258->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops,
 				V4L2_CID_PIXEL_RATE,
@@ -1174,6 +1304,10 @@ static int imx258_get_regulators(struct imx258 *imx258,
 static int imx258_probe(struct i2c_client *client)
 {
 	struct imx258 *imx258;
+	struct fwnode_handle *endpoint;
+	struct v4l2_fwnode_endpoint ep = {
+		.bus_type = V4L2_MBUS_CSI2_DPHY
+	};
 	int ret;
 	u32 val = 0;
 
@@ -1216,13 +1350,38 @@ static int imx258_probe(struct i2c_client *client)
 		return -EINVAL;
 	}
 
+	endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev), NULL);
+	if (!endpoint) {
+		dev_err(&client->dev, "Endpoint node not found\n");
+		return -EINVAL;
+	}
+
+	ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &ep);
+	fwnode_handle_put(endpoint);
+	if (ret == -ENXIO) {
+		dev_err(&client->dev, "Unsupported bus type, should be CSI2\n");
+		goto error_endpoint_poweron;
+	} else if (ret) {
+		dev_err(&client->dev, "Parsing endpoint node failed\n");
+		goto error_endpoint_poweron;
+	}
+
+	/* Get number of data lanes */
+	imx258->nlanes = ep.bus.mipi_csi2.num_data_lanes;
+	if (imx258->nlanes != 2 && imx258->nlanes != 4) {
+		dev_err(&client->dev, "Invalid data lanes: %u\n",
+			imx258->nlanes);
+		ret = -EINVAL;
+		goto error_endpoint_poweron;
+	}
+
 	/* Initialize subdev */
 	v4l2_i2c_subdev_init(&imx258->sd, client, &imx258_subdev_ops);
 
 	/* Will be powered off via pm_runtime_idle */
 	ret = imx258_power_on(&client->dev);
 	if (ret)
-		return ret;
+		goto error_endpoint_poweron;
 
 	/* Check module identity */
 	ret = imx258_identify_module(imx258);
@@ -1255,6 +1414,7 @@ static int imx258_probe(struct i2c_client *client)
 	pm_runtime_set_active(&client->dev);
 	pm_runtime_enable(&client->dev);
 	pm_runtime_idle(&client->dev);
+	v4l2_fwnode_endpoint_free(&endpoint);
 
 	return 0;
 
@@ -1267,6 +1427,9 @@ static int imx258_probe(struct i2c_client *client)
 error_identify:
 	imx258_power_off(&client->dev);
 
+error_endpoint_poweron:
+	v4l2_fwnode_endpoint_free(&ep);
+
 	return ret;
 }
 
-- 
2.25.1


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

* [PATCH 10/21] media: i2c: imx258: Follow normal V4L2 behaviours for clipping exposure
  2023-05-30 17:29 [PATCH 00/21] imx258 improvements series Dave Stevenson
                   ` (8 preceding siblings ...)
  2023-05-30 17:29 ` [PATCH 09/21] media: i2c: imx258: Add support for running on 2 CSI data lanes Dave Stevenson
@ 2023-05-30 17:29 ` Dave Stevenson
  2023-05-31 15:27   ` Jacopo Mondi
  2023-05-30 17:29 ` [PATCH 11/21] media: i2c: imx258: Add get_selection for pixel array information Dave Stevenson
                   ` (11 subsequent siblings)
  21 siblings, 1 reply; 54+ messages in thread
From: Dave Stevenson @ 2023-05-30 17:29 UTC (permalink / raw)
  To: Sakari Ailus, linux-media, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree
  Cc: Dave Stevenson

V4L2 sensor drivers are expected are expected to clip the supported
exposure range based on the VBLANK configured.
IMX258 wasn't doing that as register 0x350 (FRM_LENGTH_CTL)
switches it to a mode where frame length tracks coarse exposure time.

Disable this mode and clip the range for V4L2_CID_EXPOSURE appropriately
based on V4L2_CID_VBLANK.

Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
 drivers/media/i2c/imx258.c | 25 +++++++++++++++++++++++--
 1 file changed, 23 insertions(+), 2 deletions(-)

diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
index 433dff7f1fa0..82ffe09e3bdc 100644
--- a/drivers/media/i2c/imx258.c
+++ b/drivers/media/i2c/imx258.c
@@ -37,10 +37,11 @@
 
 /* Exposure control */
 #define IMX258_REG_EXPOSURE		0x0202
+#define IMX258_EXPOSURE_OFFSET		10
 #define IMX258_EXPOSURE_MIN		4
 #define IMX258_EXPOSURE_STEP		1
 #define IMX258_EXPOSURE_DEFAULT		0x640
-#define IMX258_EXPOSURE_MAX		65535
+#define IMX258_EXPOSURE_MAX		(IMX258_VTS_MAX - IMX258_EXPOSURE_OFFSET)
 
 /* Analog gain control */
 #define IMX258_REG_ANALOG_GAIN		0x0204
@@ -366,7 +367,7 @@ static const struct imx258_reg mode_common_regs[] = {
 	{ 0x303A, 0x00 },
 	{ 0x303B, 0x10 },
 	{ 0x300D, 0x00 },
-	{ 0x0350, 0x01 },
+	{ 0x0350, 0x00 },
 	{ 0x0204, 0x00 },
 	{ 0x0205, 0x00 },
 	{ 0x020E, 0x01 },
@@ -739,6 +740,19 @@ static int imx258_update_digital_gain(struct imx258 *imx258, u32 len, u32 val)
 	return 0;
 }
 
+static void imx258_adjust_exposure_range(struct imx258 *imx258)
+{
+	int exposure_max, exposure_def;
+
+	/* Honour the VBLANK limits when setting exposure. */
+	exposure_max = imx258->cur_mode->height + imx258->vblank->val -
+		       IMX258_EXPOSURE_OFFSET;
+	exposure_def = min(exposure_max, imx258->exposure->val);
+	__v4l2_ctrl_modify_range(imx258->exposure, imx258->exposure->minimum,
+				 exposure_max, imx258->exposure->step,
+				 exposure_def);
+}
+
 static int imx258_set_ctrl(struct v4l2_ctrl *ctrl)
 {
 	struct imx258 *imx258 =
@@ -746,6 +760,13 @@ static int imx258_set_ctrl(struct v4l2_ctrl *ctrl)
 	struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd);
 	int ret = 0;
 
+	/*
+	 * The VBLANK control may change the limits of usable exposure, so check
+	 * and adjust if necessary.
+	 */
+	if (ctrl->id == V4L2_CID_VBLANK)
+		imx258_adjust_exposure_range(imx258);
+
 	/*
 	 * Applying V4L2 control value only happens
 	 * when power is up for streaming
-- 
2.25.1


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

* [PATCH 11/21] media: i2c: imx258: Add get_selection for pixel array information
  2023-05-30 17:29 [PATCH 00/21] imx258 improvements series Dave Stevenson
                   ` (9 preceding siblings ...)
  2023-05-30 17:29 ` [PATCH 10/21] media: i2c: imx258: Follow normal V4L2 behaviours for clipping exposure Dave Stevenson
@ 2023-05-30 17:29 ` Dave Stevenson
  2023-06-02 13:24   ` Jacopo Mondi
  2023-05-30 17:29 ` [PATCH 12/21] media: i2c: imx258: Allow configuration of clock lane behaviour Dave Stevenson
                   ` (10 subsequent siblings)
  21 siblings, 1 reply; 54+ messages in thread
From: Dave Stevenson @ 2023-05-30 17:29 UTC (permalink / raw)
  To: Sakari Ailus, linux-media, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree
  Cc: Dave Stevenson

Libcamera requires the cropping information for each mode, so
add this information to the driver.

Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
 drivers/media/i2c/imx258.c | 90 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 90 insertions(+)

diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
index 82ffe09e3bdc..1fa83fe82f27 100644
--- a/drivers/media/i2c/imx258.c
+++ b/drivers/media/i2c/imx258.c
@@ -77,6 +77,14 @@
 #define REG_CONFIG_MIRROR_FLIP		0x03
 #define REG_CONFIG_FLIP_TEST_PATTERN	0x02
 
+/* IMX258 native and active pixel array size. */
+#define IMX258_NATIVE_WIDTH		4224U
+#define IMX258_NATIVE_HEIGHT		3192U
+#define IMX258_PIXEL_ARRAY_LEFT		8U
+#define IMX258_PIXEL_ARRAY_TOP		16U
+#define IMX258_PIXEL_ARRAY_WIDTH	4208U
+#define IMX258_PIXEL_ARRAY_HEIGHT	3120U
+
 struct imx258_reg {
 	u16 address;
 	u8 val;
@@ -115,6 +123,9 @@ struct imx258_mode {
 	u32 link_freq_index;
 	/* Default register values */
 	struct imx258_reg_list reg_list;
+
+	/* Analog crop rectangle. */
+	struct v4l2_rect crop;
 };
 
 /* 4208x3120 needs 1267Mbps/lane, 4 lanes. Use that rate on 2 lanes as well */
@@ -562,6 +573,12 @@ static const struct imx258_mode supported_modes[] = {
 			.regs = mode_4208x3120_regs,
 		},
 		.link_freq_index = IMX258_LINK_FREQ_1267MBPS,
+		.crop = {
+			.left = IMX258_PIXEL_ARRAY_LEFT,
+			.top = IMX258_PIXEL_ARRAY_TOP,
+			.width = 4208,
+			.height = 3120,
+		},
 	},
 	{
 		.width = 2104,
@@ -573,6 +590,12 @@ static const struct imx258_mode supported_modes[] = {
 			.regs = mode_2104_1560_regs,
 		},
 		.link_freq_index = IMX258_LINK_FREQ_640MBPS,
+		.crop = {
+			.left = IMX258_PIXEL_ARRAY_LEFT,
+			.top = IMX258_PIXEL_ARRAY_TOP,
+			.width = 4208,
+			.height = 3120,
+		},
 	},
 	{
 		.width = 1048,
@@ -584,6 +607,12 @@ static const struct imx258_mode supported_modes[] = {
 			.regs = mode_1048_780_regs,
 		},
 		.link_freq_index = IMX258_LINK_FREQ_640MBPS,
+		.crop = {
+			.left = IMX258_PIXEL_ARRAY_LEFT,
+			.top = IMX258_PIXEL_ARRAY_TOP,
+			.width = 4208,
+			.height = 3120,
+		},
 	},
 };
 
@@ -703,6 +732,7 @@ static int imx258_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 {
 	struct v4l2_mbus_framefmt *try_fmt =
 		v4l2_subdev_get_try_format(sd, fh->state, 0);
+	struct v4l2_rect *try_crop;
 
 	/* Initialize try_fmt */
 	try_fmt->width = supported_modes[0].width;
@@ -710,6 +740,13 @@ static int imx258_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 	try_fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
 	try_fmt->field = V4L2_FIELD_NONE;
 
+	/* Initialize try_crop */
+	try_crop = v4l2_subdev_get_try_crop(sd, fh->state, 0);
+	try_crop->left = IMX258_PIXEL_ARRAY_LEFT;
+	try_crop->top = IMX258_PIXEL_ARRAY_TOP;
+	try_crop->width = IMX258_PIXEL_ARRAY_WIDTH;
+	try_crop->height = IMX258_PIXEL_ARRAY_HEIGHT;
+
 	return 0;
 }
 
@@ -958,6 +995,58 @@ static int imx258_set_pad_format(struct v4l2_subdev *sd,
 	return 0;
 }
 
+static const struct v4l2_rect *
+__imx258_get_pad_crop(struct imx258 *imx258,
+		      struct v4l2_subdev_state *sd_state,
+		      unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+	switch (which) {
+	case V4L2_SUBDEV_FORMAT_TRY:
+		return v4l2_subdev_get_try_crop(&imx258->sd, sd_state, pad);
+	case V4L2_SUBDEV_FORMAT_ACTIVE:
+		return &imx258->cur_mode->crop;
+	}
+
+	return NULL;
+}
+
+static int imx258_get_selection(struct v4l2_subdev *sd,
+				struct v4l2_subdev_state *sd_state,
+				struct v4l2_subdev_selection *sel)
+{
+	switch (sel->target) {
+	case V4L2_SEL_TGT_CROP: {
+		struct imx258 *imx258 = to_imx258(sd);
+
+		mutex_lock(&imx258->mutex);
+		sel->r = *__imx258_get_pad_crop(imx258, sd_state, sel->pad,
+						sel->which);
+		mutex_unlock(&imx258->mutex);
+
+		return 0;
+	}
+
+	case V4L2_SEL_TGT_NATIVE_SIZE:
+		sel->r.left = 0;
+		sel->r.top = 0;
+		sel->r.width = IMX258_NATIVE_WIDTH;
+		sel->r.height = IMX258_NATIVE_HEIGHT;
+
+		return 0;
+
+	case V4L2_SEL_TGT_CROP_DEFAULT:
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+		sel->r.left = IMX258_PIXEL_ARRAY_LEFT;
+		sel->r.top = IMX258_PIXEL_ARRAY_TOP;
+		sel->r.width = IMX258_PIXEL_ARRAY_WIDTH;
+		sel->r.height = IMX258_PIXEL_ARRAY_HEIGHT;
+
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
 /* Start streaming */
 static int imx258_start_streaming(struct imx258 *imx258)
 {
@@ -1170,6 +1259,7 @@ static const struct v4l2_subdev_pad_ops imx258_pad_ops = {
 	.get_fmt = imx258_get_pad_format,
 	.set_fmt = imx258_set_pad_format,
 	.enum_frame_size = imx258_enum_frame_size,
+	.get_selection = imx258_get_selection,
 };
 
 static const struct v4l2_subdev_ops imx258_subdev_ops = {
-- 
2.25.1


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

* [PATCH 12/21] media: i2c: imx258: Allow configuration of clock lane behaviour
  2023-05-30 17:29 [PATCH 00/21] imx258 improvements series Dave Stevenson
                   ` (10 preceding siblings ...)
  2023-05-30 17:29 ` [PATCH 11/21] media: i2c: imx258: Add get_selection for pixel array information Dave Stevenson
@ 2023-05-30 17:29 ` Dave Stevenson
  2023-06-02 13:26   ` Jacopo Mondi
  2023-05-30 17:29 ` [PATCH 13/21] media: i2c: imx258: Correct max FRM_LENGTH_LINES value Dave Stevenson
                   ` (9 subsequent siblings)
  21 siblings, 1 reply; 54+ messages in thread
From: Dave Stevenson @ 2023-05-30 17:29 UTC (permalink / raw)
  To: Sakari Ailus, linux-media, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree
  Cc: Dave Stevenson

The sensor supports the clock lane either remaining in HS mode
during frame blanking, or dropping to LP11.

Add configuration of the mode via V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK.

Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
 drivers/media/i2c/imx258.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
index 1fa83fe82f27..b5c2dcb7c9e6 100644
--- a/drivers/media/i2c/imx258.c
+++ b/drivers/media/i2c/imx258.c
@@ -72,6 +72,8 @@
 /* Test Pattern Control */
 #define IMX258_REG_TEST_PATTERN		0x0600
 
+#define IMX258_CLK_BLANK_STOP		0x4040
+
 /* Orientation */
 #define REG_MIRROR_FLIP_CONTROL		0x0101
 #define REG_CONFIG_MIRROR_FLIP		0x03
@@ -634,6 +636,7 @@ struct imx258 {
 	const struct imx258_link_freq_config *link_freq_configs;
 	const s64 *link_freq_menu_items;
 	unsigned int nlanes;
+	unsigned int csi2_flags;
 
 	/*
 	 * Mutex for serialized access:
@@ -1072,6 +1075,15 @@ static int imx258_start_streaming(struct imx258 *imx258)
 		return ret;
 	}
 
+	ret = imx258_write_reg(imx258, IMX258_CLK_BLANK_STOP,
+			       IMX258_REG_VALUE_08BIT,
+			       imx258->csi2_flags & V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK ?
+			       1 : 0);
+	if (ret) {
+		dev_err(&client->dev, "%s failed to set clock lane mode\n", __func__);
+		return ret;
+	}
+
 	/* Apply default values of current mode */
 	reg_list = &imx258->cur_mode->reg_list;
 	ret = imx258_write_regs(imx258, reg_list->regs, reg_list->num_of_regs);
@@ -1486,6 +1498,8 @@ static int imx258_probe(struct i2c_client *client)
 		goto error_endpoint_poweron;
 	}
 
+	imx258->csi2_flags = ep.bus.mipi_csi2.flags;
+
 	/* Initialize subdev */
 	v4l2_i2c_subdev_init(&imx258->sd, client, &imx258_subdev_ops);
 
-- 
2.25.1


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

* [PATCH 13/21] media: i2c: imx258: Correct max FRM_LENGTH_LINES value
  2023-05-30 17:29 [PATCH 00/21] imx258 improvements series Dave Stevenson
                   ` (11 preceding siblings ...)
  2023-05-30 17:29 ` [PATCH 12/21] media: i2c: imx258: Allow configuration of clock lane behaviour Dave Stevenson
@ 2023-05-30 17:29 ` Dave Stevenson
  2023-06-02 13:33   ` Jacopo Mondi
  2023-05-30 17:29 ` [PATCH 14/21] media: i2c: imx258: Add support for long exposure modes Dave Stevenson
                   ` (8 subsequent siblings)
  21 siblings, 1 reply; 54+ messages in thread
From: Dave Stevenson @ 2023-05-30 17:29 UTC (permalink / raw)
  To: Sakari Ailus, linux-media, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree
  Cc: Dave Stevenson

The data sheet states that the maximum value for registers
0x0340/0x0341 FRM_LENGTH_LINES is 65525(decimal), not the
0xFFFF defined in this driver. Correct this limit.

Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
 drivers/media/i2c/imx258.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
index b5c2dcb7c9e6..f5199e3243e8 100644
--- a/drivers/media/i2c/imx258.c
+++ b/drivers/media/i2c/imx258.c
@@ -28,7 +28,7 @@
 #define IMX258_VTS_30FPS		0x0c50
 #define IMX258_VTS_30FPS_2K		0x0638
 #define IMX258_VTS_30FPS_VGA		0x034c
-#define IMX258_VTS_MAX			0xffff
+#define IMX258_VTS_MAX			65525
 
 #define IMX258_REG_VTS			0x0340
 
-- 
2.25.1


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

* [PATCH 14/21] media: i2c: imx258: Add support for long exposure modes
  2023-05-30 17:29 [PATCH 00/21] imx258 improvements series Dave Stevenson
                   ` (12 preceding siblings ...)
  2023-05-30 17:29 ` [PATCH 13/21] media: i2c: imx258: Correct max FRM_LENGTH_LINES value Dave Stevenson
@ 2023-05-30 17:29 ` Dave Stevenson
  2023-06-02 13:38   ` Jacopo Mondi
  2023-05-30 17:29 ` [PATCH 15/21] media: i2c: imx258: Issue reset before starting streaming Dave Stevenson
                   ` (7 subsequent siblings)
  21 siblings, 1 reply; 54+ messages in thread
From: Dave Stevenson @ 2023-05-30 17:29 UTC (permalink / raw)
  To: Sakari Ailus, linux-media, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree
  Cc: Dave Stevenson

The sensor has a register CIT_LSHIFT which extends the exposure
and frame times by the specified power of 2 for longer
exposure times.

Add support for this by configuring this register via V4L2_CID_VBLANK
and extending the V4L2_CID_EXPOSURE range accordingly.

Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
 drivers/media/i2c/imx258.c | 38 ++++++++++++++++++++++++++++++++------
 1 file changed, 32 insertions(+), 6 deletions(-)

diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
index f5199e3243e8..1e424058fcb9 100644
--- a/drivers/media/i2c/imx258.c
+++ b/drivers/media/i2c/imx258.c
@@ -69,6 +69,10 @@
 #define IMX258_HDR_RATIO_STEP		1
 #define IMX258_HDR_RATIO_DEFAULT	0x0
 
+/* Long exposure multiplier */
+#define IMX258_LONG_EXP_SHIFT_MAX	7
+#define IMX258_LONG_EXP_SHIFT_REG	0x3002
+
 /* Test Pattern Control */
 #define IMX258_REG_TEST_PATTERN		0x0600
 
@@ -629,6 +633,8 @@ struct imx258 {
 	struct v4l2_ctrl *vblank;
 	struct v4l2_ctrl *hblank;
 	struct v4l2_ctrl *exposure;
+	/* Current long exposure factor in use. Set through V4L2_CID_VBLANK */
+	unsigned int long_exp_shift;
 
 	/* Current mode */
 	const struct imx258_mode *cur_mode;
@@ -793,6 +799,26 @@ static void imx258_adjust_exposure_range(struct imx258 *imx258)
 				 exposure_def);
 }
 
+static int imx258_set_frame_length(struct imx258 *imx258, unsigned int val)
+{
+	int ret;
+
+	imx258->long_exp_shift = 0;
+
+	while (val > IMX258_VTS_MAX) {
+		imx258->long_exp_shift++;
+		val >>= 1;
+	}
+
+	ret = imx258_write_reg(imx258, IMX258_REG_VTS,
+			       IMX258_REG_VALUE_16BIT, val);
+	if (ret)
+		return ret;
+
+	return imx258_write_reg(imx258, IMX258_LONG_EXP_SHIFT_REG,
+				IMX258_REG_VALUE_08BIT, imx258->long_exp_shift);
+}
+
 static int imx258_set_ctrl(struct v4l2_ctrl *ctrl)
 {
 	struct imx258 *imx258 =
@@ -823,7 +849,7 @@ static int imx258_set_ctrl(struct v4l2_ctrl *ctrl)
 	case V4L2_CID_EXPOSURE:
 		ret = imx258_write_reg(imx258, IMX258_REG_EXPOSURE,
 				IMX258_REG_VALUE_16BIT,
-				ctrl->val);
+				ctrl->val >> imx258->long_exp_shift);
 		break;
 	case V4L2_CID_DIGITAL_GAIN:
 		ret = imx258_update_digital_gain(imx258, IMX258_REG_VALUE_16BIT,
@@ -855,9 +881,8 @@ static int imx258_set_ctrl(struct v4l2_ctrl *ctrl)
 		}
 		break;
 	case V4L2_CID_VBLANK:
-		ret = imx258_write_reg(imx258, IMX258_REG_VTS,
-				       IMX258_REG_VALUE_16BIT,
-				       imx258->cur_mode->height + ctrl->val);
+		ret = imx258_set_frame_length(imx258,
+					      imx258->cur_mode->height + ctrl->val);
 		break;
 	default:
 		dev_info(&client->dev,
@@ -983,8 +1008,9 @@ static int imx258_set_pad_format(struct v4l2_subdev *sd,
 			     imx258->cur_mode->height;
 		__v4l2_ctrl_modify_range(
 			imx258->vblank, vblank_min,
-			IMX258_VTS_MAX - imx258->cur_mode->height, 1,
-			vblank_def);
+			((1 << IMX258_LONG_EXP_SHIFT_MAX) * IMX258_VTS_MAX) -
+						imx258->cur_mode->height,
+			1, vblank_def);
 		__v4l2_ctrl_s_ctrl(imx258->vblank, vblank_def);
 		h_blank =
 			imx258->link_freq_configs[mode->link_freq_index].pixels_per_line
-- 
2.25.1


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

* [PATCH 15/21] media: i2c: imx258: Issue reset before starting streaming
  2023-05-30 17:29 [PATCH 00/21] imx258 improvements series Dave Stevenson
                   ` (13 preceding siblings ...)
  2023-05-30 17:29 ` [PATCH 14/21] media: i2c: imx258: Add support for long exposure modes Dave Stevenson
@ 2023-05-30 17:29 ` Dave Stevenson
  2023-06-02 13:42   ` Jacopo Mondi
  2023-05-30 17:29 ` [PATCH 16/21] media: i2c: imx258: Set pixel_rate range to the same as the value Dave Stevenson
                   ` (6 subsequent siblings)
  21 siblings, 1 reply; 54+ messages in thread
From: Dave Stevenson @ 2023-05-30 17:29 UTC (permalink / raw)
  To: Sakari Ailus, linux-media, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree
  Cc: Dave Stevenson

Whilst not documented, register 0x0103 bit 0 is the soft
reset for the sensor, so send it before trying to configure
the sensor.

Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
 drivers/media/i2c/imx258.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
index 1e424058fcb9..7d6528f9ca4d 100644
--- a/drivers/media/i2c/imx258.c
+++ b/drivers/media/i2c/imx258.c
@@ -20,6 +20,8 @@
 #define IMX258_MODE_STANDBY		0x00
 #define IMX258_MODE_STREAMING		0x01
 
+#define IMX258_REG_RESET		0x0103
+
 /* Chip ID */
 #define IMX258_REG_CHIP_ID		0x0016
 #define IMX258_CHIP_ID			0x0258
@@ -1084,6 +1086,14 @@ static int imx258_start_streaming(struct imx258 *imx258)
 	const struct imx258_link_freq_config *link_freq_cfg;
 	int ret, link_freq_index;
 
+	ret = imx258_write_reg(imx258, IMX258_REG_RESET, IMX258_REG_VALUE_08BIT,
+			       0x01);
+	if (ret) {
+		dev_err(&client->dev, "%s failed to reset sensor\n", __func__);
+		return ret;
+	}
+	usleep_range(10000, 15000);
+
 	/* Setup PLL */
 	link_freq_index = imx258->cur_mode->link_freq_index;
 	link_freq_cfg = &imx258->link_freq_configs[link_freq_index];
-- 
2.25.1


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

* [PATCH 16/21] media: i2c: imx258: Set pixel_rate range to the same as the value
  2023-05-30 17:29 [PATCH 00/21] imx258 improvements series Dave Stevenson
                   ` (14 preceding siblings ...)
  2023-05-30 17:29 ` [PATCH 15/21] media: i2c: imx258: Issue reset before starting streaming Dave Stevenson
@ 2023-05-30 17:29 ` Dave Stevenson
  2023-06-02 13:44   ` Jacopo Mondi
  2023-05-30 17:29 ` [PATCH 17/21] media: i2c: imx258: Support faster pixel rate on binned modes Dave Stevenson
                   ` (5 subsequent siblings)
  21 siblings, 1 reply; 54+ messages in thread
From: Dave Stevenson @ 2023-05-30 17:29 UTC (permalink / raw)
  To: Sakari Ailus, linux-media, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree
  Cc: Dave Stevenson

With a read only control there is limited point in advertising
a minimum and maximum for the control, so change to set the
value, min, and max all to the selected pixel rate.

Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
 drivers/media/i2c/imx258.c | 18 +++++++-----------
 1 file changed, 7 insertions(+), 11 deletions(-)

diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
index 7d6528f9ca4d..b9b650d40365 100644
--- a/drivers/media/i2c/imx258.c
+++ b/drivers/media/i2c/imx258.c
@@ -1002,7 +1002,8 @@ static int imx258_set_pad_format(struct v4l2_subdev *sd,
 
 		link_freq = imx258->link_freq_menu_items[mode->link_freq_index];
 		pixel_rate = link_freq_to_pixel_rate(link_freq, imx258->nlanes);
-		__v4l2_ctrl_s_ctrl_int64(imx258->pixel_rate, pixel_rate);
+		__v4l2_ctrl_modify_range(imx258->pixel_rate, pixel_rate,
+					 pixel_rate, 1, pixel_rate);
 		/* Update limits and set FPS to default */
 		vblank_def = imx258->cur_mode->vts_def -
 			     imx258->cur_mode->height;
@@ -1328,8 +1329,7 @@ static int imx258_init_controls(struct imx258 *imx258)
 	struct v4l2_ctrl *vflip, *hflip;
 	s64 vblank_def;
 	s64 vblank_min;
-	s64 pixel_rate_min;
-	s64 pixel_rate_max;
+	s64 pixel_rate;
 	int ret;
 
 	ctrl_hdlr = &imx258->ctrl_handler;
@@ -1360,17 +1360,13 @@ static int imx258_init_controls(struct imx258 *imx258)
 	if (vflip)
 		vflip->flags |= V4L2_CTRL_FLAG_READ_ONLY;
 
-	pixel_rate_max =
-		link_freq_to_pixel_rate(imx258->link_freq_menu_items[0],
-					imx258->nlanes);
-	pixel_rate_min =
-		link_freq_to_pixel_rate(imx258->link_freq_menu_items[1],
-					imx258->nlanes);
+	pixel_rate = link_freq_to_pixel_rate(imx258->link_freq_menu_items[0],
+					     imx258->nlanes);
 	/* By default, PIXEL_RATE is read only */
 	imx258->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops,
 				V4L2_CID_PIXEL_RATE,
-				pixel_rate_min, pixel_rate_max,
-				1, pixel_rate_max);
+				pixel_rate, pixel_rate,
+				1, pixel_rate);
 
 
 	vblank_def = imx258->cur_mode->vts_def - imx258->cur_mode->height;
-- 
2.25.1


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

* [PATCH 17/21] media: i2c: imx258: Support faster pixel rate on binned modes
  2023-05-30 17:29 [PATCH 00/21] imx258 improvements series Dave Stevenson
                   ` (15 preceding siblings ...)
  2023-05-30 17:29 ` [PATCH 16/21] media: i2c: imx258: Set pixel_rate range to the same as the value Dave Stevenson
@ 2023-05-30 17:29 ` Dave Stevenson
  2023-05-30 17:29 ` [PATCH 18/21] dt-bindings: media: imx258: Rename to include vendor prefix Dave Stevenson
                   ` (4 subsequent siblings)
  21 siblings, 0 replies; 54+ messages in thread
From: Dave Stevenson @ 2023-05-30 17:29 UTC (permalink / raw)
  To: Sakari Ailus, linux-media, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree
  Cc: Dave Stevenson

With the binned modes, there is little point in faithfully
reproducing the horizontal line length of 5352 pixels on the CSI2
bus, and the FIFO between the pixel array and MIPI serialiser
allows us to remove that dependency.

Allow the pixel array to run with the normal settings, with the MIPI
serialiser at half the rate. This requires some additional
information for the link frequency to pixel rate function that
needs to be added to the configuration tables.

Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
 drivers/media/i2c/imx258.c | 109 ++++++++++++++++++++++++-------------
 1 file changed, 71 insertions(+), 38 deletions(-)

diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
index b9b650d40365..986757650378 100644
--- a/drivers/media/i2c/imx258.c
+++ b/drivers/media/i2c/imx258.c
@@ -103,6 +103,11 @@ struct imx258_reg_list {
 	const struct imx258_reg *regs;
 };
 
+struct imx258_link_cfg {
+	unsigned int lf_to_pix_rate_factor;
+	struct imx258_reg_list reg_list;
+};
+
 #define IMX258_LANE_CONFIGS	2
 #define IMX258_2_LANE_MODE	0
 #define IMX258_4_LANE_MODE	1
@@ -112,8 +117,8 @@ struct imx258_link_freq_config {
 	u64 link_frequency;
 	u32 pixels_per_line;
 
-	/* PLL registers for this link frequency */
-	struct imx258_reg_list reg_list[IMX258_LANE_CONFIGS];
+	/* Configuration for this link frequency / num lanes selection */
+	struct imx258_link_cfg link_cfg[IMX258_LANE_CONFIGS];
 };
 
 /* Mode : resolution and related config&values */
@@ -272,7 +277,7 @@ static const struct imx258_reg mipi_640mbps_19_2mhz_4l[] = {
 static const struct imx258_reg mipi_642mbps_24mhz_2l[] = {
 	{ 0x0136, 0x18 },
 	{ 0x0137, 0x00 },
-	{ 0x0301, 0x0A },
+	{ 0x0301, 0x05 },
 	{ 0x0303, 0x02 },
 	{ 0x0305, 0x04 },
 	{ 0x0306, 0x00 },
@@ -478,14 +483,22 @@ enum {
 };
 
 /*
- * pixel_rate = link_freq * data-rate * nr_of_lanes / bits_per_sample
- * data rate => double data rate;
- * number of lanes => (configurable 2 or 4);
- * bits per pixel => 10
+ * Pixel rate does not necessarily relate to link frequency on this sensor as
+ * there is a FIFO between the pixel array pipeline and the MIPI serializer.
+ * The recommendation from Sony is that the pixel array is always run with a
+ * line length of 5352 pixels, which means that there is a large amount of
+ * blanking time for the 1048x780 mode. There is no need to replicate this
+ * blanking on the CSI2 bus, and the configuration of register 0x0301 allows the
+ * divider to be altered.
+ *
+ * The actual factor between link frequency and pixel rate is in the
+ * imx258_link_cfg, so use this to convert between the two.
+ * bits per pixel being 10, and D-PHY being DDR is assumed by this function, so
+ * the value is only the combination of number of lanes and pixel clock divider.
  */
-static u64 link_freq_to_pixel_rate(u64 f, unsigned int nlanes)
+static u64 link_freq_to_pixel_rate(u64 f, const struct imx258_link_cfg *link_cfg)
 {
-	f *= 2 * nlanes;
+	f *= 2 * link_cfg->lf_to_pix_rate_factor;
 	do_div(f, 10);
 
 	return f;
@@ -510,31 +523,33 @@ static const s64 link_freq_menu_items_24[] = {
 	IMX258_LINK_FREQ_321MHZ,
 };
 
+#define REGS(_list) { .num_of_regs = ARRAY_SIZE(_list), .regs = _list, }
+
 /* Link frequency configs */
 static const struct imx258_link_freq_config link_freq_configs_19_2[] = {
 	[IMX258_LINK_FREQ_1267MBPS] = {
 		.pixels_per_line = IMX258_PPL_DEFAULT,
-		.reg_list = {
+		.link_cfg = {
 			[IMX258_2_LANE_MODE] = {
-				.num_of_regs = ARRAY_SIZE(mipi_1267mbps_19_2mhz_2l),
-				.regs = mipi_1267mbps_19_2mhz_2l,
+				.lf_to_pix_rate_factor = 2 * 2,
+				.reg_list = REGS(mipi_1267mbps_19_2mhz_2l),
 			},
 			[IMX258_4_LANE_MODE] = {
-				.num_of_regs = ARRAY_SIZE(mipi_1267mbps_19_2mhz_4l),
-				.regs = mipi_1267mbps_19_2mhz_4l,
+				.lf_to_pix_rate_factor = 4,
+				.reg_list = REGS(mipi_1267mbps_19_2mhz_4l),
 			},
 		}
 	},
 	[IMX258_LINK_FREQ_640MBPS] = {
 		.pixels_per_line = IMX258_PPL_DEFAULT,
-		.reg_list = {
+		.link_cfg = {
 			[IMX258_2_LANE_MODE] = {
-				.num_of_regs = ARRAY_SIZE(mipi_640mbps_19_2mhz_2l),
-				.regs = mipi_640mbps_19_2mhz_2l,
+				.lf_to_pix_rate_factor = 2,
+				.reg_list = REGS(mipi_640mbps_19_2mhz_2l),
 			},
 			[IMX258_4_LANE_MODE] = {
-				.num_of_regs = ARRAY_SIZE(mipi_640mbps_19_2mhz_4l),
-				.regs = mipi_640mbps_19_2mhz_4l,
+				.lf_to_pix_rate_factor = 4,
+				.reg_list = REGS(mipi_640mbps_19_2mhz_4l),
 			},
 		}
 	},
@@ -543,27 +558,27 @@ static const struct imx258_link_freq_config link_freq_configs_19_2[] = {
 static const struct imx258_link_freq_config link_freq_configs_24[] = {
 	[IMX258_LINK_FREQ_1267MBPS] = {
 		.pixels_per_line = IMX258_PPL_DEFAULT,
-		.reg_list = {
+		.link_cfg = {
 			[IMX258_2_LANE_MODE] = {
-				.num_of_regs = ARRAY_SIZE(mipi_1272mbps_24mhz_2l),
-				.regs = mipi_1272mbps_24mhz_2l,
+				.lf_to_pix_rate_factor = 2,
+				.reg_list = REGS(mipi_1272mbps_24mhz_2l),
 			},
 			[IMX258_4_LANE_MODE] = {
-				.num_of_regs = ARRAY_SIZE(mipi_1272mbps_24mhz_4l),
-				.regs = mipi_1272mbps_24mhz_4l,
+				.lf_to_pix_rate_factor = 4,
+				.reg_list = REGS(mipi_1272mbps_24mhz_4l),
 			},
 		}
 	},
 	[IMX258_LINK_FREQ_640MBPS] = {
 		.pixels_per_line = IMX258_PPL_DEFAULT,
-		.reg_list = {
+		.link_cfg = {
 			[IMX258_2_LANE_MODE] = {
-				.num_of_regs = ARRAY_SIZE(mipi_642mbps_24mhz_2l),
-				.regs = mipi_642mbps_24mhz_2l,
+				.lf_to_pix_rate_factor = 2 * 2,
+				.reg_list = REGS(mipi_642mbps_24mhz_2l),
 			},
 			[IMX258_4_LANE_MODE] = {
-				.num_of_regs = ARRAY_SIZE(mipi_642mbps_24mhz_4l),
-				.regs = mipi_642mbps_24mhz_4l,
+				.lf_to_pix_rate_factor = 4,
+				.reg_list = REGS(mipi_642mbps_24mhz_4l),
 			},
 		}
 	},
@@ -643,7 +658,7 @@ struct imx258 {
 
 	const struct imx258_link_freq_config *link_freq_configs;
 	const s64 *link_freq_menu_items;
-	unsigned int nlanes;
+	unsigned int lane_mode_idx;
 	unsigned int csi2_flags;
 
 	/*
@@ -976,8 +991,10 @@ static int imx258_set_pad_format(struct v4l2_subdev *sd,
 				 struct v4l2_subdev_format *fmt)
 {
 	struct imx258 *imx258 = to_imx258(sd);
-	const struct imx258_mode *mode;
+	const struct imx258_link_freq_config *link_freq_cfgs;
+	const struct imx258_link_cfg *link_cfg;
 	struct v4l2_mbus_framefmt *framefmt;
+	const struct imx258_mode *mode;
 	s32 vblank_def;
 	s32 vblank_min;
 	s64 h_blank;
@@ -1001,7 +1018,11 @@ static int imx258_set_pad_format(struct v4l2_subdev *sd,
 		__v4l2_ctrl_s_ctrl(imx258->link_freq, mode->link_freq_index);
 
 		link_freq = imx258->link_freq_menu_items[mode->link_freq_index];
-		pixel_rate = link_freq_to_pixel_rate(link_freq, imx258->nlanes);
+		link_freq_cfgs =
+			&imx258->link_freq_configs[mode->link_freq_index];
+
+		link_cfg = &link_freq_cfgs->link_cfg[imx258->lane_mode_idx];
+		pixel_rate = link_freq_to_pixel_rate(link_freq, link_cfg);
 		__v4l2_ctrl_modify_range(imx258->pixel_rate, pixel_rate,
 					 pixel_rate, 1, pixel_rate);
 		/* Update limits and set FPS to default */
@@ -1098,7 +1119,8 @@ static int imx258_start_streaming(struct imx258 *imx258)
 	/* Setup PLL */
 	link_freq_index = imx258->cur_mode->link_freq_index;
 	link_freq_cfg = &imx258->link_freq_configs[link_freq_index];
-	reg_list = &link_freq_cfg->reg_list[imx258->nlanes == 2 ? 0 : 1];
+
+	reg_list = &link_freq_cfg->link_cfg[imx258->lane_mode_idx].reg_list;
 	ret = imx258_write_regs(imx258, reg_list->regs, reg_list->num_of_regs);
 	if (ret) {
 		dev_err(&client->dev, "%s failed to set plls\n", __func__);
@@ -1324,9 +1346,11 @@ static const struct v4l2_subdev_internal_ops imx258_internal_ops = {
 static int imx258_init_controls(struct imx258 *imx258)
 {
 	struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd);
+	const struct imx258_link_freq_config *link_freq_cfgs;
 	struct v4l2_fwnode_device_properties props;
-	struct v4l2_ctrl_handler *ctrl_hdlr;
 	struct v4l2_ctrl *vflip, *hflip;
+	struct v4l2_ctrl_handler *ctrl_hdlr;
+	const struct imx258_link_cfg *link_cfg;
 	s64 vblank_def;
 	s64 vblank_min;
 	s64 pixel_rate;
@@ -1360,8 +1384,11 @@ static int imx258_init_controls(struct imx258 *imx258)
 	if (vflip)
 		vflip->flags |= V4L2_CTRL_FLAG_READ_ONLY;
 
+	link_freq_cfgs = &imx258->link_freq_configs[0];
+	link_cfg = link_freq_cfgs[imx258->lane_mode_idx].link_cfg;
 	pixel_rate = link_freq_to_pixel_rate(imx258->link_freq_menu_items[0],
-					     imx258->nlanes);
+					     link_cfg);
+
 	/* By default, PIXEL_RATE is read only */
 	imx258->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops,
 				V4L2_CID_PIXEL_RATE,
@@ -1522,10 +1549,16 @@ static int imx258_probe(struct i2c_client *client)
 	}
 
 	/* Get number of data lanes */
-	imx258->nlanes = ep.bus.mipi_csi2.num_data_lanes;
-	if (imx258->nlanes != 2 && imx258->nlanes != 4) {
+	switch (ep.bus.mipi_csi2.num_data_lanes) {
+	case 2:
+		imx258->lane_mode_idx = IMX258_2_LANE_MODE;
+		break;
+	case 4:
+		imx258->lane_mode_idx = IMX258_4_LANE_MODE;
+		break;
+	default:
 		dev_err(&client->dev, "Invalid data lanes: %u\n",
-			imx258->nlanes);
+			ep.bus.mipi_csi2.num_data_lanes);
 		ret = -EINVAL;
 		goto error_endpoint_poweron;
 	}
-- 
2.25.1


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

* [PATCH 18/21] dt-bindings: media: imx258: Rename to include vendor prefix
  2023-05-30 17:29 [PATCH 00/21] imx258 improvements series Dave Stevenson
                   ` (16 preceding siblings ...)
  2023-05-30 17:29 ` [PATCH 17/21] media: i2c: imx258: Support faster pixel rate on binned modes Dave Stevenson
@ 2023-05-30 17:29 ` Dave Stevenson
  2023-05-30 17:35   ` Conor Dooley
  2023-05-30 17:29 ` [PATCH 19/21] dt-bindings: media: imx258: Add alternate compatible strings Dave Stevenson
                   ` (3 subsequent siblings)
  21 siblings, 1 reply; 54+ messages in thread
From: Dave Stevenson @ 2023-05-30 17:29 UTC (permalink / raw)
  To: Sakari Ailus, linux-media, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree
  Cc: Dave Stevenson

imx258.yaml doesn't include the vendor prefix of sony, so
rename to add it.
Update the id entry and MAINTAINERS to match.

Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
 .../bindings/media/i2c/{imx258.yaml => sony,imx258.yaml}        | 2 +-
 MAINTAINERS                                                     | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)
 rename Documentation/devicetree/bindings/media/i2c/{imx258.yaml => sony,imx258.yaml} (97%)

diff --git a/Documentation/devicetree/bindings/media/i2c/imx258.yaml b/Documentation/devicetree/bindings/media/i2c/sony,imx258.yaml
similarity index 97%
rename from Documentation/devicetree/bindings/media/i2c/imx258.yaml
rename to Documentation/devicetree/bindings/media/i2c/sony,imx258.yaml
index 80d24220baa0..bee61a443b23 100644
--- a/Documentation/devicetree/bindings/media/i2c/imx258.yaml
+++ b/Documentation/devicetree/bindings/media/i2c/sony,imx258.yaml
@@ -1,7 +1,7 @@
 # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
 %YAML 1.2
 ---
-$id: http://devicetree.org/schemas/media/i2c/imx258.yaml#
+$id: http://devicetree.org/schemas/media/i2c/sony,imx258.yaml#
 $schema: http://devicetree.org/meta-schemas/core.yaml#
 
 title: Sony IMX258 13 Mpixel CMOS Digital Image Sensor
diff --git a/MAINTAINERS b/MAINTAINERS
index 26f705e94a41..16d0f64d8ee8 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -19633,7 +19633,7 @@ M:	Sakari Ailus <sakari.ailus@linux.intel.com>
 L:	linux-media@vger.kernel.org
 S:	Maintained
 T:	git git://linuxtv.org/media_tree.git
-F:	Documentation/devicetree/bindings/media/i2c/imx258.yaml
+F:	Documentation/devicetree/bindings/media/i2c/sony,imx258.yaml
 F:	drivers/media/i2c/imx258.c
 
 SONY IMX274 SENSOR DRIVER
-- 
2.25.1


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

* [PATCH 19/21] dt-bindings: media: imx258: Add alternate compatible strings
  2023-05-30 17:29 [PATCH 00/21] imx258 improvements series Dave Stevenson
                   ` (17 preceding siblings ...)
  2023-05-30 17:29 ` [PATCH 18/21] dt-bindings: media: imx258: Rename to include vendor prefix Dave Stevenson
@ 2023-05-30 17:29 ` Dave Stevenson
  2023-05-30 17:38   ` Conor Dooley
  2023-05-30 17:29 ` [PATCH 20/21] media: i2c: imx258: Change register settings for variants of the sensor Dave Stevenson
                   ` (2 subsequent siblings)
  21 siblings, 1 reply; 54+ messages in thread
From: Dave Stevenson @ 2023-05-30 17:29 UTC (permalink / raw)
  To: Sakari Ailus, linux-media, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree
  Cc: Dave Stevenson

There are a number of variants of the imx258 modules that can not
be differentiated at runtime, so add compatible strings for them.

Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
 .../devicetree/bindings/media/i2c/sony,imx258.yaml         | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/media/i2c/sony,imx258.yaml b/Documentation/devicetree/bindings/media/i2c/sony,imx258.yaml
index bee61a443b23..3415b26b5991 100644
--- a/Documentation/devicetree/bindings/media/i2c/sony,imx258.yaml
+++ b/Documentation/devicetree/bindings/media/i2c/sony,imx258.yaml
@@ -14,10 +14,15 @@ description: |-
   type stacked image sensor with a square pixel array of size 4208 x 3120. It
   is programmable through I2C interface.  Image data is sent through MIPI
   CSI-2.
+  There are a number of variants of the sensor which cannot be detected at
+  runtime, so multiple compatible strings are required to differentiate these.
 
 properties:
   compatible:
-    const: sony,imx258
+    oneOf:
+      - enum:
+          - sony,imx258
+          - sony,imx258-pdaf
 
   assigned-clocks: true
   assigned-clock-parents: true
-- 
2.25.1


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

* [PATCH 20/21] media: i2c: imx258: Change register settings for variants of the sensor
  2023-05-30 17:29 [PATCH 00/21] imx258 improvements series Dave Stevenson
                   ` (18 preceding siblings ...)
  2023-05-30 17:29 ` [PATCH 19/21] dt-bindings: media: imx258: Add alternate compatible strings Dave Stevenson
@ 2023-05-30 17:29 ` Dave Stevenson
  2023-06-02 13:48   ` Jacopo Mondi
  2023-05-30 17:30 ` [PATCH 21/21] media: i2c: imx258: Make HFLIP and VFLIP controls writable Dave Stevenson
  2023-07-18 12:08 ` [PATCH 00/21] imx258 improvements series Arnaud Ferraris
  21 siblings, 1 reply; 54+ messages in thread
From: Dave Stevenson @ 2023-05-30 17:29 UTC (permalink / raw)
  To: Sakari Ailus, linux-media, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree
  Cc: Dave Stevenson

Sony have advised that there are variants of the IMX258 sensor which
require slightly different register configuration to the mainline
imx258 driver defaults.

There is no available run-time detection for the variant, so add
configuration via the DT compatible string.

The Vision Components imx258 module supports PDAF, so add the
register differences for that variant

Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
 drivers/media/i2c/imx258.c | 49 ++++++++++++++++++++++++++++++++++----
 1 file changed, 45 insertions(+), 4 deletions(-)

diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
index 986757650378..98b5c1e3abff 100644
--- a/drivers/media/i2c/imx258.c
+++ b/drivers/media/i2c/imx258.c
@@ -6,6 +6,7 @@
 #include <linux/delay.h>
 #include <linux/i2c.h>
 #include <linux/module.h>
+#include <linux/of_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/regulator/consumer.h>
 #include <media/v4l2-ctrls.h>
@@ -320,8 +321,6 @@ static const struct imx258_reg mipi_642mbps_24mhz_4l[] = {
 
 static const struct imx258_reg mode_common_regs[] = {
 	{ 0x3051, 0x00 },
-	{ 0x3052, 0x00 },
-	{ 0x4E21, 0x14 },
 	{ 0x6B11, 0xCF },
 	{ 0x7FF0, 0x08 },
 	{ 0x7FF1, 0x0F },
@@ -344,7 +343,6 @@ static const struct imx258_reg mode_common_regs[] = {
 	{ 0x7FA8, 0x03 },
 	{ 0x7FA9, 0xFE },
 	{ 0x7B24, 0x81 },
-	{ 0x7B25, 0x00 },
 	{ 0x6564, 0x07 },
 	{ 0x6B0D, 0x41 },
 	{ 0x653D, 0x04 },
@@ -459,6 +457,33 @@ static const struct imx258_reg mode_1048_780_regs[] = {
 	{ 0x034F, 0x0C },
 };
 
+struct imx258_variant_cfg {
+	const struct imx258_reg *regs;
+	unsigned int num_regs;
+};
+
+static const struct imx258_reg imx258_cfg_regs[] = {
+	{ 0x3052, 0x00 },
+	{ 0x4E21, 0x14 },
+	{ 0x7B25, 0x00 },
+};
+
+static const struct imx258_variant_cfg imx258_cfg = {
+	.regs = imx258_cfg_regs,
+	.num_regs = ARRAY_SIZE(imx258_cfg_regs),
+};
+
+static const struct imx258_reg imx258_pdaf_cfg_regs[] = {
+	{ 0x3052, 0x01 },
+	{ 0x4E21, 0x10 },
+	{ 0x7B25, 0x01 },
+};
+
+static const struct imx258_variant_cfg imx258_pdaf_cfg = {
+	.regs = imx258_pdaf_cfg_regs,
+	.num_regs = ARRAY_SIZE(imx258_pdaf_cfg_regs),
+};
+
 static const char * const imx258_test_pattern_menu[] = {
 	"Disabled",
 	"Solid Colour",
@@ -643,6 +668,8 @@ struct imx258 {
 	struct v4l2_subdev sd;
 	struct media_pad pad;
 
+	const struct imx258_variant_cfg *variant_cfg;
+
 	struct v4l2_ctrl_handler ctrl_handler;
 	/* V4L2 Controls */
 	struct v4l2_ctrl *link_freq;
@@ -1134,6 +1161,14 @@ static int imx258_start_streaming(struct imx258 *imx258)
 		return ret;
 	}
 
+	ret = imx258_write_regs(imx258, imx258->variant_cfg->regs,
+				imx258->variant_cfg->num_regs);
+	if (ret) {
+		dev_err(&client->dev, "%s failed to set variant config\n",
+			__func__);
+		return ret;
+	}
+
 	ret = imx258_write_reg(imx258, IMX258_CLK_BLANK_STOP,
 			       IMX258_REG_VALUE_08BIT,
 			       imx258->csi2_flags & V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK ?
@@ -1490,6 +1525,7 @@ static int imx258_probe(struct i2c_client *client)
 	struct v4l2_fwnode_endpoint ep = {
 		.bus_type = V4L2_MBUS_CSI2_DPHY
 	};
+	const struct of_device_id *match;
 	int ret;
 	u32 val = 0;
 
@@ -1565,6 +1601,10 @@ static int imx258_probe(struct i2c_client *client)
 
 	imx258->csi2_flags = ep.bus.mipi_csi2.flags;
 
+	imx258->variant_cfg = of_device_get_match_data(&client->dev);
+	if (!match)
+		imx258->variant_cfg = &imx258_cfg;
+
 	/* Initialize subdev */
 	v4l2_i2c_subdev_init(&imx258->sd, client, &imx258_subdev_ops);
 
@@ -1653,7 +1693,8 @@ MODULE_DEVICE_TABLE(acpi, imx258_acpi_ids);
 #endif
 
 static const struct of_device_id imx258_dt_ids[] = {
-	{ .compatible = "sony,imx258" },
+	{ .compatible = "sony,imx258", .data = &imx258_cfg },
+	{ .compatible = "sony,imx258-pdaf", .data = &imx258_pdaf_cfg },
 	{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, imx258_dt_ids);
-- 
2.25.1


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

* [PATCH 21/21] media: i2c: imx258: Make HFLIP and VFLIP controls writable
  2023-05-30 17:29 [PATCH 00/21] imx258 improvements series Dave Stevenson
                   ` (19 preceding siblings ...)
  2023-05-30 17:29 ` [PATCH 20/21] media: i2c: imx258: Change register settings for variants of the sensor Dave Stevenson
@ 2023-05-30 17:30 ` Dave Stevenson
  2023-06-02 13:58   ` Jacopo Mondi
  2023-07-18 12:08 ` [PATCH 00/21] imx258 improvements series Arnaud Ferraris
  21 siblings, 1 reply; 54+ messages in thread
From: Dave Stevenson @ 2023-05-30 17:30 UTC (permalink / raw)
  To: Sakari Ailus, linux-media, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree
  Cc: Dave Stevenson

The sensor supports H & V flips, but the controls were READ_ONLY.

Note that the Bayer order changes with these flips, therefore
they set the V4L2_CTRL_FLAG_MODIFY_LAYOUT property.

Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
 drivers/media/i2c/imx258.c | 99 ++++++++++++++++++++++++--------------
 1 file changed, 64 insertions(+), 35 deletions(-)

diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
index 98b5c1e3abff..cf90ac66e14c 100644
--- a/drivers/media/i2c/imx258.c
+++ b/drivers/media/i2c/imx258.c
@@ -83,8 +83,8 @@
 
 /* Orientation */
 #define REG_MIRROR_FLIP_CONTROL		0x0101
-#define REG_CONFIG_MIRROR_FLIP		0x03
-#define REG_CONFIG_FLIP_TEST_PATTERN	0x02
+#define REG_CONFIG_MIRROR_HFLIP		0x01
+#define REG_CONFIG_MIRROR_VFLIP		0x02
 
 /* IMX258 native and active pixel array size. */
 #define IMX258_NATIVE_WIDTH		4224U
@@ -484,6 +484,23 @@ static const struct imx258_variant_cfg imx258_pdaf_cfg = {
 	.num_regs = ARRAY_SIZE(imx258_pdaf_cfg_regs),
 };
 
+/*
+ * The supported formats.
+ * This table MUST contain 4 entries per format, to cover the various flip
+ * combinations in the order
+ * - no flip
+ * - h flip
+ * - v flip
+ * - h&v flips
+ */
+static const u32 codes[] = {
+	/* 10-bit modes. */
+	MEDIA_BUS_FMT_SRGGB10_1X10,
+	MEDIA_BUS_FMT_SGRBG10_1X10,
+	MEDIA_BUS_FMT_SGBRG10_1X10,
+	MEDIA_BUS_FMT_SBGGR10_1X10
+};
+
 static const char * const imx258_test_pattern_menu[] = {
 	"Disabled",
 	"Solid Colour",
@@ -677,6 +694,8 @@ struct imx258 {
 	struct v4l2_ctrl *vblank;
 	struct v4l2_ctrl *hblank;
 	struct v4l2_ctrl *exposure;
+	struct v4l2_ctrl *hflip;
+	struct v4l2_ctrl *vflip;
 	/* Current long exposure factor in use. Set through V4L2_CID_VBLANK */
 	unsigned int long_exp_shift;
 
@@ -780,9 +799,22 @@ static int imx258_write_regs(struct imx258 *imx258,
 	return 0;
 }
 
+/* Get bayer order based on flip setting. */
+static u32 imx258_get_format_code(struct imx258 *imx258)
+{
+	unsigned int i;
+
+	lockdep_assert_held(&imx258->mutex);
+
+	i = (imx258->vflip->val ? 2 : 0) |
+	    (imx258->hflip->val ? 1 : 0);
+
+	return codes[i];
+}
 /* Open sub-device */
 static int imx258_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 {
+	struct imx258 *imx258 = to_imx258(sd);
 	struct v4l2_mbus_framefmt *try_fmt =
 		v4l2_subdev_get_try_format(sd, fh->state, 0);
 	struct v4l2_rect *try_crop;
@@ -790,7 +822,7 @@ static int imx258_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 	/* Initialize try_fmt */
 	try_fmt->width = supported_modes[0].width;
 	try_fmt->height = supported_modes[0].height;
-	try_fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
+	try_fmt->code = imx258_get_format_code(imx258);
 	try_fmt->field = V4L2_FIELD_NONE;
 
 	/* Initialize try_crop */
@@ -903,10 +935,6 @@ static int imx258_set_ctrl(struct v4l2_ctrl *ctrl)
 		ret = imx258_write_reg(imx258, IMX258_REG_TEST_PATTERN,
 				IMX258_REG_VALUE_16BIT,
 				ctrl->val);
-		ret = imx258_write_reg(imx258, REG_MIRROR_FLIP_CONTROL,
-				IMX258_REG_VALUE_08BIT,
-				!ctrl->val ? REG_CONFIG_MIRROR_FLIP :
-				REG_CONFIG_FLIP_TEST_PATTERN);
 		break;
 	case V4L2_CID_WIDE_DYNAMIC_RANGE:
 		if (!ctrl->val) {
@@ -928,6 +956,15 @@ static int imx258_set_ctrl(struct v4l2_ctrl *ctrl)
 		ret = imx258_set_frame_length(imx258,
 					      imx258->cur_mode->height + ctrl->val);
 		break;
+	case V4L2_CID_VFLIP:
+	case V4L2_CID_HFLIP:
+		ret = imx258_write_reg(imx258, REG_MIRROR_FLIP_CONTROL,
+				       IMX258_REG_VALUE_08BIT,
+				       (imx258->hflip->val ?
+					REG_CONFIG_MIRROR_HFLIP : 0) |
+				       (imx258->vflip->val ?
+					REG_CONFIG_MIRROR_VFLIP : 0));
+		break;
 	default:
 		dev_info(&client->dev,
 			 "ctrl(id:0x%x,val:0x%x) is not handled\n",
@@ -949,11 +986,13 @@ static int imx258_enum_mbus_code(struct v4l2_subdev *sd,
 				  struct v4l2_subdev_state *sd_state,
 				  struct v4l2_subdev_mbus_code_enum *code)
 {
-	/* Only one bayer order(GRBG) is supported */
+	struct imx258 *imx258 = to_imx258(sd);
+
+	/* Only one bayer format (10 bit) is supported */
 	if (code->index > 0)
 		return -EINVAL;
 
-	code->code = MEDIA_BUS_FMT_SBGGR10_1X10;
+	code->code = imx258_get_format_code(imx258);
 
 	return 0;
 }
@@ -962,10 +1001,11 @@ static int imx258_enum_frame_size(struct v4l2_subdev *sd,
 				  struct v4l2_subdev_state *sd_state,
 				  struct v4l2_subdev_frame_size_enum *fse)
 {
+	struct imx258 *imx258 = to_imx258(sd);
 	if (fse->index >= ARRAY_SIZE(supported_modes))
 		return -EINVAL;
 
-	if (fse->code != MEDIA_BUS_FMT_SBGGR10_1X10)
+	if (fse->code != imx258_get_format_code(imx258))
 		return -EINVAL;
 
 	fse->min_width = supported_modes[fse->index].width;
@@ -976,12 +1016,13 @@ static int imx258_enum_frame_size(struct v4l2_subdev *sd,
 	return 0;
 }
 
-static void imx258_update_pad_format(const struct imx258_mode *mode,
+static void imx258_update_pad_format(struct imx258 *imx258,
+				     const struct imx258_mode *mode,
 				     struct v4l2_subdev_format *fmt)
 {
 	fmt->format.width = mode->width;
 	fmt->format.height = mode->height;
-	fmt->format.code = MEDIA_BUS_FMT_SBGGR10_1X10;
+	fmt->format.code = imx258_get_format_code(imx258);
 	fmt->format.field = V4L2_FIELD_NONE;
 }
 
@@ -994,7 +1035,7 @@ static int __imx258_get_pad_format(struct imx258 *imx258,
 							  sd_state,
 							  fmt->pad);
 	else
-		imx258_update_pad_format(imx258->cur_mode, fmt);
+		imx258_update_pad_format(imx258, imx258->cur_mode, fmt);
 
 	return 0;
 }
@@ -1030,13 +1071,12 @@ static int imx258_set_pad_format(struct v4l2_subdev *sd,
 
 	mutex_lock(&imx258->mutex);
 
-	/* Only one raw bayer(GBRG) order is supported */
-	fmt->format.code = MEDIA_BUS_FMT_SBGGR10_1X10;
+	fmt->format.code = imx258_get_format_code(imx258);
 
 	mode = v4l2_find_nearest_size(supported_modes,
 		ARRAY_SIZE(supported_modes), width, height,
 		fmt->format.width, fmt->format.height);
-	imx258_update_pad_format(mode, fmt);
+	imx258_update_pad_format(imx258, mode, fmt);
 	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
 		framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
 		*framefmt = fmt->format;
@@ -1186,15 +1226,6 @@ static int imx258_start_streaming(struct imx258 *imx258)
 		return ret;
 	}
 
-	/* Set Orientation be 180 degree */
-	ret = imx258_write_reg(imx258, REG_MIRROR_FLIP_CONTROL,
-			       IMX258_REG_VALUE_08BIT, REG_CONFIG_MIRROR_FLIP);
-	if (ret) {
-		dev_err(&client->dev, "%s failed to set orientation\n",
-			__func__);
-		return ret;
-	}
-
 	/* Apply customized values from user */
 	ret =  __v4l2_ctrl_handler_setup(imx258->sd.ctrl_handler);
 	if (ret)
@@ -1383,7 +1414,6 @@ static int imx258_init_controls(struct imx258 *imx258)
 	struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd);
 	const struct imx258_link_freq_config *link_freq_cfgs;
 	struct v4l2_fwnode_device_properties props;
-	struct v4l2_ctrl *vflip, *hflip;
 	struct v4l2_ctrl_handler *ctrl_hdlr;
 	const struct imx258_link_cfg *link_cfg;
 	s64 vblank_def;
@@ -1408,16 +1438,15 @@ static int imx258_init_controls(struct imx258 *imx258)
 	if (imx258->link_freq)
 		imx258->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
 
-	/* The driver only supports one bayer order and flips by default. */
-	hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops,
-				  V4L2_CID_HFLIP, 1, 1, 1, 1);
-	if (hflip)
-		hflip->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+	imx258->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops,
+					  V4L2_CID_HFLIP, 0, 1, 1, 1);
+	if (imx258->hflip)
+		imx258->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
 
-	vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops,
-				  V4L2_CID_VFLIP, 1, 1, 1, 1);
-	if (vflip)
-		vflip->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+	imx258->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops,
+					  V4L2_CID_VFLIP, 0, 1, 1, 1);
+	if (imx258->vflip)
+		imx258->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
 
 	link_freq_cfgs = &imx258->link_freq_configs[0];
 	link_cfg = link_freq_cfgs[imx258->lane_mode_idx].link_cfg;
-- 
2.25.1


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

* Re: [PATCH 18/21] dt-bindings: media: imx258: Rename to include vendor prefix
  2023-05-30 17:29 ` [PATCH 18/21] dt-bindings: media: imx258: Rename to include vendor prefix Dave Stevenson
@ 2023-05-30 17:35   ` Conor Dooley
  0 siblings, 0 replies; 54+ messages in thread
From: Conor Dooley @ 2023-05-30 17:35 UTC (permalink / raw)
  To: Dave Stevenson
  Cc: Sakari Ailus, linux-media, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree

[-- Attachment #1: Type: text/plain, Size: 2007 bytes --]

On Tue, May 30, 2023 at 06:29:57PM +0100, Dave Stevenson wrote:
> imx258.yaml doesn't include the vendor prefix of sony, so
> rename to add it.
> Update the id entry and MAINTAINERS to match.
> 
> Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>

Acked-by: Conor Dooley <conor.dooley@microchip.com>

Cheers,
Conor.

> ---
>  .../bindings/media/i2c/{imx258.yaml => sony,imx258.yaml}        | 2 +-
>  MAINTAINERS                                                     | 2 +-
>  2 files changed, 2 insertions(+), 2 deletions(-)
>  rename Documentation/devicetree/bindings/media/i2c/{imx258.yaml => sony,imx258.yaml} (97%)
> 
> diff --git a/Documentation/devicetree/bindings/media/i2c/imx258.yaml b/Documentation/devicetree/bindings/media/i2c/sony,imx258.yaml
> similarity index 97%
> rename from Documentation/devicetree/bindings/media/i2c/imx258.yaml
> rename to Documentation/devicetree/bindings/media/i2c/sony,imx258.yaml
> index 80d24220baa0..bee61a443b23 100644
> --- a/Documentation/devicetree/bindings/media/i2c/imx258.yaml
> +++ b/Documentation/devicetree/bindings/media/i2c/sony,imx258.yaml
> @@ -1,7 +1,7 @@
>  # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>  %YAML 1.2
>  ---
> -$id: http://devicetree.org/schemas/media/i2c/imx258.yaml#
> +$id: http://devicetree.org/schemas/media/i2c/sony,imx258.yaml#
>  $schema: http://devicetree.org/meta-schemas/core.yaml#
>  
>  title: Sony IMX258 13 Mpixel CMOS Digital Image Sensor
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 26f705e94a41..16d0f64d8ee8 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -19633,7 +19633,7 @@ M:	Sakari Ailus <sakari.ailus@linux.intel.com>
>  L:	linux-media@vger.kernel.org
>  S:	Maintained
>  T:	git git://linuxtv.org/media_tree.git
> -F:	Documentation/devicetree/bindings/media/i2c/imx258.yaml
> +F:	Documentation/devicetree/bindings/media/i2c/sony,imx258.yaml
>  F:	drivers/media/i2c/imx258.c
>  
>  SONY IMX274 SENSOR DRIVER
> -- 
> 2.25.1
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

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

* Re: [PATCH 09/21] media: i2c: imx258: Add support for running on 2 CSI data lanes
  2023-05-30 17:29 ` [PATCH 09/21] media: i2c: imx258: Add support for running on 2 CSI data lanes Dave Stevenson
@ 2023-05-30 17:37   ` Dave Stevenson
  2023-05-31  8:07   ` kernel test robot
  2023-06-02 13:23   ` Jacopo Mondi
  2 siblings, 0 replies; 54+ messages in thread
From: Dave Stevenson @ 2023-05-30 17:37 UTC (permalink / raw)
  To: Sakari Ailus, linux-media, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree

On Tue, 30 May 2023 at 18:30, Dave Stevenson
<dave.stevenson@raspberrypi.com> wrote:
>
> Extends the driver to also support 2 data lanes.
> Frame rates are obviously more restricted on 2 lanes, but some
> hardware simply hasn't wired more up.
>
> Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
> ---
>  drivers/media/i2c/imx258.c | 211 ++++++++++++++++++++++++++++++++-----
>  1 file changed, 187 insertions(+), 24 deletions(-)
>
> diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
> index d40521f9a3c6..433dff7f1fa0 100644
> --- a/drivers/media/i2c/imx258.c
> +++ b/drivers/media/i2c/imx258.c
> @@ -86,13 +86,17 @@ struct imx258_reg_list {
>         const struct imx258_reg *regs;
>  };
>
> +#define IMX258_LANE_CONFIGS    2
> +#define IMX258_2_LANE_MODE     0
> +#define IMX258_4_LANE_MODE     1
> +
>  /* Link frequency config */
>  struct imx258_link_freq_config {
>         u64 link_frequency;
>         u32 pixels_per_line;
>
>         /* PLL registers for this link frequency */
> -       struct imx258_reg_list reg_list;
> +       struct imx258_reg_list reg_list[IMX258_LANE_CONFIGS];
>  };
>
>  /* Mode : resolution and related config&values */
> @@ -112,8 +116,30 @@ struct imx258_mode {
>         struct imx258_reg_list reg_list;
>  };
>
> -/* 4208x3120 needs 1267Mbps/lane, 4 lanes */
> -static const struct imx258_reg mipi_1267mbps_19_2mhz[] = {
> +/* 4208x3120 needs 1267Mbps/lane, 4 lanes. Use that rate on 2 lanes as well */
> +static const struct imx258_reg mipi_1267mbps_19_2mhz_2l[] = {
> +       { 0x0136, 0x13 },
> +       { 0x0137, 0x33 },
> +       { 0x0301, 0x0A },
> +       { 0x0303, 0x02 },
> +       { 0x0305, 0x03 },
> +       { 0x0306, 0x00 },
> +       { 0x0307, 0xC6 },
> +       { 0x0309, 0x0A },
> +       { 0x030B, 0x01 },
> +       { 0x030D, 0x02 },
> +       { 0x030E, 0x00 },
> +       { 0x030F, 0xD8 },
> +       { 0x0310, 0x00 },
> +
> +       { 0x0114, 0x01 },
> +       { 0x0820, 0x09 },
> +       { 0x0821, 0xa6 },
> +       { 0x0822, 0x66 },
> +       { 0x0823, 0x66 },
> +};
> +
> +static const struct imx258_reg mipi_1267mbps_19_2mhz_4l[] = {
>         { 0x0136, 0x13 },
>         { 0x0137, 0x33 },
>         { 0x0301, 0x05 },
> @@ -127,16 +153,18 @@ static const struct imx258_reg mipi_1267mbps_19_2mhz[] = {
>         { 0x030E, 0x00 },
>         { 0x030F, 0xD8 },
>         { 0x0310, 0x00 },
> +
> +       { 0x0114, 0x03 },
>         { 0x0820, 0x13 },
>         { 0x0821, 0x4C },
>         { 0x0822, 0xCC },
>         { 0x0823, 0xCC },
>  };
>
> -static const struct imx258_reg mipi_1272mbps_24mhz[] = {
> +static const struct imx258_reg mipi_1272mbps_24mhz_2l[] = {
>         { 0x0136, 0x18 },
>         { 0x0137, 0x00 },
> -       { 0x0301, 0x05 },
> +       { 0x0301, 0x0a },
>         { 0x0303, 0x02 },
>         { 0x0305, 0x04 },
>         { 0x0306, 0x00 },
> @@ -147,13 +175,59 @@ static const struct imx258_reg mipi_1272mbps_24mhz[] = {
>         { 0x030E, 0x00 },
>         { 0x030F, 0xD8 },
>         { 0x0310, 0x00 },
> +
> +       { 0x0114, 0x01 },
>         { 0x0820, 0x13 },
>         { 0x0821, 0x4C },
>         { 0x0822, 0xCC },
>         { 0x0823, 0xCC },
>  };
>
> -static const struct imx258_reg mipi_640mbps_19_2mhz[] = {
> +static const struct imx258_reg mipi_1272mbps_24mhz_4l[] = {
> +       { 0x0136, 0x18 },
> +       { 0x0137, 0x00 },
> +       { 0x0301, 0x05 },
> +       { 0x0303, 0x02 },
> +       { 0x0305, 0x04 },
> +       { 0x0306, 0x00 },
> +       { 0x0307, 0xD4 },
> +       { 0x0309, 0x0A },
> +       { 0x030B, 0x01 },
> +       { 0x030D, 0x02 },
> +       { 0x030E, 0x00 },
> +       { 0x030F, 0xD8 },
> +       { 0x0310, 0x00 },
> +
> +       { 0x0114, 0x03 },
> +       { 0x0820, 0x13 },
> +       { 0x0821, 0xE0 },
> +       { 0x0822, 0x00 },
> +       { 0x0823, 0x00 },
> +};
> +
> +static const struct imx258_reg mipi_640mbps_19_2mhz_2l[] = {
> +       { 0x0136, 0x13 },
> +       { 0x0137, 0x33 },
> +       { 0x0301, 0x05 },
> +       { 0x0303, 0x02 },
> +       { 0x0305, 0x03 },
> +       { 0x0306, 0x00 },
> +       { 0x0307, 0x64 },
> +       { 0x0309, 0x0A },
> +       { 0x030B, 0x01 },
> +       { 0x030D, 0x02 },
> +       { 0x030E, 0x00 },
> +       { 0x030F, 0xD8 },
> +       { 0x0310, 0x00 },
> +
> +       { 0x0114, 0x01 },
> +       { 0x0820, 0x05 },
> +       { 0x0821, 0x00 },
> +       { 0x0822, 0x00 },
> +       { 0x0823, 0x00 },
> +};
> +
> +static const struct imx258_reg mipi_640mbps_19_2mhz_4l[] = {
>         { 0x0136, 0x13 },
>         { 0x0137, 0x33 },
>         { 0x0301, 0x05 },
> @@ -167,13 +241,37 @@ static const struct imx258_reg mipi_640mbps_19_2mhz[] = {
>         { 0x030E, 0x00 },
>         { 0x030F, 0xD8 },
>         { 0x0310, 0x00 },
> +
> +       { 0x0114, 0x03 },
>         { 0x0820, 0x0A },
>         { 0x0821, 0x00 },
>         { 0x0822, 0x00 },
>         { 0x0823, 0x00 },
>  };
>
> -static const struct imx258_reg mipi_642mbps_24mhz[] = {
> +static const struct imx258_reg mipi_642mbps_24mhz_2l[] = {
> +       { 0x0136, 0x18 },
> +       { 0x0137, 0x00 },
> +       { 0x0301, 0x0A },
> +       { 0x0303, 0x02 },
> +       { 0x0305, 0x04 },
> +       { 0x0306, 0x00 },
> +       { 0x0307, 0x6B },
> +       { 0x0309, 0x0A },
> +       { 0x030B, 0x01 },
> +       { 0x030D, 0x02 },
> +       { 0x030E, 0x00 },
> +       { 0x030F, 0xD8 },
> +       { 0x0310, 0x00 },
> +
> +       { 0x0114, 0x01 },
> +       { 0x0820, 0x0A },
> +       { 0x0821, 0x00 },
> +       { 0x0822, 0x00 },
> +       { 0x0823, 0x00 },
> +};
> +
> +static const struct imx258_reg mipi_642mbps_24mhz_4l[] = {
>         { 0x0136, 0x18 },
>         { 0x0137, 0x00 },
>         { 0x0301, 0x05 },
> @@ -187,6 +285,8 @@ static const struct imx258_reg mipi_642mbps_24mhz[] = {
>         { 0x030E, 0x00 },
>         { 0x030F, 0xD8 },
>         { 0x0310, 0x00 },
> +
> +       { 0x0114, 0x03 },
>         { 0x0820, 0x0A },
>         { 0x0821, 0x00 },
>         { 0x0822, 0x00 },
> @@ -241,7 +341,6 @@ static const struct imx258_reg mode_common_regs[] = {
>         { 0x5F05, 0xED },
>         { 0x0112, 0x0A },
>         { 0x0113, 0x0A },
> -       { 0x0114, 0x03 },
>         { 0x0342, 0x14 },
>         { 0x0343, 0xE8 },
>         { 0x0344, 0x00 },
> @@ -360,11 +459,13 @@ enum {
>
>  /*
>   * pixel_rate = link_freq * data-rate * nr_of_lanes / bits_per_sample
> - * data rate => double data rate; number of lanes => 4; bits per pixel => 10
> + * data rate => double data rate;
> + * number of lanes => (configurable 2 or 4);
> + * bits per pixel => 10
>   */
> -static u64 link_freq_to_pixel_rate(u64 f)
> +static u64 link_freq_to_pixel_rate(u64 f, unsigned int nlanes)
>  {
> -       f *= 2 * 4;
> +       f *= 2 * nlanes;
>         do_div(f, 10);
>
>         return f;
> @@ -394,15 +495,27 @@ static const struct imx258_link_freq_config link_freq_configs_19_2[] = {
>         [IMX258_LINK_FREQ_1267MBPS] = {
>                 .pixels_per_line = IMX258_PPL_DEFAULT,
>                 .reg_list = {
> -                       .num_of_regs = ARRAY_SIZE(mipi_1267mbps_19_2mhz),
> -                       .regs = mipi_1267mbps_19_2mhz,
> +                       [IMX258_2_LANE_MODE] = {
> +                               .num_of_regs = ARRAY_SIZE(mipi_1267mbps_19_2mhz_2l),
> +                               .regs = mipi_1267mbps_19_2mhz_2l,
> +                       },
> +                       [IMX258_4_LANE_MODE] = {
> +                               .num_of_regs = ARRAY_SIZE(mipi_1267mbps_19_2mhz_4l),
> +                               .regs = mipi_1267mbps_19_2mhz_4l,
> +                       },
>                 }
>         },
>         [IMX258_LINK_FREQ_640MBPS] = {
>                 .pixels_per_line = IMX258_PPL_DEFAULT,
>                 .reg_list = {
> -                       .num_of_regs = ARRAY_SIZE(mipi_640mbps_19_2mhz),
> -                       .regs = mipi_640mbps_19_2mhz,
> +                       [IMX258_2_LANE_MODE] = {
> +                               .num_of_regs = ARRAY_SIZE(mipi_640mbps_19_2mhz_2l),
> +                               .regs = mipi_640mbps_19_2mhz_2l,
> +                       },
> +                       [IMX258_4_LANE_MODE] = {
> +                               .num_of_regs = ARRAY_SIZE(mipi_640mbps_19_2mhz_4l),
> +                               .regs = mipi_640mbps_19_2mhz_4l,
> +                       },
>                 }
>         },
>  };
> @@ -411,15 +524,27 @@ static const struct imx258_link_freq_config link_freq_configs_24[] = {
>         [IMX258_LINK_FREQ_1267MBPS] = {
>                 .pixels_per_line = IMX258_PPL_DEFAULT,
>                 .reg_list = {
> -                       .num_of_regs = ARRAY_SIZE(mipi_1272mbps_24mhz),
> -                       .regs = mipi_1272mbps_24mhz,
> +                       [IMX258_2_LANE_MODE] = {
> +                               .num_of_regs = ARRAY_SIZE(mipi_1272mbps_24mhz_2l),
> +                               .regs = mipi_1272mbps_24mhz_2l,
> +                       },
> +                       [IMX258_4_LANE_MODE] = {
> +                               .num_of_regs = ARRAY_SIZE(mipi_1272mbps_24mhz_4l),
> +                               .regs = mipi_1272mbps_24mhz_4l,
> +                       },
>                 }
>         },
>         [IMX258_LINK_FREQ_640MBPS] = {
>                 .pixels_per_line = IMX258_PPL_DEFAULT,
>                 .reg_list = {
> -                       .num_of_regs = ARRAY_SIZE(mipi_642mbps_24mhz),
> -                       .regs = mipi_642mbps_24mhz,
> +                       [IMX258_2_LANE_MODE] = {
> +                               .num_of_regs = ARRAY_SIZE(mipi_642mbps_24mhz_2l),
> +                               .regs = mipi_642mbps_24mhz_2l,
> +                       },
> +                       [IMX258_4_LANE_MODE] = {
> +                               .num_of_regs = ARRAY_SIZE(mipi_642mbps_24mhz_4l),
> +                               .regs = mipi_642mbps_24mhz_4l,
> +                       },
>                 }
>         },
>  };
> @@ -478,6 +603,7 @@ struct imx258 {
>
>         const struct imx258_link_freq_config *link_freq_configs;
>         const s64 *link_freq_menu_items;
> +       unsigned int nlanes;
>
>         /*
>          * Mutex for serialized access:
> @@ -787,7 +913,7 @@ static int imx258_set_pad_format(struct v4l2_subdev *sd,
>                 __v4l2_ctrl_s_ctrl(imx258->link_freq, mode->link_freq_index);
>
>                 link_freq = imx258->link_freq_menu_items[mode->link_freq_index];
> -               pixel_rate = link_freq_to_pixel_rate(link_freq);
> +               pixel_rate = link_freq_to_pixel_rate(link_freq, imx258->nlanes);
>                 __v4l2_ctrl_s_ctrl_int64(imx258->pixel_rate, pixel_rate);
>                 /* Update limits and set FPS to default */
>                 vblank_def = imx258->cur_mode->vts_def -
> @@ -816,11 +942,13 @@ static int imx258_start_streaming(struct imx258 *imx258)
>  {
>         struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd);
>         const struct imx258_reg_list *reg_list;
> +       const struct imx258_link_freq_config *link_freq_cfg;
>         int ret, link_freq_index;
>
>         /* Setup PLL */
>         link_freq_index = imx258->cur_mode->link_freq_index;
> -       reg_list = &imx258->link_freq_configs[link_freq_index].reg_list;
> +       link_freq_cfg = &imx258->link_freq_configs[link_freq_index];
> +       reg_list = &link_freq_cfg->reg_list[imx258->nlanes == 2 ? 0 : 1];
>         ret = imx258_write_regs(imx258, reg_list->regs, reg_list->num_of_regs);
>         if (ret) {
>                 dev_err(&client->dev, "%s failed to set plls\n", __func__);
> @@ -1074,9 +1202,11 @@ static int imx258_init_controls(struct imx258 *imx258)
>                 vflip->flags |= V4L2_CTRL_FLAG_READ_ONLY;
>
>         pixel_rate_max =
> -               link_freq_to_pixel_rate(imx258->link_freq_menu_items[0]);
> +               link_freq_to_pixel_rate(imx258->link_freq_menu_items[0],
> +                                       imx258->nlanes);
>         pixel_rate_min =
> -               link_freq_to_pixel_rate(imx258->link_freq_menu_items[1]);
> +               link_freq_to_pixel_rate(imx258->link_freq_menu_items[1],
> +                                       imx258->nlanes);
>         /* By default, PIXEL_RATE is read only */
>         imx258->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops,
>                                 V4L2_CID_PIXEL_RATE,
> @@ -1174,6 +1304,10 @@ static int imx258_get_regulators(struct imx258 *imx258,
>  static int imx258_probe(struct i2c_client *client)
>  {
>         struct imx258 *imx258;
> +       struct fwnode_handle *endpoint;
> +       struct v4l2_fwnode_endpoint ep = {
> +               .bus_type = V4L2_MBUS_CSI2_DPHY
> +       };
>         int ret;
>         u32 val = 0;
>
> @@ -1216,13 +1350,38 @@ static int imx258_probe(struct i2c_client *client)
>                 return -EINVAL;
>         }
>
> +       endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev), NULL);
> +       if (!endpoint) {
> +               dev_err(&client->dev, "Endpoint node not found\n");
> +               return -EINVAL;
> +       }
> +
> +       ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &ep);
> +       fwnode_handle_put(endpoint);
> +       if (ret == -ENXIO) {
> +               dev_err(&client->dev, "Unsupported bus type, should be CSI2\n");
> +               goto error_endpoint_poweron;
> +       } else if (ret) {
> +               dev_err(&client->dev, "Parsing endpoint node failed\n");
> +               goto error_endpoint_poweron;
> +       }
> +
> +       /* Get number of data lanes */
> +       imx258->nlanes = ep.bus.mipi_csi2.num_data_lanes;
> +       if (imx258->nlanes != 2 && imx258->nlanes != 4) {
> +               dev_err(&client->dev, "Invalid data lanes: %u\n",
> +                       imx258->nlanes);
> +               ret = -EINVAL;
> +               goto error_endpoint_poweron;
> +       }
> +
>         /* Initialize subdev */
>         v4l2_i2c_subdev_init(&imx258->sd, client, &imx258_subdev_ops);
>
>         /* Will be powered off via pm_runtime_idle */
>         ret = imx258_power_on(&client->dev);
>         if (ret)
> -               return ret;
> +               goto error_endpoint_poweron;
>
>         /* Check module identity */
>         ret = imx258_identify_module(imx258);
> @@ -1255,6 +1414,7 @@ static int imx258_probe(struct i2c_client *client)
>         pm_runtime_set_active(&client->dev);
>         pm_runtime_enable(&client->dev);
>         pm_runtime_idle(&client->dev);
> +       v4l2_fwnode_endpoint_free(&endpoint);

Apologies, I've messed up in making a last minute change to fix this
leak, and didn't hit compile again :-(

This should be
   v4l2_fwnode_endpoint_free(&ep);
as in the error path below.

I'll wait a few days to action any early review comments made, and
then send a v2 fixing that up.

  Dave

>
>         return 0;
>
> @@ -1267,6 +1427,9 @@ static int imx258_probe(struct i2c_client *client)
>  error_identify:
>         imx258_power_off(&client->dev);
>
> +error_endpoint_poweron:
> +       v4l2_fwnode_endpoint_free(&ep);
> +
>         return ret;
>  }
>
> --
> 2.25.1
>

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

* Re: [PATCH 19/21] dt-bindings: media: imx258: Add alternate compatible strings
  2023-05-30 17:29 ` [PATCH 19/21] dt-bindings: media: imx258: Add alternate compatible strings Dave Stevenson
@ 2023-05-30 17:38   ` Conor Dooley
  2023-05-30 17:48     ` Dave Stevenson
  0 siblings, 1 reply; 54+ messages in thread
From: Conor Dooley @ 2023-05-30 17:38 UTC (permalink / raw)
  To: Dave Stevenson
  Cc: Sakari Ailus, linux-media, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree

[-- Attachment #1: Type: text/plain, Size: 1536 bytes --]

Hey Dave,

On Tue, May 30, 2023 at 06:29:58PM +0100, Dave Stevenson wrote:
> There are a number of variants of the imx258 modules that can not
> be differentiated at runtime, so add compatible strings for them.
> 
> Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
> ---
>  .../devicetree/bindings/media/i2c/sony,imx258.yaml         | 7 ++++++-
>  1 file changed, 6 insertions(+), 1 deletion(-)
> 
> diff --git a/Documentation/devicetree/bindings/media/i2c/sony,imx258.yaml b/Documentation/devicetree/bindings/media/i2c/sony,imx258.yaml
> index bee61a443b23..3415b26b5991 100644
> --- a/Documentation/devicetree/bindings/media/i2c/sony,imx258.yaml
> +++ b/Documentation/devicetree/bindings/media/i2c/sony,imx258.yaml
> @@ -14,10 +14,15 @@ description: |-
>    type stacked image sensor with a square pixel array of size 4208 x 3120. It
>    is programmable through I2C interface.  Image data is sent through MIPI
>    CSI-2.
> +  There are a number of variants of the sensor which cannot be detected at
> +  runtime, so multiple compatible strings are required to differentiate these.

This is implied by having several compatibles.

>  properties:
>    compatible:
> -    const: sony,imx258
> +    oneOf:
> +      - enum:
> +          - sony,imx258
> +          - sony,imx258-pdaf

Why not just
properties:
  compatible:
    enum:
?
I don't see other patches anding more complex compatibles (or they've
not arrived yet) so it doesn't appear to be avoiding churn.

Cheers,
Conor.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

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

* Re: [PATCH 19/21] dt-bindings: media: imx258: Add alternate compatible strings
  2023-05-30 17:38   ` Conor Dooley
@ 2023-05-30 17:48     ` Dave Stevenson
  2023-05-30 19:36       ` Conor Dooley
  0 siblings, 1 reply; 54+ messages in thread
From: Dave Stevenson @ 2023-05-30 17:48 UTC (permalink / raw)
  To: Conor Dooley
  Cc: Sakari Ailus, linux-media, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree

Hi Conor

Thanks for the incredibly speedy review.

On Tue, 30 May 2023 at 18:39, Conor Dooley <conor@kernel.org> wrote:
>
> Hey Dave,
>
> On Tue, May 30, 2023 at 06:29:58PM +0100, Dave Stevenson wrote:
> > There are a number of variants of the imx258 modules that can not
> > be differentiated at runtime, so add compatible strings for them.
> >
> > Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
> > ---
> >  .../devicetree/bindings/media/i2c/sony,imx258.yaml         | 7 ++++++-
> >  1 file changed, 6 insertions(+), 1 deletion(-)
> >
> > diff --git a/Documentation/devicetree/bindings/media/i2c/sony,imx258.yaml b/Documentation/devicetree/bindings/media/i2c/sony,imx258.yaml
> > index bee61a443b23..3415b26b5991 100644
> > --- a/Documentation/devicetree/bindings/media/i2c/sony,imx258.yaml
> > +++ b/Documentation/devicetree/bindings/media/i2c/sony,imx258.yaml
> > @@ -14,10 +14,15 @@ description: |-
> >    type stacked image sensor with a square pixel array of size 4208 x 3120. It
> >    is programmable through I2C interface.  Image data is sent through MIPI
> >    CSI-2.
> > +  There are a number of variants of the sensor which cannot be detected at
> > +  runtime, so multiple compatible strings are required to differentiate these.
>
> This is implied by having several compatibles.

I'm happy to drop it, just that I've seen a number of media bindings
that had debate on why extra compatible strings were required.

> >  properties:
> >    compatible:
> > -    const: sony,imx258
> > +    oneOf:
> > +      - enum:
> > +          - sony,imx258
> > +          - sony,imx258-pdaf
>
> Why not just
> properties:
>   compatible:
>     enum:
> ?
> I don't see other patches anding more complex compatibles (or they've
> not arrived yet) so it doesn't appear to be avoiding churn.

I'll freely admit that DT bindings are a black art to me, so I was
following sony,imx290.yaml [1].
properties:
  compatible:
    oneOf:
      - enum:
          - sony,imx290lqr # Colour
          - sony,imx290llr # Monochrome
          - sony,imx327lqr # Colour
      - const: sony,imx290
        deprecated: true

Looking again at that case, I assume the oneOf is selecting between
the enum and the const? Seeing as we don't have the const, I guess we
can drop the "oneOf:"

Thanks for your help.

  Dave

[1] https://github.com/torvalds/linux/blob/master/Documentation/devicetree/bindings/media/i2c/sony%2Cimx290.yaml#L27-L34

> Cheers,
> Conor.

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

* Re: [PATCH 19/21] dt-bindings: media: imx258: Add alternate compatible strings
  2023-05-30 17:48     ` Dave Stevenson
@ 2023-05-30 19:36       ` Conor Dooley
  0 siblings, 0 replies; 54+ messages in thread
From: Conor Dooley @ 2023-05-30 19:36 UTC (permalink / raw)
  To: Dave Stevenson
  Cc: Sakari Ailus, linux-media, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree

[-- Attachment #1: Type: text/plain, Size: 2861 bytes --]

On Tue, May 30, 2023 at 06:48:44PM +0100, Dave Stevenson wrote:
> Thanks for the incredibly speedy review.

Just happened to change mailboxes right as it arrived ;)

> On Tue, 30 May 2023 at 18:39, Conor Dooley <conor@kernel.org> wrote:
> >
> > Hey Dave,
> >
> > On Tue, May 30, 2023 at 06:29:58PM +0100, Dave Stevenson wrote:
> > > There are a number of variants of the imx258 modules that can not
> > > be differentiated at runtime, so add compatible strings for them.
> > >
> > > Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
> > > ---
> > >  .../devicetree/bindings/media/i2c/sony,imx258.yaml         | 7 ++++++-
> > >  1 file changed, 6 insertions(+), 1 deletion(-)
> > >
> > > diff --git a/Documentation/devicetree/bindings/media/i2c/sony,imx258.yaml b/Documentation/devicetree/bindings/media/i2c/sony,imx258.yaml
> > > index bee61a443b23..3415b26b5991 100644
> > > --- a/Documentation/devicetree/bindings/media/i2c/sony,imx258.yaml
> > > +++ b/Documentation/devicetree/bindings/media/i2c/sony,imx258.yaml
> > > @@ -14,10 +14,15 @@ description: |-
> > >    type stacked image sensor with a square pixel array of size 4208 x 3120. It
> > >    is programmable through I2C interface.  Image data is sent through MIPI
> > >    CSI-2.
> > > +  There are a number of variants of the sensor which cannot be detected at
> > > +  runtime, so multiple compatible strings are required to differentiate these.
> >
> > This is implied by having several compatibles.
> 
> I'm happy to drop it, just that I've seen a number of media bindings
> that had debate on why extra compatible strings were required.

If there were no non-detectable differences, then there should be
a fallback compatible i.e.
compatible = "sony,imx666-foo", "sony,imx666";
Maybe Laurent will come in here and scream at me, but I don't think the
pattern should be propagated.

> > >  properties:
> > >    compatible:
> > > -    const: sony,imx258
> > > +    oneOf:
> > > +      - enum:
> > > +          - sony,imx258
> > > +          - sony,imx258-pdaf
> >
> > Why not just
> > properties:
> >   compatible:
> >     enum:
> > ?
> > I don't see other patches anding more complex compatibles (or they've
> > not arrived yet) so it doesn't appear to be avoiding churn.
> 
> I'll freely admit that DT bindings are a black art to me, so I was
> following sony,imx290.yaml [1].
> properties:
>   compatible:
>     oneOf:
>       - enum:
>           - sony,imx290lqr # Colour
>           - sony,imx290llr # Monochrome
>           - sony,imx327lqr # Colour
>       - const: sony,imx290
>         deprecated: true
> 
> Looking again at that case, I assume the oneOf is selecting between
> the enum and the const?

Bingo!

> Seeing as we don't have the const, I guess we
> can drop the "oneOf:"

Cheers,
Conor.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

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

* Re: [PATCH 09/21] media: i2c: imx258: Add support for running on 2 CSI data lanes
  2023-05-30 17:29 ` [PATCH 09/21] media: i2c: imx258: Add support for running on 2 CSI data lanes Dave Stevenson
  2023-05-30 17:37   ` Dave Stevenson
@ 2023-05-31  8:07   ` kernel test robot
  2023-06-02 13:23   ` Jacopo Mondi
  2 siblings, 0 replies; 54+ messages in thread
From: kernel test robot @ 2023-05-31  8:07 UTC (permalink / raw)
  To: Dave Stevenson, Sakari Ailus, linux-media, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, devicetree
  Cc: oe-kbuild-all, Dave Stevenson

Hi Dave,

kernel test robot noticed the following build errors:

[auto build test ERROR on media-tree/master]
[also build test ERROR on linus/master v6.4-rc4 next-20230531]
[cannot apply to robh/for-next sailus-media-tree/streams]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Dave-Stevenson/media-i2c-imx258-Remove-unused-defines/20230531-013342
base:   git://linuxtv.org/media_tree.git master
patch link:    https://lore.kernel.org/r/20230530173000.3060865-10-dave.stevenson%40raspberrypi.com
patch subject: [PATCH 09/21] media: i2c: imx258: Add support for running on 2 CSI data lanes
config: m68k-allmodconfig (https://download.01.org/0day-ci/archive/20230531/202305311525.0POx1Mzk-lkp@intel.com/config)
compiler: m68k-linux-gcc (GCC) 12.3.0
reproduce (this is a W=1 build):
        mkdir -p ~/bin
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/e3fbe7eaf1c1b9f3b031308dbd3433a982bd3fe6
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Dave-Stevenson/media-i2c-imx258-Remove-unused-defines/20230531-013342
        git checkout e3fbe7eaf1c1b9f3b031308dbd3433a982bd3fe6
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.3.0 ~/bin/make.cross W=1 O=build_dir ARCH=m68k olddefconfig
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.3.0 ~/bin/make.cross W=1 O=build_dir ARCH=m68k SHELL=/bin/bash drivers/media/i2c/

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202305311525.0POx1Mzk-lkp@intel.com/

All errors (new ones prefixed by >>):

   drivers/media/i2c/imx258.c: In function 'imx258_probe':
>> drivers/media/i2c/imx258.c:1417:35: error: passing argument 1 of 'v4l2_fwnode_endpoint_free' from incompatible pointer type [-Werror=incompatible-pointer-types]
    1417 |         v4l2_fwnode_endpoint_free(&endpoint);
         |                                   ^~~~~~~~~
         |                                   |
         |                                   struct fwnode_handle **
   In file included from drivers/media/i2c/imx258.c:13:
   include/media/v4l2-fwnode.h:239:61: note: expected 'struct v4l2_fwnode_endpoint *' but argument is of type 'struct fwnode_handle **'
     239 | void v4l2_fwnode_endpoint_free(struct v4l2_fwnode_endpoint *vep);
         |                                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~
   cc1: some warnings being treated as errors


vim +/v4l2_fwnode_endpoint_free +1417 drivers/media/i2c/imx258.c

  1303	
  1304	static int imx258_probe(struct i2c_client *client)
  1305	{
  1306		struct imx258 *imx258;
  1307		struct fwnode_handle *endpoint;
  1308		struct v4l2_fwnode_endpoint ep = {
  1309			.bus_type = V4L2_MBUS_CSI2_DPHY
  1310		};
  1311		int ret;
  1312		u32 val = 0;
  1313	
  1314		imx258 = devm_kzalloc(&client->dev, sizeof(*imx258), GFP_KERNEL);
  1315		if (!imx258)
  1316			return -ENOMEM;
  1317	
  1318		ret = imx258_get_regulators(imx258, client);
  1319		if (ret)
  1320			return ret;
  1321	
  1322		imx258->clk = devm_clk_get_optional(&client->dev, NULL);
  1323		if (IS_ERR(imx258->clk))
  1324			return dev_err_probe(&client->dev, PTR_ERR(imx258->clk),
  1325					     "error getting clock\n");
  1326		if (!imx258->clk) {
  1327			dev_dbg(&client->dev,
  1328				"no clock provided, using clock-frequency property\n");
  1329	
  1330			device_property_read_u32(&client->dev, "clock-frequency", &val);
  1331		} else if (IS_ERR(imx258->clk)) {
  1332			return dev_err_probe(&client->dev, PTR_ERR(imx258->clk),
  1333					     "error getting clock\n");
  1334		} else {
  1335			val = clk_get_rate(imx258->clk);
  1336		}
  1337	
  1338		switch (val) {
  1339		case 19200000:
  1340			imx258->link_freq_configs = link_freq_configs_19_2;
  1341			imx258->link_freq_menu_items = link_freq_menu_items_19_2;
  1342			break;
  1343		case 24000000:
  1344			imx258->link_freq_configs = link_freq_configs_24;
  1345			imx258->link_freq_menu_items = link_freq_menu_items_24;
  1346			break;
  1347		default:
  1348			dev_err(&client->dev, "input clock frequency of %u not supported\n",
  1349				val);
  1350			return -EINVAL;
  1351		}
  1352	
  1353		endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev), NULL);
  1354		if (!endpoint) {
  1355			dev_err(&client->dev, "Endpoint node not found\n");
  1356			return -EINVAL;
  1357		}
  1358	
  1359		ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &ep);
  1360		fwnode_handle_put(endpoint);
  1361		if (ret == -ENXIO) {
  1362			dev_err(&client->dev, "Unsupported bus type, should be CSI2\n");
  1363			goto error_endpoint_poweron;
  1364		} else if (ret) {
  1365			dev_err(&client->dev, "Parsing endpoint node failed\n");
  1366			goto error_endpoint_poweron;
  1367		}
  1368	
  1369		/* Get number of data lanes */
  1370		imx258->nlanes = ep.bus.mipi_csi2.num_data_lanes;
  1371		if (imx258->nlanes != 2 && imx258->nlanes != 4) {
  1372			dev_err(&client->dev, "Invalid data lanes: %u\n",
  1373				imx258->nlanes);
  1374			ret = -EINVAL;
  1375			goto error_endpoint_poweron;
  1376		}
  1377	
  1378		/* Initialize subdev */
  1379		v4l2_i2c_subdev_init(&imx258->sd, client, &imx258_subdev_ops);
  1380	
  1381		/* Will be powered off via pm_runtime_idle */
  1382		ret = imx258_power_on(&client->dev);
  1383		if (ret)
  1384			goto error_endpoint_poweron;
  1385	
  1386		/* Check module identity */
  1387		ret = imx258_identify_module(imx258);
  1388		if (ret)
  1389			goto error_identify;
  1390	
  1391		/* Set default mode to max resolution */
  1392		imx258->cur_mode = &supported_modes[0];
  1393	
  1394		ret = imx258_init_controls(imx258);
  1395		if (ret)
  1396			goto error_identify;
  1397	
  1398		/* Initialize subdev */
  1399		imx258->sd.internal_ops = &imx258_internal_ops;
  1400		imx258->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
  1401		imx258->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
  1402	
  1403		/* Initialize source pad */
  1404		imx258->pad.flags = MEDIA_PAD_FL_SOURCE;
  1405	
  1406		ret = media_entity_pads_init(&imx258->sd.entity, 1, &imx258->pad);
  1407		if (ret)
  1408			goto error_handler_free;
  1409	
  1410		ret = v4l2_async_register_subdev_sensor(&imx258->sd);
  1411		if (ret < 0)
  1412			goto error_media_entity;
  1413	
  1414		pm_runtime_set_active(&client->dev);
  1415		pm_runtime_enable(&client->dev);
  1416		pm_runtime_idle(&client->dev);
> 1417		v4l2_fwnode_endpoint_free(&endpoint);
  1418	
  1419		return 0;
  1420	
  1421	error_media_entity:
  1422		media_entity_cleanup(&imx258->sd.entity);
  1423	
  1424	error_handler_free:
  1425		imx258_free_controls(imx258);
  1426	
  1427	error_identify:
  1428		imx258_power_off(&client->dev);
  1429	
  1430	error_endpoint_poweron:
  1431		v4l2_fwnode_endpoint_free(&ep);
  1432	
  1433		return ret;
  1434	}
  1435	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

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

* Re: [PATCH 03/21] media: i2c: imx258: Disable digital cropping on binned modes
  2023-05-30 17:29 ` [PATCH 03/21] media: i2c: imx258: Disable digital cropping on binned modes Dave Stevenson
@ 2023-05-31 15:02   ` Jacopo Mondi
  0 siblings, 0 replies; 54+ messages in thread
From: Jacopo Mondi @ 2023-05-31 15:02 UTC (permalink / raw)
  To: Dave Stevenson
  Cc: Sakari Ailus, linux-media, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree

Hi Dave

On Tue, May 30, 2023 at 06:29:42PM +0100, Dave Stevenson wrote:
> The binned modes set DIG_CROP_X_OFFSET and DIG_CROP_IMAGE_WIDTH
> to less than the full image, even though the image being captured
> is meant to be a scaled version of the full array size.
>
> Reduce X_OFFSET to 0, and increase IMAGE_WIDTH to the full array.

Do I read it wrong that:

Digital crop is processed after image readout operation or in order of
[Analog crop -> Binning -> Digital crop]

Hence the digital crop output should be set to the frame output size
and not to the analog crop sizes ? In facts the DIG_CROP_IMAGE_HEIGHT
values match the frame output height.

>
> Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
> ---
>  drivers/media/i2c/imx258.c | 8 ++++----
>  1 file changed, 4 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
> index 946b1a12971d..aabd5c3e8af9 100644
> --- a/drivers/media/i2c/imx258.c
> +++ b/drivers/media/i2c/imx258.c
> @@ -340,11 +340,11 @@ static const struct imx258_reg mode_2104_1560_regs[] = {
>  	{ 0x0404, 0x00 },
>  	{ 0x0405, 0x20 },
>  	{ 0x0408, 0x00 },
> -	{ 0x0409, 0x02 },
> +	{ 0x0409, 0x00 },
>  	{ 0x040A, 0x00 },
>  	{ 0x040B, 0x00 },
>  	{ 0x040C, 0x10 },
> -	{ 0x040D, 0x6A },
> +	{ 0x040D, 0x70 },

DIG_CROP_IMAGE_WIDTH = 0x1070 = 4208

>  	{ 0x040E, 0x06 },
>  	{ 0x040F, 0x18 },

DIG_CROP_IMAGE_HEIGHT = 0x618 = 1560

>  	{ 0x3038, 0x00 },
> @@ -459,11 +459,11 @@ static const struct imx258_reg mode_1048_780_regs[] = {
>  	{ 0x0404, 0x00 },
>  	{ 0x0405, 0x40 },
>  	{ 0x0408, 0x00 },
> -	{ 0x0409, 0x06 },
> +	{ 0x0409, 0x00 },
>  	{ 0x040A, 0x00 },
>  	{ 0x040B, 0x00 },
>  	{ 0x040C, 0x10 },
> -	{ 0x040D, 0x64 },
> +	{ 0x040D, 0x70 },

DIG_CROP_IMAGE_WIDTH = 0x1070 = 4208

>  	{ 0x040E, 0x03 },
>  	{ 0x040F, 0x0C },

DIG_CROP_IMAGE_HEIGHT = 0x30c = 780

Should DIG_CROP_IMAGE_WIDTH be set to 2104 and 1048 respectively ?


>  	{ 0x3038, 0x00 },
> --
> 2.25.1
>

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

* Re: [PATCH 01/21] media: i2c: imx258: Remove unused defines
  2023-05-30 17:29 ` [PATCH 01/21] media: i2c: imx258: Remove unused defines Dave Stevenson
@ 2023-05-31 15:08   ` Jacopo Mondi
  0 siblings, 0 replies; 54+ messages in thread
From: Jacopo Mondi @ 2023-05-31 15:08 UTC (permalink / raw)
  To: Dave Stevenson
  Cc: Sakari Ailus, linux-media, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree

Hi Dave

On Tue, May 30, 2023 at 06:29:40PM +0100, Dave Stevenson wrote:
> The IMX258_FLL_* defines are unused. Remove them.
>
> Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>

Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>

> ---
>  drivers/media/i2c/imx258.c | 6 ------
>  1 file changed, 6 deletions(-)
>
> diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
> index 85d73b186111..6028579393b5 100644
> --- a/drivers/media/i2c/imx258.c
> +++ b/drivers/media/i2c/imx258.c
> @@ -29,12 +29,6 @@
>  #define IMX258_VTS_30FPS_VGA		0x034c
>  #define IMX258_VTS_MAX			0xffff
>
> -/*Frame Length Line*/
> -#define IMX258_FLL_MIN			0x08a6
> -#define IMX258_FLL_MAX			0xffff
> -#define IMX258_FLL_STEP			1
> -#define IMX258_FLL_DEFAULT		0x0c98
> -
>  /* HBLANK control - read only */
>  #define IMX258_PPL_DEFAULT		5352
>
> --
> 2.25.1
>

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

* Re: [PATCH 02/21] media: i2c: imx258: Make image geometry meet sensor requirements
  2023-05-30 17:29 ` [PATCH 02/21] media: i2c: imx258: Make image geometry meet sensor requirements Dave Stevenson
@ 2023-05-31 15:09   ` Jacopo Mondi
  0 siblings, 0 replies; 54+ messages in thread
From: Jacopo Mondi @ 2023-05-31 15:09 UTC (permalink / raw)
  To: Dave Stevenson
  Cc: Sakari Ailus, linux-media, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree

Hi Dave

On Tue, May 30, 2023 at 06:29:41PM +0100, Dave Stevenson wrote:
> The output image is defined as being 4208x3118 pixels in size.
> Y_ADD_STA register was set to 0, and Y_ADD_END to 3118, giving
> 3119 lines total.
>
> The datasheet lists a requirement for Y_ADD_STA to be a multiple
> of a power of 2 depending on binning/scaling mode (2 for full pixel,
> 4 for x2-bin/scale, 8 for (x2-bin)+(x2-subsample) or x4-bin, or 16
> for (x4-bin)+(x2-subsample)).
> (Y_ADD_END – Y_ADD_STA + 1) also has to be a similar power of 2.
>
> The current configuration for the full res modes breaks that second
> requirement, and we can't increase Y_ADD_STA to 1 to retain exactly
> the same field of view as that then breaks the first requirement.
> For the binned modes, they are worse off as 3118 is not a multiple of
> 4.
>
> Increase the main mode to 4208x3120 so that it is the same FOV as the
> binned modes, with Y_ADD_STA at 0.
> Fix Y_ADD_STA and Y_ADD_END for the binned modes so that they meet the
> sensor requirements.
>
> This does change the Bayer order as the default configuration is for
> H&V flips to be enabled, so readout is from Y_STA_END to Y_ADD_STA,
> and this patch has changed Y_STA_END.
>
> Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>

Good catch!
Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>

> ---
>  drivers/media/i2c/imx258.c | 26 +++++++++++++-------------
>  1 file changed, 13 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
> index 6028579393b5..946b1a12971d 100644
> --- a/drivers/media/i2c/imx258.c
> +++ b/drivers/media/i2c/imx258.c
> @@ -111,7 +111,7 @@ struct imx258_mode {
>  	struct imx258_reg_list reg_list;
>  };
>
> -/* 4208x3118 needs 1267Mbps/lane, 4 lanes */
> +/* 4208x3120 needs 1267Mbps/lane, 4 lanes */
>  static const struct imx258_reg mipi_data_rate_1267mbps[] = {
>  	{ 0x0301, 0x05 },
>  	{ 0x0303, 0x02 },
> @@ -148,7 +148,7 @@ static const struct imx258_reg mipi_data_rate_640mbps[] = {
>  	{ 0x0823, 0x00 },
>  };
>
> -static const struct imx258_reg mode_4208x3118_regs[] = {
> +static const struct imx258_reg mode_4208x3120_regs[] = {
>  	{ 0x0136, 0x13 },
>  	{ 0x0137, 0x33 },
>  	{ 0x3051, 0x00 },
> @@ -210,7 +210,7 @@ static const struct imx258_reg mode_4208x3118_regs[] = {
>  	{ 0x0348, 0x10 },
>  	{ 0x0349, 0x6F },
>  	{ 0x034A, 0x0C },
> -	{ 0x034B, 0x2E },
> +	{ 0x034B, 0x2F },
>  	{ 0x0381, 0x01 },
>  	{ 0x0383, 0x01 },
>  	{ 0x0385, 0x01 },
> @@ -329,7 +329,7 @@ static const struct imx258_reg mode_2104_1560_regs[] = {
>  	{ 0x0348, 0x10 },
>  	{ 0x0349, 0x6F },
>  	{ 0x034A, 0x0C },
> -	{ 0x034B, 0x2E },
> +	{ 0x034B, 0x2F },
>  	{ 0x0381, 0x01 },
>  	{ 0x0383, 0x01 },
>  	{ 0x0385, 0x01 },
> @@ -448,7 +448,7 @@ static const struct imx258_reg mode_1048_780_regs[] = {
>  	{ 0x0348, 0x10 },
>  	{ 0x0349, 0x6F },
>  	{ 0x034A, 0x0C },
> -	{ 0x034B, 0x2E },
> +	{ 0x034B, 0x2F },
>  	{ 0x0381, 0x01 },
>  	{ 0x0383, 0x01 },
>  	{ 0x0385, 0x01 },
> @@ -562,12 +562,12 @@ static const struct imx258_link_freq_config link_freq_configs[] = {
>  static const struct imx258_mode supported_modes[] = {
>  	{
>  		.width = 4208,
> -		.height = 3118,
> +		.height = 3120,
>  		.vts_def = IMX258_VTS_30FPS,
>  		.vts_min = IMX258_VTS_30FPS,
>  		.reg_list = {
> -			.num_of_regs = ARRAY_SIZE(mode_4208x3118_regs),
> -			.regs = mode_4208x3118_regs,
> +			.num_of_regs = ARRAY_SIZE(mode_4208x3120_regs),
> +			.regs = mode_4208x3120_regs,
>  		},
>  		.link_freq_index = IMX258_LINK_FREQ_1267MBPS,
>  	},
> @@ -710,7 +710,7 @@ static int imx258_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
>  	/* Initialize try_fmt */
>  	try_fmt->width = supported_modes[0].width;
>  	try_fmt->height = supported_modes[0].height;
> -	try_fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10;
> +	try_fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
>  	try_fmt->field = V4L2_FIELD_NONE;
>
>  	return 0;
> @@ -822,7 +822,7 @@ static int imx258_enum_mbus_code(struct v4l2_subdev *sd,
>  	if (code->index > 0)
>  		return -EINVAL;
>
> -	code->code = MEDIA_BUS_FMT_SGRBG10_1X10;
> +	code->code = MEDIA_BUS_FMT_SBGGR10_1X10;
>
>  	return 0;
>  }
> @@ -834,7 +834,7 @@ static int imx258_enum_frame_size(struct v4l2_subdev *sd,
>  	if (fse->index >= ARRAY_SIZE(supported_modes))
>  		return -EINVAL;
>
> -	if (fse->code != MEDIA_BUS_FMT_SGRBG10_1X10)
> +	if (fse->code != MEDIA_BUS_FMT_SBGGR10_1X10)
>  		return -EINVAL;
>
>  	fse->min_width = supported_modes[fse->index].width;
> @@ -850,7 +850,7 @@ static void imx258_update_pad_format(const struct imx258_mode *mode,
>  {
>  	fmt->format.width = mode->width;
>  	fmt->format.height = mode->height;
> -	fmt->format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
> +	fmt->format.code = MEDIA_BUS_FMT_SBGGR10_1X10;
>  	fmt->format.field = V4L2_FIELD_NONE;
>  }
>
> @@ -898,7 +898,7 @@ static int imx258_set_pad_format(struct v4l2_subdev *sd,
>  	mutex_lock(&imx258->mutex);
>
>  	/* Only one raw bayer(GBRG) order is supported */
> -	fmt->format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
> +	fmt->format.code = MEDIA_BUS_FMT_SBGGR10_1X10;
>
>  	mode = v4l2_find_nearest_size(supported_modes,
>  		ARRAY_SIZE(supported_modes), width, height,
> --
> 2.25.1
>

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

* Re: [PATCH 04/21] media: i2c: imx258: Remove redundant I2C writes.
  2023-05-30 17:29 ` [PATCH 04/21] media: i2c: imx258: Remove redundant I2C writes Dave Stevenson
@ 2023-05-31 15:10   ` Jacopo Mondi
  0 siblings, 0 replies; 54+ messages in thread
From: Jacopo Mondi @ 2023-05-31 15:10 UTC (permalink / raw)
  To: Dave Stevenson
  Cc: Sakari Ailus, linux-media, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree

Hi Dave

On Tue, May 30, 2023 at 06:29:43PM +0100, Dave Stevenson wrote:
> Registers 0x0202 and 0x0203 are written via the control handler
> for V4L2_CID_EXPOSURE, so are not needed from the mode lists.
>
> Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>

Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>

> ---
>  drivers/media/i2c/imx258.c | 6 ------
>  1 file changed, 6 deletions(-)
>
> diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
> index aabd5c3e8af9..b695fd987b71 100644
> --- a/drivers/media/i2c/imx258.c
> +++ b/drivers/media/i2c/imx258.c
> @@ -237,8 +237,6 @@ static const struct imx258_reg mode_4208x3120_regs[] = {
>  	{ 0x034E, 0x0C },
>  	{ 0x034F, 0x30 },
>  	{ 0x0350, 0x01 },
> -	{ 0x0202, 0x0C },
> -	{ 0x0203, 0x46 },
>  	{ 0x0204, 0x00 },
>  	{ 0x0205, 0x00 },
>  	{ 0x020E, 0x01 },
> @@ -356,8 +354,6 @@ static const struct imx258_reg mode_2104_1560_regs[] = {
>  	{ 0x034E, 0x06 },
>  	{ 0x034F, 0x18 },
>  	{ 0x0350, 0x01 },
> -	{ 0x0202, 0x06 },
> -	{ 0x0203, 0x2E },
>  	{ 0x0204, 0x00 },
>  	{ 0x0205, 0x00 },
>  	{ 0x020E, 0x01 },
> @@ -475,8 +471,6 @@ static const struct imx258_reg mode_1048_780_regs[] = {
>  	{ 0x034E, 0x03 },
>  	{ 0x034F, 0x0C },
>  	{ 0x0350, 0x01 },
> -	{ 0x0202, 0x03 },
> -	{ 0x0203, 0x42 },
>  	{ 0x0204, 0x00 },
>  	{ 0x0205, 0x00 },
>  	{ 0x020E, 0x01 },
> --
> 2.25.1
>

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

* Re: [PATCH 05/21] media: i2c: imx258: Add regulator control
  2023-05-30 17:29 ` [PATCH 05/21] media: i2c: imx258: Add regulator control Dave Stevenson
@ 2023-05-31 15:11   ` Jacopo Mondi
  2023-05-31 15:26     ` Dave Stevenson
  0 siblings, 1 reply; 54+ messages in thread
From: Jacopo Mondi @ 2023-05-31 15:11 UTC (permalink / raw)
  To: Dave Stevenson
  Cc: Sakari Ailus, linux-media, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree

Hi Dave

On Tue, May 30, 2023 at 06:29:44PM +0100, Dave Stevenson wrote:
> The device tree bindings define the relevant regulators for the
> sensor, so update the driver to request the regulators and control
> them at the appropriate times.
>
> Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
> ---
>  drivers/media/i2c/imx258.c | 42 +++++++++++++++++++++++++++++++++++++-
>  1 file changed, 41 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
> index b695fd987b71..30bae7388c3a 100644
> --- a/drivers/media/i2c/imx258.c
> +++ b/drivers/media/i2c/imx258.c
> @@ -7,6 +7,7 @@
>  #include <linux/i2c.h>
>  #include <linux/module.h>
>  #include <linux/pm_runtime.h>
> +#include <linux/regulator/consumer.h>
>  #include <media/v4l2-ctrls.h>
>  #include <media/v4l2-device.h>
>  #include <media/v4l2-fwnode.h>
> @@ -507,6 +508,16 @@ static const char * const imx258_test_pattern_menu[] = {
>  	"Pseudorandom Sequence (PN9)",
>  };
>
> +/* regulator supplies */
> +static const char * const imx258_supply_name[] = {
> +	/* Supplies can be enabled in any order */
> +	"vana",  /* Analog (2.8V) supply */
> +	"vdig",  /* Digital Core (1.2V) supply */
> +	"vif",  /* IF (1.8V) supply */
> +};
> +
> +#define IMX258_NUM_SUPPLIES ARRAY_SIZE(imx258_supply_name)
> +
>  /* Configurations for supported link frequencies */
>  #define IMX258_LINK_FREQ_634MHZ	633600000ULL
>  #define IMX258_LINK_FREQ_320MHZ	320000000ULL
> @@ -614,6 +625,7 @@ struct imx258 {
>  	bool streaming;
>
>  	struct clk *clk;
> +	struct regulator_bulk_data supplies[IMX258_NUM_SUPPLIES];
>  };
>
>  static inline struct imx258 *to_imx258(struct v4l2_subdev *_sd)
> @@ -999,9 +1011,19 @@ static int imx258_power_on(struct device *dev)
>  	struct imx258 *imx258 = to_imx258(sd);
>  	int ret;
>
> +	ret = regulator_bulk_enable(IMX258_NUM_SUPPLIES,
> +				    imx258->supplies);
> +	if (ret) {
> +		dev_err(dev, "%s: failed to enable regulators\n",
> +			__func__);
> +		return ret;
> +	}
> +
>  	ret = clk_prepare_enable(imx258->clk);
> -	if (ret)
> +	if (ret) {
>  		dev_err(dev, "failed to enable clock\n");
> +		regulator_bulk_disable(IMX258_NUM_SUPPLIES, imx258->supplies);
> +	}
>
>  	return ret;
>  }
> @@ -1012,6 +1034,7 @@ static int imx258_power_off(struct device *dev)
>  	struct imx258 *imx258 = to_imx258(sd);
>
>  	clk_disable_unprepare(imx258->clk);
> +	regulator_bulk_disable(IMX258_NUM_SUPPLIES, imx258->supplies);
>
>  	return 0;
>  }
> @@ -1260,6 +1283,19 @@ static void imx258_free_controls(struct imx258 *imx258)
>  	mutex_destroy(&imx258->mutex);
>  }
>
> +static int imx258_get_regulators(struct imx258 *imx258,
> +				 struct i2c_client *client)
> +{
> +	unsigned int i;
> +
> +	for (i = 0; i < IMX258_NUM_SUPPLIES; i++)
> +		imx258->supplies[i].supply = imx258_supply_name[i];
> +
> +	return devm_regulator_bulk_get(&client->dev,
> +				       IMX258_NUM_SUPPLIES,
> +				       imx258->supplies);

nit: fits on 2 lines

> +}
> +
>  static int imx258_probe(struct i2c_client *client)
>  {
>  	struct imx258 *imx258;
> @@ -1270,6 +1306,10 @@ static int imx258_probe(struct i2c_client *client)
>  	if (!imx258)
>  		return -ENOMEM;
>
> +	ret = imx258_get_regulators(imx258, client);
> +	if (ret)
> +		return ret;

Is dev_err_probe() useful here ?

> +
>  	imx258->clk = devm_clk_get_optional(&client->dev, NULL);
>  	if (IS_ERR(imx258->clk))
>  		return dev_err_probe(&client->dev, PTR_ERR(imx258->clk),
> --
> 2.25.1
>

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

* Re: [PATCH 06/21] media: i2c: imx258: Make V4L2_CID_VBLANK configurable.
  2023-05-30 17:29 ` [PATCH 06/21] media: i2c: imx258: Make V4L2_CID_VBLANK configurable Dave Stevenson
@ 2023-05-31 15:16   ` Jacopo Mondi
  2023-05-31 15:33     ` Dave Stevenson
  0 siblings, 1 reply; 54+ messages in thread
From: Jacopo Mondi @ 2023-05-31 15:16 UTC (permalink / raw)
  To: Dave Stevenson
  Cc: Sakari Ailus, linux-media, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree

Hi Dave

On Tue, May 30, 2023 at 06:29:45PM +0100, Dave Stevenson wrote:
> The values and ranges of V4L2_CID_VBLANK are all computed,
> so there is no reason for it to be a read only control.
> Remove the register values from the mode lists, add the
> handler, and remove the read only flag.
>
> Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
> ---
>  drivers/media/i2c/imx258.c | 16 +++++++---------
>  1 file changed, 7 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
> index 30bae7388c3a..c6fb649abb95 100644
> --- a/drivers/media/i2c/imx258.c
> +++ b/drivers/media/i2c/imx258.c
> @@ -30,6 +30,8 @@
>  #define IMX258_VTS_30FPS_VGA		0x034c
>  #define IMX258_VTS_MAX			0xffff
>
> +#define IMX258_REG_VTS			0x0340
> +
>  /* HBLANK control - read only */
>  #define IMX258_PPL_DEFAULT		5352
>
> @@ -202,8 +204,6 @@ static const struct imx258_reg mode_4208x3120_regs[] = {
>  	{ 0x0114, 0x03 },
>  	{ 0x0342, 0x14 },
>  	{ 0x0343, 0xE8 },
> -	{ 0x0340, 0x0C },
> -	{ 0x0341, 0x50 },
>  	{ 0x0344, 0x00 },
>  	{ 0x0345, 0x00 },
>  	{ 0x0346, 0x00 },
> @@ -319,8 +319,6 @@ static const struct imx258_reg mode_2104_1560_regs[] = {
>  	{ 0x0114, 0x03 },
>  	{ 0x0342, 0x14 },
>  	{ 0x0343, 0xE8 },
> -	{ 0x0340, 0x06 },
> -	{ 0x0341, 0x38 },
>  	{ 0x0344, 0x00 },
>  	{ 0x0345, 0x00 },
>  	{ 0x0346, 0x00 },
> @@ -436,8 +434,6 @@ static const struct imx258_reg mode_1048_780_regs[] = {
>  	{ 0x0114, 0x03 },
>  	{ 0x0342, 0x14 },
>  	{ 0x0343, 0xE8 },
> -	{ 0x0340, 0x03 },
> -	{ 0x0341, 0x4C },
>  	{ 0x0344, 0x00 },
>  	{ 0x0345, 0x00 },
>  	{ 0x0346, 0x00 },
> @@ -803,6 +799,11 @@ static int imx258_set_ctrl(struct v4l2_ctrl *ctrl)
>  					       BIT(IMX258_HDR_RATIO_MAX));
>  		}
>  		break;
> +	case V4L2_CID_VBLANK:

Should a new vblank value change the exposure limits too ?

> +		ret = imx258_write_reg(imx258, IMX258_REG_VTS,
> +				       IMX258_REG_VALUE_16BIT,
> +				       imx258->cur_mode->height + ctrl->val);
> +		break;
>  	default:
>  		dev_info(&client->dev,
>  			 "ctrl(id:0x%x,val:0x%x) is not handled\n",
> @@ -1214,9 +1215,6 @@ static int imx258_init_controls(struct imx258 *imx258)
>  				IMX258_VTS_MAX - imx258->cur_mode->height, 1,
>  				vblank_def);
>
> -	if (imx258->vblank)
> -		imx258->vblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
> -
>  	imx258->hblank = v4l2_ctrl_new_std(
>  				ctrl_hdlr, &imx258_ctrl_ops, V4L2_CID_HBLANK,
>  				IMX258_PPL_DEFAULT - imx258->cur_mode->width,
> --
> 2.25.1
>

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

* Re: [PATCH 07/21] media: i2c: imx258: Split out common registers from the mode based ones
  2023-05-30 17:29 ` [PATCH 07/21] media: i2c: imx258: Split out common registers from the mode based ones Dave Stevenson
@ 2023-05-31 15:26   ` Jacopo Mondi
  0 siblings, 0 replies; 54+ messages in thread
From: Jacopo Mondi @ 2023-05-31 15:26 UTC (permalink / raw)
  To: Dave Stevenson
  Cc: Sakari Ailus, linux-media, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree

Hi Dave

On Tue, May 30, 2023 at 06:29:46PM +0100, Dave Stevenson wrote:
> Out of all the registers that are defined for each mode, only around
> 10 differ between the modes.
>
> Split the table into common and mode specific ones.
>
> Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>

I have only visually compared the registers you have grouped together
and they seems to be identical. I have not gone through cut&paste&diff
though

Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>


> ---
>  drivers/media/i2c/imx258.c | 236 ++++---------------------------------
>  1 file changed, 21 insertions(+), 215 deletions(-)
>
> diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
> index c6fb649abb95..5a57d0b5fcd8 100644
> --- a/drivers/media/i2c/imx258.c
> +++ b/drivers/media/i2c/imx258.c
> @@ -151,7 +151,7 @@ static const struct imx258_reg mipi_data_rate_640mbps[] = {
>  	{ 0x0823, 0x00 },
>  };
>
> -static const struct imx258_reg mode_4208x3120_regs[] = {
> +static const struct imx258_reg mode_common_regs[] = {
>  	{ 0x0136, 0x13 },
>  	{ 0x0137, 0x33 },
>  	{ 0x3051, 0x00 },
> @@ -216,27 +216,17 @@ static const struct imx258_reg mode_4208x3120_regs[] = {
>  	{ 0x0383, 0x01 },
>  	{ 0x0385, 0x01 },
>  	{ 0x0387, 0x01 },
> -	{ 0x0900, 0x00 },
> -	{ 0x0901, 0x11 },
> -	{ 0x0401, 0x00 },
>  	{ 0x0404, 0x00 },
> -	{ 0x0405, 0x10 },
>  	{ 0x0408, 0x00 },
>  	{ 0x0409, 0x00 },
>  	{ 0x040A, 0x00 },
>  	{ 0x040B, 0x00 },
>  	{ 0x040C, 0x10 },
>  	{ 0x040D, 0x70 },
> -	{ 0x040E, 0x0C },
> -	{ 0x040F, 0x30 },
>  	{ 0x3038, 0x00 },
>  	{ 0x303A, 0x00 },
>  	{ 0x303B, 0x10 },
>  	{ 0x300D, 0x00 },
> -	{ 0x034C, 0x10 },
> -	{ 0x034D, 0x70 },
> -	{ 0x034E, 0x0C },
> -	{ 0x034F, 0x30 },
>  	{ 0x0350, 0x01 },
>  	{ 0x0204, 0x00 },
>  	{ 0x0205, 0x00 },
> @@ -266,234 +256,43 @@ static const struct imx258_reg mode_4208x3120_regs[] = {
>  	{ 0x0220, 0x00 },
>  };
>
> +static const struct imx258_reg mode_4208x3120_regs[] = {
> +	{ 0x0900, 0x00 },
> +	{ 0x0901, 0x11 },
> +	{ 0x0401, 0x00 },
> +	{ 0x0405, 0x10 },
> +	{ 0x040E, 0x0C },
> +	{ 0x040F, 0x30 },
> +	{ 0x034C, 0x10 },
> +	{ 0x034D, 0x70 },
> +	{ 0x034E, 0x0C },
> +	{ 0x034F, 0x30 },
> +};
> +
>  static const struct imx258_reg mode_2104_1560_regs[] = {
> -	{ 0x0136, 0x13 },
> -	{ 0x0137, 0x33 },
> -	{ 0x3051, 0x00 },
> -	{ 0x3052, 0x00 },
> -	{ 0x4E21, 0x14 },
> -	{ 0x6B11, 0xCF },
> -	{ 0x7FF0, 0x08 },
> -	{ 0x7FF1, 0x0F },
> -	{ 0x7FF2, 0x08 },
> -	{ 0x7FF3, 0x1B },
> -	{ 0x7FF4, 0x23 },
> -	{ 0x7FF5, 0x60 },
> -	{ 0x7FF6, 0x00 },
> -	{ 0x7FF7, 0x01 },
> -	{ 0x7FF8, 0x00 },
> -	{ 0x7FF9, 0x78 },
> -	{ 0x7FFA, 0x00 },
> -	{ 0x7FFB, 0x00 },
> -	{ 0x7FFC, 0x00 },
> -	{ 0x7FFD, 0x00 },
> -	{ 0x7FFE, 0x00 },
> -	{ 0x7FFF, 0x03 },
> -	{ 0x7F76, 0x03 },
> -	{ 0x7F77, 0xFE },
> -	{ 0x7FA8, 0x03 },
> -	{ 0x7FA9, 0xFE },
> -	{ 0x7B24, 0x81 },
> -	{ 0x7B25, 0x00 },
> -	{ 0x6564, 0x07 },
> -	{ 0x6B0D, 0x41 },
> -	{ 0x653D, 0x04 },
> -	{ 0x6B05, 0x8C },
> -	{ 0x6B06, 0xF9 },
> -	{ 0x6B08, 0x65 },
> -	{ 0x6B09, 0xFC },
> -	{ 0x6B0A, 0xCF },
> -	{ 0x6B0B, 0xD2 },
> -	{ 0x6700, 0x0E },
> -	{ 0x6707, 0x0E },
> -	{ 0x9104, 0x00 },
> -	{ 0x4648, 0x7F },
> -	{ 0x7420, 0x00 },
> -	{ 0x7421, 0x1C },
> -	{ 0x7422, 0x00 },
> -	{ 0x7423, 0xD7 },
> -	{ 0x5F04, 0x00 },
> -	{ 0x5F05, 0xED },
> -	{ 0x0112, 0x0A },
> -	{ 0x0113, 0x0A },
> -	{ 0x0114, 0x03 },
> -	{ 0x0342, 0x14 },
> -	{ 0x0343, 0xE8 },
> -	{ 0x0344, 0x00 },
> -	{ 0x0345, 0x00 },
> -	{ 0x0346, 0x00 },
> -	{ 0x0347, 0x00 },
> -	{ 0x0348, 0x10 },
> -	{ 0x0349, 0x6F },
> -	{ 0x034A, 0x0C },
> -	{ 0x034B, 0x2F },
> -	{ 0x0381, 0x01 },
> -	{ 0x0383, 0x01 },
> -	{ 0x0385, 0x01 },
> -	{ 0x0387, 0x01 },
>  	{ 0x0900, 0x01 },
>  	{ 0x0901, 0x12 },
>  	{ 0x0401, 0x01 },
> -	{ 0x0404, 0x00 },
>  	{ 0x0405, 0x20 },
> -	{ 0x0408, 0x00 },
> -	{ 0x0409, 0x00 },
> -	{ 0x040A, 0x00 },
> -	{ 0x040B, 0x00 },
> -	{ 0x040C, 0x10 },
> -	{ 0x040D, 0x70 },
>  	{ 0x040E, 0x06 },
>  	{ 0x040F, 0x18 },
> -	{ 0x3038, 0x00 },
> -	{ 0x303A, 0x00 },
> -	{ 0x303B, 0x10 },
> -	{ 0x300D, 0x00 },
>  	{ 0x034C, 0x08 },
>  	{ 0x034D, 0x38 },
>  	{ 0x034E, 0x06 },
>  	{ 0x034F, 0x18 },
> -	{ 0x0350, 0x01 },
> -	{ 0x0204, 0x00 },
> -	{ 0x0205, 0x00 },
> -	{ 0x020E, 0x01 },
> -	{ 0x020F, 0x00 },
> -	{ 0x0210, 0x01 },
> -	{ 0x0211, 0x00 },
> -	{ 0x0212, 0x01 },
> -	{ 0x0213, 0x00 },
> -	{ 0x0214, 0x01 },
> -	{ 0x0215, 0x00 },
> -	{ 0x7BCD, 0x01 },
> -	{ 0x94DC, 0x20 },
> -	{ 0x94DD, 0x20 },
> -	{ 0x94DE, 0x20 },
> -	{ 0x95DC, 0x20 },
> -	{ 0x95DD, 0x20 },
> -	{ 0x95DE, 0x20 },
> -	{ 0x7FB0, 0x00 },
> -	{ 0x9010, 0x3E },
> -	{ 0x9419, 0x50 },
> -	{ 0x941B, 0x50 },
> -	{ 0x9519, 0x50 },
> -	{ 0x951B, 0x50 },
> -	{ 0x3030, 0x00 },
> -	{ 0x3032, 0x00 },
> -	{ 0x0220, 0x00 },
>  };
>
>  static const struct imx258_reg mode_1048_780_regs[] = {
> -	{ 0x0136, 0x13 },
> -	{ 0x0137, 0x33 },
> -	{ 0x3051, 0x00 },
> -	{ 0x3052, 0x00 },
> -	{ 0x4E21, 0x14 },
> -	{ 0x6B11, 0xCF },
> -	{ 0x7FF0, 0x08 },
> -	{ 0x7FF1, 0x0F },
> -	{ 0x7FF2, 0x08 },
> -	{ 0x7FF3, 0x1B },
> -	{ 0x7FF4, 0x23 },
> -	{ 0x7FF5, 0x60 },
> -	{ 0x7FF6, 0x00 },
> -	{ 0x7FF7, 0x01 },
> -	{ 0x7FF8, 0x00 },
> -	{ 0x7FF9, 0x78 },
> -	{ 0x7FFA, 0x00 },
> -	{ 0x7FFB, 0x00 },
> -	{ 0x7FFC, 0x00 },
> -	{ 0x7FFD, 0x00 },
> -	{ 0x7FFE, 0x00 },
> -	{ 0x7FFF, 0x03 },
> -	{ 0x7F76, 0x03 },
> -	{ 0x7F77, 0xFE },
> -	{ 0x7FA8, 0x03 },
> -	{ 0x7FA9, 0xFE },
> -	{ 0x7B24, 0x81 },
> -	{ 0x7B25, 0x00 },
> -	{ 0x6564, 0x07 },
> -	{ 0x6B0D, 0x41 },
> -	{ 0x653D, 0x04 },
> -	{ 0x6B05, 0x8C },
> -	{ 0x6B06, 0xF9 },
> -	{ 0x6B08, 0x65 },
> -	{ 0x6B09, 0xFC },
> -	{ 0x6B0A, 0xCF },
> -	{ 0x6B0B, 0xD2 },
> -	{ 0x6700, 0x0E },
> -	{ 0x6707, 0x0E },
> -	{ 0x9104, 0x00 },
> -	{ 0x4648, 0x7F },
> -	{ 0x7420, 0x00 },
> -	{ 0x7421, 0x1C },
> -	{ 0x7422, 0x00 },
> -	{ 0x7423, 0xD7 },
> -	{ 0x5F04, 0x00 },
> -	{ 0x5F05, 0xED },
> -	{ 0x0112, 0x0A },
> -	{ 0x0113, 0x0A },
> -	{ 0x0114, 0x03 },
> -	{ 0x0342, 0x14 },
> -	{ 0x0343, 0xE8 },
> -	{ 0x0344, 0x00 },
> -	{ 0x0345, 0x00 },
> -	{ 0x0346, 0x00 },
> -	{ 0x0347, 0x00 },
> -	{ 0x0348, 0x10 },
> -	{ 0x0349, 0x6F },
> -	{ 0x034A, 0x0C },
> -	{ 0x034B, 0x2F },
> -	{ 0x0381, 0x01 },
> -	{ 0x0383, 0x01 },
> -	{ 0x0385, 0x01 },
> -	{ 0x0387, 0x01 },
>  	{ 0x0900, 0x01 },
>  	{ 0x0901, 0x14 },
>  	{ 0x0401, 0x01 },
> -	{ 0x0404, 0x00 },
>  	{ 0x0405, 0x40 },
> -	{ 0x0408, 0x00 },
> -	{ 0x0409, 0x00 },
> -	{ 0x040A, 0x00 },
> -	{ 0x040B, 0x00 },
> -	{ 0x040C, 0x10 },
> -	{ 0x040D, 0x70 },
>  	{ 0x040E, 0x03 },
>  	{ 0x040F, 0x0C },
> -	{ 0x3038, 0x00 },
> -	{ 0x303A, 0x00 },
> -	{ 0x303B, 0x10 },
> -	{ 0x300D, 0x00 },
>  	{ 0x034C, 0x04 },
>  	{ 0x034D, 0x18 },
>  	{ 0x034E, 0x03 },
>  	{ 0x034F, 0x0C },
> -	{ 0x0350, 0x01 },
> -	{ 0x0204, 0x00 },
> -	{ 0x0205, 0x00 },
> -	{ 0x020E, 0x01 },
> -	{ 0x020F, 0x00 },
> -	{ 0x0210, 0x01 },
> -	{ 0x0211, 0x00 },
> -	{ 0x0212, 0x01 },
> -	{ 0x0213, 0x00 },
> -	{ 0x0214, 0x01 },
> -	{ 0x0215, 0x00 },
> -	{ 0x7BCD, 0x00 },
> -	{ 0x94DC, 0x20 },
> -	{ 0x94DD, 0x20 },
> -	{ 0x94DE, 0x20 },
> -	{ 0x95DC, 0x20 },
> -	{ 0x95DD, 0x20 },
> -	{ 0x95DE, 0x20 },
> -	{ 0x7FB0, 0x00 },
> -	{ 0x9010, 0x3E },
> -	{ 0x9419, 0x50 },
> -	{ 0x941B, 0x50 },
> -	{ 0x9519, 0x50 },
> -	{ 0x951B, 0x50 },
> -	{ 0x3030, 0x00 },
> -	{ 0x3032, 0x00 },
> -	{ 0x0220, 0x00 },
>  };
>
>  static const char * const imx258_test_pattern_menu[] = {
> @@ -959,6 +758,13 @@ static int imx258_start_streaming(struct imx258 *imx258)
>  		return ret;
>  	}
>
> +	ret = imx258_write_regs(imx258, mode_common_regs,
> +				ARRAY_SIZE(mode_common_regs));
> +	if (ret) {
> +		dev_err(&client->dev, "%s failed to set common regs\n", __func__);
> +		return ret;
> +	}
> +
>  	/* Apply default values of current mode */
>  	reg_list = &imx258->cur_mode->reg_list;
>  	ret = imx258_write_regs(imx258, reg_list->regs, reg_list->num_of_regs);
> --
> 2.25.1
>

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

* Re: [PATCH 05/21] media: i2c: imx258: Add regulator control
  2023-05-31 15:11   ` Jacopo Mondi
@ 2023-05-31 15:26     ` Dave Stevenson
  0 siblings, 0 replies; 54+ messages in thread
From: Dave Stevenson @ 2023-05-31 15:26 UTC (permalink / raw)
  To: Jacopo Mondi
  Cc: Sakari Ailus, linux-media, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree

Hi Jacopo

On Wed, 31 May 2023 at 16:11, Jacopo Mondi
<jacopo.mondi@ideasonboard.com> wrote:
>
> Hi Dave
>
> On Tue, May 30, 2023 at 06:29:44PM +0100, Dave Stevenson wrote:
> > The device tree bindings define the relevant regulators for the
> > sensor, so update the driver to request the regulators and control
> > them at the appropriate times.
> >
> > Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
> > ---
> >  drivers/media/i2c/imx258.c | 42 +++++++++++++++++++++++++++++++++++++-
> >  1 file changed, 41 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
> > index b695fd987b71..30bae7388c3a 100644
> > --- a/drivers/media/i2c/imx258.c
> > +++ b/drivers/media/i2c/imx258.c
> > @@ -7,6 +7,7 @@
> >  #include <linux/i2c.h>
> >  #include <linux/module.h>
> >  #include <linux/pm_runtime.h>
> > +#include <linux/regulator/consumer.h>
> >  #include <media/v4l2-ctrls.h>
> >  #include <media/v4l2-device.h>
> >  #include <media/v4l2-fwnode.h>
> > @@ -507,6 +508,16 @@ static const char * const imx258_test_pattern_menu[] = {
> >       "Pseudorandom Sequence (PN9)",
> >  };
> >
> > +/* regulator supplies */
> > +static const char * const imx258_supply_name[] = {
> > +     /* Supplies can be enabled in any order */
> > +     "vana",  /* Analog (2.8V) supply */
> > +     "vdig",  /* Digital Core (1.2V) supply */
> > +     "vif",  /* IF (1.8V) supply */
> > +};
> > +
> > +#define IMX258_NUM_SUPPLIES ARRAY_SIZE(imx258_supply_name)
> > +
> >  /* Configurations for supported link frequencies */
> >  #define IMX258_LINK_FREQ_634MHZ      633600000ULL
> >  #define IMX258_LINK_FREQ_320MHZ      320000000ULL
> > @@ -614,6 +625,7 @@ struct imx258 {
> >       bool streaming;
> >
> >       struct clk *clk;
> > +     struct regulator_bulk_data supplies[IMX258_NUM_SUPPLIES];
> >  };
> >
> >  static inline struct imx258 *to_imx258(struct v4l2_subdev *_sd)
> > @@ -999,9 +1011,19 @@ static int imx258_power_on(struct device *dev)
> >       struct imx258 *imx258 = to_imx258(sd);
> >       int ret;
> >
> > +     ret = regulator_bulk_enable(IMX258_NUM_SUPPLIES,
> > +                                 imx258->supplies);
> > +     if (ret) {
> > +             dev_err(dev, "%s: failed to enable regulators\n",
> > +                     __func__);
> > +             return ret;
> > +     }
> > +
> >       ret = clk_prepare_enable(imx258->clk);
> > -     if (ret)
> > +     if (ret) {
> >               dev_err(dev, "failed to enable clock\n");
> > +             regulator_bulk_disable(IMX258_NUM_SUPPLIES, imx258->supplies);
> > +     }
> >
> >       return ret;
> >  }
> > @@ -1012,6 +1034,7 @@ static int imx258_power_off(struct device *dev)
> >       struct imx258 *imx258 = to_imx258(sd);
> >
> >       clk_disable_unprepare(imx258->clk);
> > +     regulator_bulk_disable(IMX258_NUM_SUPPLIES, imx258->supplies);
> >
> >       return 0;
> >  }
> > @@ -1260,6 +1283,19 @@ static void imx258_free_controls(struct imx258 *imx258)
> >       mutex_destroy(&imx258->mutex);
> >  }
> >
> > +static int imx258_get_regulators(struct imx258 *imx258,
> > +                              struct i2c_client *client)
> > +{
> > +     unsigned int i;
> > +
> > +     for (i = 0; i < IMX258_NUM_SUPPLIES; i++)
> > +             imx258->supplies[i].supply = imx258_supply_name[i];
> > +
> > +     return devm_regulator_bulk_get(&client->dev,
> > +                                    IMX258_NUM_SUPPLIES,
> > +                                    imx258->supplies);
>
> nit: fits on 2 lines

Done

> > +}
> > +
> >  static int imx258_probe(struct i2c_client *client)
> >  {
> >       struct imx258 *imx258;
> > @@ -1270,6 +1306,10 @@ static int imx258_probe(struct i2c_client *client)
> >       if (!imx258)
> >               return -ENOMEM;
> >
> > +     ret = imx258_get_regulators(imx258, client);
> > +     if (ret)
> > +             return ret;
>
> Is dev_err_probe() useful here ?

Sure, can do.

  Dave

> > +
> >       imx258->clk = devm_clk_get_optional(&client->dev, NULL);
> >       if (IS_ERR(imx258->clk))
> >               return dev_err_probe(&client->dev, PTR_ERR(imx258->clk),
> > --
> > 2.25.1
> >

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

* Re: [PATCH 10/21] media: i2c: imx258: Follow normal V4L2 behaviours for clipping exposure
  2023-05-30 17:29 ` [PATCH 10/21] media: i2c: imx258: Follow normal V4L2 behaviours for clipping exposure Dave Stevenson
@ 2023-05-31 15:27   ` Jacopo Mondi
  0 siblings, 0 replies; 54+ messages in thread
From: Jacopo Mondi @ 2023-05-31 15:27 UTC (permalink / raw)
  To: Dave Stevenson
  Cc: Sakari Ailus, linux-media, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree

Hi Dave

On Tue, May 30, 2023 at 06:29:49PM +0100, Dave Stevenson wrote:
> V4L2 sensor drivers are expected are expected to clip the supported
> exposure range based on the VBLANK configured.
> IMX258 wasn't doing that as register 0x350 (FRM_LENGTH_CTL)
> switches it to a mode where frame length tracks coarse exposure time.
>
> Disable this mode and clip the range for V4L2_CID_EXPOSURE appropriately
> based on V4L2_CID_VBLANK.
>
> Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>

Ah, here you go!
Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>

thanks
   j

> ---
>  drivers/media/i2c/imx258.c | 25 +++++++++++++++++++++++--
>  1 file changed, 23 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
> index 433dff7f1fa0..82ffe09e3bdc 100644
> --- a/drivers/media/i2c/imx258.c
> +++ b/drivers/media/i2c/imx258.c
> @@ -37,10 +37,11 @@
>
>  /* Exposure control */
>  #define IMX258_REG_EXPOSURE		0x0202
> +#define IMX258_EXPOSURE_OFFSET		10
>  #define IMX258_EXPOSURE_MIN		4
>  #define IMX258_EXPOSURE_STEP		1
>  #define IMX258_EXPOSURE_DEFAULT		0x640
> -#define IMX258_EXPOSURE_MAX		65535
> +#define IMX258_EXPOSURE_MAX		(IMX258_VTS_MAX - IMX258_EXPOSURE_OFFSET)
>
>  /* Analog gain control */
>  #define IMX258_REG_ANALOG_GAIN		0x0204
> @@ -366,7 +367,7 @@ static const struct imx258_reg mode_common_regs[] = {
>  	{ 0x303A, 0x00 },
>  	{ 0x303B, 0x10 },
>  	{ 0x300D, 0x00 },
> -	{ 0x0350, 0x01 },
> +	{ 0x0350, 0x00 },
>  	{ 0x0204, 0x00 },
>  	{ 0x0205, 0x00 },
>  	{ 0x020E, 0x01 },
> @@ -739,6 +740,19 @@ static int imx258_update_digital_gain(struct imx258 *imx258, u32 len, u32 val)
>  	return 0;
>  }
>
> +static void imx258_adjust_exposure_range(struct imx258 *imx258)
> +{
> +	int exposure_max, exposure_def;
> +
> +	/* Honour the VBLANK limits when setting exposure. */
> +	exposure_max = imx258->cur_mode->height + imx258->vblank->val -
> +		       IMX258_EXPOSURE_OFFSET;
> +	exposure_def = min(exposure_max, imx258->exposure->val);
> +	__v4l2_ctrl_modify_range(imx258->exposure, imx258->exposure->minimum,
> +				 exposure_max, imx258->exposure->step,
> +				 exposure_def);
> +}
> +
>  static int imx258_set_ctrl(struct v4l2_ctrl *ctrl)
>  {
>  	struct imx258 *imx258 =
> @@ -746,6 +760,13 @@ static int imx258_set_ctrl(struct v4l2_ctrl *ctrl)
>  	struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd);
>  	int ret = 0;
>
> +	/*
> +	 * The VBLANK control may change the limits of usable exposure, so check
> +	 * and adjust if necessary.
> +	 */
> +	if (ctrl->id == V4L2_CID_VBLANK)
> +		imx258_adjust_exposure_range(imx258);
> +
>  	/*
>  	 * Applying V4L2 control value only happens
>  	 * when power is up for streaming
> --
> 2.25.1
>

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

* Re: [PATCH 06/21] media: i2c: imx258: Make V4L2_CID_VBLANK configurable.
  2023-05-31 15:16   ` Jacopo Mondi
@ 2023-05-31 15:33     ` Dave Stevenson
  0 siblings, 0 replies; 54+ messages in thread
From: Dave Stevenson @ 2023-05-31 15:33 UTC (permalink / raw)
  To: Jacopo Mondi
  Cc: Sakari Ailus, linux-media, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree

Hi Jacopo

Thanks for the review.

On Wed, 31 May 2023 at 16:16, Jacopo Mondi
<jacopo.mondi@ideasonboard.com> wrote:
>
> Hi Dave
>
> On Tue, May 30, 2023 at 06:29:45PM +0100, Dave Stevenson wrote:
> > The values and ranges of V4L2_CID_VBLANK are all computed,
> > so there is no reason for it to be a read only control.
> > Remove the register values from the mode lists, add the
> > handler, and remove the read only flag.
> >
> > Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
> > ---
> >  drivers/media/i2c/imx258.c | 16 +++++++---------
> >  1 file changed, 7 insertions(+), 9 deletions(-)
> >
> > diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
> > index 30bae7388c3a..c6fb649abb95 100644
> > --- a/drivers/media/i2c/imx258.c
> > +++ b/drivers/media/i2c/imx258.c
> > @@ -30,6 +30,8 @@
> >  #define IMX258_VTS_30FPS_VGA         0x034c
> >  #define IMX258_VTS_MAX                       0xffff
> >
> > +#define IMX258_REG_VTS                       0x0340
> > +
> >  /* HBLANK control - read only */
> >  #define IMX258_PPL_DEFAULT           5352
> >
> > @@ -202,8 +204,6 @@ static const struct imx258_reg mode_4208x3120_regs[] = {
> >       { 0x0114, 0x03 },
> >       { 0x0342, 0x14 },
> >       { 0x0343, 0xE8 },
> > -     { 0x0340, 0x0C },
> > -     { 0x0341, 0x50 },
> >       { 0x0344, 0x00 },
> >       { 0x0345, 0x00 },
> >       { 0x0346, 0x00 },
> > @@ -319,8 +319,6 @@ static const struct imx258_reg mode_2104_1560_regs[] = {
> >       { 0x0114, 0x03 },
> >       { 0x0342, 0x14 },
> >       { 0x0343, 0xE8 },
> > -     { 0x0340, 0x06 },
> > -     { 0x0341, 0x38 },
> >       { 0x0344, 0x00 },
> >       { 0x0345, 0x00 },
> >       { 0x0346, 0x00 },
> > @@ -436,8 +434,6 @@ static const struct imx258_reg mode_1048_780_regs[] = {
> >       { 0x0114, 0x03 },
> >       { 0x0342, 0x14 },
> >       { 0x0343, 0xE8 },
> > -     { 0x0340, 0x03 },
> > -     { 0x0341, 0x4C },
> >       { 0x0344, 0x00 },
> >       { 0x0345, 0x00 },
> >       { 0x0346, 0x00 },
> > @@ -803,6 +799,11 @@ static int imx258_set_ctrl(struct v4l2_ctrl *ctrl)
> >                                              BIT(IMX258_HDR_RATIO_MAX));
> >               }
> >               break;
> > +     case V4L2_CID_VBLANK:
>
> Should a new vblank value change the exposure limits too ?

Yes, however until "media: i2c: imx258: Follow normal V4L2 behaviours
for clipping exposure" (patch 10) the driver tells the sensor to
automatically extend blanking to allow for the requested exposure,
totally without userspace knowing. That patch adds in the
recomputation of exposure based on VBLANK changing.

I can swap the patch order if you feel it is necessary, but seeing as
exposure isn't limited in reality at this point I'm not too fussed.

  Dave

> > +             ret = imx258_write_reg(imx258, IMX258_REG_VTS,
> > +                                    IMX258_REG_VALUE_16BIT,
> > +                                    imx258->cur_mode->height + ctrl->val);
> > +             break;
> >       default:
> >               dev_info(&client->dev,
> >                        "ctrl(id:0x%x,val:0x%x) is not handled\n",
> > @@ -1214,9 +1215,6 @@ static int imx258_init_controls(struct imx258 *imx258)
> >                               IMX258_VTS_MAX - imx258->cur_mode->height, 1,
> >                               vblank_def);
> >
> > -     if (imx258->vblank)
> > -             imx258->vblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
> > -
> >       imx258->hblank = v4l2_ctrl_new_std(
> >                               ctrl_hdlr, &imx258_ctrl_ops, V4L2_CID_HBLANK,
> >                               IMX258_PPL_DEFAULT - imx258->cur_mode->width,
> > --
> > 2.25.1
> >

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

* Re: [PATCH 08/21] media: i2c: imx258: Add support for 24MHz clock
  2023-05-30 17:29 ` [PATCH 08/21] media: i2c: imx258: Add support for 24MHz clock Dave Stevenson
@ 2023-06-02 12:59   ` Jacopo Mondi
  0 siblings, 0 replies; 54+ messages in thread
From: Jacopo Mondi @ 2023-06-02 12:59 UTC (permalink / raw)
  To: Dave Stevenson
  Cc: Sakari Ailus, linux-media, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree

Hi Dave

On Tue, May 30, 2023 at 06:29:47PM +0100, Dave Stevenson wrote:
> There's no reason why only a clock of 19.2MHz is supported.
> Indeed this isn't even a frequency listed in the datasheet.
>
> Add support for 24MHz as well.
> The PLL settings result in slightly different link frequencies,
> so parameterise those.
>
> Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
> ---
>  drivers/media/i2c/imx258.c | 137 ++++++++++++++++++++++++++++++-------
>  1 file changed, 111 insertions(+), 26 deletions(-)
>
> diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
> index 5a57d0b5fcd8..d40521f9a3c6 100644
> --- a/drivers/media/i2c/imx258.c
> +++ b/drivers/media/i2c/imx258.c
> @@ -76,9 +76,6 @@
>  #define REG_CONFIG_MIRROR_FLIP		0x03
>  #define REG_CONFIG_FLIP_TEST_PATTERN	0x02
>
> -/* Input clock frequency in Hz */
> -#define IMX258_INPUT_CLOCK_FREQ		19200000
> -
>  struct imx258_reg {
>  	u16 address;
>  	u8 val;
> @@ -91,6 +88,7 @@ struct imx258_reg_list {
>
>  /* Link frequency config */
>  struct imx258_link_freq_config {
> +	u64 link_frequency;

Is this used ?

>  	u32 pixels_per_line;

Also this seems to be set a fixed value of IMX258_PPL_DEFAULT

>
>  	/* PLL registers for this link frequency */
> @@ -115,7 +113,9 @@ struct imx258_mode {
>  };
>
>  /* 4208x3120 needs 1267Mbps/lane, 4 lanes */
> -static const struct imx258_reg mipi_data_rate_1267mbps[] = {
> +static const struct imx258_reg mipi_1267mbps_19_2mhz[] = {
> +	{ 0x0136, 0x13 },
> +	{ 0x0137, 0x33 },
>  	{ 0x0301, 0x05 },
>  	{ 0x0303, 0x02 },
>  	{ 0x0305, 0x03 },
> @@ -133,7 +133,29 @@ static const struct imx258_reg mipi_data_rate_1267mbps[] = {
>  	{ 0x0823, 0xCC },
>  };
>
> -static const struct imx258_reg mipi_data_rate_640mbps[] = {
> +static const struct imx258_reg mipi_1272mbps_24mhz[] = {
> +	{ 0x0136, 0x18 },
> +	{ 0x0137, 0x00 },
> +	{ 0x0301, 0x05 },
> +	{ 0x0303, 0x02 },
> +	{ 0x0305, 0x04 },
> +	{ 0x0306, 0x00 },
> +	{ 0x0307, 0xD4 },
> +	{ 0x0309, 0x0A },
> +	{ 0x030B, 0x01 },
> +	{ 0x030D, 0x02 },
> +	{ 0x030E, 0x00 },
> +	{ 0x030F, 0xD8 },
> +	{ 0x0310, 0x00 },
> +	{ 0x0820, 0x13 },
> +	{ 0x0821, 0x4C },
> +	{ 0x0822, 0xCC },
> +	{ 0x0823, 0xCC },
> +};

I'll assume that if this work as intended, the register sequence is
correct (ie: I've not checked the registers configuration)

> +
> +static const struct imx258_reg mipi_640mbps_19_2mhz[] = {
> +	{ 0x0136, 0x13 },
> +	{ 0x0137, 0x33 },
>  	{ 0x0301, 0x05 },
>  	{ 0x0303, 0x02 },
>  	{ 0x0305, 0x03 },
> @@ -151,9 +173,27 @@ static const struct imx258_reg mipi_data_rate_640mbps[] = {
>  	{ 0x0823, 0x00 },
>  };
>
> +static const struct imx258_reg mipi_642mbps_24mhz[] = {
> +	{ 0x0136, 0x18 },
> +	{ 0x0137, 0x00 },
> +	{ 0x0301, 0x05 },
> +	{ 0x0303, 0x02 },
> +	{ 0x0305, 0x04 },
> +	{ 0x0306, 0x00 },
> +	{ 0x0307, 0x6B },
> +	{ 0x0309, 0x0A },
> +	{ 0x030B, 0x01 },
> +	{ 0x030D, 0x02 },
> +	{ 0x030E, 0x00 },
> +	{ 0x030F, 0xD8 },
> +	{ 0x0310, 0x00 },
> +	{ 0x0820, 0x0A },
> +	{ 0x0821, 0x00 },
> +	{ 0x0822, 0x00 },
> +	{ 0x0823, 0x00 },
> +};
> +
>  static const struct imx258_reg mode_common_regs[] = {
> -	{ 0x0136, 0x13 },
> -	{ 0x0137, 0x33 },
>  	{ 0x3051, 0x00 },
>  	{ 0x3052, 0x00 },
>  	{ 0x4E21, 0x14 },
> @@ -313,10 +353,6 @@ static const char * const imx258_supply_name[] = {
>
>  #define IMX258_NUM_SUPPLIES ARRAY_SIZE(imx258_supply_name)
>
> -/* Configurations for supported link frequencies */
> -#define IMX258_LINK_FREQ_634MHZ	633600000ULL
> -#define IMX258_LINK_FREQ_320MHZ	320000000ULL
> -
>  enum {
>  	IMX258_LINK_FREQ_1267MBPS,
>  	IMX258_LINK_FREQ_640MBPS,
> @@ -335,25 +371,55 @@ static u64 link_freq_to_pixel_rate(u64 f)
>  }
>
>  /* Menu items for LINK_FREQ V4L2 control */
> -static const s64 link_freq_menu_items[] = {
> +/* Configurations for supported link frequencies */
> +#define IMX258_LINK_FREQ_634MHZ	633600000ULL
> +#define IMX258_LINK_FREQ_320MHZ	320000000ULL
> +
> +static const s64 link_freq_menu_items_19_2[] = {
>  	IMX258_LINK_FREQ_634MHZ,
>  	IMX258_LINK_FREQ_320MHZ,
>  };
>
> +/* Configurations for supported link frequencies */
> +#define IMX258_LINK_FREQ_636MHZ	636000000ULL
> +#define IMX258_LINK_FREQ_321MHZ	321000000ULL
> +
> +static const s64 link_freq_menu_items_24[] = {
> +	IMX258_LINK_FREQ_636MHZ,
> +	IMX258_LINK_FREQ_321MHZ,
> +};
> +
>  /* Link frequency configs */
> -static const struct imx258_link_freq_config link_freq_configs[] = {
> +static const struct imx258_link_freq_config link_freq_configs_19_2[] = {
> +	[IMX258_LINK_FREQ_1267MBPS] = {
> +		.pixels_per_line = IMX258_PPL_DEFAULT,
> +		.reg_list = {
> +			.num_of_regs = ARRAY_SIZE(mipi_1267mbps_19_2mhz),
> +			.regs = mipi_1267mbps_19_2mhz,
> +		}
> +	},
> +	[IMX258_LINK_FREQ_640MBPS] = {
> +		.pixels_per_line = IMX258_PPL_DEFAULT,
> +		.reg_list = {
> +			.num_of_regs = ARRAY_SIZE(mipi_640mbps_19_2mhz),
> +			.regs = mipi_640mbps_19_2mhz,
> +		}
> +	},
> +};
> +
> +static const struct imx258_link_freq_config link_freq_configs_24[] = {
>  	[IMX258_LINK_FREQ_1267MBPS] = {

This doesn't match anymore the actual bus freq, I don't think it's
a real issue, but I wonder if simply indexing with '0' and '1'
wouldn't be less confusing..

>  		.pixels_per_line = IMX258_PPL_DEFAULT,
>  		.reg_list = {
> -			.num_of_regs = ARRAY_SIZE(mipi_data_rate_1267mbps),
> -			.regs = mipi_data_rate_1267mbps,
> +			.num_of_regs = ARRAY_SIZE(mipi_1272mbps_24mhz),
> +			.regs = mipi_1272mbps_24mhz,
>  		}
>  	},
>  	[IMX258_LINK_FREQ_640MBPS] = {
>  		.pixels_per_line = IMX258_PPL_DEFAULT,
>  		.reg_list = {
> -			.num_of_regs = ARRAY_SIZE(mipi_data_rate_640mbps),
> -			.regs = mipi_data_rate_640mbps,
> +			.num_of_regs = ARRAY_SIZE(mipi_642mbps_24mhz),
> +			.regs = mipi_642mbps_24mhz,
>  		}
>  	},
>  };
> @@ -410,6 +476,9 @@ struct imx258 {
>  	/* Current mode */
>  	const struct imx258_mode *cur_mode;
>
> +	const struct imx258_link_freq_config *link_freq_configs;
> +	const s64 *link_freq_menu_items;
> +
>  	/*
>  	 * Mutex for serialized access:
>  	 * Protect sensor module set pad format and start/stop streaming safely.
> @@ -717,7 +786,7 @@ static int imx258_set_pad_format(struct v4l2_subdev *sd,
>  		imx258->cur_mode = mode;
>  		__v4l2_ctrl_s_ctrl(imx258->link_freq, mode->link_freq_index);
>
> -		link_freq = link_freq_menu_items[mode->link_freq_index];
> +		link_freq = imx258->link_freq_menu_items[mode->link_freq_index];
>  		pixel_rate = link_freq_to_pixel_rate(link_freq);
>  		__v4l2_ctrl_s_ctrl_int64(imx258->pixel_rate, pixel_rate);
>  		/* Update limits and set FPS to default */
> @@ -731,7 +800,7 @@ static int imx258_set_pad_format(struct v4l2_subdev *sd,
>  			vblank_def);
>  		__v4l2_ctrl_s_ctrl(imx258->vblank, vblank_def);
>  		h_blank =
> -			link_freq_configs[mode->link_freq_index].pixels_per_line
> +			imx258->link_freq_configs[mode->link_freq_index].pixels_per_line
>  			 - imx258->cur_mode->width;
>  		__v4l2_ctrl_modify_range(imx258->hblank, h_blank,
>  					 h_blank, 1, h_blank);
> @@ -751,7 +820,7 @@ static int imx258_start_streaming(struct imx258 *imx258)
>
>  	/* Setup PLL */
>  	link_freq_index = imx258->cur_mode->link_freq_index;
> -	reg_list = &link_freq_configs[link_freq_index].reg_list;
> +	reg_list = &imx258->link_freq_configs[link_freq_index].reg_list;
>  	ret = imx258_write_regs(imx258, reg_list->regs, reg_list->num_of_regs);
>  	if (ret) {
>  		dev_err(&client->dev, "%s failed to set plls\n", __func__);
> @@ -986,9 +1055,9 @@ static int imx258_init_controls(struct imx258 *imx258)
>  	imx258->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr,
>  				&imx258_ctrl_ops,
>  				V4L2_CID_LINK_FREQ,
> -				ARRAY_SIZE(link_freq_menu_items) - 1,
> +				ARRAY_SIZE(link_freq_menu_items_19_2) - 1,
>  				0,
> -				link_freq_menu_items);
> +				imx258->link_freq_menu_items);
>
>  	if (imx258->link_freq)
>  		imx258->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
> @@ -1004,8 +1073,10 @@ static int imx258_init_controls(struct imx258 *imx258)
>  	if (vflip)
>  		vflip->flags |= V4L2_CTRL_FLAG_READ_ONLY;
>
> -	pixel_rate_max = link_freq_to_pixel_rate(link_freq_menu_items[0]);
> -	pixel_rate_min = link_freq_to_pixel_rate(link_freq_menu_items[1]);
> +	pixel_rate_max =
> +		link_freq_to_pixel_rate(imx258->link_freq_menu_items[0]);
> +	pixel_rate_min =
> +		link_freq_to_pixel_rate(imx258->link_freq_menu_items[1]);
>  	/* By default, PIXEL_RATE is read only */
>  	imx258->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops,
>  				V4L2_CID_PIXEL_RATE,
> @@ -1123,11 +1194,25 @@ static int imx258_probe(struct i2c_client *client)
>  			"no clock provided, using clock-frequency property\n");
>
>  		device_property_read_u32(&client->dev, "clock-frequency", &val);
> +	} else if (IS_ERR(imx258->clk)) {
> +		return dev_err_probe(&client->dev, PTR_ERR(imx258->clk),
> +				     "error getting clock\n");

Maybe a copy&paste error, as I see the IS_ERR(imx258->clk) condition
being handled just after getting the clock

>  	} else {
>  		val = clk_get_rate(imx258->clk);
>  	}
> -	if (val != IMX258_INPUT_CLOCK_FREQ) {
> -		dev_err(&client->dev, "input clock frequency not supported\n");
> +
> +	switch (val) {
> +	case 19200000:
> +		imx258->link_freq_configs = link_freq_configs_19_2;
> +		imx258->link_freq_menu_items = link_freq_menu_items_19_2;
> +		break;
> +	case 24000000:
> +		imx258->link_freq_configs = link_freq_configs_24;
> +		imx258->link_freq_menu_items = link_freq_menu_items_24;
> +		break;
> +	default:
> +		dev_err(&client->dev, "input clock frequency of %u not supported\n",
> +			val);
>  		return -EINVAL;
>  	}
>
> --
> 2.25.1
>

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

* Re: [PATCH 09/21] media: i2c: imx258: Add support for running on 2 CSI data lanes
  2023-05-30 17:29 ` [PATCH 09/21] media: i2c: imx258: Add support for running on 2 CSI data lanes Dave Stevenson
  2023-05-30 17:37   ` Dave Stevenson
  2023-05-31  8:07   ` kernel test robot
@ 2023-06-02 13:23   ` Jacopo Mondi
  2023-06-02 17:46     ` Dave Stevenson
  2 siblings, 1 reply; 54+ messages in thread
From: Jacopo Mondi @ 2023-06-02 13:23 UTC (permalink / raw)
  To: Dave Stevenson
  Cc: Sakari Ailus, linux-media, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree

Hi Dave

On Tue, May 30, 2023 at 06:29:48PM +0100, Dave Stevenson wrote:
> Extends the driver to also support 2 data lanes.
> Frame rates are obviously more restricted on 2 lanes, but some
> hardware simply hasn't wired more up.
>
> Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
> ---
>  drivers/media/i2c/imx258.c | 211 ++++++++++++++++++++++++++++++++-----
>  1 file changed, 187 insertions(+), 24 deletions(-)
>
> diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
> index d40521f9a3c6..433dff7f1fa0 100644
> --- a/drivers/media/i2c/imx258.c
> +++ b/drivers/media/i2c/imx258.c
> @@ -86,13 +86,17 @@ struct imx258_reg_list {
>  	const struct imx258_reg *regs;
>  };
>
> +#define IMX258_LANE_CONFIGS	2
> +#define IMX258_2_LANE_MODE	0
> +#define IMX258_4_LANE_MODE	1
> +

nit: This might be better expressed as an enum...

>  /* Link frequency config */
>  struct imx258_link_freq_config {
>  	u64 link_frequency;
>  	u32 pixels_per_line;
>
>  	/* PLL registers for this link frequency */
> -	struct imx258_reg_list reg_list;
> +	struct imx258_reg_list reg_list[IMX258_LANE_CONFIGS];
>  };
>
>  /* Mode : resolution and related config&values */
> @@ -112,8 +116,30 @@ struct imx258_mode {
>  	struct imx258_reg_list reg_list;
>  };
>
> -/* 4208x3120 needs 1267Mbps/lane, 4 lanes */
> -static const struct imx258_reg mipi_1267mbps_19_2mhz[] = {
> +/* 4208x3120 needs 1267Mbps/lane, 4 lanes. Use that rate on 2 lanes as well */

I might be missing how the same link freq (and thus lane bandwidth)
gives the same frame rate on 4 and 2 data lanes setup..

I get a total bandwidth with default VTS and PPL for 10bpp mode at 30
fps of

        vts * ppl * bpp * fps =
        3152 * 5352 * 10 * 30 = 5060851200 bit/sec

The resulting lane bandwidth for 4 lanes is
        1.265.212.800 which ~= 1267 Mbps/lane you have above
and results in a link frequency of
        632606400 which matches your 634MHz/636MHz

With 2 lanes either you double the bandwidth or you halve the frame
rate. Seeing that now link_freq_to_pixel_rate() will give you a *2
result in 4 lanes configuration, I presume full res mode runs at 15FPS
on 2 lanes ? If that's the case, should you remove '30FPS' from the
VTS default value defines ?


> +static const struct imx258_reg mipi_1267mbps_19_2mhz_2l[] = {
> +	{ 0x0136, 0x13 },
> +	{ 0x0137, 0x33 },
> +	{ 0x0301, 0x0A },
> +	{ 0x0303, 0x02 },
> +	{ 0x0305, 0x03 },
> +	{ 0x0306, 0x00 },
> +	{ 0x0307, 0xC6 },
> +	{ 0x0309, 0x0A },
> +	{ 0x030B, 0x01 },
> +	{ 0x030D, 0x02 },
> +	{ 0x030E, 0x00 },
> +	{ 0x030F, 0xD8 },
> +	{ 0x0310, 0x00 },
> +
> +	{ 0x0114, 0x01 },
> +	{ 0x0820, 0x09 },
> +	{ 0x0821, 0xa6 },
> +	{ 0x0822, 0x66 },
> +	{ 0x0823, 0x66 },
> +};
> +
> +static const struct imx258_reg mipi_1267mbps_19_2mhz_4l[] = {
>  	{ 0x0136, 0x13 },
>  	{ 0x0137, 0x33 },
>  	{ 0x0301, 0x05 },
> @@ -127,16 +153,18 @@ static const struct imx258_reg mipi_1267mbps_19_2mhz[] = {
>  	{ 0x030E, 0x00 },
>  	{ 0x030F, 0xD8 },
>  	{ 0x0310, 0x00 },
> +
> +	{ 0x0114, 0x03 },
>  	{ 0x0820, 0x13 },
>  	{ 0x0821, 0x4C },
>  	{ 0x0822, 0xCC },
>  	{ 0x0823, 0xCC },
>  };
>
> -static const struct imx258_reg mipi_1272mbps_24mhz[] = {
> +static const struct imx258_reg mipi_1272mbps_24mhz_2l[] = {
>  	{ 0x0136, 0x18 },
>  	{ 0x0137, 0x00 },
> -	{ 0x0301, 0x05 },
> +	{ 0x0301, 0x0a },
>  	{ 0x0303, 0x02 },
>  	{ 0x0305, 0x04 },
>  	{ 0x0306, 0x00 },
> @@ -147,13 +175,59 @@ static const struct imx258_reg mipi_1272mbps_24mhz[] = {
>  	{ 0x030E, 0x00 },
>  	{ 0x030F, 0xD8 },
>  	{ 0x0310, 0x00 },
> +
> +	{ 0x0114, 0x01 },
>  	{ 0x0820, 0x13 },
>  	{ 0x0821, 0x4C },
>  	{ 0x0822, 0xCC },
>  	{ 0x0823, 0xCC },
>  };
>
> -static const struct imx258_reg mipi_640mbps_19_2mhz[] = {
> +static const struct imx258_reg mipi_1272mbps_24mhz_4l[] = {
> +	{ 0x0136, 0x18 },
> +	{ 0x0137, 0x00 },
> +	{ 0x0301, 0x05 },
> +	{ 0x0303, 0x02 },
> +	{ 0x0305, 0x04 },
> +	{ 0x0306, 0x00 },
> +	{ 0x0307, 0xD4 },
> +	{ 0x0309, 0x0A },
> +	{ 0x030B, 0x01 },
> +	{ 0x030D, 0x02 },
> +	{ 0x030E, 0x00 },
> +	{ 0x030F, 0xD8 },
> +	{ 0x0310, 0x00 },
> +
> +	{ 0x0114, 0x03 },
> +	{ 0x0820, 0x13 },
> +	{ 0x0821, 0xE0 },
> +	{ 0x0822, 0x00 },
> +	{ 0x0823, 0x00 },
> +};
> +
> +static const struct imx258_reg mipi_640mbps_19_2mhz_2l[] = {
> +	{ 0x0136, 0x13 },
> +	{ 0x0137, 0x33 },
> +	{ 0x0301, 0x05 },
> +	{ 0x0303, 0x02 },
> +	{ 0x0305, 0x03 },
> +	{ 0x0306, 0x00 },
> +	{ 0x0307, 0x64 },
> +	{ 0x0309, 0x0A },
> +	{ 0x030B, 0x01 },
> +	{ 0x030D, 0x02 },
> +	{ 0x030E, 0x00 },
> +	{ 0x030F, 0xD8 },
> +	{ 0x0310, 0x00 },
> +
> +	{ 0x0114, 0x01 },
> +	{ 0x0820, 0x05 },
> +	{ 0x0821, 0x00 },
> +	{ 0x0822, 0x00 },
> +	{ 0x0823, 0x00 },
> +};
> +
> +static const struct imx258_reg mipi_640mbps_19_2mhz_4l[] = {
>  	{ 0x0136, 0x13 },
>  	{ 0x0137, 0x33 },
>  	{ 0x0301, 0x05 },
> @@ -167,13 +241,37 @@ static const struct imx258_reg mipi_640mbps_19_2mhz[] = {
>  	{ 0x030E, 0x00 },
>  	{ 0x030F, 0xD8 },
>  	{ 0x0310, 0x00 },
> +
> +	{ 0x0114, 0x03 },
>  	{ 0x0820, 0x0A },
>  	{ 0x0821, 0x00 },
>  	{ 0x0822, 0x00 },
>  	{ 0x0823, 0x00 },
>  };
>
> -static const struct imx258_reg mipi_642mbps_24mhz[] = {
> +static const struct imx258_reg mipi_642mbps_24mhz_2l[] = {
> +	{ 0x0136, 0x18 },
> +	{ 0x0137, 0x00 },
> +	{ 0x0301, 0x0A },
> +	{ 0x0303, 0x02 },
> +	{ 0x0305, 0x04 },
> +	{ 0x0306, 0x00 },
> +	{ 0x0307, 0x6B },
> +	{ 0x0309, 0x0A },
> +	{ 0x030B, 0x01 },
> +	{ 0x030D, 0x02 },
> +	{ 0x030E, 0x00 },
> +	{ 0x030F, 0xD8 },
> +	{ 0x0310, 0x00 },
> +
> +	{ 0x0114, 0x01 },
> +	{ 0x0820, 0x0A },
> +	{ 0x0821, 0x00 },
> +	{ 0x0822, 0x00 },
> +	{ 0x0823, 0x00 },
> +};
> +
> +static const struct imx258_reg mipi_642mbps_24mhz_4l[] = {
>  	{ 0x0136, 0x18 },
>  	{ 0x0137, 0x00 },
>  	{ 0x0301, 0x05 },
> @@ -187,6 +285,8 @@ static const struct imx258_reg mipi_642mbps_24mhz[] = {
>  	{ 0x030E, 0x00 },
>  	{ 0x030F, 0xD8 },
>  	{ 0x0310, 0x00 },
> +
> +	{ 0x0114, 0x03 },
>  	{ 0x0820, 0x0A },
>  	{ 0x0821, 0x00 },
>  	{ 0x0822, 0x00 },
> @@ -241,7 +341,6 @@ static const struct imx258_reg mode_common_regs[] = {
>  	{ 0x5F05, 0xED },
>  	{ 0x0112, 0x0A },
>  	{ 0x0113, 0x0A },
> -	{ 0x0114, 0x03 },
>  	{ 0x0342, 0x14 },
>  	{ 0x0343, 0xE8 },
>  	{ 0x0344, 0x00 },
> @@ -360,11 +459,13 @@ enum {
>
>  /*
>   * pixel_rate = link_freq * data-rate * nr_of_lanes / bits_per_sample
> - * data rate => double data rate; number of lanes => 4; bits per pixel => 10
> + * data rate => double data rate;
> + * number of lanes => (configurable 2 or 4);
> + * bits per pixel => 10
>   */
> -static u64 link_freq_to_pixel_rate(u64 f)
> +static u64 link_freq_to_pixel_rate(u64 f, unsigned int nlanes)
>  {
> -	f *= 2 * 4;
> +	f *= 2 * nlanes;
>  	do_div(f, 10);
>
>  	return f;
> @@ -394,15 +495,27 @@ static const struct imx258_link_freq_config link_freq_configs_19_2[] = {
>  	[IMX258_LINK_FREQ_1267MBPS] = {
>  		.pixels_per_line = IMX258_PPL_DEFAULT,
>  		.reg_list = {
> -			.num_of_regs = ARRAY_SIZE(mipi_1267mbps_19_2mhz),
> -			.regs = mipi_1267mbps_19_2mhz,
> +			[IMX258_2_LANE_MODE] = {
> +				.num_of_regs = ARRAY_SIZE(mipi_1267mbps_19_2mhz_2l),
> +				.regs = mipi_1267mbps_19_2mhz_2l,
> +			},
> +			[IMX258_4_LANE_MODE] = {
> +				.num_of_regs = ARRAY_SIZE(mipi_1267mbps_19_2mhz_4l),
> +				.regs = mipi_1267mbps_19_2mhz_4l,
> +			},
>  		}
>  	},
>  	[IMX258_LINK_FREQ_640MBPS] = {
>  		.pixels_per_line = IMX258_PPL_DEFAULT,
>  		.reg_list = {
> -			.num_of_regs = ARRAY_SIZE(mipi_640mbps_19_2mhz),
> -			.regs = mipi_640mbps_19_2mhz,
> +			[IMX258_2_LANE_MODE] = {
> +				.num_of_regs = ARRAY_SIZE(mipi_640mbps_19_2mhz_2l),
> +				.regs = mipi_640mbps_19_2mhz_2l,
> +			},
> +			[IMX258_4_LANE_MODE] = {
> +				.num_of_regs = ARRAY_SIZE(mipi_640mbps_19_2mhz_4l),
> +				.regs = mipi_640mbps_19_2mhz_4l,
> +			},
>  		}
>  	},
>  };
> @@ -411,15 +524,27 @@ static const struct imx258_link_freq_config link_freq_configs_24[] = {
>  	[IMX258_LINK_FREQ_1267MBPS] = {
>  		.pixels_per_line = IMX258_PPL_DEFAULT,
>  		.reg_list = {
> -			.num_of_regs = ARRAY_SIZE(mipi_1272mbps_24mhz),
> -			.regs = mipi_1272mbps_24mhz,
> +			[IMX258_2_LANE_MODE] = {
> +				.num_of_regs = ARRAY_SIZE(mipi_1272mbps_24mhz_2l),
> +				.regs = mipi_1272mbps_24mhz_2l,
> +			},
> +			[IMX258_4_LANE_MODE] = {
> +				.num_of_regs = ARRAY_SIZE(mipi_1272mbps_24mhz_4l),
> +				.regs = mipi_1272mbps_24mhz_4l,
> +			},
>  		}
>  	},
>  	[IMX258_LINK_FREQ_640MBPS] = {
>  		.pixels_per_line = IMX258_PPL_DEFAULT,
>  		.reg_list = {
> -			.num_of_regs = ARRAY_SIZE(mipi_642mbps_24mhz),
> -			.regs = mipi_642mbps_24mhz,
> +			[IMX258_2_LANE_MODE] = {
> +				.num_of_regs = ARRAY_SIZE(mipi_642mbps_24mhz_2l),
> +				.regs = mipi_642mbps_24mhz_2l,
> +			},
> +			[IMX258_4_LANE_MODE] = {
> +				.num_of_regs = ARRAY_SIZE(mipi_642mbps_24mhz_4l),
> +				.regs = mipi_642mbps_24mhz_4l,
> +			},
>  		}
>  	},
>  };
> @@ -478,6 +603,7 @@ struct imx258 {
>
>  	const struct imx258_link_freq_config *link_freq_configs;
>  	const s64 *link_freq_menu_items;
> +	unsigned int nlanes;
>
>  	/*
>  	 * Mutex for serialized access:
> @@ -787,7 +913,7 @@ static int imx258_set_pad_format(struct v4l2_subdev *sd,
>  		__v4l2_ctrl_s_ctrl(imx258->link_freq, mode->link_freq_index);
>
>  		link_freq = imx258->link_freq_menu_items[mode->link_freq_index];
> -		pixel_rate = link_freq_to_pixel_rate(link_freq);
> +		pixel_rate = link_freq_to_pixel_rate(link_freq, imx258->nlanes);
>  		__v4l2_ctrl_s_ctrl_int64(imx258->pixel_rate, pixel_rate);
>  		/* Update limits and set FPS to default */
>  		vblank_def = imx258->cur_mode->vts_def -
> @@ -816,11 +942,13 @@ static int imx258_start_streaming(struct imx258 *imx258)
>  {
>  	struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd);
>  	const struct imx258_reg_list *reg_list;
> +	const struct imx258_link_freq_config *link_freq_cfg;
>  	int ret, link_freq_index;
>
>  	/* Setup PLL */
>  	link_freq_index = imx258->cur_mode->link_freq_index;
> -	reg_list = &imx258->link_freq_configs[link_freq_index].reg_list;
> +	link_freq_cfg = &imx258->link_freq_configs[link_freq_index];
> +	reg_list = &link_freq_cfg->reg_list[imx258->nlanes == 2 ? 0 : 1];
>  	ret = imx258_write_regs(imx258, reg_list->regs, reg_list->num_of_regs);
>  	if (ret) {
>  		dev_err(&client->dev, "%s failed to set plls\n", __func__);
> @@ -1074,9 +1202,11 @@ static int imx258_init_controls(struct imx258 *imx258)
>  		vflip->flags |= V4L2_CTRL_FLAG_READ_ONLY;
>
>  	pixel_rate_max =
> -		link_freq_to_pixel_rate(imx258->link_freq_menu_items[0]);
> +		link_freq_to_pixel_rate(imx258->link_freq_menu_items[0],
> +					imx258->nlanes);
>  	pixel_rate_min =
> -		link_freq_to_pixel_rate(imx258->link_freq_menu_items[1]);
> +		link_freq_to_pixel_rate(imx258->link_freq_menu_items[1],
> +					imx258->nlanes);
>  	/* By default, PIXEL_RATE is read only */
>  	imx258->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops,
>  				V4L2_CID_PIXEL_RATE,
> @@ -1174,6 +1304,10 @@ static int imx258_get_regulators(struct imx258 *imx258,
>  static int imx258_probe(struct i2c_client *client)
>  {
>  	struct imx258 *imx258;
> +	struct fwnode_handle *endpoint;
> +	struct v4l2_fwnode_endpoint ep = {
> +		.bus_type = V4L2_MBUS_CSI2_DPHY
> +	};
>  	int ret;
>  	u32 val = 0;
>
> @@ -1216,13 +1350,38 @@ static int imx258_probe(struct i2c_client *client)
>  		return -EINVAL;
>  	}
>
> +	endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev), NULL);
> +	if (!endpoint) {
> +		dev_err(&client->dev, "Endpoint node not found\n");
> +		return -EINVAL;
> +	}
> +
> +	ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &ep);
> +	fwnode_handle_put(endpoint);
> +	if (ret == -ENXIO) {

Doesn't the core warns you already ? Anywy, doesn't hurt I suppose

> +		dev_err(&client->dev, "Unsupported bus type, should be CSI2\n");
> +		goto error_endpoint_poweron;
> +	} else if (ret) {
> +		dev_err(&client->dev, "Parsing endpoint node failed\n");
> +		goto error_endpoint_poweron;

It's a pretty peculiar name :) Why not 'error_endpoint_free' ?

Anyway, if parsing fails, I don't think you need to v4l2_fwnode_endpoint_free()
as the core should take care of doing so.

> +	}
> +
> +	/* Get number of data lanes */
> +	imx258->nlanes = ep.bus.mipi_csi2.num_data_lanes;
> +	if (imx258->nlanes != 2 && imx258->nlanes != 4) {
> +		dev_err(&client->dev, "Invalid data lanes: %u\n",
> +			imx258->nlanes);
> +		ret = -EINVAL;
> +		goto error_endpoint_poweron;
> +	}
> +
>  	/* Initialize subdev */
>  	v4l2_i2c_subdev_init(&imx258->sd, client, &imx258_subdev_ops);
>
>  	/* Will be powered off via pm_runtime_idle */
>  	ret = imx258_power_on(&client->dev);
>  	if (ret)
> -		return ret;
> +		goto error_endpoint_poweron;
>
>  	/* Check module identity */
>  	ret = imx258_identify_module(imx258);
> @@ -1255,6 +1414,7 @@ static int imx258_probe(struct i2c_client *client)
>  	pm_runtime_set_active(&client->dev);
>  	pm_runtime_enable(&client->dev);
>  	pm_runtime_idle(&client->dev);
> +	v4l2_fwnode_endpoint_free(&endpoint);

Do you need to free in _remove() too ?

>
>  	return 0;
>
> @@ -1267,6 +1427,9 @@ static int imx258_probe(struct i2c_client *client)
>  error_identify:
>  	imx258_power_off(&client->dev);
>
> +error_endpoint_poweron:
> +	v4l2_fwnode_endpoint_free(&ep);
> +
>  	return ret;
>  }
>
> --
> 2.25.1
>

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

* Re: [PATCH 11/21] media: i2c: imx258: Add get_selection for pixel array information
  2023-05-30 17:29 ` [PATCH 11/21] media: i2c: imx258: Add get_selection for pixel array information Dave Stevenson
@ 2023-06-02 13:24   ` Jacopo Mondi
  0 siblings, 0 replies; 54+ messages in thread
From: Jacopo Mondi @ 2023-06-02 13:24 UTC (permalink / raw)
  To: Dave Stevenson
  Cc: Sakari Ailus, linux-media, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree

Hi Dave

On Tue, May 30, 2023 at 06:29:50PM +0100, Dave Stevenson wrote:
> Libcamera requires the cropping information for each mode, so
> add this information to the driver.
>
Looks good!
Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>

> Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
> ---
>  drivers/media/i2c/imx258.c | 90 ++++++++++++++++++++++++++++++++++++++
>  1 file changed, 90 insertions(+)
>
> diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
> index 82ffe09e3bdc..1fa83fe82f27 100644
> --- a/drivers/media/i2c/imx258.c
> +++ b/drivers/media/i2c/imx258.c
> @@ -77,6 +77,14 @@
>  #define REG_CONFIG_MIRROR_FLIP		0x03
>  #define REG_CONFIG_FLIP_TEST_PATTERN	0x02
>
> +/* IMX258 native and active pixel array size. */
> +#define IMX258_NATIVE_WIDTH		4224U
> +#define IMX258_NATIVE_HEIGHT		3192U
> +#define IMX258_PIXEL_ARRAY_LEFT		8U
> +#define IMX258_PIXEL_ARRAY_TOP		16U
> +#define IMX258_PIXEL_ARRAY_WIDTH	4208U
> +#define IMX258_PIXEL_ARRAY_HEIGHT	3120U
> +
>  struct imx258_reg {
>  	u16 address;
>  	u8 val;
> @@ -115,6 +123,9 @@ struct imx258_mode {
>  	u32 link_freq_index;
>  	/* Default register values */
>  	struct imx258_reg_list reg_list;
> +
> +	/* Analog crop rectangle. */
> +	struct v4l2_rect crop;
>  };
>
>  /* 4208x3120 needs 1267Mbps/lane, 4 lanes. Use that rate on 2 lanes as well */
> @@ -562,6 +573,12 @@ static const struct imx258_mode supported_modes[] = {
>  			.regs = mode_4208x3120_regs,
>  		},
>  		.link_freq_index = IMX258_LINK_FREQ_1267MBPS,
> +		.crop = {
> +			.left = IMX258_PIXEL_ARRAY_LEFT,
> +			.top = IMX258_PIXEL_ARRAY_TOP,
> +			.width = 4208,
> +			.height = 3120,
> +		},
>  	},
>  	{
>  		.width = 2104,
> @@ -573,6 +590,12 @@ static const struct imx258_mode supported_modes[] = {
>  			.regs = mode_2104_1560_regs,
>  		},
>  		.link_freq_index = IMX258_LINK_FREQ_640MBPS,
> +		.crop = {
> +			.left = IMX258_PIXEL_ARRAY_LEFT,
> +			.top = IMX258_PIXEL_ARRAY_TOP,
> +			.width = 4208,
> +			.height = 3120,
> +		},
>  	},
>  	{
>  		.width = 1048,
> @@ -584,6 +607,12 @@ static const struct imx258_mode supported_modes[] = {
>  			.regs = mode_1048_780_regs,
>  		},
>  		.link_freq_index = IMX258_LINK_FREQ_640MBPS,
> +		.crop = {
> +			.left = IMX258_PIXEL_ARRAY_LEFT,
> +			.top = IMX258_PIXEL_ARRAY_TOP,
> +			.width = 4208,
> +			.height = 3120,
> +		},
>  	},
>  };
>
> @@ -703,6 +732,7 @@ static int imx258_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
>  {
>  	struct v4l2_mbus_framefmt *try_fmt =
>  		v4l2_subdev_get_try_format(sd, fh->state, 0);
> +	struct v4l2_rect *try_crop;
>
>  	/* Initialize try_fmt */
>  	try_fmt->width = supported_modes[0].width;
> @@ -710,6 +740,13 @@ static int imx258_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
>  	try_fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
>  	try_fmt->field = V4L2_FIELD_NONE;
>
> +	/* Initialize try_crop */
> +	try_crop = v4l2_subdev_get_try_crop(sd, fh->state, 0);
> +	try_crop->left = IMX258_PIXEL_ARRAY_LEFT;
> +	try_crop->top = IMX258_PIXEL_ARRAY_TOP;
> +	try_crop->width = IMX258_PIXEL_ARRAY_WIDTH;
> +	try_crop->height = IMX258_PIXEL_ARRAY_HEIGHT;
> +
>  	return 0;
>  }
>
> @@ -958,6 +995,58 @@ static int imx258_set_pad_format(struct v4l2_subdev *sd,
>  	return 0;
>  }
>
> +static const struct v4l2_rect *
> +__imx258_get_pad_crop(struct imx258 *imx258,
> +		      struct v4l2_subdev_state *sd_state,
> +		      unsigned int pad, enum v4l2_subdev_format_whence which)
> +{
> +	switch (which) {
> +	case V4L2_SUBDEV_FORMAT_TRY:
> +		return v4l2_subdev_get_try_crop(&imx258->sd, sd_state, pad);
> +	case V4L2_SUBDEV_FORMAT_ACTIVE:
> +		return &imx258->cur_mode->crop;
> +	}
> +
> +	return NULL;
> +}
> +
> +static int imx258_get_selection(struct v4l2_subdev *sd,
> +				struct v4l2_subdev_state *sd_state,
> +				struct v4l2_subdev_selection *sel)
> +{
> +	switch (sel->target) {
> +	case V4L2_SEL_TGT_CROP: {
> +		struct imx258 *imx258 = to_imx258(sd);
> +
> +		mutex_lock(&imx258->mutex);
> +		sel->r = *__imx258_get_pad_crop(imx258, sd_state, sel->pad,
> +						sel->which);
> +		mutex_unlock(&imx258->mutex);
> +
> +		return 0;
> +	}
> +
> +	case V4L2_SEL_TGT_NATIVE_SIZE:
> +		sel->r.left = 0;
> +		sel->r.top = 0;
> +		sel->r.width = IMX258_NATIVE_WIDTH;
> +		sel->r.height = IMX258_NATIVE_HEIGHT;
> +
> +		return 0;
> +
> +	case V4L2_SEL_TGT_CROP_DEFAULT:
> +	case V4L2_SEL_TGT_CROP_BOUNDS:
> +		sel->r.left = IMX258_PIXEL_ARRAY_LEFT;
> +		sel->r.top = IMX258_PIXEL_ARRAY_TOP;
> +		sel->r.width = IMX258_PIXEL_ARRAY_WIDTH;
> +		sel->r.height = IMX258_PIXEL_ARRAY_HEIGHT;
> +
> +		return 0;
> +	}
> +
> +	return -EINVAL;
> +}
> +
>  /* Start streaming */
>  static int imx258_start_streaming(struct imx258 *imx258)
>  {
> @@ -1170,6 +1259,7 @@ static const struct v4l2_subdev_pad_ops imx258_pad_ops = {
>  	.get_fmt = imx258_get_pad_format,
>  	.set_fmt = imx258_set_pad_format,
>  	.enum_frame_size = imx258_enum_frame_size,
> +	.get_selection = imx258_get_selection,
>  };
>
>  static const struct v4l2_subdev_ops imx258_subdev_ops = {
> --
> 2.25.1
>

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

* Re: [PATCH 12/21] media: i2c: imx258: Allow configuration of clock lane behaviour
  2023-05-30 17:29 ` [PATCH 12/21] media: i2c: imx258: Allow configuration of clock lane behaviour Dave Stevenson
@ 2023-06-02 13:26   ` Jacopo Mondi
  2023-06-02 15:18     ` Dave Stevenson
  0 siblings, 1 reply; 54+ messages in thread
From: Jacopo Mondi @ 2023-06-02 13:26 UTC (permalink / raw)
  To: Dave Stevenson
  Cc: Sakari Ailus, linux-media, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree

Hi Dave

On Tue, May 30, 2023 at 06:29:51PM +0100, Dave Stevenson wrote:
> The sensor supports the clock lane either remaining in HS mode
> during frame blanking, or dropping to LP11.
>
> Add configuration of the mode via V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK.

Assuming a follow-up patch for DT
Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>

>
> Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
> ---
>  drivers/media/i2c/imx258.c | 14 ++++++++++++++
>  1 file changed, 14 insertions(+)
>
> diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
> index 1fa83fe82f27..b5c2dcb7c9e6 100644
> --- a/drivers/media/i2c/imx258.c
> +++ b/drivers/media/i2c/imx258.c
> @@ -72,6 +72,8 @@
>  /* Test Pattern Control */
>  #define IMX258_REG_TEST_PATTERN		0x0600
>
> +#define IMX258_CLK_BLANK_STOP		0x4040
> +
>  /* Orientation */
>  #define REG_MIRROR_FLIP_CONTROL		0x0101
>  #define REG_CONFIG_MIRROR_FLIP		0x03
> @@ -634,6 +636,7 @@ struct imx258 {
>  	const struct imx258_link_freq_config *link_freq_configs;
>  	const s64 *link_freq_menu_items;
>  	unsigned int nlanes;
> +	unsigned int csi2_flags;
>
>  	/*
>  	 * Mutex for serialized access:
> @@ -1072,6 +1075,15 @@ static int imx258_start_streaming(struct imx258 *imx258)
>  		return ret;
>  	}
>
> +	ret = imx258_write_reg(imx258, IMX258_CLK_BLANK_STOP,
> +			       IMX258_REG_VALUE_08BIT,
> +			       imx258->csi2_flags & V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK ?
> +			       1 : 0);
> +	if (ret) {
> +		dev_err(&client->dev, "%s failed to set clock lane mode\n", __func__);
> +		return ret;
> +	}
> +
>  	/* Apply default values of current mode */
>  	reg_list = &imx258->cur_mode->reg_list;
>  	ret = imx258_write_regs(imx258, reg_list->regs, reg_list->num_of_regs);
> @@ -1486,6 +1498,8 @@ static int imx258_probe(struct i2c_client *client)
>  		goto error_endpoint_poweron;
>  	}
>
> +	imx258->csi2_flags = ep.bus.mipi_csi2.flags;
> +
>  	/* Initialize subdev */
>  	v4l2_i2c_subdev_init(&imx258->sd, client, &imx258_subdev_ops);
>
> --
> 2.25.1
>

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

* Re: [PATCH 13/21] media: i2c: imx258: Correct max FRM_LENGTH_LINES value
  2023-05-30 17:29 ` [PATCH 13/21] media: i2c: imx258: Correct max FRM_LENGTH_LINES value Dave Stevenson
@ 2023-06-02 13:33   ` Jacopo Mondi
  0 siblings, 0 replies; 54+ messages in thread
From: Jacopo Mondi @ 2023-06-02 13:33 UTC (permalink / raw)
  To: Dave Stevenson
  Cc: Sakari Ailus, linux-media, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree

On Tue, May 30, 2023 at 06:29:52PM +0100, Dave Stevenson wrote:
> The data sheet states that the maximum value for registers
> 0x0340/0x0341 FRM_LENGTH_LINES is 65525(decimal), not the
> 0xFFFF defined in this driver. Correct this limit.

It was close indeed :)
Good catch
Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>

>
> Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
> ---
>  drivers/media/i2c/imx258.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
> index b5c2dcb7c9e6..f5199e3243e8 100644
> --- a/drivers/media/i2c/imx258.c
> +++ b/drivers/media/i2c/imx258.c
> @@ -28,7 +28,7 @@
>  #define IMX258_VTS_30FPS		0x0c50
>  #define IMX258_VTS_30FPS_2K		0x0638
>  #define IMX258_VTS_30FPS_VGA		0x034c
> -#define IMX258_VTS_MAX			0xffff
> +#define IMX258_VTS_MAX			65525
>
>  #define IMX258_REG_VTS			0x0340
>
> --
> 2.25.1
>

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

* Re: [PATCH 14/21] media: i2c: imx258: Add support for long exposure modes
  2023-05-30 17:29 ` [PATCH 14/21] media: i2c: imx258: Add support for long exposure modes Dave Stevenson
@ 2023-06-02 13:38   ` Jacopo Mondi
  2023-06-02 17:12     ` Dave Stevenson
  0 siblings, 1 reply; 54+ messages in thread
From: Jacopo Mondi @ 2023-06-02 13:38 UTC (permalink / raw)
  To: Dave Stevenson
  Cc: Sakari Ailus, linux-media, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree

Hi Dave

On Tue, May 30, 2023 at 06:29:53PM +0100, Dave Stevenson wrote:
> The sensor has a register CIT_LSHIFT which extends the exposure
> and frame times by the specified power of 2 for longer
> exposure times.
>
> Add support for this by configuring this register via V4L2_CID_VBLANK
> and extending the V4L2_CID_EXPOSURE range accordingly.
>
> Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
> ---
>  drivers/media/i2c/imx258.c | 38 ++++++++++++++++++++++++++++++++------
>  1 file changed, 32 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
> index f5199e3243e8..1e424058fcb9 100644
> --- a/drivers/media/i2c/imx258.c
> +++ b/drivers/media/i2c/imx258.c
> @@ -69,6 +69,10 @@
>  #define IMX258_HDR_RATIO_STEP		1
>  #define IMX258_HDR_RATIO_DEFAULT	0x0
>
> +/* Long exposure multiplier */
> +#define IMX258_LONG_EXP_SHIFT_MAX	7
> +#define IMX258_LONG_EXP_SHIFT_REG	0x3002
> +
>  /* Test Pattern Control */
>  #define IMX258_REG_TEST_PATTERN		0x0600
>
> @@ -629,6 +633,8 @@ struct imx258 {
>  	struct v4l2_ctrl *vblank;
>  	struct v4l2_ctrl *hblank;
>  	struct v4l2_ctrl *exposure;
> +	/* Current long exposure factor in use. Set through V4L2_CID_VBLANK */
> +	unsigned int long_exp_shift;
>
>  	/* Current mode */
>  	const struct imx258_mode *cur_mode;
> @@ -793,6 +799,26 @@ static void imx258_adjust_exposure_range(struct imx258 *imx258)
>  				 exposure_def);
>  }
>
> +static int imx258_set_frame_length(struct imx258 *imx258, unsigned int val)
> +{
> +	int ret;
> +
> +	imx258->long_exp_shift = 0;
> +
> +	while (val > IMX258_VTS_MAX) {
> +		imx258->long_exp_shift++;
> +		val >>= 1;
> +	}
> +
> +	ret = imx258_write_reg(imx258, IMX258_REG_VTS,
> +			       IMX258_REG_VALUE_16BIT, val);
> +	if (ret)
> +		return ret;
> +
> +	return imx258_write_reg(imx258, IMX258_LONG_EXP_SHIFT_REG,
> +				IMX258_REG_VALUE_08BIT, imx258->long_exp_shift);
> +}
> +
>  static int imx258_set_ctrl(struct v4l2_ctrl *ctrl)
>  {
>  	struct imx258 *imx258 =
> @@ -823,7 +849,7 @@ static int imx258_set_ctrl(struct v4l2_ctrl *ctrl)
>  	case V4L2_CID_EXPOSURE:
>  		ret = imx258_write_reg(imx258, IMX258_REG_EXPOSURE,
>  				IMX258_REG_VALUE_16BIT,
> -				ctrl->val);
> +				ctrl->val >> imx258->long_exp_shift);

Shouldn't this be done only if vblank > VTS_MAX ?

>  		break;
>  	case V4L2_CID_DIGITAL_GAIN:
>  		ret = imx258_update_digital_gain(imx258, IMX258_REG_VALUE_16BIT,
> @@ -855,9 +881,8 @@ static int imx258_set_ctrl(struct v4l2_ctrl *ctrl)
>  		}
>  		break;
>  	case V4L2_CID_VBLANK:
> -		ret = imx258_write_reg(imx258, IMX258_REG_VTS,
> -				       IMX258_REG_VALUE_16BIT,
> -				       imx258->cur_mode->height + ctrl->val);
> +		ret = imx258_set_frame_length(imx258,
> +					      imx258->cur_mode->height + ctrl->val);
>  		break;
>  	default:
>  		dev_info(&client->dev,
> @@ -983,8 +1008,9 @@ static int imx258_set_pad_format(struct v4l2_subdev *sd,
>  			     imx258->cur_mode->height;
>  		__v4l2_ctrl_modify_range(
>  			imx258->vblank, vblank_min,
> -			IMX258_VTS_MAX - imx258->cur_mode->height, 1,
> -			vblank_def);
> +			((1 << IMX258_LONG_EXP_SHIFT_MAX) * IMX258_VTS_MAX) -
> +						imx258->cur_mode->height,
> +			1, vblank_def);
>  		__v4l2_ctrl_s_ctrl(imx258->vblank, vblank_def);
>  		h_blank =
>  			imx258->link_freq_configs[mode->link_freq_index].pixels_per_line
> --
> 2.25.1
>

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

* Re: [PATCH 15/21] media: i2c: imx258: Issue reset before starting streaming
  2023-05-30 17:29 ` [PATCH 15/21] media: i2c: imx258: Issue reset before starting streaming Dave Stevenson
@ 2023-06-02 13:42   ` Jacopo Mondi
  0 siblings, 0 replies; 54+ messages in thread
From: Jacopo Mondi @ 2023-06-02 13:42 UTC (permalink / raw)
  To: Dave Stevenson
  Cc: Sakari Ailus, linux-media, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree

Hi Dave

On Tue, May 30, 2023 at 06:29:54PM +0100, Dave Stevenson wrote:
> Whilst not documented, register 0x0103 bit 0 is the soft
> reset for the sensor, so send it before trying to configure
> the sensor.
>
> Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
> ---
>  drivers/media/i2c/imx258.c | 10 ++++++++++
>  1 file changed, 10 insertions(+)
>
> diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
> index 1e424058fcb9..7d6528f9ca4d 100644
> --- a/drivers/media/i2c/imx258.c
> +++ b/drivers/media/i2c/imx258.c
> @@ -20,6 +20,8 @@
>  #define IMX258_MODE_STANDBY		0x00
>  #define IMX258_MODE_STREAMING		0x01
>
> +#define IMX258_REG_RESET		0x0103
> +
>  /* Chip ID */
>  #define IMX258_REG_CHIP_ID		0x0016
>  #define IMX258_CHIP_ID			0x0258
> @@ -1084,6 +1086,14 @@ static int imx258_start_streaming(struct imx258 *imx258)
>  	const struct imx258_link_freq_config *link_freq_cfg;
>  	int ret, link_freq_index;
>
> +	ret = imx258_write_reg(imx258, IMX258_REG_RESET, IMX258_REG_VALUE_08BIT,
> +			       0x01);
> +	if (ret) {
> +		dev_err(&client->dev, "%s failed to reset sensor\n", __func__);
> +		return ret;
> +	}
> +	usleep_range(10000, 15000);

Is the reset delay documented as well ?

up to 15msec seems a long time. Also, you can use fsleep() if you
don't have very precise constraints..

> +
>  	/* Setup PLL */
>  	link_freq_index = imx258->cur_mode->link_freq_index;
>  	link_freq_cfg = &imx258->link_freq_configs[link_freq_index];
> --
> 2.25.1
>

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

* Re: [PATCH 16/21] media: i2c: imx258: Set pixel_rate range to the same as the value
  2023-05-30 17:29 ` [PATCH 16/21] media: i2c: imx258: Set pixel_rate range to the same as the value Dave Stevenson
@ 2023-06-02 13:44   ` Jacopo Mondi
  0 siblings, 0 replies; 54+ messages in thread
From: Jacopo Mondi @ 2023-06-02 13:44 UTC (permalink / raw)
  To: Dave Stevenson
  Cc: Sakari Ailus, linux-media, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree

On Tue, May 30, 2023 at 06:29:55PM +0100, Dave Stevenson wrote:
> With a read only control there is limited point in advertising
> a minimum and maximum for the control, so change to set the
> value, min, and max all to the selected pixel rate.
>
> Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
> ---
>  drivers/media/i2c/imx258.c | 18 +++++++-----------
>  1 file changed, 7 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
> index 7d6528f9ca4d..b9b650d40365 100644
> --- a/drivers/media/i2c/imx258.c
> +++ b/drivers/media/i2c/imx258.c
> @@ -1002,7 +1002,8 @@ static int imx258_set_pad_format(struct v4l2_subdev *sd,
>
>  		link_freq = imx258->link_freq_menu_items[mode->link_freq_index];
>  		pixel_rate = link_freq_to_pixel_rate(link_freq, imx258->nlanes);
> -		__v4l2_ctrl_s_ctrl_int64(imx258->pixel_rate, pixel_rate);
> +		__v4l2_ctrl_modify_range(imx258->pixel_rate, pixel_rate,
> +					 pixel_rate, 1, pixel_rate);
>  		/* Update limits and set FPS to default */
>  		vblank_def = imx258->cur_mode->vts_def -
>  			     imx258->cur_mode->height;
> @@ -1328,8 +1329,7 @@ static int imx258_init_controls(struct imx258 *imx258)
>  	struct v4l2_ctrl *vflip, *hflip;
>  	s64 vblank_def;
>  	s64 vblank_min;
> -	s64 pixel_rate_min;
> -	s64 pixel_rate_max;
> +	s64 pixel_rate;
>  	int ret;
>
>  	ctrl_hdlr = &imx258->ctrl_handler;
> @@ -1360,17 +1360,13 @@ static int imx258_init_controls(struct imx258 *imx258)
>  	if (vflip)
>  		vflip->flags |= V4L2_CTRL_FLAG_READ_ONLY;
>
> -	pixel_rate_max =
> -		link_freq_to_pixel_rate(imx258->link_freq_menu_items[0],
> -					imx258->nlanes);
> -	pixel_rate_min =
> -		link_freq_to_pixel_rate(imx258->link_freq_menu_items[1],
> -					imx258->nlanes);
> +	pixel_rate = link_freq_to_pixel_rate(imx258->link_freq_menu_items[0],
> +					     imx258->nlanes);
>  	/* By default, PIXEL_RATE is read only */
>  	imx258->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops,
>  				V4L2_CID_PIXEL_RATE,
> -				pixel_rate_min, pixel_rate_max,
> -				1, pixel_rate_max);
> +				pixel_rate, pixel_rate,
> +				1, pixel_rate);

seems legit!
Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>

>
>

Is there a double blank line here ? Could you take the occasion and
drop it ?

>  	vblank_def = imx258->cur_mode->vts_def - imx258->cur_mode->height;
> --
> 2.25.1
>

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

* Re: [PATCH 20/21] media: i2c: imx258: Change register settings for variants of the sensor
  2023-05-30 17:29 ` [PATCH 20/21] media: i2c: imx258: Change register settings for variants of the sensor Dave Stevenson
@ 2023-06-02 13:48   ` Jacopo Mondi
  2023-06-02 14:30     ` Dave Stevenson
  0 siblings, 1 reply; 54+ messages in thread
From: Jacopo Mondi @ 2023-06-02 13:48 UTC (permalink / raw)
  To: Dave Stevenson
  Cc: Sakari Ailus, linux-media, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree

Hi Dave

On Tue, May 30, 2023 at 06:29:59PM +0100, Dave Stevenson wrote:
> Sony have advised that there are variants of the IMX258 sensor which
> require slightly different register configuration to the mainline
> imx258 driver defaults.
>
> There is no available run-time detection for the variant, so add
> configuration via the DT compatible string.
>
> The Vision Components imx258 module supports PDAF, so add the
> register differences for that variant
>
> Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
> ---
>  drivers/media/i2c/imx258.c | 49 ++++++++++++++++++++++++++++++++++----
>  1 file changed, 45 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
> index 986757650378..98b5c1e3abff 100644
> --- a/drivers/media/i2c/imx258.c
> +++ b/drivers/media/i2c/imx258.c
> @@ -6,6 +6,7 @@
>  #include <linux/delay.h>
>  #include <linux/i2c.h>
>  #include <linux/module.h>
> +#include <linux/of_device.h>
>  #include <linux/pm_runtime.h>
>  #include <linux/regulator/consumer.h>
>  #include <media/v4l2-ctrls.h>
> @@ -320,8 +321,6 @@ static const struct imx258_reg mipi_642mbps_24mhz_4l[] = {
>
>  static const struct imx258_reg mode_common_regs[] = {
>  	{ 0x3051, 0x00 },
> -	{ 0x3052, 0x00 },
> -	{ 0x4E21, 0x14 },
>  	{ 0x6B11, 0xCF },
>  	{ 0x7FF0, 0x08 },
>  	{ 0x7FF1, 0x0F },
> @@ -344,7 +343,6 @@ static const struct imx258_reg mode_common_regs[] = {
>  	{ 0x7FA8, 0x03 },
>  	{ 0x7FA9, 0xFE },
>  	{ 0x7B24, 0x81 },
> -	{ 0x7B25, 0x00 },
>  	{ 0x6564, 0x07 },
>  	{ 0x6B0D, 0x41 },
>  	{ 0x653D, 0x04 },
> @@ -459,6 +457,33 @@ static const struct imx258_reg mode_1048_780_regs[] = {
>  	{ 0x034F, 0x0C },
>  };
>
> +struct imx258_variant_cfg {
> +	const struct imx258_reg *regs;
> +	unsigned int num_regs;
> +};
> +
> +static const struct imx258_reg imx258_cfg_regs[] = {
> +	{ 0x3052, 0x00 },
> +	{ 0x4E21, 0x14 },
> +	{ 0x7B25, 0x00 },
> +};
> +
> +static const struct imx258_variant_cfg imx258_cfg = {
> +	.regs = imx258_cfg_regs,
> +	.num_regs = ARRAY_SIZE(imx258_cfg_regs),
> +};
> +
> +static const struct imx258_reg imx258_pdaf_cfg_regs[] = {
> +	{ 0x3052, 0x01 },
> +	{ 0x4E21, 0x10 },
> +	{ 0x7B25, 0x01 },
> +};
> +
> +static const struct imx258_variant_cfg imx258_pdaf_cfg = {
> +	.regs = imx258_pdaf_cfg_regs,
> +	.num_regs = ARRAY_SIZE(imx258_pdaf_cfg_regs),
> +};
> +
>  static const char * const imx258_test_pattern_menu[] = {
>  	"Disabled",
>  	"Solid Colour",
> @@ -643,6 +668,8 @@ struct imx258 {
>  	struct v4l2_subdev sd;
>  	struct media_pad pad;
>
> +	const struct imx258_variant_cfg *variant_cfg;
> +
>  	struct v4l2_ctrl_handler ctrl_handler;
>  	/* V4L2 Controls */
>  	struct v4l2_ctrl *link_freq;
> @@ -1134,6 +1161,14 @@ static int imx258_start_streaming(struct imx258 *imx258)
>  		return ret;
>  	}
>
> +	ret = imx258_write_regs(imx258, imx258->variant_cfg->regs,
> +				imx258->variant_cfg->num_regs);
> +	if (ret) {
> +		dev_err(&client->dev, "%s failed to set variant config\n",
> +			__func__);
> +		return ret;
> +	}
> +
>  	ret = imx258_write_reg(imx258, IMX258_CLK_BLANK_STOP,
>  			       IMX258_REG_VALUE_08BIT,
>  			       imx258->csi2_flags & V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK ?
> @@ -1490,6 +1525,7 @@ static int imx258_probe(struct i2c_client *client)
>  	struct v4l2_fwnode_endpoint ep = {
>  		.bus_type = V4L2_MBUS_CSI2_DPHY
>  	};
> +	const struct of_device_id *match;

This seems to be unused

>  	int ret;
>  	u32 val = 0;
>
> @@ -1565,6 +1601,10 @@ static int imx258_probe(struct i2c_client *client)
>
>  	imx258->csi2_flags = ep.bus.mipi_csi2.flags;
>
> +	imx258->variant_cfg = of_device_get_match_data(&client->dev);
> +	if (!match)

Here you could check for !imx258->variant_cfg

> +		imx258->variant_cfg = &imx258_cfg;
> +
>  	/* Initialize subdev */
>  	v4l2_i2c_subdev_init(&imx258->sd, client, &imx258_subdev_ops);
>
> @@ -1653,7 +1693,8 @@ MODULE_DEVICE_TABLE(acpi, imx258_acpi_ids);
>  #endif
>
>  static const struct of_device_id imx258_dt_ids[] = {
> -	{ .compatible = "sony,imx258" },
> +	{ .compatible = "sony,imx258", .data = &imx258_cfg },
> +	{ .compatible = "sony,imx258-pdaf", .data = &imx258_pdaf_cfg },
>  	{ /* sentinel */ }
>  };
>  MODULE_DEVICE_TABLE(of, imx258_dt_ids);
> --
> 2.25.1
>

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

* Re: [PATCH 21/21] media: i2c: imx258: Make HFLIP and VFLIP controls writable
  2023-05-30 17:30 ` [PATCH 21/21] media: i2c: imx258: Make HFLIP and VFLIP controls writable Dave Stevenson
@ 2023-06-02 13:58   ` Jacopo Mondi
  2023-06-02 14:42     ` Dave Stevenson
  0 siblings, 1 reply; 54+ messages in thread
From: Jacopo Mondi @ 2023-06-02 13:58 UTC (permalink / raw)
  To: Dave Stevenson
  Cc: Sakari Ailus, linux-media, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree

Hi Dave

On Tue, May 30, 2023 at 06:30:00PM +0100, Dave Stevenson wrote:
> The sensor supports H & V flips, but the controls were READ_ONLY.
>
> Note that the Bayer order changes with these flips, therefore
> they set the V4L2_CTRL_FLAG_MODIFY_LAYOUT property.

Nice!

>
> Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
> ---
>  drivers/media/i2c/imx258.c | 99 ++++++++++++++++++++++++--------------
>  1 file changed, 64 insertions(+), 35 deletions(-)
>
> diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
> index 98b5c1e3abff..cf90ac66e14c 100644
> --- a/drivers/media/i2c/imx258.c
> +++ b/drivers/media/i2c/imx258.c
> @@ -83,8 +83,8 @@
>
>  /* Orientation */
>  #define REG_MIRROR_FLIP_CONTROL		0x0101
> -#define REG_CONFIG_MIRROR_FLIP		0x03
> -#define REG_CONFIG_FLIP_TEST_PATTERN	0x02
> +#define REG_CONFIG_MIRROR_HFLIP		0x01
> +#define REG_CONFIG_MIRROR_VFLIP		0x02
>
>  /* IMX258 native and active pixel array size. */
>  #define IMX258_NATIVE_WIDTH		4224U
> @@ -484,6 +484,23 @@ static const struct imx258_variant_cfg imx258_pdaf_cfg = {
>  	.num_regs = ARRAY_SIZE(imx258_pdaf_cfg_regs),
>  };
>
> +/*
> + * The supported formats.
> + * This table MUST contain 4 entries per format, to cover the various flip
> + * combinations in the order
> + * - no flip
> + * - h flip
> + * - v flip
> + * - h&v flips
> + */
> +static const u32 codes[] = {
> +	/* 10-bit modes. */
> +	MEDIA_BUS_FMT_SRGGB10_1X10,
> +	MEDIA_BUS_FMT_SGRBG10_1X10,
> +	MEDIA_BUS_FMT_SGBRG10_1X10,
> +	MEDIA_BUS_FMT_SBGGR10_1X10
> +};
> +
>  static const char * const imx258_test_pattern_menu[] = {
>  	"Disabled",
>  	"Solid Colour",
> @@ -677,6 +694,8 @@ struct imx258 {
>  	struct v4l2_ctrl *vblank;
>  	struct v4l2_ctrl *hblank;
>  	struct v4l2_ctrl *exposure;
> +	struct v4l2_ctrl *hflip;
> +	struct v4l2_ctrl *vflip;
>  	/* Current long exposure factor in use. Set through V4L2_CID_VBLANK */
>  	unsigned int long_exp_shift;
>
> @@ -780,9 +799,22 @@ static int imx258_write_regs(struct imx258 *imx258,
>  	return 0;
>  }
>
> +/* Get bayer order based on flip setting. */
> +static u32 imx258_get_format_code(struct imx258 *imx258)

can struct imx258 be const ?

> +{
> +	unsigned int i;
> +
> +	lockdep_assert_held(&imx258->mutex);
> +
> +	i = (imx258->vflip->val ? 2 : 0) |
> +	    (imx258->hflip->val ? 1 : 0);
> +
> +	return codes[i];
> +}

An empty line wouldn't hurt

>  /* Open sub-device */
>  static int imx258_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
>  {
> +	struct imx258 *imx258 = to_imx258(sd);
>  	struct v4l2_mbus_framefmt *try_fmt =
>  		v4l2_subdev_get_try_format(sd, fh->state, 0);
>  	struct v4l2_rect *try_crop;
> @@ -790,7 +822,7 @@ static int imx258_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
>  	/* Initialize try_fmt */
>  	try_fmt->width = supported_modes[0].width;
>  	try_fmt->height = supported_modes[0].height;
> -	try_fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
> +	try_fmt->code = imx258_get_format_code(imx258);
>  	try_fmt->field = V4L2_FIELD_NONE;
>
>  	/* Initialize try_crop */
> @@ -903,10 +935,6 @@ static int imx258_set_ctrl(struct v4l2_ctrl *ctrl)
>  		ret = imx258_write_reg(imx258, IMX258_REG_TEST_PATTERN,
>  				IMX258_REG_VALUE_16BIT,
>  				ctrl->val);
> -		ret = imx258_write_reg(imx258, REG_MIRROR_FLIP_CONTROL,
> -				IMX258_REG_VALUE_08BIT,
> -				!ctrl->val ? REG_CONFIG_MIRROR_FLIP :
> -				REG_CONFIG_FLIP_TEST_PATTERN);
>  		break;
>  	case V4L2_CID_WIDE_DYNAMIC_RANGE:
>  		if (!ctrl->val) {
> @@ -928,6 +956,15 @@ static int imx258_set_ctrl(struct v4l2_ctrl *ctrl)
>  		ret = imx258_set_frame_length(imx258,
>  					      imx258->cur_mode->height + ctrl->val);
>  		break;
> +	case V4L2_CID_VFLIP:
> +	case V4L2_CID_HFLIP:
> +		ret = imx258_write_reg(imx258, REG_MIRROR_FLIP_CONTROL,
> +				       IMX258_REG_VALUE_08BIT,
> +				       (imx258->hflip->val ?
> +					REG_CONFIG_MIRROR_HFLIP : 0) |
> +				       (imx258->vflip->val ?
> +					REG_CONFIG_MIRROR_VFLIP : 0));
> +		break;
>  	default:
>  		dev_info(&client->dev,
>  			 "ctrl(id:0x%x,val:0x%x) is not handled\n",
> @@ -949,11 +986,13 @@ static int imx258_enum_mbus_code(struct v4l2_subdev *sd,
>  				  struct v4l2_subdev_state *sd_state,
>  				  struct v4l2_subdev_mbus_code_enum *code)
>  {
> -	/* Only one bayer order(GRBG) is supported */
> +	struct imx258 *imx258 = to_imx258(sd);
> +
> +	/* Only one bayer format (10 bit) is supported */
>  	if (code->index > 0)
>  		return -EINVAL;
>
> -	code->code = MEDIA_BUS_FMT_SBGGR10_1X10;
> +	code->code = imx258_get_format_code(imx258);
>
>  	return 0;
>  }
> @@ -962,10 +1001,11 @@ static int imx258_enum_frame_size(struct v4l2_subdev *sd,
>  				  struct v4l2_subdev_state *sd_state,
>  				  struct v4l2_subdev_frame_size_enum *fse)
>  {
> +	struct imx258 *imx258 = to_imx258(sd);
>  	if (fse->index >= ARRAY_SIZE(supported_modes))
>  		return -EINVAL;
>
> -	if (fse->code != MEDIA_BUS_FMT_SBGGR10_1X10)
> +	if (fse->code != imx258_get_format_code(imx258))
>  		return -EINVAL;
>
>  	fse->min_width = supported_modes[fse->index].width;
> @@ -976,12 +1016,13 @@ static int imx258_enum_frame_size(struct v4l2_subdev *sd,
>  	return 0;
>  }
>
> -static void imx258_update_pad_format(const struct imx258_mode *mode,
> +static void imx258_update_pad_format(struct imx258 *imx258,
> +				     const struct imx258_mode *mode,

Can't you get mode from imx258->cur_mode ?

>  				     struct v4l2_subdev_format *fmt)
>  {
>  	fmt->format.width = mode->width;
>  	fmt->format.height = mode->height;
> -	fmt->format.code = MEDIA_BUS_FMT_SBGGR10_1X10;
> +	fmt->format.code = imx258_get_format_code(imx258);
>  	fmt->format.field = V4L2_FIELD_NONE;
>  }
>
> @@ -994,7 +1035,7 @@ static int __imx258_get_pad_format(struct imx258 *imx258,
>  							  sd_state,
>  							  fmt->pad);
>  	else
> -		imx258_update_pad_format(imx258->cur_mode, fmt);
> +		imx258_update_pad_format(imx258, imx258->cur_mode, fmt);
>
>  	return 0;
>  }
> @@ -1030,13 +1071,12 @@ static int imx258_set_pad_format(struct v4l2_subdev *sd,
>
>  	mutex_lock(&imx258->mutex);
>
> -	/* Only one raw bayer(GBRG) order is supported */
> -	fmt->format.code = MEDIA_BUS_FMT_SBGGR10_1X10;
> +	fmt->format.code = imx258_get_format_code(imx258);
>
>  	mode = v4l2_find_nearest_size(supported_modes,
>  		ARRAY_SIZE(supported_modes), width, height,
>  		fmt->format.width, fmt->format.height);
> -	imx258_update_pad_format(mode, fmt);
> +	imx258_update_pad_format(imx258, mode, fmt);
>  	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
>  		framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
>  		*framefmt = fmt->format;
> @@ -1186,15 +1226,6 @@ static int imx258_start_streaming(struct imx258 *imx258)
>  		return ret;
>  	}
>
> -	/* Set Orientation be 180 degree */
> -	ret = imx258_write_reg(imx258, REG_MIRROR_FLIP_CONTROL,
> -			       IMX258_REG_VALUE_08BIT, REG_CONFIG_MIRROR_FLIP);
> -	if (ret) {
> -		dev_err(&client->dev, "%s failed to set orientation\n",
> -			__func__);
> -		return ret;
> -	}
> -
>  	/* Apply customized values from user */
>  	ret =  __v4l2_ctrl_handler_setup(imx258->sd.ctrl_handler);
>  	if (ret)
> @@ -1383,7 +1414,6 @@ static int imx258_init_controls(struct imx258 *imx258)
>  	struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd);
>  	const struct imx258_link_freq_config *link_freq_cfgs;
>  	struct v4l2_fwnode_device_properties props;
> -	struct v4l2_ctrl *vflip, *hflip;
>  	struct v4l2_ctrl_handler *ctrl_hdlr;
>  	const struct imx258_link_cfg *link_cfg;
>  	s64 vblank_def;
> @@ -1408,16 +1438,15 @@ static int imx258_init_controls(struct imx258 *imx258)
>  	if (imx258->link_freq)
>  		imx258->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
>
> -	/* The driver only supports one bayer order and flips by default. */
> -	hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops,
> -				  V4L2_CID_HFLIP, 1, 1, 1, 1);
> -	if (hflip)
> -		hflip->flags |= V4L2_CTRL_FLAG_READ_ONLY;
> +	imx258->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops,
> +					  V4L2_CID_HFLIP, 0, 1, 1, 1);
> +	if (imx258->hflip)
> +		imx258->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
>
> -	vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops,
> -				  V4L2_CID_VFLIP, 1, 1, 1, 1);
> -	if (vflip)
> -		vflip->flags |= V4L2_CTRL_FLAG_READ_ONLY;
> +	imx258->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops,
> +					  V4L2_CID_VFLIP, 0, 1, 1, 1);
> +	if (imx258->vflip)
> +		imx258->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;

if flips are now writable, should they be enabled by default ?

>
>  	link_freq_cfgs = &imx258->link_freq_configs[0];
>  	link_cfg = link_freq_cfgs[imx258->lane_mode_idx].link_cfg;
> --
> 2.25.1
>

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

* Re: [PATCH 20/21] media: i2c: imx258: Change register settings for variants of the sensor
  2023-06-02 13:48   ` Jacopo Mondi
@ 2023-06-02 14:30     ` Dave Stevenson
  0 siblings, 0 replies; 54+ messages in thread
From: Dave Stevenson @ 2023-06-02 14:30 UTC (permalink / raw)
  To: Jacopo Mondi
  Cc: Sakari Ailus, linux-media, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree

Hi Jacopo

On Fri, 2 Jun 2023 at 14:48, Jacopo Mondi <jacopo.mondi@ideasonboard.com> wrote:
>
> Hi Dave
>
> On Tue, May 30, 2023 at 06:29:59PM +0100, Dave Stevenson wrote:
> > Sony have advised that there are variants of the IMX258 sensor which
> > require slightly different register configuration to the mainline
> > imx258 driver defaults.
> >
> > There is no available run-time detection for the variant, so add
> > configuration via the DT compatible string.
> >
> > The Vision Components imx258 module supports PDAF, so add the
> > register differences for that variant
> >
> > Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
> > ---
> >  drivers/media/i2c/imx258.c | 49 ++++++++++++++++++++++++++++++++++----
> >  1 file changed, 45 insertions(+), 4 deletions(-)
> >
> > diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
> > index 986757650378..98b5c1e3abff 100644
> > --- a/drivers/media/i2c/imx258.c
> > +++ b/drivers/media/i2c/imx258.c
> > @@ -6,6 +6,7 @@
> >  #include <linux/delay.h>
> >  #include <linux/i2c.h>
> >  #include <linux/module.h>
> > +#include <linux/of_device.h>
> >  #include <linux/pm_runtime.h>
> >  #include <linux/regulator/consumer.h>
> >  #include <media/v4l2-ctrls.h>
> > @@ -320,8 +321,6 @@ static const struct imx258_reg mipi_642mbps_24mhz_4l[] = {
> >
> >  static const struct imx258_reg mode_common_regs[] = {
> >       { 0x3051, 0x00 },
> > -     { 0x3052, 0x00 },
> > -     { 0x4E21, 0x14 },
> >       { 0x6B11, 0xCF },
> >       { 0x7FF0, 0x08 },
> >       { 0x7FF1, 0x0F },
> > @@ -344,7 +343,6 @@ static const struct imx258_reg mode_common_regs[] = {
> >       { 0x7FA8, 0x03 },
> >       { 0x7FA9, 0xFE },
> >       { 0x7B24, 0x81 },
> > -     { 0x7B25, 0x00 },
> >       { 0x6564, 0x07 },
> >       { 0x6B0D, 0x41 },
> >       { 0x653D, 0x04 },
> > @@ -459,6 +457,33 @@ static const struct imx258_reg mode_1048_780_regs[] = {
> >       { 0x034F, 0x0C },
> >  };
> >
> > +struct imx258_variant_cfg {
> > +     const struct imx258_reg *regs;
> > +     unsigned int num_regs;
> > +};
> > +
> > +static const struct imx258_reg imx258_cfg_regs[] = {
> > +     { 0x3052, 0x00 },
> > +     { 0x4E21, 0x14 },
> > +     { 0x7B25, 0x00 },
> > +};
> > +
> > +static const struct imx258_variant_cfg imx258_cfg = {
> > +     .regs = imx258_cfg_regs,
> > +     .num_regs = ARRAY_SIZE(imx258_cfg_regs),
> > +};
> > +
> > +static const struct imx258_reg imx258_pdaf_cfg_regs[] = {
> > +     { 0x3052, 0x01 },
> > +     { 0x4E21, 0x10 },
> > +     { 0x7B25, 0x01 },
> > +};
> > +
> > +static const struct imx258_variant_cfg imx258_pdaf_cfg = {
> > +     .regs = imx258_pdaf_cfg_regs,
> > +     .num_regs = ARRAY_SIZE(imx258_pdaf_cfg_regs),
> > +};
> > +
> >  static const char * const imx258_test_pattern_menu[] = {
> >       "Disabled",
> >       "Solid Colour",
> > @@ -643,6 +668,8 @@ struct imx258 {
> >       struct v4l2_subdev sd;
> >       struct media_pad pad;
> >
> > +     const struct imx258_variant_cfg *variant_cfg;
> > +
> >       struct v4l2_ctrl_handler ctrl_handler;
> >       /* V4L2 Controls */
> >       struct v4l2_ctrl *link_freq;
> > @@ -1134,6 +1161,14 @@ static int imx258_start_streaming(struct imx258 *imx258)
> >               return ret;
> >       }
> >
> > +     ret = imx258_write_regs(imx258, imx258->variant_cfg->regs,
> > +                             imx258->variant_cfg->num_regs);
> > +     if (ret) {
> > +             dev_err(&client->dev, "%s failed to set variant config\n",
> > +                     __func__);
> > +             return ret;
> > +     }
> > +
> >       ret = imx258_write_reg(imx258, IMX258_CLK_BLANK_STOP,
> >                              IMX258_REG_VALUE_08BIT,
> >                              imx258->csi2_flags & V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK ?
> > @@ -1490,6 +1525,7 @@ static int imx258_probe(struct i2c_client *client)
> >       struct v4l2_fwnode_endpoint ep = {
> >               .bus_type = V4L2_MBUS_CSI2_DPHY
> >       };
> > +     const struct of_device_id *match;
>
> This seems to be unused
>
> >       int ret;
> >       u32 val = 0;
> >
> > @@ -1565,6 +1601,10 @@ static int imx258_probe(struct i2c_client *client)
> >
> >       imx258->csi2_flags = ep.bus.mipi_csi2.flags;
> >
> > +     imx258->variant_cfg = of_device_get_match_data(&client->dev);
> > +     if (!match)
>
> Here you could check for !imx258->variant_cfg

Thank you.

I did have
match = i2c_of_match_device(imx258_dt_ids, client);
but swapped to of_device_get_match_data as it's cleaner and avoids
having to move imx258_dt_ids around. Shame I missed the error
condition :-(

> > +             imx258->variant_cfg = &imx258_cfg;
> > +
> >       /* Initialize subdev */
> >       v4l2_i2c_subdev_init(&imx258->sd, client, &imx258_subdev_ops);
> >
> > @@ -1653,7 +1693,8 @@ MODULE_DEVICE_TABLE(acpi, imx258_acpi_ids);
> >  #endif
> >
> >  static const struct of_device_id imx258_dt_ids[] = {
> > -     { .compatible = "sony,imx258" },
> > +     { .compatible = "sony,imx258", .data = &imx258_cfg },
> > +     { .compatible = "sony,imx258-pdaf", .data = &imx258_pdaf_cfg },
> >       { /* sentinel */ }
> >  };
> >  MODULE_DEVICE_TABLE(of, imx258_dt_ids);
> > --
> > 2.25.1
> >

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

* Re: [PATCH 21/21] media: i2c: imx258: Make HFLIP and VFLIP controls writable
  2023-06-02 13:58   ` Jacopo Mondi
@ 2023-06-02 14:42     ` Dave Stevenson
  0 siblings, 0 replies; 54+ messages in thread
From: Dave Stevenson @ 2023-06-02 14:42 UTC (permalink / raw)
  To: Jacopo Mondi
  Cc: Sakari Ailus, linux-media, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree

Hi Jacopo

On Fri, 2 Jun 2023 at 14:58, Jacopo Mondi <jacopo.mondi@ideasonboard.com> wrote:
>
> Hi Dave
>
> On Tue, May 30, 2023 at 06:30:00PM +0100, Dave Stevenson wrote:
> > The sensor supports H & V flips, but the controls were READ_ONLY.
> >
> > Note that the Bayer order changes with these flips, therefore
> > they set the V4L2_CTRL_FLAG_MODIFY_LAYOUT property.
>
> Nice!
>
> >
> > Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
> > ---
> >  drivers/media/i2c/imx258.c | 99 ++++++++++++++++++++++++--------------
> >  1 file changed, 64 insertions(+), 35 deletions(-)
> >
> > diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
> > index 98b5c1e3abff..cf90ac66e14c 100644
> > --- a/drivers/media/i2c/imx258.c
> > +++ b/drivers/media/i2c/imx258.c
> > @@ -83,8 +83,8 @@
> >
> >  /* Orientation */
> >  #define REG_MIRROR_FLIP_CONTROL              0x0101
> > -#define REG_CONFIG_MIRROR_FLIP               0x03
> > -#define REG_CONFIG_FLIP_TEST_PATTERN 0x02
> > +#define REG_CONFIG_MIRROR_HFLIP              0x01
> > +#define REG_CONFIG_MIRROR_VFLIP              0x02
> >
> >  /* IMX258 native and active pixel array size. */
> >  #define IMX258_NATIVE_WIDTH          4224U
> > @@ -484,6 +484,23 @@ static const struct imx258_variant_cfg imx258_pdaf_cfg = {
> >       .num_regs = ARRAY_SIZE(imx258_pdaf_cfg_regs),
> >  };
> >
> > +/*
> > + * The supported formats.
> > + * This table MUST contain 4 entries per format, to cover the various flip
> > + * combinations in the order
> > + * - no flip
> > + * - h flip
> > + * - v flip
> > + * - h&v flips
> > + */
> > +static const u32 codes[] = {
> > +     /* 10-bit modes. */
> > +     MEDIA_BUS_FMT_SRGGB10_1X10,
> > +     MEDIA_BUS_FMT_SGRBG10_1X10,
> > +     MEDIA_BUS_FMT_SGBRG10_1X10,
> > +     MEDIA_BUS_FMT_SBGGR10_1X10
> > +};
> > +
> >  static const char * const imx258_test_pattern_menu[] = {
> >       "Disabled",
> >       "Solid Colour",
> > @@ -677,6 +694,8 @@ struct imx258 {
> >       struct v4l2_ctrl *vblank;
> >       struct v4l2_ctrl *hblank;
> >       struct v4l2_ctrl *exposure;
> > +     struct v4l2_ctrl *hflip;
> > +     struct v4l2_ctrl *vflip;
> >       /* Current long exposure factor in use. Set through V4L2_CID_VBLANK */
> >       unsigned int long_exp_shift;
> >
> > @@ -780,9 +799,22 @@ static int imx258_write_regs(struct imx258 *imx258,
> >       return 0;
> >  }
> >
> > +/* Get bayer order based on flip setting. */
> > +static u32 imx258_get_format_code(struct imx258 *imx258)
>
> can struct imx258 be const ?

It can

> > +{
> > +     unsigned int i;
> > +
> > +     lockdep_assert_held(&imx258->mutex);
> > +
> > +     i = (imx258->vflip->val ? 2 : 0) |
> > +         (imx258->hflip->val ? 1 : 0);
> > +
> > +     return codes[i];
> > +}
>
> An empty line wouldn't hurt

Done

> >  /* Open sub-device */
> >  static int imx258_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
> >  {
> > +     struct imx258 *imx258 = to_imx258(sd);
> >       struct v4l2_mbus_framefmt *try_fmt =
> >               v4l2_subdev_get_try_format(sd, fh->state, 0);
> >       struct v4l2_rect *try_crop;
> > @@ -790,7 +822,7 @@ static int imx258_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
> >       /* Initialize try_fmt */
> >       try_fmt->width = supported_modes[0].width;
> >       try_fmt->height = supported_modes[0].height;
> > -     try_fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
> > +     try_fmt->code = imx258_get_format_code(imx258);
> >       try_fmt->field = V4L2_FIELD_NONE;
> >
> >       /* Initialize try_crop */
> > @@ -903,10 +935,6 @@ static int imx258_set_ctrl(struct v4l2_ctrl *ctrl)
> >               ret = imx258_write_reg(imx258, IMX258_REG_TEST_PATTERN,
> >                               IMX258_REG_VALUE_16BIT,
> >                               ctrl->val);
> > -             ret = imx258_write_reg(imx258, REG_MIRROR_FLIP_CONTROL,
> > -                             IMX258_REG_VALUE_08BIT,
> > -                             !ctrl->val ? REG_CONFIG_MIRROR_FLIP :
> > -                             REG_CONFIG_FLIP_TEST_PATTERN);
> >               break;
> >       case V4L2_CID_WIDE_DYNAMIC_RANGE:
> >               if (!ctrl->val) {
> > @@ -928,6 +956,15 @@ static int imx258_set_ctrl(struct v4l2_ctrl *ctrl)
> >               ret = imx258_set_frame_length(imx258,
> >                                             imx258->cur_mode->height + ctrl->val);
> >               break;
> > +     case V4L2_CID_VFLIP:
> > +     case V4L2_CID_HFLIP:
> > +             ret = imx258_write_reg(imx258, REG_MIRROR_FLIP_CONTROL,
> > +                                    IMX258_REG_VALUE_08BIT,
> > +                                    (imx258->hflip->val ?
> > +                                     REG_CONFIG_MIRROR_HFLIP : 0) |
> > +                                    (imx258->vflip->val ?
> > +                                     REG_CONFIG_MIRROR_VFLIP : 0));
> > +             break;
> >       default:
> >               dev_info(&client->dev,
> >                        "ctrl(id:0x%x,val:0x%x) is not handled\n",
> > @@ -949,11 +986,13 @@ static int imx258_enum_mbus_code(struct v4l2_subdev *sd,
> >                                 struct v4l2_subdev_state *sd_state,
> >                                 struct v4l2_subdev_mbus_code_enum *code)
> >  {
> > -     /* Only one bayer order(GRBG) is supported */
> > +     struct imx258 *imx258 = to_imx258(sd);
> > +
> > +     /* Only one bayer format (10 bit) is supported */
> >       if (code->index > 0)
> >               return -EINVAL;
> >
> > -     code->code = MEDIA_BUS_FMT_SBGGR10_1X10;
> > +     code->code = imx258_get_format_code(imx258);
> >
> >       return 0;
> >  }
> > @@ -962,10 +1001,11 @@ static int imx258_enum_frame_size(struct v4l2_subdev *sd,
> >                                 struct v4l2_subdev_state *sd_state,
> >                                 struct v4l2_subdev_frame_size_enum *fse)
> >  {
> > +     struct imx258 *imx258 = to_imx258(sd);
> >       if (fse->index >= ARRAY_SIZE(supported_modes))
> >               return -EINVAL;
> >
> > -     if (fse->code != MEDIA_BUS_FMT_SBGGR10_1X10)
> > +     if (fse->code != imx258_get_format_code(imx258))
> >               return -EINVAL;
> >
> >       fse->min_width = supported_modes[fse->index].width;
> > @@ -976,12 +1016,13 @@ static int imx258_enum_frame_size(struct v4l2_subdev *sd,
> >       return 0;
> >  }
> >
> > -static void imx258_update_pad_format(const struct imx258_mode *mode,
> > +static void imx258_update_pad_format(struct imx258 *imx258,
> > +                                  const struct imx258_mode *mode,
>
> Can't you get mode from imx258->cur_mode ?

It's called from imx258_set_pad_format for both SET and TRY, so needs
to be able to work on the new mode to be selected/tried as well as the
current mode.

> >                                    struct v4l2_subdev_format *fmt)
> >  {
> >       fmt->format.width = mode->width;
> >       fmt->format.height = mode->height;
> > -     fmt->format.code = MEDIA_BUS_FMT_SBGGR10_1X10;
> > +     fmt->format.code = imx258_get_format_code(imx258);
> >       fmt->format.field = V4L2_FIELD_NONE;
> >  }
> >
> > @@ -994,7 +1035,7 @@ static int __imx258_get_pad_format(struct imx258 *imx258,
> >                                                         sd_state,
> >                                                         fmt->pad);
> >       else
> > -             imx258_update_pad_format(imx258->cur_mode, fmt);
> > +             imx258_update_pad_format(imx258, imx258->cur_mode, fmt);
> >
> >       return 0;
> >  }
> > @@ -1030,13 +1071,12 @@ static int imx258_set_pad_format(struct v4l2_subdev *sd,
> >
> >       mutex_lock(&imx258->mutex);
> >
> > -     /* Only one raw bayer(GBRG) order is supported */
> > -     fmt->format.code = MEDIA_BUS_FMT_SBGGR10_1X10;
> > +     fmt->format.code = imx258_get_format_code(imx258);
> >
> >       mode = v4l2_find_nearest_size(supported_modes,
> >               ARRAY_SIZE(supported_modes), width, height,
> >               fmt->format.width, fmt->format.height);
> > -     imx258_update_pad_format(mode, fmt);
> > +     imx258_update_pad_format(imx258, mode, fmt);
> >       if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
> >               framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
> >               *framefmt = fmt->format;
> > @@ -1186,15 +1226,6 @@ static int imx258_start_streaming(struct imx258 *imx258)
> >               return ret;
> >       }
> >
> > -     /* Set Orientation be 180 degree */
> > -     ret = imx258_write_reg(imx258, REG_MIRROR_FLIP_CONTROL,
> > -                            IMX258_REG_VALUE_08BIT, REG_CONFIG_MIRROR_FLIP);
> > -     if (ret) {
> > -             dev_err(&client->dev, "%s failed to set orientation\n",
> > -                     __func__);
> > -             return ret;
> > -     }
> > -
> >       /* Apply customized values from user */
> >       ret =  __v4l2_ctrl_handler_setup(imx258->sd.ctrl_handler);
> >       if (ret)
> > @@ -1383,7 +1414,6 @@ static int imx258_init_controls(struct imx258 *imx258)
> >       struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd);
> >       const struct imx258_link_freq_config *link_freq_cfgs;
> >       struct v4l2_fwnode_device_properties props;
> > -     struct v4l2_ctrl *vflip, *hflip;
> >       struct v4l2_ctrl_handler *ctrl_hdlr;
> >       const struct imx258_link_cfg *link_cfg;
> >       s64 vblank_def;
> > @@ -1408,16 +1438,15 @@ static int imx258_init_controls(struct imx258 *imx258)
> >       if (imx258->link_freq)
> >               imx258->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
> >
> > -     /* The driver only supports one bayer order and flips by default. */
> > -     hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops,
> > -                               V4L2_CID_HFLIP, 1, 1, 1, 1);
> > -     if (hflip)
> > -             hflip->flags |= V4L2_CTRL_FLAG_READ_ONLY;
> > +     imx258->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops,
> > +                                       V4L2_CID_HFLIP, 0, 1, 1, 1);
> > +     if (imx258->hflip)
> > +             imx258->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
> >
> > -     vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops,
> > -                               V4L2_CID_VFLIP, 1, 1, 1, 1);
> > -     if (vflip)
> > -             vflip->flags |= V4L2_CTRL_FLAG_READ_ONLY;
> > +     imx258->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops,
> > +                                       V4L2_CID_VFLIP, 0, 1, 1, 1);
> > +     if (imx258->vflip)
> > +             imx258->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
>
> if flips are now writable, should they be enabled by default ?

This is the potential debate.

An existing userspace app is using this driver and it renders as
desired. Merge this change and suddenly all their images are upside
down, and that's assuming they haven't hard coded the Bayer order
which has now changed due to correcting the cropping registers.
Some would say that is a regression.

I know you'd discussed it with Sakari, but wasn't totally clear on the
final decision. It's part of the reason why I had this as the final
patch, because then it's easy to drop whilst discussing it.

  Dave

> >
> >       link_freq_cfgs = &imx258->link_freq_configs[0];
> >       link_cfg = link_freq_cfgs[imx258->lane_mode_idx].link_cfg;
> > --
> > 2.25.1
> >

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

* Re: [PATCH 12/21] media: i2c: imx258: Allow configuration of clock lane behaviour
  2023-06-02 13:26   ` Jacopo Mondi
@ 2023-06-02 15:18     ` Dave Stevenson
  0 siblings, 0 replies; 54+ messages in thread
From: Dave Stevenson @ 2023-06-02 15:18 UTC (permalink / raw)
  To: Jacopo Mondi
  Cc: Sakari Ailus, linux-media, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree

Hi Jacopo

On Fri, 2 Jun 2023 at 14:27, Jacopo Mondi <jacopo.mondi@ideasonboard.com> wrote:
>
> Hi Dave
>
> On Tue, May 30, 2023 at 06:29:51PM +0100, Dave Stevenson wrote:
> > The sensor supports the clock lane either remaining in HS mode
> > during frame blanking, or dropping to LP11.
> >
> > Add configuration of the mode via V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK.
>
> Assuming a follow-up patch for DT
> Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>

It's already covered in video-interfaces.yaml, and is an optional flag
as the driver will work in either manner, so do the bindings need
updating?

In checking the default value for this register, it is 0x01, or non-continuous.
The original omission of this property from the binding and driver
therefore means that an existing binding will most likely have omitted
it and be believing the sensor is in continuous clock mode when it
isn't.
Now that we check the mode requested, it will actually adopt
continuous clock mode and may no longer work with the receiver.

Perhaps it's best to drop this patch, and add it as a note to anyone
preparing a talk on Camera Sensor Drivers Compliance ;-)

  Dave

> >
> > Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
> > ---
> >  drivers/media/i2c/imx258.c | 14 ++++++++++++++
> >  1 file changed, 14 insertions(+)
> >
> > diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
> > index 1fa83fe82f27..b5c2dcb7c9e6 100644
> > --- a/drivers/media/i2c/imx258.c
> > +++ b/drivers/media/i2c/imx258.c
> > @@ -72,6 +72,8 @@
> >  /* Test Pattern Control */
> >  #define IMX258_REG_TEST_PATTERN              0x0600
> >
> > +#define IMX258_CLK_BLANK_STOP                0x4040
> > +
> >  /* Orientation */
> >  #define REG_MIRROR_FLIP_CONTROL              0x0101
> >  #define REG_CONFIG_MIRROR_FLIP               0x03
> > @@ -634,6 +636,7 @@ struct imx258 {
> >       const struct imx258_link_freq_config *link_freq_configs;
> >       const s64 *link_freq_menu_items;
> >       unsigned int nlanes;
> > +     unsigned int csi2_flags;
> >
> >       /*
> >        * Mutex for serialized access:
> > @@ -1072,6 +1075,15 @@ static int imx258_start_streaming(struct imx258 *imx258)
> >               return ret;
> >       }
> >
> > +     ret = imx258_write_reg(imx258, IMX258_CLK_BLANK_STOP,
> > +                            IMX258_REG_VALUE_08BIT,
> > +                            imx258->csi2_flags & V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK ?
> > +                            1 : 0);
> > +     if (ret) {
> > +             dev_err(&client->dev, "%s failed to set clock lane mode\n", __func__);
> > +             return ret;
> > +     }
> > +
> >       /* Apply default values of current mode */
> >       reg_list = &imx258->cur_mode->reg_list;
> >       ret = imx258_write_regs(imx258, reg_list->regs, reg_list->num_of_regs);
> > @@ -1486,6 +1498,8 @@ static int imx258_probe(struct i2c_client *client)
> >               goto error_endpoint_poweron;
> >       }
> >
> > +     imx258->csi2_flags = ep.bus.mipi_csi2.flags;
> > +
> >       /* Initialize subdev */
> >       v4l2_i2c_subdev_init(&imx258->sd, client, &imx258_subdev_ops);
> >
> > --
> > 2.25.1
> >

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

* Re: [PATCH 14/21] media: i2c: imx258: Add support for long exposure modes
  2023-06-02 13:38   ` Jacopo Mondi
@ 2023-06-02 17:12     ` Dave Stevenson
  0 siblings, 0 replies; 54+ messages in thread
From: Dave Stevenson @ 2023-06-02 17:12 UTC (permalink / raw)
  To: Jacopo Mondi
  Cc: Sakari Ailus, linux-media, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree, Naushir Patuck

Hi Jacopo

On Fri, 2 Jun 2023 at 14:38, Jacopo Mondi <jacopo.mondi@ideasonboard.com> wrote:
>
> Hi Dave
>
> On Tue, May 30, 2023 at 06:29:53PM +0100, Dave Stevenson wrote:
> > The sensor has a register CIT_LSHIFT which extends the exposure
> > and frame times by the specified power of 2 for longer
> > exposure times.
> >
> > Add support for this by configuring this register via V4L2_CID_VBLANK
> > and extending the V4L2_CID_EXPOSURE range accordingly.
> >
> > Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
> > ---
> >  drivers/media/i2c/imx258.c | 38 ++++++++++++++++++++++++++++++++------
> >  1 file changed, 32 insertions(+), 6 deletions(-)
> >
> > diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
> > index f5199e3243e8..1e424058fcb9 100644
> > --- a/drivers/media/i2c/imx258.c
> > +++ b/drivers/media/i2c/imx258.c
> > @@ -69,6 +69,10 @@
> >  #define IMX258_HDR_RATIO_STEP                1
> >  #define IMX258_HDR_RATIO_DEFAULT     0x0
> >
> > +/* Long exposure multiplier */
> > +#define IMX258_LONG_EXP_SHIFT_MAX    7
> > +#define IMX258_LONG_EXP_SHIFT_REG    0x3002
> > +
> >  /* Test Pattern Control */
> >  #define IMX258_REG_TEST_PATTERN              0x0600
> >
> > @@ -629,6 +633,8 @@ struct imx258 {
> >       struct v4l2_ctrl *vblank;
> >       struct v4l2_ctrl *hblank;
> >       struct v4l2_ctrl *exposure;
> > +     /* Current long exposure factor in use. Set through V4L2_CID_VBLANK */
> > +     unsigned int long_exp_shift;
> >
> >       /* Current mode */
> >       const struct imx258_mode *cur_mode;
> > @@ -793,6 +799,26 @@ static void imx258_adjust_exposure_range(struct imx258 *imx258)
> >                                exposure_def);
> >  }
> >
> > +static int imx258_set_frame_length(struct imx258 *imx258, unsigned int val)
> > +{
> > +     int ret;
> > +
> > +     imx258->long_exp_shift = 0;
> > +
> > +     while (val > IMX258_VTS_MAX) {
> > +             imx258->long_exp_shift++;
> > +             val >>= 1;
> > +     }
> > +
> > +     ret = imx258_write_reg(imx258, IMX258_REG_VTS,
> > +                            IMX258_REG_VALUE_16BIT, val);
> > +     if (ret)
> > +             return ret;
> > +
> > +     return imx258_write_reg(imx258, IMX258_LONG_EXP_SHIFT_REG,
> > +                             IMX258_REG_VALUE_08BIT, imx258->long_exp_shift);
> > +}
> > +
> >  static int imx258_set_ctrl(struct v4l2_ctrl *ctrl)
> >  {
> >       struct imx258 *imx258 =
> > @@ -823,7 +849,7 @@ static int imx258_set_ctrl(struct v4l2_ctrl *ctrl)
> >       case V4L2_CID_EXPOSURE:
> >               ret = imx258_write_reg(imx258, IMX258_REG_EXPOSURE,
> >                               IMX258_REG_VALUE_16BIT,
> > -                             ctrl->val);
> > +                             ctrl->val >> imx258->long_exp_shift);
>
> Shouldn't this be done only if vblank > VTS_MAX ?

You're partly right, and it's a bug in our imx477 and imx708 drivers
too. (cc Naush for info)

Computing imx258->long_exp_shift should be done in the early part of
imx258_set_ctrl before the pm_runtime_get_if_in_use check. Otherwise
the __v4l2_ctrl_handler_setup call will potentially be setting
exposure before vblank, and exposure register will be based on the
wrong shift.
If (vblank + mode->height) <= VTS_MAX then long_exp_shift will be 0,
so the value written here will be the same.

The slightly more awkward one to handle is that if long_exp_shift
changes then we need to recompute and write IMX258_REG_EXPOSURE based
on the new shift. You have to love the niggles.

Thanks
  Dave

> >               break;
> >       case V4L2_CID_DIGITAL_GAIN:
> >               ret = imx258_update_digital_gain(imx258, IMX258_REG_VALUE_16BIT,
> > @@ -855,9 +881,8 @@ static int imx258_set_ctrl(struct v4l2_ctrl *ctrl)
> >               }
> >               break;
> >       case V4L2_CID_VBLANK:
> > -             ret = imx258_write_reg(imx258, IMX258_REG_VTS,
> > -                                    IMX258_REG_VALUE_16BIT,
> > -                                    imx258->cur_mode->height + ctrl->val);
> > +             ret = imx258_set_frame_length(imx258,
> > +                                           imx258->cur_mode->height + ctrl->val);
> >               break;
> >       default:
> >               dev_info(&client->dev,
> > @@ -983,8 +1008,9 @@ static int imx258_set_pad_format(struct v4l2_subdev *sd,
> >                            imx258->cur_mode->height;
> >               __v4l2_ctrl_modify_range(
> >                       imx258->vblank, vblank_min,
> > -                     IMX258_VTS_MAX - imx258->cur_mode->height, 1,
> > -                     vblank_def);
> > +                     ((1 << IMX258_LONG_EXP_SHIFT_MAX) * IMX258_VTS_MAX) -
> > +                                             imx258->cur_mode->height,
> > +                     1, vblank_def);
> >               __v4l2_ctrl_s_ctrl(imx258->vblank, vblank_def);
> >               h_blank =
> >                       imx258->link_freq_configs[mode->link_freq_index].pixels_per_line
> > --
> > 2.25.1
> >

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

* Re: [PATCH 09/21] media: i2c: imx258: Add support for running on 2 CSI data lanes
  2023-06-02 13:23   ` Jacopo Mondi
@ 2023-06-02 17:46     ` Dave Stevenson
  0 siblings, 0 replies; 54+ messages in thread
From: Dave Stevenson @ 2023-06-02 17:46 UTC (permalink / raw)
  To: Jacopo Mondi
  Cc: Sakari Ailus, linux-media, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree

Hi Jacopo

Thanks for the review

On Fri, 2 Jun 2023 at 14:23, Jacopo Mondi <jacopo.mondi@ideasonboard.com> wrote:
>
> Hi Dave
>
> On Tue, May 30, 2023 at 06:29:48PM +0100, Dave Stevenson wrote:
> > Extends the driver to also support 2 data lanes.
> > Frame rates are obviously more restricted on 2 lanes, but some
> > hardware simply hasn't wired more up.
> >
> > Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
> > ---
> >  drivers/media/i2c/imx258.c | 211 ++++++++++++++++++++++++++++++++-----
> >  1 file changed, 187 insertions(+), 24 deletions(-)
> >
> > diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
> > index d40521f9a3c6..433dff7f1fa0 100644
> > --- a/drivers/media/i2c/imx258.c
> > +++ b/drivers/media/i2c/imx258.c
> > @@ -86,13 +86,17 @@ struct imx258_reg_list {
> >       const struct imx258_reg *regs;
> >  };
> >
> > +#define IMX258_LANE_CONFIGS  2
> > +#define IMX258_2_LANE_MODE   0
> > +#define IMX258_4_LANE_MODE   1
> > +
>
> nit: This might be better expressed as an enum...

Will do. It's always a toss up between the two.

> >  /* Link frequency config */
> >  struct imx258_link_freq_config {
> >       u64 link_frequency;
> >       u32 pixels_per_line;
> >
> >       /* PLL registers for this link frequency */
> > -     struct imx258_reg_list reg_list;
> > +     struct imx258_reg_list reg_list[IMX258_LANE_CONFIGS];
> >  };
> >
> >  /* Mode : resolution and related config&values */
> > @@ -112,8 +116,30 @@ struct imx258_mode {
> >       struct imx258_reg_list reg_list;
> >  };
> >
> > -/* 4208x3120 needs 1267Mbps/lane, 4 lanes */
> > -static const struct imx258_reg mipi_1267mbps_19_2mhz[] = {
> > +/* 4208x3120 needs 1267Mbps/lane, 4 lanes. Use that rate on 2 lanes as well */
>
> I might be missing how the same link freq (and thus lane bandwidth)
> gives the same frame rate on 4 and 2 data lanes setup..
>
> I get a total bandwidth with default VTS and PPL for 10bpp mode at 30
> fps of
>
>         vts * ppl * bpp * fps =
>         3152 * 5352 * 10 * 30 = 5060851200 bit/sec
>
> The resulting lane bandwidth for 4 lanes is
>         1.265.212.800 which ~= 1267 Mbps/lane you have above
> and results in a link frequency of
>         632606400 which matches your 634MHz/636MHz
>
> With 2 lanes either you double the bandwidth or you halve the frame
> rate. Seeing that now link_freq_to_pixel_rate() will give you a *2
> result in 4 lanes configuration, I presume full res mode runs at 15FPS
> on 2 lanes ? If that's the case, should you remove '30FPS' from the
> VTS default value defines ?

The comment here doesn't specify a frame rate, although admittedly it
is ambiguously worded.
I'll reword to:
4208x3120 @ 30fps needs 1267Mbps/lane when using 4 lanes.
To avoid further computation of clock settings, adopt the same per
lane data rate when using 2 lanes, thus allowing a maximum of 15fps.

> > +static const struct imx258_reg mipi_1267mbps_19_2mhz_2l[] = {
> > +     { 0x0136, 0x13 },
> > +     { 0x0137, 0x33 },
> > +     { 0x0301, 0x0A },
> > +     { 0x0303, 0x02 },
> > +     { 0x0305, 0x03 },
> > +     { 0x0306, 0x00 },
> > +     { 0x0307, 0xC6 },
> > +     { 0x0309, 0x0A },
> > +     { 0x030B, 0x01 },
> > +     { 0x030D, 0x02 },
> > +     { 0x030E, 0x00 },
> > +     { 0x030F, 0xD8 },
> > +     { 0x0310, 0x00 },
> > +
> > +     { 0x0114, 0x01 },
> > +     { 0x0820, 0x09 },
> > +     { 0x0821, 0xa6 },
> > +     { 0x0822, 0x66 },
> > +     { 0x0823, 0x66 },
> > +};
> > +
> > +static const struct imx258_reg mipi_1267mbps_19_2mhz_4l[] = {
> >       { 0x0136, 0x13 },
> >       { 0x0137, 0x33 },
> >       { 0x0301, 0x05 },
> > @@ -127,16 +153,18 @@ static const struct imx258_reg mipi_1267mbps_19_2mhz[] = {
> >       { 0x030E, 0x00 },
> >       { 0x030F, 0xD8 },
> >       { 0x0310, 0x00 },
> > +
> > +     { 0x0114, 0x03 },
> >       { 0x0820, 0x13 },
> >       { 0x0821, 0x4C },
> >       { 0x0822, 0xCC },
> >       { 0x0823, 0xCC },
> >  };
> >
> > -static const struct imx258_reg mipi_1272mbps_24mhz[] = {
> > +static const struct imx258_reg mipi_1272mbps_24mhz_2l[] = {
> >       { 0x0136, 0x18 },
> >       { 0x0137, 0x00 },
> > -     { 0x0301, 0x05 },
> > +     { 0x0301, 0x0a },
> >       { 0x0303, 0x02 },
> >       { 0x0305, 0x04 },
> >       { 0x0306, 0x00 },
> > @@ -147,13 +175,59 @@ static const struct imx258_reg mipi_1272mbps_24mhz[] = {
> >       { 0x030E, 0x00 },
> >       { 0x030F, 0xD8 },
> >       { 0x0310, 0x00 },
> > +
> > +     { 0x0114, 0x01 },
> >       { 0x0820, 0x13 },
> >       { 0x0821, 0x4C },
> >       { 0x0822, 0xCC },
> >       { 0x0823, 0xCC },
> >  };
> >
> > -static const struct imx258_reg mipi_640mbps_19_2mhz[] = {
> > +static const struct imx258_reg mipi_1272mbps_24mhz_4l[] = {
> > +     { 0x0136, 0x18 },
> > +     { 0x0137, 0x00 },
> > +     { 0x0301, 0x05 },
> > +     { 0x0303, 0x02 },
> > +     { 0x0305, 0x04 },
> > +     { 0x0306, 0x00 },
> > +     { 0x0307, 0xD4 },
> > +     { 0x0309, 0x0A },
> > +     { 0x030B, 0x01 },
> > +     { 0x030D, 0x02 },
> > +     { 0x030E, 0x00 },
> > +     { 0x030F, 0xD8 },
> > +     { 0x0310, 0x00 },
> > +
> > +     { 0x0114, 0x03 },
> > +     { 0x0820, 0x13 },
> > +     { 0x0821, 0xE0 },
> > +     { 0x0822, 0x00 },
> > +     { 0x0823, 0x00 },
> > +};
> > +
> > +static const struct imx258_reg mipi_640mbps_19_2mhz_2l[] = {
> > +     { 0x0136, 0x13 },
> > +     { 0x0137, 0x33 },
> > +     { 0x0301, 0x05 },
> > +     { 0x0303, 0x02 },
> > +     { 0x0305, 0x03 },
> > +     { 0x0306, 0x00 },
> > +     { 0x0307, 0x64 },
> > +     { 0x0309, 0x0A },
> > +     { 0x030B, 0x01 },
> > +     { 0x030D, 0x02 },
> > +     { 0x030E, 0x00 },
> > +     { 0x030F, 0xD8 },
> > +     { 0x0310, 0x00 },
> > +
> > +     { 0x0114, 0x01 },
> > +     { 0x0820, 0x05 },
> > +     { 0x0821, 0x00 },
> > +     { 0x0822, 0x00 },
> > +     { 0x0823, 0x00 },
> > +};
> > +
> > +static const struct imx258_reg mipi_640mbps_19_2mhz_4l[] = {
> >       { 0x0136, 0x13 },
> >       { 0x0137, 0x33 },
> >       { 0x0301, 0x05 },
> > @@ -167,13 +241,37 @@ static const struct imx258_reg mipi_640mbps_19_2mhz[] = {
> >       { 0x030E, 0x00 },
> >       { 0x030F, 0xD8 },
> >       { 0x0310, 0x00 },
> > +
> > +     { 0x0114, 0x03 },
> >       { 0x0820, 0x0A },
> >       { 0x0821, 0x00 },
> >       { 0x0822, 0x00 },
> >       { 0x0823, 0x00 },
> >  };
> >
> > -static const struct imx258_reg mipi_642mbps_24mhz[] = {
> > +static const struct imx258_reg mipi_642mbps_24mhz_2l[] = {
> > +     { 0x0136, 0x18 },
> > +     { 0x0137, 0x00 },
> > +     { 0x0301, 0x0A },
> > +     { 0x0303, 0x02 },
> > +     { 0x0305, 0x04 },
> > +     { 0x0306, 0x00 },
> > +     { 0x0307, 0x6B },
> > +     { 0x0309, 0x0A },
> > +     { 0x030B, 0x01 },
> > +     { 0x030D, 0x02 },
> > +     { 0x030E, 0x00 },
> > +     { 0x030F, 0xD8 },
> > +     { 0x0310, 0x00 },
> > +
> > +     { 0x0114, 0x01 },
> > +     { 0x0820, 0x0A },
> > +     { 0x0821, 0x00 },
> > +     { 0x0822, 0x00 },
> > +     { 0x0823, 0x00 },
> > +};
> > +
> > +static const struct imx258_reg mipi_642mbps_24mhz_4l[] = {
> >       { 0x0136, 0x18 },
> >       { 0x0137, 0x00 },
> >       { 0x0301, 0x05 },
> > @@ -187,6 +285,8 @@ static const struct imx258_reg mipi_642mbps_24mhz[] = {
> >       { 0x030E, 0x00 },
> >       { 0x030F, 0xD8 },
> >       { 0x0310, 0x00 },
> > +
> > +     { 0x0114, 0x03 },
> >       { 0x0820, 0x0A },
> >       { 0x0821, 0x00 },
> >       { 0x0822, 0x00 },
> > @@ -241,7 +341,6 @@ static const struct imx258_reg mode_common_regs[] = {
> >       { 0x5F05, 0xED },
> >       { 0x0112, 0x0A },
> >       { 0x0113, 0x0A },
> > -     { 0x0114, 0x03 },
> >       { 0x0342, 0x14 },
> >       { 0x0343, 0xE8 },
> >       { 0x0344, 0x00 },
> > @@ -360,11 +459,13 @@ enum {
> >
> >  /*
> >   * pixel_rate = link_freq * data-rate * nr_of_lanes / bits_per_sample
> > - * data rate => double data rate; number of lanes => 4; bits per pixel => 10
> > + * data rate => double data rate;
> > + * number of lanes => (configurable 2 or 4);
> > + * bits per pixel => 10
> >   */
> > -static u64 link_freq_to_pixel_rate(u64 f)
> > +static u64 link_freq_to_pixel_rate(u64 f, unsigned int nlanes)
> >  {
> > -     f *= 2 * 4;
> > +     f *= 2 * nlanes;
> >       do_div(f, 10);
> >
> >       return f;
> > @@ -394,15 +495,27 @@ static const struct imx258_link_freq_config link_freq_configs_19_2[] = {
> >       [IMX258_LINK_FREQ_1267MBPS] = {
> >               .pixels_per_line = IMX258_PPL_DEFAULT,
> >               .reg_list = {
> > -                     .num_of_regs = ARRAY_SIZE(mipi_1267mbps_19_2mhz),
> > -                     .regs = mipi_1267mbps_19_2mhz,
> > +                     [IMX258_2_LANE_MODE] = {
> > +                             .num_of_regs = ARRAY_SIZE(mipi_1267mbps_19_2mhz_2l),
> > +                             .regs = mipi_1267mbps_19_2mhz_2l,
> > +                     },
> > +                     [IMX258_4_LANE_MODE] = {
> > +                             .num_of_regs = ARRAY_SIZE(mipi_1267mbps_19_2mhz_4l),
> > +                             .regs = mipi_1267mbps_19_2mhz_4l,
> > +                     },
> >               }
> >       },
> >       [IMX258_LINK_FREQ_640MBPS] = {
> >               .pixels_per_line = IMX258_PPL_DEFAULT,
> >               .reg_list = {
> > -                     .num_of_regs = ARRAY_SIZE(mipi_640mbps_19_2mhz),
> > -                     .regs = mipi_640mbps_19_2mhz,
> > +                     [IMX258_2_LANE_MODE] = {
> > +                             .num_of_regs = ARRAY_SIZE(mipi_640mbps_19_2mhz_2l),
> > +                             .regs = mipi_640mbps_19_2mhz_2l,
> > +                     },
> > +                     [IMX258_4_LANE_MODE] = {
> > +                             .num_of_regs = ARRAY_SIZE(mipi_640mbps_19_2mhz_4l),
> > +                             .regs = mipi_640mbps_19_2mhz_4l,
> > +                     },
> >               }
> >       },
> >  };
> > @@ -411,15 +524,27 @@ static const struct imx258_link_freq_config link_freq_configs_24[] = {
> >       [IMX258_LINK_FREQ_1267MBPS] = {
> >               .pixels_per_line = IMX258_PPL_DEFAULT,
> >               .reg_list = {
> > -                     .num_of_regs = ARRAY_SIZE(mipi_1272mbps_24mhz),
> > -                     .regs = mipi_1272mbps_24mhz,
> > +                     [IMX258_2_LANE_MODE] = {
> > +                             .num_of_regs = ARRAY_SIZE(mipi_1272mbps_24mhz_2l),
> > +                             .regs = mipi_1272mbps_24mhz_2l,
> > +                     },
> > +                     [IMX258_4_LANE_MODE] = {
> > +                             .num_of_regs = ARRAY_SIZE(mipi_1272mbps_24mhz_4l),
> > +                             .regs = mipi_1272mbps_24mhz_4l,
> > +                     },
> >               }
> >       },
> >       [IMX258_LINK_FREQ_640MBPS] = {
> >               .pixels_per_line = IMX258_PPL_DEFAULT,
> >               .reg_list = {
> > -                     .num_of_regs = ARRAY_SIZE(mipi_642mbps_24mhz),
> > -                     .regs = mipi_642mbps_24mhz,
> > +                     [IMX258_2_LANE_MODE] = {
> > +                             .num_of_regs = ARRAY_SIZE(mipi_642mbps_24mhz_2l),
> > +                             .regs = mipi_642mbps_24mhz_2l,
> > +                     },
> > +                     [IMX258_4_LANE_MODE] = {
> > +                             .num_of_regs = ARRAY_SIZE(mipi_642mbps_24mhz_4l),
> > +                             .regs = mipi_642mbps_24mhz_4l,
> > +                     },
> >               }
> >       },
> >  };
> > @@ -478,6 +603,7 @@ struct imx258 {
> >
> >       const struct imx258_link_freq_config *link_freq_configs;
> >       const s64 *link_freq_menu_items;
> > +     unsigned int nlanes;
> >
> >       /*
> >        * Mutex for serialized access:
> > @@ -787,7 +913,7 @@ static int imx258_set_pad_format(struct v4l2_subdev *sd,
> >               __v4l2_ctrl_s_ctrl(imx258->link_freq, mode->link_freq_index);
> >
> >               link_freq = imx258->link_freq_menu_items[mode->link_freq_index];
> > -             pixel_rate = link_freq_to_pixel_rate(link_freq);
> > +             pixel_rate = link_freq_to_pixel_rate(link_freq, imx258->nlanes);
> >               __v4l2_ctrl_s_ctrl_int64(imx258->pixel_rate, pixel_rate);
> >               /* Update limits and set FPS to default */
> >               vblank_def = imx258->cur_mode->vts_def -
> > @@ -816,11 +942,13 @@ static int imx258_start_streaming(struct imx258 *imx258)
> >  {
> >       struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd);
> >       const struct imx258_reg_list *reg_list;
> > +     const struct imx258_link_freq_config *link_freq_cfg;
> >       int ret, link_freq_index;
> >
> >       /* Setup PLL */
> >       link_freq_index = imx258->cur_mode->link_freq_index;
> > -     reg_list = &imx258->link_freq_configs[link_freq_index].reg_list;
> > +     link_freq_cfg = &imx258->link_freq_configs[link_freq_index];
> > +     reg_list = &link_freq_cfg->reg_list[imx258->nlanes == 2 ? 0 : 1];
> >       ret = imx258_write_regs(imx258, reg_list->regs, reg_list->num_of_regs);
> >       if (ret) {
> >               dev_err(&client->dev, "%s failed to set plls\n", __func__);
> > @@ -1074,9 +1202,11 @@ static int imx258_init_controls(struct imx258 *imx258)
> >               vflip->flags |= V4L2_CTRL_FLAG_READ_ONLY;
> >
> >       pixel_rate_max =
> > -             link_freq_to_pixel_rate(imx258->link_freq_menu_items[0]);
> > +             link_freq_to_pixel_rate(imx258->link_freq_menu_items[0],
> > +                                     imx258->nlanes);
> >       pixel_rate_min =
> > -             link_freq_to_pixel_rate(imx258->link_freq_menu_items[1]);
> > +             link_freq_to_pixel_rate(imx258->link_freq_menu_items[1],
> > +                                     imx258->nlanes);
> >       /* By default, PIXEL_RATE is read only */
> >       imx258->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops,
> >                               V4L2_CID_PIXEL_RATE,
> > @@ -1174,6 +1304,10 @@ static int imx258_get_regulators(struct imx258 *imx258,
> >  static int imx258_probe(struct i2c_client *client)
> >  {
> >       struct imx258 *imx258;
> > +     struct fwnode_handle *endpoint;
> > +     struct v4l2_fwnode_endpoint ep = {
> > +             .bus_type = V4L2_MBUS_CSI2_DPHY
> > +     };
> >       int ret;
> >       u32 val = 0;
> >
> > @@ -1216,13 +1350,38 @@ static int imx258_probe(struct i2c_client *client)
> >               return -EINVAL;
> >       }
> >
> > +     endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev), NULL);
> > +     if (!endpoint) {
> > +             dev_err(&client->dev, "Endpoint node not found\n");
> > +             return -EINVAL;
> > +     }
> > +
> > +     ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &ep);
> > +     fwnode_handle_put(endpoint);
> > +     if (ret == -ENXIO) {
>
> Doesn't the core warns you already ? Anywy, doesn't hurt I suppose

It looks to me like it's a pr_debug, so not apparently.
https://elixir.bootlin.com/linux/latest/source/drivers/media/v4l2-core/v4l2-fwnode.c#L443

There's no real need to differentiate why it failed here, so I'll
combine the two error cases and include the error code.

> > +             dev_err(&client->dev, "Unsupported bus type, should be CSI2\n");
> > +             goto error_endpoint_poweron;
> > +     } else if (ret) {
> > +             dev_err(&client->dev, "Parsing endpoint node failed\n");
> > +             goto error_endpoint_poweron;
>
> It's a pretty peculiar name :) Why not 'error_endpoint_free' ?

It's been a while since I originally wrote this. Probably because it's
called if either the endpoint parsing fails, or if power_on fails.
I'll rename it as you suggest.

> Anyway, if parsing fails, I don't think you need to v4l2_fwnode_endpoint_free()
> as the core should take care of doing so.

Yes, it looks like it does, so I can just return here.
I still need the error path should the number of lanes be invalid, or
imx258_power_on fails, just not here.

> > +     }
> > +
> > +     /* Get number of data lanes */
> > +     imx258->nlanes = ep.bus.mipi_csi2.num_data_lanes;
> > +     if (imx258->nlanes != 2 && imx258->nlanes != 4) {
> > +             dev_err(&client->dev, "Invalid data lanes: %u\n",
> > +                     imx258->nlanes);
> > +             ret = -EINVAL;
> > +             goto error_endpoint_poweron;
> > +     }
> > +
> >       /* Initialize subdev */
> >       v4l2_i2c_subdev_init(&imx258->sd, client, &imx258_subdev_ops);
> >
> >       /* Will be powered off via pm_runtime_idle */
> >       ret = imx258_power_on(&client->dev);
> >       if (ret)
> > -             return ret;
> > +             goto error_endpoint_poweron;
> >
> >       /* Check module identity */
> >       ret = imx258_identify_module(imx258);
> > @@ -1255,6 +1414,7 @@ static int imx258_probe(struct i2c_client *client)
> >       pm_runtime_set_active(&client->dev);
> >       pm_runtime_enable(&client->dev);
> >       pm_runtime_idle(&client->dev);
> > +     v4l2_fwnode_endpoint_free(&endpoint);
>
> Do you need to free in _remove() too ?

This is the success path at the end of _probe. We don't need the
endpoint after this, and it's a local to this function, therefore
cleaning up here.
As noted earlier, this should be:
v4l2_fwnode_endpoint_free(&ep);

Thanks
  Dave

> >
> >       return 0;
> >
> > @@ -1267,6 +1427,9 @@ static int imx258_probe(struct i2c_client *client)
> >  error_identify:
> >       imx258_power_off(&client->dev);
> >
> > +error_endpoint_poweron:
> > +     v4l2_fwnode_endpoint_free(&ep);
> > +
> >       return ret;
> >  }
> >
> > --
> > 2.25.1
> >

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

* Re: [PATCH 00/21] imx258 improvements series
  2023-05-30 17:29 [PATCH 00/21] imx258 improvements series Dave Stevenson
                   ` (20 preceding siblings ...)
  2023-05-30 17:30 ` [PATCH 21/21] media: i2c: imx258: Make HFLIP and VFLIP controls writable Dave Stevenson
@ 2023-07-18 12:08 ` Arnaud Ferraris
  21 siblings, 0 replies; 54+ messages in thread
From: Arnaud Ferraris @ 2023-07-18 12:08 UTC (permalink / raw)
  To: Dave Stevenson, Sakari Ailus, linux-media, devicetree

Hi Dave,

Le 30/05/2023 à 19:29, Dave Stevenson a écrit :
> This is a set of patches for imx258 that allow it to work with alternate clock
> frequencies, over either 2 or 4 lanes, and generally adding flexibility to the
> driver.
>
> Tested with an IMX258 module from Soho Enterprises that has a 24MHz oscillator.
> Both 2 and 4 lane configurations work with correct link frequencies and pixel
> rates.
>
> Jacopo has tested on a PinePhone Pro which has an ~19.2MHz clock fed from the SoC,
> He confirms that the two lower resolution modes work, but not the full res mode.
> Comparing to the BSP it looks like they have some weird clock configuration in
> the 4208x3120 mode (nominally 1224Mb/s/lane instead of 1267).
> As it has never previously worked directly with the mainline driver this isn't a
> regression but may indicate that there is a need for support of additional link
> frequencies in the future.

FYI, I have tested this series on PinePhone Pro as well, but this time 
changing the clock to 24 MHz.
I didn't test all modes (not sure how to do this), but feel free to add 
my Tested-by to the whole series for v2.

Thanks for your work on this,
Arnaud

>
> The last patch that makes HFLIP and VFLIP configurable may be contentious as I've
> retained the default configuration of inverted from the original driver. I know
> this was discussed recently, but I can't recall the final outcome.
>
> I am relying on someone from Intel testing this out, as correcting the cropping
> and supporting flips has changed the Bayer order. Seeing as this is all above
> board in V4L2 terms I really hope that the layers above it behave themselves.
>
> Cheers
>    Dave
>
> Dave Stevenson (21):
>    media: i2c: imx258: Remove unused defines
>    media: i2c: imx258: Make image geometry meet sensor requirements
>    media: i2c: imx258: Disable digital cropping on binned modes
>    media: i2c: imx258: Remove redundant I2C writes.
>    media: i2c: imx258: Add regulator control
>    media: i2c: imx258: Make V4L2_CID_VBLANK configurable.
>    media: i2c: imx258: Split out common registers from the mode based
>      ones
>    media: i2c: imx258: Add support for 24MHz clock
>    media: i2c: imx258: Add support for running on 2 CSI data lanes
>    media: i2c: imx258: Follow normal V4L2 behaviours for clipping
>      exposure
>    media: i2c: imx258: Add get_selection for pixel array information
>    media: i2c: imx258: Allow configuration of clock lane behaviour
>    media: i2c: imx258: Correct max FRM_LENGTH_LINES value
>    media: i2c: imx258: Add support for long exposure modes
>    media: i2c: imx258: Issue reset before starting streaming
>    media: i2c: imx258: Set pixel_rate range to the same as the value
>    media: i2c: imx258: Support faster pixel rate on binned modes
>    dt-bindings: media: imx258: Rename to include vendor prefix
>    dt-bindings: media: imx258: Add alternate compatible strings
>    media: i2c: imx258: Change register settings for variants of the
>      sensor
>    media: i2c: imx258: Make HFLIP and VFLIP controls writable
>
>   .../i2c/{imx258.yaml => sony,imx258.yaml}     |   9 +-
>   MAINTAINERS                                   |   2 +-
>   drivers/media/i2c/imx258.c                    | 994 ++++++++++++------
>   3 files changed, 675 insertions(+), 330 deletions(-)
>   rename Documentation/devicetree/bindings/media/i2c/{imx258.yaml => sony,imx258.yaml} (90%)
>


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

end of thread, other threads:[~2023-07-18 12:08 UTC | newest]

Thread overview: 54+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-05-30 17:29 [PATCH 00/21] imx258 improvements series Dave Stevenson
2023-05-30 17:29 ` [PATCH 01/21] media: i2c: imx258: Remove unused defines Dave Stevenson
2023-05-31 15:08   ` Jacopo Mondi
2023-05-30 17:29 ` [PATCH 02/21] media: i2c: imx258: Make image geometry meet sensor requirements Dave Stevenson
2023-05-31 15:09   ` Jacopo Mondi
2023-05-30 17:29 ` [PATCH 03/21] media: i2c: imx258: Disable digital cropping on binned modes Dave Stevenson
2023-05-31 15:02   ` Jacopo Mondi
2023-05-30 17:29 ` [PATCH 04/21] media: i2c: imx258: Remove redundant I2C writes Dave Stevenson
2023-05-31 15:10   ` Jacopo Mondi
2023-05-30 17:29 ` [PATCH 05/21] media: i2c: imx258: Add regulator control Dave Stevenson
2023-05-31 15:11   ` Jacopo Mondi
2023-05-31 15:26     ` Dave Stevenson
2023-05-30 17:29 ` [PATCH 06/21] media: i2c: imx258: Make V4L2_CID_VBLANK configurable Dave Stevenson
2023-05-31 15:16   ` Jacopo Mondi
2023-05-31 15:33     ` Dave Stevenson
2023-05-30 17:29 ` [PATCH 07/21] media: i2c: imx258: Split out common registers from the mode based ones Dave Stevenson
2023-05-31 15:26   ` Jacopo Mondi
2023-05-30 17:29 ` [PATCH 08/21] media: i2c: imx258: Add support for 24MHz clock Dave Stevenson
2023-06-02 12:59   ` Jacopo Mondi
2023-05-30 17:29 ` [PATCH 09/21] media: i2c: imx258: Add support for running on 2 CSI data lanes Dave Stevenson
2023-05-30 17:37   ` Dave Stevenson
2023-05-31  8:07   ` kernel test robot
2023-06-02 13:23   ` Jacopo Mondi
2023-06-02 17:46     ` Dave Stevenson
2023-05-30 17:29 ` [PATCH 10/21] media: i2c: imx258: Follow normal V4L2 behaviours for clipping exposure Dave Stevenson
2023-05-31 15:27   ` Jacopo Mondi
2023-05-30 17:29 ` [PATCH 11/21] media: i2c: imx258: Add get_selection for pixel array information Dave Stevenson
2023-06-02 13:24   ` Jacopo Mondi
2023-05-30 17:29 ` [PATCH 12/21] media: i2c: imx258: Allow configuration of clock lane behaviour Dave Stevenson
2023-06-02 13:26   ` Jacopo Mondi
2023-06-02 15:18     ` Dave Stevenson
2023-05-30 17:29 ` [PATCH 13/21] media: i2c: imx258: Correct max FRM_LENGTH_LINES value Dave Stevenson
2023-06-02 13:33   ` Jacopo Mondi
2023-05-30 17:29 ` [PATCH 14/21] media: i2c: imx258: Add support for long exposure modes Dave Stevenson
2023-06-02 13:38   ` Jacopo Mondi
2023-06-02 17:12     ` Dave Stevenson
2023-05-30 17:29 ` [PATCH 15/21] media: i2c: imx258: Issue reset before starting streaming Dave Stevenson
2023-06-02 13:42   ` Jacopo Mondi
2023-05-30 17:29 ` [PATCH 16/21] media: i2c: imx258: Set pixel_rate range to the same as the value Dave Stevenson
2023-06-02 13:44   ` Jacopo Mondi
2023-05-30 17:29 ` [PATCH 17/21] media: i2c: imx258: Support faster pixel rate on binned modes Dave Stevenson
2023-05-30 17:29 ` [PATCH 18/21] dt-bindings: media: imx258: Rename to include vendor prefix Dave Stevenson
2023-05-30 17:35   ` Conor Dooley
2023-05-30 17:29 ` [PATCH 19/21] dt-bindings: media: imx258: Add alternate compatible strings Dave Stevenson
2023-05-30 17:38   ` Conor Dooley
2023-05-30 17:48     ` Dave Stevenson
2023-05-30 19:36       ` Conor Dooley
2023-05-30 17:29 ` [PATCH 20/21] media: i2c: imx258: Change register settings for variants of the sensor Dave Stevenson
2023-06-02 13:48   ` Jacopo Mondi
2023-06-02 14:30     ` Dave Stevenson
2023-05-30 17:30 ` [PATCH 21/21] media: i2c: imx258: Make HFLIP and VFLIP controls writable Dave Stevenson
2023-06-02 13:58   ` Jacopo Mondi
2023-06-02 14:42     ` Dave Stevenson
2023-07-18 12:08 ` [PATCH 00/21] imx258 improvements series Arnaud Ferraris

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).