Linux-Media Archive on lore.kernel.org
 help / color / Atom feed
* [PATCH 00/25] media: ov5647: Support RaspberryPi Camera Module v1
@ 2020-06-23 10:07 Jacopo Mondi
  2020-06-23 10:07 ` [PATCH 01/25] dt-bindings: media: ov5647: Document pwdn-gpios Jacopo Mondi
                   ` (26 more replies)
  0 siblings, 27 replies; 56+ messages in thread
From: Jacopo Mondi @ 2020-06-23 10:07 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dave.stevenson, naush
  Cc: Jacopo Mondi, mrodin, hugues.fruchet, mripard, aford173, sudipi,
	andrew_gabbasov, erosca, linux-media, libcamera-devel

-------------------------------------------------------------------------------
Second attempt after my ISP blocked the part of the first sending.
Also removed Luis Oliveira email from the receiver list as it gets
bounced back.
550 5.1.1 <lolivei@synopsys.com>... User unknown
-------------------------------------------------------------------------------

Hello,
  this series improves and expand the existing ov5647 sensor driver to
the same feature level as found in RaspberryPi BSP.

It is based on recent media tree master and the sensor bindings conversion
to dt-schema I sent out a few days ago:
"[PATCH 0/2] dt-bidings: media: ov5647 bindings + small fix"

The first patches in the series has been sent by Roman as part of
"[PATCH v2 0/6] ov5647 driver improvement"
I took his patches in, addressed review comments and rebased on top
of the new dt-schema bindings. I kept the extensive receiver list he had
in his series for this reason.

The series continues by polishing and cleaning up the driver and expanding
its functionalities to support multiple modes and image formats.

The series has been tested with libcamera and the driver functionalities
compared with the BSP driver ones, and tested stand-alone by capturing
raw frames with yavta.

Thanks
   j

Dave Stevenson (8):
  media: ov5647: Add support for PWDN GPIO.
  media: ov5647: Add support for non-continuous clock mode
  media: ov5647: Add set_fmt and get_fmt calls.
  media: ov5647: Add support for get_selection()
  media: ov5647: Set V4L2_SUBDEV_FL_HAS_EVENTS flag
  media: ov5647: Support V4L2_CID_PIXEL_RATE
  media: ov5647: Support V4L2_CID_VBLANK control
  media: ov5647: Advertise the correct exposure range

David Plowman (1):
  media: ov5647: Support gain, exposure and AWB controls

Jacopo Mondi (16):
  dt-bindings: media: ov5647: Document pwdn-gpios
  dt-bindings: media: ov5647: Document clock-noncontinuous
  media: ov5647: Fix format initialization
  media: ov5647: Fix style issues
  media: ov5647: Replace license with SPDX identifier
  media: ov5647: Fix return value from read/write
  media: ov5647: Program mode at s_stream(1) time
  media: ov5647: Implement enum_frame_size()
  media: ov5647: Protect s_stream() with mutex
  media: ov5647: Rationalize driver structure name
  media: ov5647: Break out format handling
  media: ov5647: Rename SBGGR8 VGA mode
  media: ov5647: Add SGGBR10_1X10 modes
  media: ov5647: Implement set_fmt pad operation
  media: ov5647: Program mode only if it has changed
  media: ov5647: Support V4L2_CID_HBLANK control

 .../devicetree/bindings/media/i2c/ov5647.yaml |   11 +
 drivers/media/i2c/ov5647.c                    | 1267 +++++++++++++++--
 2 files changed, 1126 insertions(+), 152 deletions(-)

--
2.27.0


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

* [PATCH 01/25] dt-bindings: media: ov5647: Document pwdn-gpios
  2020-06-23 10:07 [PATCH 00/25] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
@ 2020-06-23 10:07 ` Jacopo Mondi
  2020-06-23 10:07 ` [PATCH 02/25] dt-bindings: media: ov5647: Document clock-noncontinuous Jacopo Mondi
                   ` (25 subsequent siblings)
  26 siblings, 0 replies; 56+ messages in thread
From: Jacopo Mondi @ 2020-06-23 10:07 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dave.stevenson, naush
  Cc: Jacopo Mondi, mrodin, hugues.fruchet, mripard, aford173, sudipi,
	andrew_gabbasov, erosca, linux-media, libcamera-devel

Document in dt-schema bindings for the ov5647 sensor the optional
'pwdn-gpios' property.

Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
---
 Documentation/devicetree/bindings/media/i2c/ov5647.yaml | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Documentation/devicetree/bindings/media/i2c/ov5647.yaml b/Documentation/devicetree/bindings/media/i2c/ov5647.yaml
index 067e222e0c7c3..58d64a69e9640 100644
--- a/Documentation/devicetree/bindings/media/i2c/ov5647.yaml
+++ b/Documentation/devicetree/bindings/media/i2c/ov5647.yaml
@@ -25,6 +25,10 @@ properties:
     description: Reference to the xclk clock
     maxItems: 1
 
+  pwdn-gpios:
+    description: Reference to the GPIO connected to the pwdn pin. Active high.
+    maxItems: 1
+
   port:
     type: object
     description: |-
@@ -61,6 +65,7 @@ additionalProperties: false
 
 examples:
   - |
+    #include <dt-bindings/gpio/gpio.h>
 
     i2c {
         #address-cells = <1>;
@@ -70,6 +75,7 @@ examples:
             compatible = "ovti,ov5647";
             reg = <0x36>;
             clocks = <&camera_clk>;
+            pwdn-gpios = <&pioE 29 GPIO_ACTIVE_HIGH>;
 
             port {
                 camera_out: endpoint {
-- 
2.27.0


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

* [PATCH 02/25] dt-bindings: media: ov5647: Document clock-noncontinuous
  2020-06-23 10:07 [PATCH 00/25] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
  2020-06-23 10:07 ` [PATCH 01/25] dt-bindings: media: ov5647: Document pwdn-gpios Jacopo Mondi
@ 2020-06-23 10:07 ` Jacopo Mondi
  2020-06-23 10:07 ` [PATCH 03/25] media: ov5647: Add support for PWDN GPIO Jacopo Mondi
                   ` (24 subsequent siblings)
  26 siblings, 0 replies; 56+ messages in thread
From: Jacopo Mondi @ 2020-06-23 10:07 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dave.stevenson, naush
  Cc: Jacopo Mondi, mrodin, hugues.fruchet, mripard, aford173, sudipi,
	andrew_gabbasov, erosca, linux-media, libcamera-devel

Document the optional clock-noncontinuous endpoint property that
allows enabling MIPI CSI-2 non-continuous clock operations.

Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
---
 Documentation/devicetree/bindings/media/i2c/ov5647.yaml | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/Documentation/devicetree/bindings/media/i2c/ov5647.yaml b/Documentation/devicetree/bindings/media/i2c/ov5647.yaml
index 58d64a69e9640..68d6998d7180c 100644
--- a/Documentation/devicetree/bindings/media/i2c/ov5647.yaml
+++ b/Documentation/devicetree/bindings/media/i2c/ov5647.yaml
@@ -45,6 +45,11 @@ properties:
             description: |-
               phandle to the video receiver input port
 
+          clock-noncontinuous:
+            type: boolean
+            description: |-
+              Set to true to allow MIPI CSI-2 non-continuous clock operations
+
         required:
           - remote-endpoint
 
-- 
2.27.0


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

* [PATCH 03/25] media: ov5647: Add support for PWDN GPIO.
  2020-06-23 10:07 [PATCH 00/25] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
  2020-06-23 10:07 ` [PATCH 01/25] dt-bindings: media: ov5647: Document pwdn-gpios Jacopo Mondi
  2020-06-23 10:07 ` [PATCH 02/25] dt-bindings: media: ov5647: Document clock-noncontinuous Jacopo Mondi
@ 2020-06-23 10:07 ` Jacopo Mondi
  2020-07-09 20:04   ` [libcamera-devel] " Dafna Hirschfeld
  2020-06-23 10:07 ` [PATCH 04/25] media: ov5647: Add support for non-continuous clock mode Jacopo Mondi
                   ` (23 subsequent siblings)
  26 siblings, 1 reply; 56+ messages in thread
From: Jacopo Mondi @ 2020-06-23 10:07 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dave.stevenson, naush
  Cc: Jacopo Mondi, mrodin, hugues.fruchet, mripard, aford173, sudipi,
	andrew_gabbasov, erosca, linux-media, libcamera-devel

From: Dave Stevenson <dave.stevenson@raspberrypi.org>

Add support for an optional GPIO connected to PWDN on the sensor. This
allows the use of hardware standby mode where internal device clock
and circuit activities are halted.

Please note that power is off when PWDN is high.

Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
Signed-off-by: Roman Kovalivskyi <roman.kovalivskyi@globallogic.com>
Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
---
 drivers/media/i2c/ov5647.c | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
index e7d2e5b4ad4b9..105ff7f899b34 100644
--- a/drivers/media/i2c/ov5647.c
+++ b/drivers/media/i2c/ov5647.c
@@ -21,6 +21,7 @@
 
 #include <linux/clk.h>
 #include <linux/delay.h>
+#include <linux/gpio/consumer.h>
 #include <linux/i2c.h>
 #include <linux/init.h>
 #include <linux/io.h>
@@ -35,6 +36,13 @@
 
 #define SENSOR_NAME "ov5647"
 
+/*
+ * From the datasheet, "20ms after PWDN goes low or 20ms after RESETB goes
+ * high if reset is inserted after PWDN goes high, host can access sensor's
+ * SCCB to initialize sensor."
+ */
+#define PWDN_ACTIVE_DELAY_MS	20
+
 #define MIPI_CTRL00_CLOCK_LANE_GATE		BIT(5)
 #define MIPI_CTRL00_BUS_IDLE			BIT(2)
 #define MIPI_CTRL00_CLOCK_LANE_DISABLE		BIT(0)
@@ -86,6 +94,7 @@ struct ov5647 {
 	unsigned int			height;
 	int				power_count;
 	struct clk			*xclk;
+	struct gpio_desc		*pwdn;
 };
 
 static inline struct ov5647 *to_state(struct v4l2_subdev *sd)
@@ -355,6 +364,11 @@ static int ov5647_sensor_power(struct v4l2_subdev *sd, int on)
 	if (on && !ov5647->power_count)	{
 		dev_dbg(&client->dev, "OV5647 power on\n");
 
+		if (ov5647->pwdn) {
+			gpiod_set_value_cansleep(ov5647->pwdn, 0);
+			msleep(PWDN_ACTIVE_DELAY_MS);
+		}
+
 		ret = clk_prepare_enable(ov5647->xclk);
 		if (ret < 0) {
 			dev_err(&client->dev, "clk prepare enable failed\n");
@@ -392,6 +406,8 @@ static int ov5647_sensor_power(struct v4l2_subdev *sd, int on)
 			dev_dbg(&client->dev, "soft stby failed\n");
 
 		clk_disable_unprepare(ov5647->xclk);
+
+		gpiod_set_value_cansleep(ov5647->pwdn, 1);
 	}
 
 	/* Update the power count. */
@@ -581,6 +597,10 @@ static int ov5647_probe(struct i2c_client *client)
 		return -EINVAL;
 	}
 
+	/* Request the power down GPIO asserted */
+	sensor->pwdn = devm_gpiod_get_optional(&client->dev, "pwdn",
+					       GPIOD_OUT_HIGH);
+
 	mutex_init(&sensor->lock);
 
 	sd = &sensor->sd;
@@ -594,7 +614,15 @@ static int ov5647_probe(struct i2c_client *client)
 	if (ret < 0)
 		goto mutex_remove;
 
+	if (sensor->pwdn) {
+		gpiod_set_value_cansleep(sensor->pwdn, 0);
+		msleep(PWDN_ACTIVE_DELAY_MS);
+	}
+
 	ret = ov5647_detect(sd);
+
+	gpiod_set_value_cansleep(sensor->pwdn, 1);
+
 	if (ret < 0)
 		goto error;
 
-- 
2.27.0


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

* [PATCH 04/25] media: ov5647: Add support for non-continuous clock mode
  2020-06-23 10:07 [PATCH 00/25] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
                   ` (2 preceding siblings ...)
  2020-06-23 10:07 ` [PATCH 03/25] media: ov5647: Add support for PWDN GPIO Jacopo Mondi
@ 2020-06-23 10:07 ` Jacopo Mondi
  2020-06-23 10:07 ` [PATCH 05/25] media: ov5647: Add set_fmt and get_fmt calls Jacopo Mondi
                   ` (22 subsequent siblings)
  26 siblings, 0 replies; 56+ messages in thread
From: Jacopo Mondi @ 2020-06-23 10:07 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dave.stevenson, naush
  Cc: Jacopo Mondi, mrodin, hugues.fruchet, mripard, aford173, sudipi,
	andrew_gabbasov, erosca, linux-media, libcamera-devel

From: Dave Stevenson <dave.stevenson@raspberrypi.org>

Add support for optional non-continuous clock mode to the ov5647
sensor driver.

Non-continuous clock saves a small amount of power and on some SoCs
is easier to interface with.

Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
Signed-off-by: Roman Kovalivskyi <roman.kovalivskyi@globallogic.com>
Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
---
 drivers/media/i2c/ov5647.c | 24 ++++++++++++++++++++----
 1 file changed, 20 insertions(+), 4 deletions(-)

diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
index 105ff7f899b34..2d69cd97142d7 100644
--- a/drivers/media/i2c/ov5647.c
+++ b/drivers/media/i2c/ov5647.c
@@ -44,6 +44,7 @@
 #define PWDN_ACTIVE_DELAY_MS	20
 
 #define MIPI_CTRL00_CLOCK_LANE_GATE		BIT(5)
+#define MIPI_CTRL00_LINE_SYNC_ENABLE		BIT(4)
 #define MIPI_CTRL00_BUS_IDLE			BIT(2)
 #define MIPI_CTRL00_CLOCK_LANE_DISABLE		BIT(0)
 
@@ -95,6 +96,7 @@ struct ov5647 {
 	int				power_count;
 	struct clk			*xclk;
 	struct gpio_desc		*pwdn;
+	bool				clock_ncont;
 };
 
 static inline struct ov5647 *to_state(struct v4l2_subdev *sd)
@@ -269,9 +271,15 @@ static int ov5647_set_virtual_channel(struct v4l2_subdev *sd, int channel)
 
 static int ov5647_stream_on(struct v4l2_subdev *sd)
 {
+	struct ov5647 *ov5647 = to_state(sd);
+	u8 val = MIPI_CTRL00_BUS_IDLE;
 	int ret;
 
-	ret = ov5647_write(sd, OV5647_REG_MIPI_CTRL00, MIPI_CTRL00_BUS_IDLE);
+	if (ov5647->clock_ncont)
+		val |= MIPI_CTRL00_CLOCK_LANE_GATE |
+		       MIPI_CTRL00_LINE_SYNC_ENABLE;
+
+	ret = ov5647_write(sd, OV5647_REG_MIPI_CTRL00, val);
 	if (ret < 0)
 		return ret;
 
@@ -546,9 +554,11 @@ static const struct v4l2_subdev_internal_ops ov5647_subdev_internal_ops = {
 	.open = ov5647_open,
 };
 
-static int ov5647_parse_dt(struct device_node *np)
+static int ov5647_parse_dt(struct ov5647 *sensor, struct device_node *np)
 {
-	struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = 0 };
+	struct v4l2_fwnode_endpoint bus_cfg = {
+		.bus_type = V4L2_MBUS_CSI2_DPHY,
+	};
 	struct device_node *ep;
 
 	int ret;
@@ -558,7 +568,13 @@ static int ov5647_parse_dt(struct device_node *np)
 		return -EINVAL;
 
 	ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &bus_cfg);
+	if (ret)
+		goto out;
 
+	sensor->clock_ncont = bus_cfg.bus.mipi_csi2.flags &
+			      V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK;
+
+out:
 	of_node_put(ep);
 	return ret;
 }
@@ -577,7 +593,7 @@ static int ov5647_probe(struct i2c_client *client)
 		return -ENOMEM;
 
 	if (IS_ENABLED(CONFIG_OF) && np) {
-		ret = ov5647_parse_dt(np);
+		ret = ov5647_parse_dt(sensor, np);
 		if (ret) {
 			dev_err(dev, "DT parsing error: %d\n", ret);
 			return ret;
-- 
2.27.0


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

* [PATCH 05/25] media: ov5647: Add set_fmt and get_fmt calls.
  2020-06-23 10:07 [PATCH 00/25] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
                   ` (3 preceding siblings ...)
  2020-06-23 10:07 ` [PATCH 04/25] media: ov5647: Add support for non-continuous clock mode Jacopo Mondi
@ 2020-06-23 10:07 ` Jacopo Mondi
  2020-06-23 10:07 ` [PATCH 06/25] media: ov5647: Fix format initialization Jacopo Mondi
                   ` (21 subsequent siblings)
  26 siblings, 0 replies; 56+ messages in thread
From: Jacopo Mondi @ 2020-06-23 10:07 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dave.stevenson, naush
  Cc: Jacopo Mondi, mrodin, hugues.fruchet, mripard, aford173, sudipi,
	andrew_gabbasov, erosca, linux-media, libcamera-devel

From: Dave Stevenson <dave.stevenson@raspberrypi.org>

There's no way to query the subdevice for the supported
resolutions. Add set_fmt and get_fmt implementations. Since there's
only one format supported set_fmt does nothing and get returns single
format.

Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
Signed-off-by: Roman Kovalivskyi <roman.kovalivskyi@globallogic.com>
Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
---
 drivers/media/i2c/ov5647.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
index 2d69cd97142d7..43fecf0ca58f3 100644
--- a/drivers/media/i2c/ov5647.c
+++ b/drivers/media/i2c/ov5647.c
@@ -487,8 +487,27 @@ static int ov5647_enum_mbus_code(struct v4l2_subdev *sd,
 	return 0;
 }
 
+static int ov5647_set_get_fmt(struct v4l2_subdev *sd,
+			      struct v4l2_subdev_pad_config *cfg,
+			      struct v4l2_subdev_format *format)
+{
+	struct v4l2_mbus_framefmt *fmt = &format->format;
+
+	/* Only one format is supported, so return that */
+	memset(fmt, 0, sizeof(*fmt));
+	fmt->code = MEDIA_BUS_FMT_SBGGR8_1X8;
+	fmt->colorspace = V4L2_COLORSPACE_SRGB;
+	fmt->field = V4L2_FIELD_NONE;
+	fmt->width = 640;
+	fmt->height = 480;
+
+	return 0;
+}
+
 static const struct v4l2_subdev_pad_ops ov5647_subdev_pad_ops = {
 	.enum_mbus_code = ov5647_enum_mbus_code,
+	.set_fmt =	  ov5647_set_get_fmt,
+	.get_fmt =	  ov5647_set_get_fmt,
 };
 
 static const struct v4l2_subdev_ops ov5647_subdev_ops = {
-- 
2.27.0


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

* [PATCH 06/25] media: ov5647: Fix format initialization
  2020-06-23 10:07 [PATCH 00/25] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
                   ` (4 preceding siblings ...)
  2020-06-23 10:07 ` [PATCH 05/25] media: ov5647: Add set_fmt and get_fmt calls Jacopo Mondi
@ 2020-06-23 10:07 ` Jacopo Mondi
  2020-06-23 10:07 ` [PATCH 07/25] media: ov5647: Fix style issues Jacopo Mondi
                   ` (20 subsequent siblings)
  26 siblings, 0 replies; 56+ messages in thread
From: Jacopo Mondi @ 2020-06-23 10:07 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dave.stevenson, naush
  Cc: Jacopo Mondi, mrodin, hugues.fruchet, mripard, aford173, sudipi,
	andrew_gabbasov, erosca, linux-media, libcamera-devel

The driver currently support a single format. Fix its initialization to
use the only supported resolution.

Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
---
 drivers/media/i2c/ov5647.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
index 43fecf0ca58f3..c92856d3aa81c 100644
--- a/drivers/media/i2c/ov5647.c
+++ b/drivers/media/i2c/ov5647.c
@@ -560,9 +560,8 @@ static int ov5647_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 	crop->height = OV5647_WINDOW_HEIGHT_DEF;
 
 	format->code = MEDIA_BUS_FMT_SBGGR8_1X8;
-
-	format->width = OV5647_WINDOW_WIDTH_DEF;
-	format->height = OV5647_WINDOW_HEIGHT_DEF;
+	format->width = 640;
+	format->height = 480;
 	format->field = V4L2_FIELD_NONE;
 	format->colorspace = V4L2_COLORSPACE_SRGB;
 
-- 
2.27.0


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

* [PATCH 07/25] media: ov5647: Fix style issues
  2020-06-23 10:07 [PATCH 00/25] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
                   ` (5 preceding siblings ...)
  2020-06-23 10:07 ` [PATCH 06/25] media: ov5647: Fix format initialization Jacopo Mondi
@ 2020-06-23 10:07 ` Jacopo Mondi
  2020-06-23 10:07 ` [PATCH 08/25] media: ov5647: Replace license with SPDX identifier Jacopo Mondi
                   ` (19 subsequent siblings)
  26 siblings, 0 replies; 56+ messages in thread
From: Jacopo Mondi @ 2020-06-23 10:07 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dave.stevenson, naush
  Cc: Jacopo Mondi, mrodin, hugues.fruchet, mripard, aford173, sudipi,
	andrew_gabbasov, erosca, linux-media, libcamera-devel

The driver has some obvious style issues which are worth fixing before
expanding the driver capabilities.

Fix:
- Variable declaration order
- Function parameters alignment
- Multi-line comments and spurious line breaks
- Use lowercase for hexadecimal values

Cosmetic change, no functional changes intended.

Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
---
 drivers/media/i2c/ov5647.c | 101 +++++++++++++++++--------------------
 1 file changed, 45 insertions(+), 56 deletions(-)

diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
index c92856d3aa81c..e9679382623f9 100644
--- a/drivers/media/i2c/ov5647.c
+++ b/drivers/media/i2c/ov5647.c
@@ -34,8 +34,6 @@
 #include <media/v4l2-image-sizes.h>
 #include <media/v4l2-mediabus.h>
 
-#define SENSOR_NAME "ov5647"
-
 /*
  * From the datasheet, "20ms after PWDN goes low or 20ms after RESETB goes
  * high if reset is inserted after PWDN goes high, host can access sensor's
@@ -50,9 +48,9 @@
 
 #define OV5647_SW_STANDBY		0x0100
 #define OV5647_SW_RESET			0x0103
-#define OV5647_REG_CHIPID_H		0x300A
-#define OV5647_REG_CHIPID_L		0x300B
-#define OV5640_REG_PAD_OUT		0x300D
+#define OV5647_REG_CHIPID_H		0x300a
+#define OV5647_REG_CHIPID_L		0x300b
+#define OV5640_REG_PAD_OUT		0x300d
 #define OV5647_REG_FRAME_OFF_NUMBER	0x4202
 #define OV5647_REG_MIPI_CTRL00		0x4800
 #define OV5647_REG_MIPI_CTRL14		0x4814
@@ -158,7 +156,7 @@ static struct regval_list ov5647_640x480[] = {
 	{0x3808, 0x02},
 	{0x3809, 0x80},
 	{0x380a, 0x01},
-	{0x380b, 0xE0},
+	{0x380b, 0xe0},
 	{0x3801, 0x00},
 	{0x3802, 0x00},
 	{0x3803, 0x00},
@@ -209,9 +207,9 @@ static struct regval_list ov5647_640x480[] = {
 
 static int ov5647_write(struct v4l2_subdev *sd, u16 reg, u8 val)
 {
-	int ret;
 	unsigned char data[3] = { reg >> 8, reg & 0xff, val};
 	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	int ret;
 
 	ret = i2c_master_send(client, data, 3);
 	if (ret < 0)
@@ -223,9 +221,9 @@ static int ov5647_write(struct v4l2_subdev *sd, u16 reg, u8 val)
 
 static int ov5647_read(struct v4l2_subdev *sd, u16 reg, u8 *val)
 {
-	int ret;
 	unsigned char data_w[2] = { reg >> 8, reg & 0xff };
 	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	int ret;
 
 	ret = i2c_master_send(client, data_w, 2);
 	if (ret < 0) {
@@ -243,7 +241,7 @@ static int ov5647_read(struct v4l2_subdev *sd, u16 reg, u8 *val)
 }
 
 static int ov5647_write_array(struct v4l2_subdev *sd,
-				struct regval_list *regs, int array_size)
+			      struct regval_list *regs, int array_size)
 {
 	int i, ret;
 
@@ -266,6 +264,7 @@ static int ov5647_set_virtual_channel(struct v4l2_subdev *sd, int channel)
 		return ret;
 
 	channel_id &= ~(3 << 6);
+
 	return ov5647_write(sd, OV5647_REG_MIPI_CTRL14, channel_id | (channel << 6));
 }
 
@@ -294,8 +293,8 @@ static int ov5647_stream_off(struct v4l2_subdev *sd)
 {
 	int ret;
 
-	ret = ov5647_write(sd, OV5647_REG_MIPI_CTRL00, MIPI_CTRL00_CLOCK_LANE_GATE
-			   | MIPI_CTRL00_BUS_IDLE | MIPI_CTRL00_CLOCK_LANE_DISABLE);
+	ret = ov5647_write(sd, OV5647_REG_MIPI_CTRL00, MIPI_CTRL00_CLOCK_LANE_GATE |
+			       MIPI_CTRL00_BUS_IDLE | MIPI_CTRL00_CLOCK_LANE_DISABLE);
 	if (ret < 0)
 		return ret;
 
@@ -325,16 +324,16 @@ static int set_sw_standby(struct v4l2_subdev *sd, bool standby)
 
 static int __sensor_init(struct v4l2_subdev *sd)
 {
-	int ret;
-	u8 resetval, rdval;
 	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	u8 resetval, rdval;
+	int ret;
 
 	ret = ov5647_read(sd, OV5647_SW_STANDBY, &rdval);
 	if (ret < 0)
 		return ret;
 
 	ret = ov5647_write_array(sd, ov5647_640x480,
-					ARRAY_SIZE(ov5647_640x480));
+				 ARRAY_SIZE(ov5647_640x480));
 	if (ret < 0) {
 		dev_err(&client->dev, "write sensor default regs error\n");
 		return ret;
@@ -355,17 +354,15 @@ static int __sensor_init(struct v4l2_subdev *sd)
 			return ret;
 	}
 
-	/*
-	 * stream off to make the clock lane into LP-11 state.
-	 */
+	/* Stream off to make the clock lane into LP-11 state. */
 	return ov5647_stream_off(sd);
 }
 
 static int ov5647_sensor_power(struct v4l2_subdev *sd, int on)
 {
-	int ret = 0;
-	struct ov5647 *ov5647 = to_state(sd);
 	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ov5647 *ov5647 = to_state(sd);
+	int ret = 0;
 
 	mutex_lock(&ov5647->lock);
 
@@ -384,7 +381,7 @@ static int ov5647_sensor_power(struct v4l2_subdev *sd, int on)
 		}
 
 		ret = ov5647_write_array(sd, sensor_oe_enable_regs,
-				ARRAY_SIZE(sensor_oe_enable_regs));
+					 ARRAY_SIZE(sensor_oe_enable_regs));
 		if (ret < 0) {
 			clk_disable_unprepare(ov5647->xclk);
 			dev_err(&client->dev,
@@ -403,18 +400,15 @@ static int ov5647_sensor_power(struct v4l2_subdev *sd, int on)
 		dev_dbg(&client->dev, "OV5647 power off\n");
 
 		ret = ov5647_write_array(sd, sensor_oe_disable_regs,
-				ARRAY_SIZE(sensor_oe_disable_regs));
-
+					 ARRAY_SIZE(sensor_oe_disable_regs));
 		if (ret < 0)
 			dev_dbg(&client->dev, "disable oe failed\n");
 
 		ret = set_sw_standby(sd, true);
-
 		if (ret < 0)
 			dev_dbg(&client->dev, "soft stby failed\n");
 
 		clk_disable_unprepare(ov5647->xclk);
-
 		gpiod_set_value_cansleep(ov5647->pwdn, 1);
 	}
 
@@ -430,10 +424,10 @@ static int ov5647_sensor_power(struct v4l2_subdev *sd, int on)
 
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 static int ov5647_sensor_get_register(struct v4l2_subdev *sd,
-				struct v4l2_dbg_register *reg)
+				      struct v4l2_dbg_register *reg)
 {
-	u8 val;
 	int ret;
+	u8 val;
 
 	ret = ov5647_read(sd, reg->reg & 0xff, &val);
 	if (ret < 0)
@@ -446,15 +440,13 @@ static int ov5647_sensor_get_register(struct v4l2_subdev *sd,
 }
 
 static int ov5647_sensor_set_register(struct v4l2_subdev *sd,
-				const struct v4l2_dbg_register *reg)
+				      const struct v4l2_dbg_register *reg)
 {
 	return ov5647_write(sd, reg->reg & 0xff, reg->val & 0xff);
 }
 #endif
 
-/*
- * Subdev core operations registration
- */
+/* Subdev core operations registration */
 static const struct v4l2_subdev_core_ops ov5647_subdev_core_ops = {
 	.s_power		= ov5647_sensor_power,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
@@ -476,8 +468,8 @@ static const struct v4l2_subdev_video_ops ov5647_subdev_video_ops = {
 };
 
 static int ov5647_enum_mbus_code(struct v4l2_subdev *sd,
-				struct v4l2_subdev_pad_config *cfg,
-				struct v4l2_subdev_mbus_code_enum *code)
+				 struct v4l2_subdev_pad_config *cfg,
+				 struct v4l2_subdev_mbus_code_enum *code)
 {
 	if (code->index > 0)
 		return -EINVAL;
@@ -493,7 +485,7 @@ static int ov5647_set_get_fmt(struct v4l2_subdev *sd,
 {
 	struct v4l2_mbus_framefmt *fmt = &format->format;
 
-	/* Only one format is supported, so return that */
+	/* Only one format is supported, so return that. */
 	memset(fmt, 0, sizeof(*fmt));
 	fmt->code = MEDIA_BUS_FMT_SBGGR8_1X8;
 	fmt->colorspace = V4L2_COLORSPACE_SRGB;
@@ -518,9 +510,9 @@ static const struct v4l2_subdev_ops ov5647_subdev_ops = {
 
 static int ov5647_detect(struct v4l2_subdev *sd)
 {
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
 	u8 read;
 	int ret;
-	struct i2c_client *client = v4l2_get_subdevdata(sd);
 
 	ret = ov5647_write(sd, OV5647_SW_RESET, 0x01);
 	if (ret < 0)
@@ -549,10 +541,8 @@ static int ov5647_detect(struct v4l2_subdev *sd)
 
 static int ov5647_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 {
-	struct v4l2_mbus_framefmt *format =
-				v4l2_subdev_get_try_format(sd, fh->pad, 0);
-	struct v4l2_rect *crop =
-				v4l2_subdev_get_try_crop(sd, fh->pad, 0);
+	struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(sd, fh->pad, 0);
+	struct v4l2_rect *crop = v4l2_subdev_get_try_crop(sd, fh->pad, 0);
 
 	crop->left = OV5647_COLUMN_START_DEF;
 	crop->top = OV5647_ROW_START_DEF;
@@ -578,7 +568,6 @@ static int ov5647_parse_dt(struct ov5647 *sensor, struct device_node *np)
 		.bus_type = V4L2_MBUS_CSI2_DPHY,
 	};
 	struct device_node *ep;
-
 	int ret;
 
 	ep = of_graph_get_next_endpoint(np, NULL);
@@ -594,17 +583,18 @@ static int ov5647_parse_dt(struct ov5647 *sensor, struct device_node *np)
 
 out:
 	of_node_put(ep);
+
 	return ret;
 }
 
 static int ov5647_probe(struct i2c_client *client)
 {
+	struct device_node *np = client->dev.of_node;
 	struct device *dev = &client->dev;
 	struct ov5647 *sensor;
-	int ret;
 	struct v4l2_subdev *sd;
-	struct device_node *np = client->dev.of_node;
 	u32 xclk_freq;
+	int ret;
 
 	sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
 	if (!sensor)
@@ -618,7 +608,6 @@ static int ov5647_probe(struct i2c_client *client)
 		}
 	}
 
-	/* get system clock (xclk) */
 	sensor->xclk = devm_clk_get(dev, NULL);
 	if (IS_ERR(sensor->xclk)) {
 		dev_err(dev, "could not get xclk");
@@ -631,22 +620,21 @@ static int ov5647_probe(struct i2c_client *client)
 		return -EINVAL;
 	}
 
-	/* Request the power down GPIO asserted */
-	sensor->pwdn = devm_gpiod_get_optional(&client->dev, "pwdn",
-					       GPIOD_OUT_HIGH);
+	/* Request the power down GPIO asserted. */
+	sensor->pwdn = devm_gpiod_get_optional(dev, "pwdn", GPIOD_OUT_HIGH);
 
 	mutex_init(&sensor->lock);
 
 	sd = &sensor->sd;
 	v4l2_i2c_subdev_init(sd, client, &ov5647_subdev_ops);
-	sensor->sd.internal_ops = &ov5647_subdev_internal_ops;
-	sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	sd->internal_ops = &ov5647_subdev_internal_ops;
+	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
 
 	sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
 	sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
 	ret = media_entity_pads_init(&sd->entity, 1, &sensor->pad);
 	if (ret < 0)
-		goto mutex_remove;
+		goto mutex_destroy;
 
 	if (sensor->pwdn) {
 		gpiod_set_value_cansleep(sensor->pwdn, 0);
@@ -654,22 +642,23 @@ static int ov5647_probe(struct i2c_client *client)
 	}
 
 	ret = ov5647_detect(sd);
-
 	gpiod_set_value_cansleep(sensor->pwdn, 1);
-
 	if (ret < 0)
-		goto error;
+		goto entity_cleanup;
 
 	ret = v4l2_async_register_subdev(sd);
 	if (ret < 0)
-		goto error;
+		goto entity_cleanup;
 
 	dev_dbg(dev, "OmniVision OV5647 camera driver probed\n");
+
 	return 0;
-error:
+
+entity_cleanup:
 	media_entity_cleanup(&sd->entity);
-mutex_remove:
+mutex_destroy:
 	mutex_destroy(&sensor->lock);
+
 	return ret;
 }
 
@@ -688,7 +677,7 @@ static int ov5647_remove(struct i2c_client *client)
 
 static const struct i2c_device_id ov5647_id[] = {
 	{ "ov5647", 0 },
-	{ }
+	{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(i2c, ov5647_id);
 
@@ -703,7 +692,7 @@ MODULE_DEVICE_TABLE(of, ov5647_of_match);
 static struct i2c_driver ov5647_driver = {
 	.driver = {
 		.of_match_table = of_match_ptr(ov5647_of_match),
-		.name	= SENSOR_NAME,
+		.name	= "ov5647",
 	},
 	.probe_new	= ov5647_probe,
 	.remove		= ov5647_remove,
-- 
2.27.0


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

* [PATCH 08/25] media: ov5647: Replace license with SPDX identifier
  2020-06-23 10:07 [PATCH 00/25] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
                   ` (6 preceding siblings ...)
  2020-06-23 10:07 ` [PATCH 07/25] media: ov5647: Fix style issues Jacopo Mondi
@ 2020-06-23 10:07 ` Jacopo Mondi
  2020-06-23 10:07 ` [PATCH 09/25] media: ov5647: Fix return value from read/write Jacopo Mondi
                   ` (18 subsequent siblings)
  26 siblings, 0 replies; 56+ messages in thread
From: Jacopo Mondi @ 2020-06-23 10:07 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dave.stevenson, naush
  Cc: Jacopo Mondi, mrodin, hugues.fruchet, mripard, aford173, sudipi,
	andrew_gabbasov, erosca, linux-media, libcamera-devel

Replace the boilerplate license text with the SPDX identifier.

Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
---
 drivers/media/i2c/ov5647.c | 10 +---------
 1 file changed, 1 insertion(+), 9 deletions(-)

diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
index e9679382623f9..61aa86e507b32 100644
--- a/drivers/media/i2c/ov5647.c
+++ b/drivers/media/i2c/ov5647.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * A V4L2 driver for OmniVision OV5647 cameras.
  *
@@ -8,15 +9,6 @@
  * Copyright (C) 2006-7 Jonathan Corbet <corbet@lwn.net>
  *
  * Copyright (C) 2016, Synopsys, Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2.
- *
- * This program is distributed .as is. WITHOUT ANY WARRANTY of any
- * kind, whether express or implied; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
  */
 
 #include <linux/clk.h>
-- 
2.27.0


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

* [PATCH 09/25] media: ov5647: Fix return value from read/write
  2020-06-23 10:07 [PATCH 00/25] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
                   ` (7 preceding siblings ...)
  2020-06-23 10:07 ` [PATCH 08/25] media: ov5647: Replace license with SPDX identifier Jacopo Mondi
@ 2020-06-23 10:07 ` Jacopo Mondi
  2020-06-23 10:08 ` [PATCH 10/25] media: ov5647: Program mode at s_stream(1) time Jacopo Mondi
                   ` (17 subsequent siblings)
  26 siblings, 0 replies; 56+ messages in thread
From: Jacopo Mondi @ 2020-06-23 10:07 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dave.stevenson, naush
  Cc: Jacopo Mondi, mrodin, hugues.fruchet, mripard, aford173, sudipi,
	andrew_gabbasov, erosca, linux-media, libcamera-devel

The ov5647_read()/ov5647_write() return in case of success the number
of bytes read or written respectively. This requires callers to check
if the return value is less than zero to detect an error. Unfortunately,
in several places, callers directly return the result of a read/write
call, causing issues when the returned valued is checked to be different
from zero to detect an error.

Fix this by returning zero if i2c_master_send() and i2c_master_read()
return a positive value (the number of bytes written or read).

Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
---
 drivers/media/i2c/ov5647.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
index 61aa86e507b32..0c88f682de9b9 100644
--- a/drivers/media/i2c/ov5647.c
+++ b/drivers/media/i2c/ov5647.c
@@ -204,11 +204,13 @@ static int ov5647_write(struct v4l2_subdev *sd, u16 reg, u8 val)
 	int ret;
 
 	ret = i2c_master_send(client, data, 3);
-	if (ret < 0)
+	if (ret < 0) {
 		dev_dbg(&client->dev, "%s: i2c write error, reg: %x\n",
 				__func__, reg);
+		return ret;
+	}
 
-	return ret;
+	return 0;
 }
 
 static int ov5647_read(struct v4l2_subdev *sd, u16 reg, u8 *val)
@@ -225,11 +227,13 @@ static int ov5647_read(struct v4l2_subdev *sd, u16 reg, u8 *val)
 	}
 
 	ret = i2c_master_recv(client, val, 1);
-	if (ret < 0)
+	if (ret < 0) {
 		dev_dbg(&client->dev, "%s: i2c read error, reg: %x\n",
 				__func__, reg);
+		return ret;
+	}
 
-	return ret;
+	return 0;
 }
 
 static int ov5647_write_array(struct v4l2_subdev *sd,
-- 
2.27.0


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

* [PATCH 10/25] media: ov5647: Program mode at s_stream(1) time
  2020-06-23 10:07 [PATCH 00/25] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
                   ` (8 preceding siblings ...)
  2020-06-23 10:07 ` [PATCH 09/25] media: ov5647: Fix return value from read/write Jacopo Mondi
@ 2020-06-23 10:08 ` Jacopo Mondi
  2020-06-23 16:42 ` [PATCH 11/25] media: ov5647: Implement enum_frame_size() Jacopo Mondi
                   ` (16 subsequent siblings)
  26 siblings, 0 replies; 56+ messages in thread
From: Jacopo Mondi @ 2020-06-23 10:08 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dave.stevenson, naush
  Cc: Jacopo Mondi, mrodin, hugues.fruchet, mripard, aford173, sudipi,
	andrew_gabbasov, erosca, linux-media, libcamera-devel

Rename __sensor_init() function to ov5647_set_mode() as the function
is a regular one and the double underscores prefix shall be removed, and
then move it to program the mode at s_stream(1) time, not at sensor power
up.

Break out from __sensor_init() the stream_off() operation call at sensor
power up to coax the lanes in LP-11 state.

Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
---
 drivers/media/i2c/ov5647.c | 81 +++++++++++++++++++++-----------------
 1 file changed, 44 insertions(+), 37 deletions(-)

diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
index 0c88f682de9b9..bb9ff77f49fe0 100644
--- a/drivers/media/i2c/ov5647.c
+++ b/drivers/media/i2c/ov5647.c
@@ -264,12 +264,54 @@ static int ov5647_set_virtual_channel(struct v4l2_subdev *sd, int channel)
 	return ov5647_write(sd, OV5647_REG_MIPI_CTRL14, channel_id | (channel << 6));
 }
 
+static int ov5647_set_mode(struct v4l2_subdev *sd)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	u8 resetval, rdval;
+	int ret;
+
+	ret = ov5647_read(sd, OV5647_SW_STANDBY, &rdval);
+	if (ret < 0)
+		return ret;
+
+	ret = ov5647_write_array(sd, ov5647_640x480,
+				 ARRAY_SIZE(ov5647_640x480));
+	if (ret < 0) {
+		dev_err(&client->dev, "write sensor default regs error\n");
+		return ret;
+	}
+
+	ret = ov5647_set_virtual_channel(sd, 0);
+	if (ret < 0)
+		return ret;
+
+	ret = ov5647_read(sd, OV5647_SW_STANDBY, &resetval);
+	if (ret < 0)
+		return ret;
+
+	if (!(resetval & 0x01)) {
+		dev_err(&client->dev, "Device was in SW standby");
+		ret = ov5647_write(sd, OV5647_SW_STANDBY, 0x01);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
 static int ov5647_stream_on(struct v4l2_subdev *sd)
 {
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
 	struct ov5647 *ov5647 = to_state(sd);
 	u8 val = MIPI_CTRL00_BUS_IDLE;
 	int ret;
 
+	ret = ov5647_set_mode(sd);
+	if (ret) {
+		dev_err(&client->dev, "Failed to program sensor mode: %d\n", ret);
+		return ret;
+	}
+
 	if (ov5647->clock_ncont)
 		val |= MIPI_CTRL00_CLOCK_LANE_GATE |
 		       MIPI_CTRL00_LINE_SYNC_ENABLE;
@@ -318,42 +360,6 @@ static int set_sw_standby(struct v4l2_subdev *sd, bool standby)
 	return ov5647_write(sd, OV5647_SW_STANDBY, rdval);
 }
 
-static int __sensor_init(struct v4l2_subdev *sd)
-{
-	struct i2c_client *client = v4l2_get_subdevdata(sd);
-	u8 resetval, rdval;
-	int ret;
-
-	ret = ov5647_read(sd, OV5647_SW_STANDBY, &rdval);
-	if (ret < 0)
-		return ret;
-
-	ret = ov5647_write_array(sd, ov5647_640x480,
-				 ARRAY_SIZE(ov5647_640x480));
-	if (ret < 0) {
-		dev_err(&client->dev, "write sensor default regs error\n");
-		return ret;
-	}
-
-	ret = ov5647_set_virtual_channel(sd, 0);
-	if (ret < 0)
-		return ret;
-
-	ret = ov5647_read(sd, OV5647_SW_STANDBY, &resetval);
-	if (ret < 0)
-		return ret;
-
-	if (!(resetval & 0x01)) {
-		dev_err(&client->dev, "Device was in SW standby");
-		ret = ov5647_write(sd, OV5647_SW_STANDBY, 0x01);
-		if (ret < 0)
-			return ret;
-	}
-
-	/* Stream off to make the clock lane into LP-11 state. */
-	return ov5647_stream_off(sd);
-}
-
 static int ov5647_sensor_power(struct v4l2_subdev *sd, int on)
 {
 	struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -385,7 +391,8 @@ static int ov5647_sensor_power(struct v4l2_subdev *sd, int on)
 			goto out;
 		}
 
-		ret = __sensor_init(sd);
+		/* Stream off to coax lanes into LP-11 state. */
+		ret = ov5647_stream_off(sd);
 		if (ret < 0) {
 			clk_disable_unprepare(ov5647->xclk);
 			dev_err(&client->dev,
-- 
2.27.0


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

* [PATCH 11/25] media: ov5647: Implement enum_frame_size()
  2020-06-23 10:07 [PATCH 00/25] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
                   ` (9 preceding siblings ...)
  2020-06-23 10:08 ` [PATCH 10/25] media: ov5647: Program mode at s_stream(1) time Jacopo Mondi
@ 2020-06-23 16:42 ` Jacopo Mondi
  2020-08-18  7:33   ` Sakari Ailus
  2020-06-23 16:42 ` [PATCH 12/25] media: ov5647: Protect s_stream() with mutex Jacopo Mondi
                   ` (15 subsequent siblings)
  26 siblings, 1 reply; 56+ messages in thread
From: Jacopo Mondi @ 2020-06-23 16:42 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dave.stevenson, naush
  Cc: mrodin, hugues.fruchet, mripard, aford173, sudipi,
	andrew_gabbasov, erosca, linux-media, libcamera-devel,
	Jacopo Mondi

Implement the .enum_frame_size subdev pad operation.

As the driver only supports one format and one resolution at the moment
the implementation is trivial.

Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
---
 drivers/media/i2c/ov5647.c | 25 ++++++++++++++++++++++---
 1 file changed, 22 insertions(+), 3 deletions(-)

diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
index bb9ff77f49fe0..859cc5b0d14a3 100644
--- a/drivers/media/i2c/ov5647.c
+++ b/drivers/media/i2c/ov5647.c
@@ -482,6 +482,24 @@ static int ov5647_enum_mbus_code(struct v4l2_subdev *sd,
 	return 0;
 }
 
+static int ov5647_enum_frame_size(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_pad_config *cfg,
+				  struct v4l2_subdev_frame_size_enum *fse)
+{
+	if (fse->index)
+		return -EINVAL;
+
+	if (fse->code != MEDIA_BUS_FMT_SBGGR8_1X8)
+		return -EINVAL;
+
+	fse->min_width = 640;
+	fse->max_width = 640;
+	fse->min_height = 480;
+	fse->max_height = 480;
+
+	return 0;
+}
+
 static int ov5647_set_get_fmt(struct v4l2_subdev *sd,
 			      struct v4l2_subdev_pad_config *cfg,
 			      struct v4l2_subdev_format *format)
@@ -500,9 +518,10 @@ static int ov5647_set_get_fmt(struct v4l2_subdev *sd,
 }
 
 static const struct v4l2_subdev_pad_ops ov5647_subdev_pad_ops = {
-	.enum_mbus_code = ov5647_enum_mbus_code,
-	.set_fmt =	  ov5647_set_get_fmt,
-	.get_fmt =	  ov5647_set_get_fmt,
+	.enum_mbus_code		= ov5647_enum_mbus_code,
+	.enum_frame_size	= ov5647_enum_frame_size,
+	.set_fmt		= ov5647_set_get_fmt,
+	.get_fmt		= ov5647_set_get_fmt,
 };
 
 static const struct v4l2_subdev_ops ov5647_subdev_ops = {
-- 
2.27.0


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

* [PATCH 12/25] media: ov5647: Protect s_stream() with mutex
  2020-06-23 10:07 [PATCH 00/25] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
                   ` (10 preceding siblings ...)
  2020-06-23 16:42 ` [PATCH 11/25] media: ov5647: Implement enum_frame_size() Jacopo Mondi
@ 2020-06-23 16:42 ` Jacopo Mondi
  2020-06-23 16:42 ` [PATCH 13/25] media: ov5647: Support gain, exposure and AWB controls Jacopo Mondi
                   ` (14 subsequent siblings)
  26 siblings, 0 replies; 56+ messages in thread
From: Jacopo Mondi @ 2020-06-23 16:42 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dave.stevenson, naush
  Cc: mrodin, hugues.fruchet, mripard, aford173, sudipi,
	andrew_gabbasov, erosca, linux-media, libcamera-devel,
	Jacopo Mondi

Use the driver mutex to protect s_stream() operations.
This will become more relevant once the sensor will support more formats
and set_format() could be issue concurrently to s_stream().

Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
---
 drivers/media/i2c/ov5647.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
index 859cc5b0d14a3..2d2829f934c3c 100644
--- a/drivers/media/i2c/ov5647.c
+++ b/drivers/media/i2c/ov5647.c
@@ -460,10 +460,17 @@ static const struct v4l2_subdev_core_ops ov5647_subdev_core_ops = {
 
 static int ov5647_s_stream(struct v4l2_subdev *sd, int enable)
 {
+	struct ov5647 *sensor = to_state(sd);
+	int ret;
+
+	mutex_lock(&sensor->lock);
 	if (enable)
-		return ov5647_stream_on(sd);
+		ret = ov5647_stream_on(sd);
 	else
-		return ov5647_stream_off(sd);
+		ret = ov5647_stream_off(sd);
+	mutex_unlock(&sensor->lock);
+
+	return ret;
 }
 
 static const struct v4l2_subdev_video_ops ov5647_subdev_video_ops = {
-- 
2.27.0


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

* [PATCH 13/25] media: ov5647: Support gain, exposure and AWB controls
  2020-06-23 10:07 [PATCH 00/25] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
                   ` (11 preceding siblings ...)
  2020-06-23 16:42 ` [PATCH 12/25] media: ov5647: Protect s_stream() with mutex Jacopo Mondi
@ 2020-06-23 16:42 ` Jacopo Mondi
  2020-06-23 16:42 ` [PATCH 14/25] media: ov5647: Rationalize driver structure name Jacopo Mondi
                   ` (13 subsequent siblings)
  26 siblings, 0 replies; 56+ messages in thread
From: Jacopo Mondi @ 2020-06-23 16:42 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dave.stevenson, naush
  Cc: mrodin, hugues.fruchet, mripard, aford173, sudipi,
	andrew_gabbasov, erosca, linux-media, libcamera-devel,
	David Plowman, Jacopo Mondi

From: David Plowman <david.plowman@raspberrypi.com>

Add controls to support AWB, AEC and AGC. Also add control support to
set exposure (in lines) and analogue gain (as a register code).

Signed-off-by: David Plowman <david.plowman@raspberrypi.com>
Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
---
 drivers/media/i2c/ov5647.c | 170 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 168 insertions(+), 2 deletions(-)

diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
index 2d2829f934c3c..8cfe315cfd00b 100644
--- a/drivers/media/i2c/ov5647.c
+++ b/drivers/media/i2c/ov5647.c
@@ -21,6 +21,7 @@
 #include <linux/of_graph.h>
 #include <linux/slab.h>
 #include <linux/videodev2.h>
+#include <media/v4l2-ctrls.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-fwnode.h>
 #include <media/v4l2-image-sizes.h>
@@ -43,9 +44,16 @@
 #define OV5647_REG_CHIPID_H		0x300a
 #define OV5647_REG_CHIPID_L		0x300b
 #define OV5640_REG_PAD_OUT		0x300d
+#define OV5647_REG_EXP_HI		0x3500
+#define OV5647_REG_EXP_MID		0x3501
+#define OV5647_REG_EXP_LO		0x3502
+#define OV5647_REG_AEC_AGC		0x3503
+#define OV5647_REG_GAIN_HI		0x350a
+#define OV5647_REG_GAIN_LO		0x350b
 #define OV5647_REG_FRAME_OFF_NUMBER	0x4202
 #define OV5647_REG_MIPI_CTRL00		0x4800
 #define OV5647_REG_MIPI_CTRL14		0x4814
+#define OV5647_REG_AWB			0x5001
 
 #define REG_TERM 0xfffe
 #define VAL_TERM 0xfe
@@ -87,6 +95,7 @@ struct ov5647 {
 	struct clk			*xclk;
 	struct gpio_desc		*pwdn;
 	bool				clock_ncont;
+	struct v4l2_ctrl_handler	ctrls;
 };
 
 static inline struct ov5647 *to_state(struct v4l2_subdev *sd)
@@ -121,7 +130,6 @@ static struct regval_list ov5647_640x480[] = {
 	{0x3612, 0x59},
 	{0x3618, 0x00},
 	{0x5000, 0x06},
-	{0x5001, 0x01},
 	{0x5002, 0x41},
 	{0x5003, 0x08},
 	{0x5a00, 0x08},
@@ -312,6 +320,11 @@ static int ov5647_stream_on(struct v4l2_subdev *sd)
 		return ret;
 	}
 
+	/* Apply customized values from user when stream starts. */
+	ret =  __v4l2_ctrl_handler_setup(sd->ctrl_handler);
+	if (ret)
+		return ret;
+
 	if (ov5647->clock_ncont)
 		val |= MIPI_CTRL00_CLOCK_LANE_GATE |
 		       MIPI_CTRL00_LINE_SYNC_ENABLE;
@@ -591,6 +604,152 @@ static const struct v4l2_subdev_internal_ops ov5647_subdev_internal_ops = {
 	.open = ov5647_open,
 };
 
+static int ov5647_s_auto_white_balance(struct v4l2_subdev *sd, u32 val)
+{
+	return ov5647_write(sd, OV5647_REG_AWB, val ? 1 : 0);
+}
+
+static int ov5647_s_autogain(struct v4l2_subdev *sd, u32 val)
+{
+	int ret;
+	u8 reg;
+
+	/* Non-zero turns on AGC by clearing bit 1.*/
+	ret = ov5647_read(sd, OV5647_REG_AEC_AGC, &reg);
+	if (ret)
+		return ret;
+
+	return ov5647_write(sd, OV5647_REG_AEC_AGC, val ? reg & ~BIT(1)
+							: reg | BIT(1));
+}
+
+static int ov5647_s_exposure_auto(struct v4l2_subdev *sd, u32 val)
+{
+	int ret;
+	u8 reg;
+
+	/*
+	 * Everything except V4L2_EXPOSURE_MANUAL turns on AEC by
+	 * clearing bit 0.
+	 */
+	ret = ov5647_read(sd, OV5647_REG_AEC_AGC, &reg);
+	if (ret)
+		return ret;
+
+	return ov5647_write(sd, OV5647_REG_AEC_AGC, val == V4L2_EXPOSURE_MANUAL ?
+						    reg | BIT(0) : reg & ~BIT(0));
+}
+
+static int ov5647_s_analogue_gain(struct v4l2_subdev *sd, u32 val)
+{
+	int ret;
+
+	/* 10 bits of gain, 2 in the high register. */
+	ret = ov5647_write(sd, OV5647_REG_GAIN_HI, (val >> 8) & 3);
+	if (ret)
+		return ret;
+
+	return ov5647_write(sd, OV5647_REG_GAIN_LO, val & 0xff);
+}
+
+static int ov5647_s_exposure(struct v4l2_subdev *sd, u32 val)
+{
+	int ret;
+
+	/*
+	 * Sensor has 20 bits, but the bottom 4 bits are fractions of a line
+	 * which we leave as zero (and don't receive in "val").
+	 */
+	ret = ov5647_write(sd, OV5647_REG_EXP_HI, (val >> 12) & 0xf);
+	if (ret)
+		return ret;
+
+	ret = ov5647_write(sd, OV5647_REG_EXP_MID, (val >> 4) & 0xff);
+	if (ret)
+		return ret;
+
+	return ov5647_write(sd, OV5647_REG_EXP_LO, (val & 0xf) << 4);
+}
+
+static int ov5647_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct ov5647 *sensor = container_of(ctrl->handler,
+					    struct ov5647, ctrls);
+	struct v4l2_subdev *sd = &sensor->sd;
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	/* v4l2_ctrl_lock() locks our own mutex */
+
+	/*
+	 * If the device is not powered up by the host driver do
+	 * not apply any controls to H/W at this time. Instead
+	 * the controls will be restored at s_stream(1) time.
+	 */
+	if (!sensor->power_count)
+		return 0;
+
+	switch (ctrl->id) {
+	case V4L2_CID_AUTO_WHITE_BALANCE:
+		return ov5647_s_auto_white_balance(sd, ctrl->val);
+	case V4L2_CID_AUTOGAIN:
+		return ov5647_s_autogain(sd, ctrl->val);
+	case V4L2_CID_EXPOSURE_AUTO:
+		return ov5647_s_exposure_auto(sd, ctrl->val);
+	case V4L2_CID_ANALOGUE_GAIN:
+		return  ov5647_s_analogue_gain(sd, ctrl->val);
+	case V4L2_CID_EXPOSURE:
+		return ov5647_s_exposure(sd, ctrl->val);
+	default:
+		dev_info(&client->dev,
+			 "Control (id:0x%x, val:0x%x) not supported\n",
+			 ctrl->id, ctrl->val);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct v4l2_ctrl_ops ov5647_ctrl_ops = {
+	.s_ctrl = ov5647_s_ctrl,
+};
+
+static int ov5647_init_controls(struct ov5647 *sensor)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->sd);
+
+	v4l2_ctrl_handler_init(&sensor->ctrls, 5);
+
+	v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,
+			  V4L2_CID_AUTOGAIN, 0, 1, 1, 0);
+
+	v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,
+			  V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 0);
+
+	v4l2_ctrl_new_std_menu(&sensor->ctrls, &ov5647_ctrl_ops,
+			       V4L2_CID_EXPOSURE_AUTO, V4L2_EXPOSURE_MANUAL,
+			       0, V4L2_EXPOSURE_MANUAL);
+
+	/* min: 4 lines; max: 0xffff lines; default: 1000 lines. */
+	v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,
+			  V4L2_CID_EXPOSURE, 4, 65535, 1, 1000);
+
+	/* min: 16 = 1.0x; max (10 bits); default: 32 = 2.0x. */
+	v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,
+			  V4L2_CID_ANALOGUE_GAIN, 16, 1023, 1, 32);
+
+	if (sensor->ctrls.error) {
+		dev_err(&client->dev, "%s Controls initialization failed (%d)\n",
+			__func__, sensor->ctrls.error);
+		v4l2_ctrl_handler_free(&sensor->ctrls);
+
+		return sensor->ctrls.error;
+	}
+
+	sensor->sd.ctrl_handler = &sensor->ctrls;
+
+	return 0;
+}
+
 static int ov5647_parse_dt(struct ov5647 *sensor, struct device_node *np)
 {
 	struct v4l2_fwnode_endpoint bus_cfg = {
@@ -654,6 +813,10 @@ static int ov5647_probe(struct i2c_client *client)
 
 	mutex_init(&sensor->lock);
 
+	ret = ov5647_init_controls(sensor);
+	if (ret)
+		goto mutex_destroy;
+
 	sd = &sensor->sd;
 	v4l2_i2c_subdev_init(sd, client, &ov5647_subdev_ops);
 	sd->internal_ops = &ov5647_subdev_internal_ops;
@@ -663,7 +826,7 @@ static int ov5647_probe(struct i2c_client *client)
 	sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
 	ret = media_entity_pads_init(&sd->entity, 1, &sensor->pad);
 	if (ret < 0)
-		goto mutex_destroy;
+		goto ctrl_handler_free;
 
 	if (sensor->pwdn) {
 		gpiod_set_value_cansleep(sensor->pwdn, 0);
@@ -685,6 +848,8 @@ static int ov5647_probe(struct i2c_client *client)
 
 entity_cleanup:
 	media_entity_cleanup(&sd->entity);
+ctrl_handler_free:
+	v4l2_ctrl_handler_free(&sensor->ctrls);
 mutex_destroy:
 	mutex_destroy(&sensor->lock);
 
@@ -698,6 +863,7 @@ static int ov5647_remove(struct i2c_client *client)
 
 	v4l2_async_unregister_subdev(&ov5647->sd);
 	media_entity_cleanup(&ov5647->sd.entity);
+	v4l2_ctrl_handler_free(&ov5647->ctrls);
 	v4l2_device_unregister_subdev(sd);
 	mutex_destroy(&ov5647->lock);
 
-- 
2.27.0


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

* [PATCH 14/25] media: ov5647: Rationalize driver structure name
  2020-06-23 10:07 [PATCH 00/25] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
                   ` (12 preceding siblings ...)
  2020-06-23 16:42 ` [PATCH 13/25] media: ov5647: Support gain, exposure and AWB controls Jacopo Mondi
@ 2020-06-23 16:42 ` Jacopo Mondi
  2020-06-23 16:42 ` [PATCH 15/25] media: ov5647: Break out format handling Jacopo Mondi
                   ` (12 subsequent siblings)
  26 siblings, 0 replies; 56+ messages in thread
From: Jacopo Mondi @ 2020-06-23 16:42 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dave.stevenson, naush
  Cc: mrodin, hugues.fruchet, mripard, aford173, sudipi,
	andrew_gabbasov, erosca, linux-media, libcamera-devel,
	Jacopo Mondi

The driver structure name is referred to with different names ('ov5647',
'state', 'sensor') in different functions in the driver.

Polish this up by using 'struct ov5647 *sensor' everywhere.

Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
---
 drivers/media/i2c/ov5647.c | 44 +++++++++++++++++++-------------------
 1 file changed, 22 insertions(+), 22 deletions(-)

diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
index 8cfe315cfd00b..03f4f1a257ecd 100644
--- a/drivers/media/i2c/ov5647.c
+++ b/drivers/media/i2c/ov5647.c
@@ -98,7 +98,7 @@ struct ov5647 {
 	struct v4l2_ctrl_handler	ctrls;
 };
 
-static inline struct ov5647 *to_state(struct v4l2_subdev *sd)
+static inline struct ov5647 *to_sensor(struct v4l2_subdev *sd)
 {
 	return container_of(sd, struct ov5647, sd);
 }
@@ -310,7 +310,7 @@ static int ov5647_set_mode(struct v4l2_subdev *sd)
 static int ov5647_stream_on(struct v4l2_subdev *sd)
 {
 	struct i2c_client *client = v4l2_get_subdevdata(sd);
-	struct ov5647 *ov5647 = to_state(sd);
+	struct ov5647 *sensor = to_sensor(sd);
 	u8 val = MIPI_CTRL00_BUS_IDLE;
 	int ret;
 
@@ -325,7 +325,7 @@ static int ov5647_stream_on(struct v4l2_subdev *sd)
 	if (ret)
 		return ret;
 
-	if (ov5647->clock_ncont)
+	if (sensor->clock_ncont)
 		val |= MIPI_CTRL00_CLOCK_LANE_GATE |
 		       MIPI_CTRL00_LINE_SYNC_ENABLE;
 
@@ -379,17 +379,17 @@ static int ov5647_sensor_power(struct v4l2_subdev *sd, int on)
 	struct ov5647 *ov5647 = to_state(sd);
 	int ret = 0;
 
-	mutex_lock(&ov5647->lock);
+	mutex_lock(&sensor->lock);
 
-	if (on && !ov5647->power_count)	{
+	if (on && !sensor->power_count)	{
 		dev_dbg(&client->dev, "OV5647 power on\n");
 
-		if (ov5647->pwdn) {
-			gpiod_set_value_cansleep(ov5647->pwdn, 0);
+		if (sensor->pwdn) {
+			gpiod_set_value_cansleep(sensor->pwdn, 0);
 			msleep(PWDN_ACTIVE_DELAY_MS);
 		}
 
-		ret = clk_prepare_enable(ov5647->xclk);
+		ret = clk_prepare_enable(sensor->xclk);
 		if (ret < 0) {
 			dev_err(&client->dev, "clk prepare enable failed\n");
 			goto out;
@@ -398,7 +398,7 @@ static int ov5647_sensor_power(struct v4l2_subdev *sd, int on)
 		ret = ov5647_write_array(sd, sensor_oe_enable_regs,
 					 ARRAY_SIZE(sensor_oe_enable_regs));
 		if (ret < 0) {
-			clk_disable_unprepare(ov5647->xclk);
+			clk_disable_unprepare(sensor->xclk);
 			dev_err(&client->dev,
 				"write sensor_oe_enable_regs error\n");
 			goto out;
@@ -407,12 +407,12 @@ static int ov5647_sensor_power(struct v4l2_subdev *sd, int on)
 		/* Stream off to coax lanes into LP-11 state. */
 		ret = ov5647_stream_off(sd);
 		if (ret < 0) {
-			clk_disable_unprepare(ov5647->xclk);
+			clk_disable_unprepare(sensor->xclk);
 			dev_err(&client->dev,
 				"Camera not available, check Power\n");
 			goto out;
 		}
-	} else if (!on && ov5647->power_count == 1) {
+	} else if (!on && sensor->power_count == 1) {
 		dev_dbg(&client->dev, "OV5647 power off\n");
 
 		ret = ov5647_write_array(sd, sensor_oe_disable_regs,
@@ -424,16 +424,16 @@ static int ov5647_sensor_power(struct v4l2_subdev *sd, int on)
 		if (ret < 0)
 			dev_dbg(&client->dev, "soft stby failed\n");
 
-		clk_disable_unprepare(ov5647->xclk);
-		gpiod_set_value_cansleep(ov5647->pwdn, 1);
+		clk_disable_unprepare(sensor->xclk);
+		gpiod_set_value_cansleep(sensor->pwdn, 1);
 	}
 
 	/* Update the power count. */
-	ov5647->power_count += on ? 1 : -1;
-	WARN_ON(ov5647->power_count < 0);
+	sensor->power_count += on ? 1 : -1;
+	WARN_ON(sensor->power_count < 0);
 
 out:
-	mutex_unlock(&ov5647->lock);
+	mutex_unlock(&sensor->lock);
 
 	return ret;
 }
@@ -473,7 +473,7 @@ static const struct v4l2_subdev_core_ops ov5647_subdev_core_ops = {
 
 static int ov5647_s_stream(struct v4l2_subdev *sd, int enable)
 {
-	struct ov5647 *sensor = to_state(sd);
+	struct ov5647 *sensor = to_sensor(sd);
 	int ret;
 
 	mutex_lock(&sensor->lock);
@@ -859,13 +859,13 @@ static int ov5647_probe(struct i2c_client *client)
 static int ov5647_remove(struct i2c_client *client)
 {
 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
-	struct ov5647 *ov5647 = to_state(sd);
+	struct ov5647 *sensor = to_sensor(sd);
 
-	v4l2_async_unregister_subdev(&ov5647->sd);
-	media_entity_cleanup(&ov5647->sd.entity);
-	v4l2_ctrl_handler_free(&ov5647->ctrls);
+	v4l2_async_unregister_subdev(&sensor->sd);
+	media_entity_cleanup(&sensor->sd.entity);
+	v4l2_ctrl_handler_free(&sensor->ctrls);
 	v4l2_device_unregister_subdev(sd);
-	mutex_destroy(&ov5647->lock);
+	mutex_destroy(&sensor->lock);
 
 	return 0;
 }
-- 
2.27.0


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

* [PATCH 15/25] media: ov5647: Break out format handling
  2020-06-23 10:07 [PATCH 00/25] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
                   ` (13 preceding siblings ...)
  2020-06-23 16:42 ` [PATCH 14/25] media: ov5647: Rationalize driver structure name Jacopo Mondi
@ 2020-06-23 16:42 ` Jacopo Mondi
  2020-07-31 11:44   ` Sakari Ailus
  2020-06-23 16:49 ` [PATCH 16/25] media: ov5647: Add support for get_selection() Jacopo Mondi
                   ` (11 subsequent siblings)
  26 siblings, 1 reply; 56+ messages in thread
From: Jacopo Mondi @ 2020-06-23 16:42 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dave.stevenson, naush
  Cc: mrodin, hugues.fruchet, mripard, aford173, sudipi,
	andrew_gabbasov, erosca, linux-media, libcamera-devel,
	Jacopo Mondi

Break format handling out from the main driver structure.

This commit prepares for the introduction of more sensor formats and
resolutions by instrumenting the existing operation to work on multiple
modes instead of assuming a single one supported.

Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
---
 drivers/media/i2c/ov5647.c | 84 +++++++++++++++++++++++++++-----------
 1 file changed, 61 insertions(+), 23 deletions(-)

diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
index 03f4f1a257ecd..a801ed0249aad 100644
--- a/drivers/media/i2c/ov5647.c
+++ b/drivers/media/i2c/ov5647.c
@@ -84,18 +84,28 @@ struct regval_list {
 	u8 data;
 };
 
+struct ov5647_mode {
+	struct v4l2_mbus_framefmt	format;
+	struct regval_list		*reg_list;
+	unsigned int			num_regs;
+};
+
+struct ov5647_format_list {
+	unsigned int			mbus_code;
+	struct ov5647_mode		*modes;
+	unsigned int			num_modes;
+};
+
 struct ov5647 {
 	struct v4l2_subdev		sd;
 	struct media_pad		pad;
 	struct mutex			lock;
-	struct v4l2_mbus_framefmt	format;
-	unsigned int			width;
-	unsigned int			height;
 	int				power_count;
 	struct clk			*xclk;
 	struct gpio_desc		*pwdn;
 	bool				clock_ncont;
 	struct v4l2_ctrl_handler	ctrls;
+	struct ov5647_mode		*mode;
 };
 
 static inline struct ov5647 *to_sensor(struct v4l2_subdev *sd)
@@ -205,6 +215,33 @@ static struct regval_list ov5647_640x480[] = {
 	{0x0100, 0x01},
 };
 
+static struct ov5647_mode ov5647_8bit_modes[] = {
+	{
+		.format	= {
+			.code		= MEDIA_BUS_FMT_SBGGR8_1X8,
+			.colorspace	= V4L2_COLORSPACE_SRGB,
+			.field		= V4L2_FIELD_NONE,
+			.width		= 640,
+			.height		= 480
+		},
+		.reg_list	= ov5647_640x480,
+		.num_regs	= ARRAY_SIZE(ov5647_640x480)
+	},
+};
+
+static const struct ov5647_format_list ov5647_formats[] = {
+	{
+		.mbus_code	= MEDIA_BUS_FMT_SBGGR8_1X8,
+		.modes		= ov5647_8bit_modes,
+		.num_modes	= ARRAY_SIZE(ov5647_8bit_modes),
+	},
+};
+
+#define OV5647_NUM_FORMATS	(ARRAY_SIZE(ov5647_formats))
+
+#define OV5647_DEFAULT_MODE	(&ov5647_formats[0].modes[0])
+#define OV5647_DEFAULT_FORMAT	(ov5647_formats[0].modes[0].format)
+
 static int ov5647_write(struct v4l2_subdev *sd, u16 reg, u8 val)
 {
 	unsigned char data[3] = { reg >> 8, reg & 0xff, val};
@@ -282,8 +319,7 @@ static int ov5647_set_mode(struct v4l2_subdev *sd)
 	if (ret < 0)
 		return ret;
 
-	ret = ov5647_write_array(sd, ov5647_640x480,
-				 ARRAY_SIZE(ov5647_640x480));
+	ret = ov5647_write_array(sd, sensor->mode->reg_list, sensor->mode->num_regs);
 	if (ret < 0) {
 		dev_err(&client->dev, "write sensor default regs error\n");
 		return ret;
@@ -494,10 +530,10 @@ static int ov5647_enum_mbus_code(struct v4l2_subdev *sd,
 				 struct v4l2_subdev_pad_config *cfg,
 				 struct v4l2_subdev_mbus_code_enum *code)
 {
-	if (code->index > 0)
+	if (code->index >= OV5647_NUM_FORMATS)
 		return -EINVAL;
 
-	code->code = MEDIA_BUS_FMT_SBGGR8_1X8;
+	code->code = ov5647_formats[code->index].mbus_code;
 
 	return 0;
 }
@@ -506,16 +542,24 @@ static int ov5647_enum_frame_size(struct v4l2_subdev *sd,
 				  struct v4l2_subdev_pad_config *cfg,
 				  struct v4l2_subdev_frame_size_enum *fse)
 {
-	if (fse->index)
+	const struct v4l2_mbus_framefmt *fmt;
+	unsigned int i = 0;
+
+	for (; i < OV5647_NUM_FORMATS; ++i) {
+		if (ov5647_formats[i].mbus_code == fse->code)
+			break;
+	}
+	if (i == OV5647_NUM_FORMATS)
 		return -EINVAL;
 
-	if (fse->code != MEDIA_BUS_FMT_SBGGR8_1X8)
+	if (fse->index >= ov5647_formats[i].num_modes)
 		return -EINVAL;
 
-	fse->min_width = 640;
-	fse->max_width = 640;
-	fse->min_height = 480;
-	fse->max_height = 480;
+	fmt = &ov5647_formats[i].modes[fse->index].format;
+	fse->min_width = fmt->width;
+	fse->max_width = fmt->width;
+	fse->min_height = fmt->height;
+	fse->max_height = fmt->height;
 
 	return 0;
 }
@@ -528,11 +572,7 @@ static int ov5647_set_get_fmt(struct v4l2_subdev *sd,
 
 	/* Only one format is supported, so return that. */
 	memset(fmt, 0, sizeof(*fmt));
-	fmt->code = MEDIA_BUS_FMT_SBGGR8_1X8;
-	fmt->colorspace = V4L2_COLORSPACE_SRGB;
-	fmt->field = V4L2_FIELD_NONE;
-	fmt->width = 640;
-	fmt->height = 480;
+	*fmt = OV5647_DEFAULT_FORMAT;
 
 	return 0;
 }
@@ -591,11 +631,7 @@ static int ov5647_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 	crop->width = OV5647_WINDOW_WIDTH_DEF;
 	crop->height = OV5647_WINDOW_HEIGHT_DEF;
 
-	format->code = MEDIA_BUS_FMT_SBGGR8_1X8;
-	format->width = 640;
-	format->height = 480;
-	format->field = V4L2_FIELD_NONE;
-	format->colorspace = V4L2_COLORSPACE_SRGB;
+	*format = OV5647_DEFAULT_FORMAT;
 
 	return 0;
 }
@@ -813,6 +849,8 @@ static int ov5647_probe(struct i2c_client *client)
 
 	mutex_init(&sensor->lock);
 
+	sensor->mode = OV5647_DEFAULT_MODE;
+
 	ret = ov5647_init_controls(sensor);
 	if (ret)
 		goto mutex_destroy;
-- 
2.27.0


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

* [PATCH 16/25] media: ov5647: Add support for get_selection()
  2020-06-23 10:07 [PATCH 00/25] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
                   ` (14 preceding siblings ...)
  2020-06-23 16:42 ` [PATCH 15/25] media: ov5647: Break out format handling Jacopo Mondi
@ 2020-06-23 16:49 ` Jacopo Mondi
  2020-07-09 19:56   ` [libcamera-devel] " Dafna Hirschfeld
  2020-06-23 16:49 ` [PATCH 17/25] media: ov5647: Rename SBGGR8 VGA mode Jacopo Mondi
                   ` (10 subsequent siblings)
  26 siblings, 1 reply; 56+ messages in thread
From: Jacopo Mondi @ 2020-06-23 16:49 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dave.stevenson, naush
  Cc: mrodin, hugues.fruchet, mripard, aford173, sudipi,
	andrew_gabbasov, erosca, linux-media, libcamera-devel,
	Dave Stevenson, Jacopo Mondi

From: Dave Stevenson <dave.stevenson@raspberrypi.com>

Support the get_selection() pad operation to report the device
full pixel array size, the currently applied analogue crop rectangle and
the active pixel array dimensions.

Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
---
 drivers/media/i2c/ov5647.c | 95 ++++++++++++++++++++++++++++----------
 1 file changed, 71 insertions(+), 24 deletions(-)

diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
index a801ed0249aad..3757f0b10fe93 100644
--- a/drivers/media/i2c/ov5647.c
+++ b/drivers/media/i2c/ov5647.c
@@ -59,25 +59,14 @@
 #define VAL_TERM 0xfe
 #define REG_DLY  0xffff
 
-#define OV5647_ROW_START		0x01
-#define OV5647_ROW_START_MIN		0
-#define OV5647_ROW_START_MAX		2004
-#define OV5647_ROW_START_DEF		54
-
-#define OV5647_COLUMN_START		0x02
-#define OV5647_COLUMN_START_MIN		0
-#define OV5647_COLUMN_START_MAX		2750
-#define OV5647_COLUMN_START_DEF		16
-
-#define OV5647_WINDOW_HEIGHT		0x03
-#define OV5647_WINDOW_HEIGHT_MIN	2
-#define OV5647_WINDOW_HEIGHT_MAX	2006
-#define OV5647_WINDOW_HEIGHT_DEF	1944
-
-#define OV5647_WINDOW_WIDTH		0x04
-#define OV5647_WINDOW_WIDTH_MIN		2
-#define OV5647_WINDOW_WIDTH_MAX		2752
-#define OV5647_WINDOW_WIDTH_DEF		2592
+/* OV5647 native and active pixel array size */
+#define OV5647_NATIVE_WIDTH		2624U
+#define OV5647_NATIVE_HEIGHT		1956U
+
+#define OV5647_PIXEL_ARRAY_LEFT		16U
+#define OV5647_PIXEL_ARRAY_TOP		16U
+#define OV5647_PIXEL_ARRAY_WIDTH	2592U
+#define OV5647_PIXEL_ARRAY_HEIGHT	1944U
 
 struct regval_list {
 	u16 addr;
@@ -86,6 +75,7 @@ struct regval_list {
 
 struct ov5647_mode {
 	struct v4l2_mbus_framefmt	format;
+	struct v4l2_rect		crop;
 	struct regval_list		*reg_list;
 	unsigned int			num_regs;
 };
@@ -224,6 +214,12 @@ static struct ov5647_mode ov5647_8bit_modes[] = {
 			.width		= 640,
 			.height		= 480
 		},
+		.crop = {
+			.left		= 0,
+			.top		= 0,
+			.width		= 1280,
+			.height		= 960,
+		},
 		.reg_list	= ov5647_640x480,
 		.num_regs	= ARRAY_SIZE(ov5647_640x480)
 	},
@@ -412,7 +408,7 @@ static int set_sw_standby(struct v4l2_subdev *sd, bool standby)
 static int ov5647_sensor_power(struct v4l2_subdev *sd, int on)
 {
 	struct i2c_client *client = v4l2_get_subdevdata(sd);
-	struct ov5647 *ov5647 = to_state(sd);
+	struct ov5647 *sensor = to_sensor(sd);
 	int ret = 0;
 
 	mutex_lock(&sensor->lock);
@@ -507,6 +503,20 @@ static const struct v4l2_subdev_core_ops ov5647_subdev_core_ops = {
 #endif
 };
 
+static const struct v4l2_rect *
+__ov5647_get_pad_crop(struct ov5647 *ov5647, struct v4l2_subdev_pad_config *cfg,
+		      unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+	switch (which) {
+	case V4L2_SUBDEV_FORMAT_TRY:
+		return v4l2_subdev_get_try_crop(&ov5647->sd, cfg, pad);
+	case V4L2_SUBDEV_FORMAT_ACTIVE:
+		return &ov5647->mode->crop;
+	}
+
+	return NULL;
+}
+
 static int ov5647_s_stream(struct v4l2_subdev *sd, int enable)
 {
 	struct ov5647 *sensor = to_sensor(sd);
@@ -577,11 +587,48 @@ static int ov5647_set_get_fmt(struct v4l2_subdev *sd,
 	return 0;
 }
 
+static int ov5647_get_selection(struct v4l2_subdev *sd,
+				struct v4l2_subdev_pad_config *cfg,
+				struct v4l2_subdev_selection *sel)
+{
+	switch (sel->target) {
+	case V4L2_SEL_TGT_CROP: {
+		struct ov5647 *sensor = to_sensor(sd);
+
+		mutex_lock(&sensor->lock);
+		sel->r = *__ov5647_get_pad_crop(sensor, cfg, sel->pad,
+						sel->which);
+		mutex_unlock(&sensor->lock);
+
+		return 0;
+	}
+
+	case V4L2_SEL_TGT_NATIVE_SIZE:
+		sel->r.top = 0;
+		sel->r.left = 0;
+		sel->r.width = OV5647_NATIVE_WIDTH;
+		sel->r.height = OV5647_NATIVE_HEIGHT;
+
+		return 0;
+
+	case V4L2_SEL_TGT_CROP_DEFAULT:
+		sel->r.top = OV5647_PIXEL_ARRAY_TOP;
+		sel->r.left = OV5647_PIXEL_ARRAY_LEFT;
+		sel->r.width = OV5647_PIXEL_ARRAY_WIDTH;
+		sel->r.height = OV5647_PIXEL_ARRAY_HEIGHT;
+
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
 static const struct v4l2_subdev_pad_ops ov5647_subdev_pad_ops = {
 	.enum_mbus_code		= ov5647_enum_mbus_code,
 	.enum_frame_size	= ov5647_enum_frame_size,
 	.set_fmt		= ov5647_set_get_fmt,
 	.get_fmt		= ov5647_set_get_fmt,
+	.get_selection		= ov5647_get_selection,
 };
 
 static const struct v4l2_subdev_ops ov5647_subdev_ops = {
@@ -626,10 +673,10 @@ static int ov5647_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 	struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(sd, fh->pad, 0);
 	struct v4l2_rect *crop = v4l2_subdev_get_try_crop(sd, fh->pad, 0);
 
-	crop->left = OV5647_COLUMN_START_DEF;
-	crop->top = OV5647_ROW_START_DEF;
-	crop->width = OV5647_WINDOW_WIDTH_DEF;
-	crop->height = OV5647_WINDOW_HEIGHT_DEF;
+	crop->left = OV5647_PIXEL_ARRAY_LEFT;
+	crop->top = OV5647_PIXEL_ARRAY_TOP;
+	crop->width = OV5647_PIXEL_ARRAY_WIDTH;
+	crop->height = OV5647_PIXEL_ARRAY_HEIGHT;
 
 	*format = OV5647_DEFAULT_FORMAT;
 
-- 
2.27.0


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

* [PATCH 17/25] media: ov5647: Rename SBGGR8 VGA mode
  2020-06-23 10:07 [PATCH 00/25] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
                   ` (15 preceding siblings ...)
  2020-06-23 16:49 ` [PATCH 16/25] media: ov5647: Add support for get_selection() Jacopo Mondi
@ 2020-06-23 16:49 ` Jacopo Mondi
  2020-06-23 16:49 ` [PATCH 18/25] media: ov5647: Add SGGBR10_1X10 modes Jacopo Mondi
                   ` (9 subsequent siblings)
  26 siblings, 0 replies; 56+ messages in thread
From: Jacopo Mondi @ 2020-06-23 16:49 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dave.stevenson, naush
  Cc: mrodin, hugues.fruchet, mripard, aford173, sudipi,
	andrew_gabbasov, erosca, linux-media, libcamera-devel,
	Jacopo Mondi

Before adding new modes, rename the only existing one to report
the media bus format in the name to distinguish it from future
additions.

While at it, briefly describe the mode.

Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
---
 drivers/media/i2c/ov5647.c | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
index 3757f0b10fe93..c36d6b92b97a0 100644
--- a/drivers/media/i2c/ov5647.c
+++ b/drivers/media/i2c/ov5647.c
@@ -115,7 +115,7 @@ static struct regval_list sensor_oe_enable_regs[] = {
 	{0x3002, 0xe4},
 };
 
-static struct regval_list ov5647_640x480[] = {
+static struct regval_list ov5647_640x480_sbggr8[] = {
 	{0x0100, 0x00},
 	{0x0103, 0x01},
 	{0x3034, 0x08},
@@ -205,7 +205,8 @@ static struct regval_list ov5647_640x480[] = {
 	{0x0100, 0x01},
 };
 
-static struct ov5647_mode ov5647_8bit_modes[] = {
+static struct ov5647_mode ov5647_sbggr8_modes[] = {
+	/* 8-bit VGA mode: Uncentred crop 2x2 binned 1296x972 image. */
 	{
 		.format	= {
 			.code		= MEDIA_BUS_FMT_SBGGR8_1X8,
@@ -220,16 +221,16 @@ static struct ov5647_mode ov5647_8bit_modes[] = {
 			.width		= 1280,
 			.height		= 960,
 		},
-		.reg_list	= ov5647_640x480,
-		.num_regs	= ARRAY_SIZE(ov5647_640x480)
+		.reg_list	= ov5647_640x480_sbggr8,
+		.num_regs	= ARRAY_SIZE(ov5647_640x480_sbggr8)
 	},
 };
 
 static const struct ov5647_format_list ov5647_formats[] = {
 	{
 		.mbus_code	= MEDIA_BUS_FMT_SBGGR8_1X8,
-		.modes		= ov5647_8bit_modes,
-		.num_modes	= ARRAY_SIZE(ov5647_8bit_modes),
+		.modes		= ov5647_sbggr8_modes,
+		.num_modes	= ARRAY_SIZE(ov5647_sbggr8_modes),
 	},
 };
 
-- 
2.27.0


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

* [PATCH 18/25] media: ov5647: Add SGGBR10_1X10 modes
  2020-06-23 10:07 [PATCH 00/25] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
                   ` (16 preceding siblings ...)
  2020-06-23 16:49 ` [PATCH 17/25] media: ov5647: Rename SBGGR8 VGA mode Jacopo Mondi
@ 2020-06-23 16:49 ` Jacopo Mondi
  2020-06-23 16:49 ` [PATCH 19/25] media: ov5647: Implement set_fmt pad operation Jacopo Mondi
                   ` (8 subsequent siblings)
  26 siblings, 0 replies; 56+ messages in thread
From: Jacopo Mondi @ 2020-06-23 16:49 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dave.stevenson, naush
  Cc: mrodin, hugues.fruchet, mripard, aford173, sudipi,
	andrew_gabbasov, erosca, linux-media, libcamera-devel,
	Jacopo Mondi

Add 4 additional sensor modes in SBGGR10_1X10 format.

Add the following resolutions in SBGGR10_1X10 format:
- 2592x1944 full resolution
- 1920x1080 1080p cropped
- 1296x972 2x2 binned
- 640x480 2x2 binned, 2x2 subsampled

The register lists and modes definition have been upported from the
RaspberryPi BSP at revision:
commit 581dfda6d0a62 ("media: i2c: ov5647: Advertise the correct exposure range")

Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
---
 drivers/media/i2c/ov5647.c | 441 +++++++++++++++++++++++++++++++++++++
 1 file changed, 441 insertions(+)

diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
index c36d6b92b97a0..af9e6d43967d8 100644
--- a/drivers/media/i2c/ov5647.c
+++ b/drivers/media/i2c/ov5647.c
@@ -205,6 +205,367 @@ static struct regval_list ov5647_640x480_sbggr8[] = {
 	{0x0100, 0x01},
 };
 
+static struct regval_list ov5647_2592x1944_sbggr10[] = {
+	{0x0100, 0x00},
+	{0x0103, 0x01},
+	{0x3034, 0x1a},
+	{0x3035, 0x21},
+	{0x3036, 0x69},
+	{0x303c, 0x11},
+	{0x3106, 0xf5},
+	{0x3821, 0x06},
+	{0x3820, 0x00},
+	{0x3827, 0xec},
+	{0x370c, 0x03},
+	{0x3612, 0x5b},
+	{0x3618, 0x04},
+	{0x5000, 0x06},
+	{0x5002, 0x41},
+	{0x5003, 0x08},
+	{0x5a00, 0x08},
+	{0x3000, 0x00},
+	{0x3001, 0x00},
+	{0x3002, 0x00},
+	{0x3016, 0x08},
+	{0x3017, 0xe0},
+	{0x3018, 0x44},
+	{0x301c, 0xf8},
+	{0x301d, 0xf0},
+	{0x3a18, 0x00},
+	{0x3a19, 0xf8},
+	{0x3c01, 0x80},
+	{0x3b07, 0x0c},
+	{0x380c, 0x0b},
+	{0x380d, 0x1c},
+	{0x3814, 0x11},
+	{0x3815, 0x11},
+	{0x3708, 0x64},
+	{0x3709, 0x12},
+	{0x3808, 0x0a},
+	{0x3809, 0x20},
+	{0x380a, 0x07},
+	{0x380b, 0x98},
+	{0x3800, 0x00},
+	{0x3801, 0x00},
+	{0x3802, 0x00},
+	{0x3803, 0x00},
+	{0x3804, 0x0a},
+	{0x3805, 0x3f},
+	{0x3806, 0x07},
+	{0x3807, 0xa3},
+	{0x3811, 0x10},
+	{0x3813, 0x06},
+	{0x3630, 0x2e},
+	{0x3632, 0xe2},
+	{0x3633, 0x23},
+	{0x3634, 0x44},
+	{0x3636, 0x06},
+	{0x3620, 0x64},
+	{0x3621, 0xe0},
+	{0x3600, 0x37},
+	{0x3704, 0xa0},
+	{0x3703, 0x5a},
+	{0x3715, 0x78},
+	{0x3717, 0x01},
+	{0x3731, 0x02},
+	{0x370b, 0x60},
+	{0x3705, 0x1a},
+	{0x3f05, 0x02},
+	{0x3f06, 0x10},
+	{0x3f01, 0x0a},
+	{0x3a08, 0x01},
+	{0x3a09, 0x28},
+	{0x3a0a, 0x00},
+	{0x3a0b, 0xf6},
+	{0x3a0d, 0x08},
+	{0x3a0e, 0x06},
+	{0x3a0f, 0x58},
+	{0x3a10, 0x50},
+	{0x3a1b, 0x58},
+	{0x3a1e, 0x50},
+	{0x3a11, 0x60},
+	{0x3a1f, 0x28},
+	{0x4001, 0x02},
+	{0x4004, 0x04},
+	{0x4000, 0x09},
+	{0x4837, 0x19},
+	{0x4800, 0x24},
+	{0x3503, 0x03},
+	{0x0100, 0x01},
+};
+
+static struct regval_list ov5647_1080p30_sbggr10[] = {
+	{0x0100, 0x00},
+	{0x0103, 0x01},
+	{0x3034, 0x1a},
+	{0x3035, 0x21},
+	{0x3036, 0x62},
+	{0x303c, 0x11},
+	{0x3106, 0xf5},
+	{0x3821, 0x06},
+	{0x3820, 0x00},
+	{0x3827, 0xec},
+	{0x370c, 0x03},
+	{0x3612, 0x5b},
+	{0x3618, 0x04},
+	{0x5000, 0x06},
+	{0x5002, 0x41},
+	{0x5003, 0x08},
+	{0x5a00, 0x08},
+	{0x3000, 0x00},
+	{0x3001, 0x00},
+	{0x3002, 0x00},
+	{0x3016, 0x08},
+	{0x3017, 0xe0},
+	{0x3018, 0x44},
+	{0x301c, 0xf8},
+	{0x301d, 0xf0},
+	{0x3a18, 0x00},
+	{0x3a19, 0xf8},
+	{0x3c01, 0x80},
+	{0x3b07, 0x0c},
+	{0x380c, 0x09},
+	{0x380d, 0x70},
+	{0x3814, 0x11},
+	{0x3815, 0x11},
+	{0x3708, 0x64},
+	{0x3709, 0x12},
+	{0x3808, 0x07},
+	{0x3809, 0x80},
+	{0x380a, 0x04},
+	{0x380b, 0x38},
+	{0x3800, 0x01},
+	{0x3801, 0x5c},
+	{0x3802, 0x01},
+	{0x3803, 0xb2},
+	{0x3804, 0x08},
+	{0x3805, 0xe3},
+	{0x3806, 0x05},
+	{0x3807, 0xf1},
+	{0x3811, 0x04},
+	{0x3813, 0x02},
+	{0x3630, 0x2e},
+	{0x3632, 0xe2},
+	{0x3633, 0x23},
+	{0x3634, 0x44},
+	{0x3636, 0x06},
+	{0x3620, 0x64},
+	{0x3621, 0xe0},
+	{0x3600, 0x37},
+	{0x3704, 0xa0},
+	{0x3703, 0x5a},
+	{0x3715, 0x78},
+	{0x3717, 0x01},
+	{0x3731, 0x02},
+	{0x370b, 0x60},
+	{0x3705, 0x1a},
+	{0x3f05, 0x02},
+	{0x3f06, 0x10},
+	{0x3f01, 0x0a},
+	{0x3a08, 0x01},
+	{0x3a09, 0x4b},
+	{0x3a0a, 0x01},
+	{0x3a0b, 0x13},
+	{0x3a0d, 0x04},
+	{0x3a0e, 0x03},
+	{0x3a0f, 0x58},
+	{0x3a10, 0x50},
+	{0x3a1b, 0x58},
+	{0x3a1e, 0x50},
+	{0x3a11, 0x60},
+	{0x3a1f, 0x28},
+	{0x4001, 0x02},
+	{0x4004, 0x04},
+	{0x4000, 0x09},
+	{0x4837, 0x19},
+	{0x4800, 0x34},
+	{0x3503, 0x03},
+	{0x0100, 0x01},
+};
+
+static struct regval_list ov5647_2x2binned_sbggr10[] = {
+	{0x0100, 0x00},
+	{0x0103, 0x01},
+	{0x3034, 0x1a},
+	{0x3035, 0x21},
+	{0x3036, 0x62},
+	{0x303c, 0x11},
+	{0x3106, 0xf5},
+	{0x3827, 0xec},
+	{0x370c, 0x03},
+	{0x3612, 0x59},
+	{0x3618, 0x00},
+	{0x5000, 0x06},
+	{0x5002, 0x41},
+	{0x5003, 0x08},
+	{0x5a00, 0x08},
+	{0x3000, 0x00},
+	{0x3001, 0x00},
+	{0x3002, 0x00},
+	{0x3016, 0x08},
+	{0x3017, 0xe0},
+	{0x3018, 0x44},
+	{0x301c, 0xf8},
+	{0x301d, 0xf0},
+	{0x3a18, 0x00},
+	{0x3a19, 0xf8},
+	{0x3c01, 0x80},
+	{0x3b07, 0x0c},
+	{0x3800, 0x00},
+	{0x3801, 0x00},
+	{0x3802, 0x00},
+	{0x3803, 0x00},
+	{0x3804, 0x0a},
+	{0x3805, 0x3f},
+	{0x3806, 0x07},
+	{0x3807, 0xa3},
+	{0x3808, 0x05},
+	{0x3809, 0x10},
+	{0x380a, 0x03},
+	{0x380b, 0xcc},
+	{0x380c, 0x07},
+	{0x380d, 0x68},
+	{0x3811, 0x0c},
+	{0x3813, 0x06},
+	{0x3814, 0x31},
+	{0x3815, 0x31},
+	{0x3630, 0x2e},
+	{0x3632, 0xe2},
+	{0x3633, 0x23},
+	{0x3634, 0x44},
+	{0x3636, 0x06},
+	{0x3620, 0x64},
+	{0x3621, 0xe0},
+	{0x3600, 0x37},
+	{0x3704, 0xa0},
+	{0x3703, 0x5a},
+	{0x3715, 0x78},
+	{0x3717, 0x01},
+	{0x3731, 0x02},
+	{0x370b, 0x60},
+	{0x3705, 0x1a},
+	{0x3f05, 0x02},
+	{0x3f06, 0x10},
+	{0x3f01, 0x0a},
+	{0x3a08, 0x01},
+	{0x3a09, 0x28},
+	{0x3a0a, 0x00},
+	{0x3a0b, 0xf6},
+	{0x3a0d, 0x08},
+	{0x3a0e, 0x06},
+	{0x3a0f, 0x58},
+	{0x3a10, 0x50},
+	{0x3a1b, 0x58},
+	{0x3a1e, 0x50},
+	{0x3a11, 0x60},
+	{0x3a1f, 0x28},
+	{0x4001, 0x02},
+	{0x4004, 0x04},
+	{0x4000, 0x09},
+	{0x4837, 0x16},
+	{0x4800, 0x24},
+	{0x3503, 0x03},
+	{0x3820, 0x41},
+	{0x3821, 0x07},
+	{0x350a, 0x00},
+	{0x350b, 0x10},
+	{0x3500, 0x00},
+	{0x3501, 0x1a},
+	{0x3502, 0xf0},
+	{0x3212, 0xa0},
+	{0x0100, 0x01},
+};
+
+static struct regval_list ov5647_640x480_sbggr10[] = {
+	{0x0100, 0x00},
+	{0x0103, 0x01},
+	{0x3035, 0x11},
+	{0x3036, 0x46},
+	{0x303c, 0x11},
+	{0x3821, 0x07},
+	{0x3820, 0x41},
+	{0x370c, 0x03},
+	{0x3612, 0x59},
+	{0x3618, 0x00},
+	{0x5000, 0x06},
+	{0x5003, 0x08},
+	{0x5a00, 0x08},
+	{0x3000, 0xff},
+	{0x3001, 0xff},
+	{0x3002, 0xff},
+	{0x301d, 0xf0},
+	{0x3a18, 0x00},
+	{0x3a19, 0xf8},
+	{0x3c01, 0x80},
+	{0x3b07, 0x0c},
+	{0x380c, 0x07},
+	{0x380d, 0x3c},
+	{0x3814, 0x35},
+	{0x3815, 0x35},
+	{0x3708, 0x64},
+	{0x3709, 0x52},
+	{0x3808, 0x02},
+	{0x3809, 0x80},
+	{0x380a, 0x01},
+	{0x380b, 0xe0},
+	{0x3800, 0x00},
+	{0x3801, 0x10},
+	{0x3802, 0x00},
+	{0x3803, 0x00},
+	{0x3804, 0x0a},
+	{0x3805, 0x2f},
+	{0x3806, 0x07},
+	{0x3807, 0x9f},
+	{0x3630, 0x2e},
+	{0x3632, 0xe2},
+	{0x3633, 0x23},
+	{0x3634, 0x44},
+	{0x3620, 0x64},
+	{0x3621, 0xe0},
+	{0x3600, 0x37},
+	{0x3704, 0xa0},
+	{0x3703, 0x5a},
+	{0x3715, 0x78},
+	{0x3717, 0x01},
+	{0x3731, 0x02},
+	{0x370b, 0x60},
+	{0x3705, 0x1a},
+	{0x3f05, 0x02},
+	{0x3f06, 0x10},
+	{0x3f01, 0x0a},
+	{0x3a08, 0x01},
+	{0x3a09, 0x2e},
+	{0x3a0a, 0x00},
+	{0x3a0b, 0xfb},
+	{0x3a0d, 0x02},
+	{0x3a0e, 0x01},
+	{0x3a0f, 0x58},
+	{0x3a10, 0x50},
+	{0x3a1b, 0x58},
+	{0x3a1e, 0x50},
+	{0x3a11, 0x60},
+	{0x3a1f, 0x28},
+	{0x4001, 0x02},
+	{0x4004, 0x02},
+	{0x4000, 0x09},
+	{0x3000, 0x00},
+	{0x3001, 0x00},
+	{0x3002, 0x00},
+	{0x3017, 0xe0},
+	{0x301c, 0xfc},
+	{0x3636, 0x06},
+	{0x3016, 0x08},
+	{0x3827, 0xec},
+	{0x3018, 0x44},
+	{0x3035, 0x21},
+	{0x3106, 0xf5},
+	{0x3034, 0x1a},
+	{0x301c, 0xf8},
+	{0x4800, 0x34},
+	{0x3503, 0x03},
+	{0x0100, 0x01},
+};
+
 static struct ov5647_mode ov5647_sbggr8_modes[] = {
 	/* 8-bit VGA mode: Uncentred crop 2x2 binned 1296x972 image. */
 	{
@@ -226,12 +587,92 @@ static struct ov5647_mode ov5647_sbggr8_modes[] = {
 	},
 };
 
+static struct ov5647_mode ov5647_sbggr10_modes[] = {
+	/* 2592x1944 full resolution full FOV 10-bit mode. */
+	{
+		.format = {
+			.code		= MEDIA_BUS_FMT_SBGGR10_1X10,
+			.colorspace	= V4L2_COLORSPACE_SRGB,
+			.field		= V4L2_FIELD_NONE,
+			.width		= 2592,
+			.height		= 1944
+		},
+		.crop = {
+			.left		= 0,
+			.top		= 0,
+			.width		= 2592,
+			.height		= 1944
+		},
+		.reg_list	= ov5647_2592x1944_sbggr10,
+		.num_regs	= ARRAY_SIZE(ov5647_2592x1944_sbggr10)
+	},
+	/* 1080p30 10-bit mode. Full resolution centre-cropped down to 1080p. */
+	{
+		.format = {
+			.code		= MEDIA_BUS_FMT_SBGGR10_1X10,
+			.colorspace	= V4L2_COLORSPACE_SRGB,
+			.field		= V4L2_FIELD_NONE,
+			.width		= 1920,
+			.height		= 1080
+		},
+		.crop = {
+			.left		= 348,
+			.top		= 434,
+			.width		= 1928,
+			.height		= 1080,
+		},
+		.reg_list	= ov5647_1080p30_sbggr10,
+		.num_regs	= ARRAY_SIZE(ov5647_1080p30_sbggr10)
+	},
+	/* 2x2 binned full FOV 10-bit mode. */
+	{
+		.format = {
+			.code		= MEDIA_BUS_FMT_SBGGR10_1X10,
+			.colorspace	= V4L2_COLORSPACE_SRGB,
+			.field		= V4L2_FIELD_NONE,
+			.width		= 1296,
+			.height		= 972
+		},
+		.crop = {
+			.left		= 0,
+			.top		= 0,
+			.width		= 2592,
+			.height		= 1944,
+		},
+		.reg_list	= ov5647_2x2binned_sbggr10,
+		.num_regs	= ARRAY_SIZE(ov5647_2x2binned_sbggr10)
+	},
+	/* 10-bit VGA full FOV 60fps. 2x2 binned and subsampled down to VGA. */
+	{
+		.format = {
+			.code		= MEDIA_BUS_FMT_SBGGR10_1X10,
+			.colorspace	= V4L2_COLORSPACE_SRGB,
+			.field		= V4L2_FIELD_NONE,
+			.width		= 640,
+			.height		= 480
+		},
+		.crop = {
+			.left		= 16,
+			.top		= 0,
+			.width		= 2560,
+			.height		= 1920,
+		},
+		.reg_list	= ov5647_640x480_sbggr10,
+		.num_regs	= ARRAY_SIZE(ov5647_640x480_sbggr10)
+	},
+};
+
 static const struct ov5647_format_list ov5647_formats[] = {
 	{
 		.mbus_code	= MEDIA_BUS_FMT_SBGGR8_1X8,
 		.modes		= ov5647_sbggr8_modes,
 		.num_modes	= ARRAY_SIZE(ov5647_sbggr8_modes),
 	},
+	{
+		.mbus_code	= MEDIA_BUS_FMT_SBGGR10_1X10,
+		.modes		= ov5647_sbggr10_modes,
+		.num_modes	= ARRAY_SIZE(ov5647_sbggr10_modes),
+	},
 };
 
 #define OV5647_NUM_FORMATS	(ARRAY_SIZE(ov5647_formats))
-- 
2.27.0


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

* [PATCH 19/25] media: ov5647: Implement set_fmt pad operation
  2020-06-23 10:07 [PATCH 00/25] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
                   ` (17 preceding siblings ...)
  2020-06-23 16:49 ` [PATCH 18/25] media: ov5647: Add SGGBR10_1X10 modes Jacopo Mondi
@ 2020-06-23 16:49 ` Jacopo Mondi
  2020-06-29 16:54   ` [libcamera-devel] " Dafna Hirschfeld
  2020-06-23 16:55 ` [PATCH 20/25] media: ov5647: Program mode only if it has changed Jacopo Mondi
                   ` (7 subsequent siblings)
  26 siblings, 1 reply; 56+ messages in thread
From: Jacopo Mondi @ 2020-06-23 16:49 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dave.stevenson, naush
  Cc: mrodin, hugues.fruchet, mripard, aford173, sudipi,
	andrew_gabbasov, erosca, linux-media, libcamera-devel,
	Jacopo Mondi

Now that the driver supports more than a single mode, implement the
.set_fmt pad operation and adjust the existing .get_fmt one to report
the currently applied format.

Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
---
 drivers/media/i2c/ov5647.c | 67 +++++++++++++++++++++++++++++++++++---
 1 file changed, 62 insertions(+), 5 deletions(-)

diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
index af9e6d43967d8..39e320f321bd8 100644
--- a/drivers/media/i2c/ov5647.c
+++ b/drivers/media/i2c/ov5647.c
@@ -1016,15 +1016,72 @@ static int ov5647_enum_frame_size(struct v4l2_subdev *sd,
 	return 0;
 }
 
-static int ov5647_set_get_fmt(struct v4l2_subdev *sd,
+static int ov5647_get_pad_fmt(struct v4l2_subdev *sd,
 			      struct v4l2_subdev_pad_config *cfg,
 			      struct v4l2_subdev_format *format)
 {
 	struct v4l2_mbus_framefmt *fmt = &format->format;
+	struct v4l2_mbus_framefmt *sensor_format;
+	struct ov5647 *sensor = to_sensor(sd);
 
-	/* Only one format is supported, so return that. */
+	mutex_lock(&sensor->lock);
 	memset(fmt, 0, sizeof(*fmt));
-	*fmt = OV5647_DEFAULT_FORMAT;
+
+	switch (format->which) {
+	case V4L2_SUBDEV_FORMAT_TRY:
+		sensor_format = v4l2_subdev_get_try_format(sd, cfg, format->pad);
+		break;
+	default:
+		sensor_format = &sensor->mode->format;
+		break;
+	}
+
+	*fmt = *sensor_format;
+	mutex_unlock(&sensor->lock);
+
+	return 0;
+}
+
+static int ov5647_set_pad_fmt(struct v4l2_subdev *sd,
+			      struct v4l2_subdev_pad_config *cfg,
+			      struct v4l2_subdev_format *format)
+{
+	struct v4l2_mbus_framefmt *fmt = &format->format;
+	struct ov5647 *sensor = to_sensor(sd);
+	struct ov5647_mode *ov5647_mode_list;
+	struct ov5647_mode *mode;
+	unsigned int num_modes;
+
+	/*
+	 * Default mbus code MEDIA_BUS_FMT_SBGGR10_1X10 if the requested one
+	 * is not supported.
+	 */
+	if (fmt->code == MEDIA_BUS_FMT_SBGGR8_1X8) {
+		ov5647_mode_list = ov5647_sbggr8_modes;
+		num_modes = ARRAY_SIZE(ov5647_sbggr8_modes);
+	} else {
+		ov5647_mode_list = ov5647_sbggr10_modes;
+		num_modes = ARRAY_SIZE(ov5647_sbggr10_modes);
+	}
+
+	mode = v4l2_find_nearest_size(ov5647_mode_list, num_modes,
+				      format.width, format.height,
+				      fmt->width, fmt->height);
+
+	if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
+		mutex_lock(&sensor->lock);
+		*v4l2_subdev_get_try_format(sd, cfg, format->pad) = mode->format;
+		*fmt = mode->format;
+		mutex_unlock(&sensor->lock);
+
+		return 0;
+	}
+
+	/* Update the sensor mode and apply at it at streamon time. */
+	mutex_lock(&sensor->lock);
+	sensor->mode = mode;
+	*fmt = mode->format;
+	mutex_unlock(&sensor->lock);
 
 	return 0;
 }
@@ -1068,8 +1125,8 @@ static int ov5647_get_selection(struct v4l2_subdev *sd,
 static const struct v4l2_subdev_pad_ops ov5647_subdev_pad_ops = {
 	.enum_mbus_code		= ov5647_enum_mbus_code,
 	.enum_frame_size	= ov5647_enum_frame_size,
-	.set_fmt		= ov5647_set_get_fmt,
-	.get_fmt		= ov5647_set_get_fmt,
+	.set_fmt		= ov5647_set_pad_fmt,
+	.get_fmt		= ov5647_get_pad_fmt,
 	.get_selection		= ov5647_get_selection,
 };
 
-- 
2.27.0


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

* [PATCH 20/25] media: ov5647: Program mode only if it has changed
  2020-06-23 10:07 [PATCH 00/25] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
                   ` (18 preceding siblings ...)
  2020-06-23 16:49 ` [PATCH 19/25] media: ov5647: Implement set_fmt pad operation Jacopo Mondi
@ 2020-06-23 16:55 ` Jacopo Mondi
  2020-06-29 17:48   ` Dafna Hirschfeld
  2020-06-23 16:55 ` [PATCH 21/25] media: ov5647: Set V4L2_SUBDEV_FL_HAS_EVENTS flag Jacopo Mondi
                   ` (6 subsequent siblings)
  26 siblings, 1 reply; 56+ messages in thread
From: Jacopo Mondi @ 2020-06-23 16:55 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dave.stevenson, naush
  Cc: mrodin, hugues.fruchet, mripard, aford173, sudipi,
	andrew_gabbasov, erosca, linux-media, libcamera-devel,
	Jacopo Mondi

Store in the driver structure a pointer to the currently applied mode
and program a new one at s_stream(1) time only if it has changed.

Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
---
 drivers/media/i2c/ov5647.c | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
index 39e320f321bd8..ac114269e1c73 100644
--- a/drivers/media/i2c/ov5647.c
+++ b/drivers/media/i2c/ov5647.c
@@ -96,6 +96,7 @@ struct ov5647 {
 	bool				clock_ncont;
 	struct v4l2_ctrl_handler	ctrls;
 	struct ov5647_mode		*mode;
+	struct ov5647_mode		*current_mode;
 };
 
 static inline struct ov5647 *to_sensor(struct v4l2_subdev *sd)
@@ -750,9 +751,13 @@ static int ov5647_set_virtual_channel(struct v4l2_subdev *sd, int channel)
 static int ov5647_set_mode(struct v4l2_subdev *sd)
 {
 	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct ov5647 *sensor = to_sensor(sd);
 	u8 resetval, rdval;
 	int ret;
 
+	if (sensor->mode == sensor->current_mode)
+		return 0;
+
 	ret = ov5647_read(sd, OV5647_SW_STANDBY, &rdval);
 	if (ret < 0)
 		return ret;
@@ -778,6 +783,8 @@ static int ov5647_set_mode(struct v4l2_subdev *sd)
 			return ret;
 	}
 
+	sensor->current_mode = sensor->mode;
+
 	return 0;
 }
 
@@ -816,6 +823,7 @@ static int ov5647_stream_on(struct v4l2_subdev *sd)
 
 static int ov5647_stream_off(struct v4l2_subdev *sd)
 {
+	struct ov5647 *sensor = to_sensor(sd);
 	int ret;
 
 	ret = ov5647_write(sd, OV5647_REG_MIPI_CTRL00, MIPI_CTRL00_CLOCK_LANE_GATE |
@@ -827,7 +835,13 @@ static int ov5647_stream_off(struct v4l2_subdev *sd)
 	if (ret < 0)
 		return ret;
 
-	return ov5647_write(sd, OV5640_REG_PAD_OUT, 0x01);
+	ret = ov5647_write(sd, OV5640_REG_PAD_OUT, 0x01);
+	if (ret < 0)
+		return ret;
+
+	sensor->current_mode = NULL;
+
+	return 0;
 }
 
 static int set_sw_standby(struct v4l2_subdev *sd, bool standby)
-- 
2.27.0


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

* [PATCH 21/25] media: ov5647: Set V4L2_SUBDEV_FL_HAS_EVENTS flag
  2020-06-23 10:07 [PATCH 00/25] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
                   ` (19 preceding siblings ...)
  2020-06-23 16:55 ` [PATCH 20/25] media: ov5647: Program mode only if it has changed Jacopo Mondi
@ 2020-06-23 16:55 ` Jacopo Mondi
  2020-06-23 16:55 ` [PATCH 22/25] media: ov5647: Support V4L2_CID_PIXEL_RATE Jacopo Mondi
                   ` (5 subsequent siblings)
  26 siblings, 0 replies; 56+ messages in thread
From: Jacopo Mondi @ 2020-06-23 16:55 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dave.stevenson, naush
  Cc: mrodin, hugues.fruchet, mripard, aford173, sudipi,
	andrew_gabbasov, erosca, linux-media, libcamera-devel,
	Dave Stevenson, Jacopo Mondi

From: Dave Stevenson <dave.stevenson@raspberrypi.com>

The ov5647 subdev can generate control events, therefore set
the V4L2_SUBDEV_FL_HAS_EVENTS flag.

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

diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
index ac114269e1c73..35865e56de5f9 100644
--- a/drivers/media/i2c/ov5647.c
+++ b/drivers/media/i2c/ov5647.c
@@ -1418,7 +1418,7 @@ static int ov5647_probe(struct i2c_client *client)
 	sd = &sensor->sd;
 	v4l2_i2c_subdev_init(sd, client, &ov5647_subdev_ops);
 	sd->internal_ops = &ov5647_subdev_internal_ops;
-	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
 
 	sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
 	sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
-- 
2.27.0


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

* [PATCH 22/25] media: ov5647: Support V4L2_CID_PIXEL_RATE
  2020-06-23 10:07 [PATCH 00/25] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
                   ` (20 preceding siblings ...)
  2020-06-23 16:55 ` [PATCH 21/25] media: ov5647: Set V4L2_SUBDEV_FL_HAS_EVENTS flag Jacopo Mondi
@ 2020-06-23 16:55 ` Jacopo Mondi
  2020-06-29 17:01   ` [libcamera-devel] " Dafna Hirschfeld
  2020-06-23 16:55 ` [PATCH 23/25] media: ov5647: Support V4L2_CID_HBLANK control Jacopo Mondi
                   ` (4 subsequent siblings)
  26 siblings, 1 reply; 56+ messages in thread
From: Jacopo Mondi @ 2020-06-23 16:55 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dave.stevenson, naush
  Cc: mrodin, hugues.fruchet, mripard, aford173, sudipi,
	andrew_gabbasov, erosca, linux-media, libcamera-devel,
	Dave Stevenson, Jacopo Mondi

From: Dave Stevenson <dave.stevenson@raspberrypi.com>

Clients need to know the pixel rate in order to compute exposure
and frame rate values. Advertise it.

Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
---
 drivers/media/i2c/ov5647.c | 40 +++++++++++++++++++++++++++++++-------
 1 file changed, 33 insertions(+), 7 deletions(-)

diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
index 35865e56de5f9..218576a05e66b 100644
--- a/drivers/media/i2c/ov5647.c
+++ b/drivers/media/i2c/ov5647.c
@@ -76,6 +76,7 @@ struct regval_list {
 struct ov5647_mode {
 	struct v4l2_mbus_framefmt	format;
 	struct v4l2_rect		crop;
+	u64				pixel_rate;
 	struct regval_list		*reg_list;
 	unsigned int			num_regs;
 };
@@ -97,6 +98,7 @@ struct ov5647 {
 	struct v4l2_ctrl_handler	ctrls;
 	struct ov5647_mode		*mode;
 	struct ov5647_mode		*current_mode;
+	struct v4l2_ctrl		*pixel_rate;
 };
 
 static inline struct ov5647 *to_sensor(struct v4l2_subdev *sd)
@@ -583,6 +585,7 @@ static struct ov5647_mode ov5647_sbggr8_modes[] = {
 			.width		= 1280,
 			.height		= 960,
 		},
+		.pixel_rate	= 77291670,
 		.reg_list	= ov5647_640x480_sbggr8,
 		.num_regs	= ARRAY_SIZE(ov5647_640x480_sbggr8)
 	},
@@ -604,6 +607,7 @@ static struct ov5647_mode ov5647_sbggr10_modes[] = {
 			.width		= 2592,
 			.height		= 1944
 		},
+		.pixel_rate	= 87500000,
 		.reg_list	= ov5647_2592x1944_sbggr10,
 		.num_regs	= ARRAY_SIZE(ov5647_2592x1944_sbggr10)
 	},
@@ -622,6 +626,7 @@ static struct ov5647_mode ov5647_sbggr10_modes[] = {
 			.width		= 1928,
 			.height		= 1080,
 		},
+		.pixel_rate	= 81666700,
 		.reg_list	= ov5647_1080p30_sbggr10,
 		.num_regs	= ARRAY_SIZE(ov5647_1080p30_sbggr10)
 	},
@@ -640,6 +645,7 @@ static struct ov5647_mode ov5647_sbggr10_modes[] = {
 			.width		= 2592,
 			.height		= 1944,
 		},
+		.pixel_rate	= 81666700,
 		.reg_list	= ov5647_2x2binned_sbggr10,
 		.num_regs	= ARRAY_SIZE(ov5647_2x2binned_sbggr10)
 	},
@@ -658,6 +664,7 @@ static struct ov5647_mode ov5647_sbggr10_modes[] = {
 			.width		= 2560,
 			.height		= 1920,
 		},
+		.pixel_rate	= 55000000,
 		.reg_list	= ov5647_640x480_sbggr10,
 		.num_regs	= ARRAY_SIZE(ov5647_640x480_sbggr10)
 	},
@@ -1094,6 +1101,10 @@ static int ov5647_set_pad_fmt(struct v4l2_subdev *sd,
 	/* Update the sensor mode and apply at it at streamon time. */
 	mutex_lock(&sensor->lock);
 	sensor->mode = mode;
+
+	__v4l2_ctrl_modify_range(sensor->pixel_rate, mode->pixel_rate,
+				 mode->pixel_rate, 1, mode->pixel_rate);
+
 	*fmt = mode->format;
 	mutex_unlock(&sensor->lock);
 
@@ -1295,6 +1306,9 @@ static int ov5647_s_ctrl(struct v4l2_ctrl *ctrl)
 		return  ov5647_s_analogue_gain(sd, ctrl->val);
 	case V4L2_CID_EXPOSURE:
 		return ov5647_s_exposure(sd, ctrl->val);
+	case V4L2_CID_PIXEL_RATE:
+		/* Read-only, but we adjust it based on mode. */
+		return 0;
 	default:
 		dev_info(&client->dev,
 			 "Control (id:0x%x, val:0x%x) not supported\n",
@@ -1313,7 +1327,7 @@ static int ov5647_init_controls(struct ov5647 *sensor)
 {
 	struct i2c_client *client = v4l2_get_subdevdata(&sensor->sd);
 
-	v4l2_ctrl_handler_init(&sensor->ctrls, 5);
+	v4l2_ctrl_handler_init(&sensor->ctrls, 6);
 
 	v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,
 			  V4L2_CID_AUTOGAIN, 0, 1, 1, 0);
@@ -1333,17 +1347,29 @@ static int ov5647_init_controls(struct ov5647 *sensor)
 	v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,
 			  V4L2_CID_ANALOGUE_GAIN, 16, 1023, 1, 32);
 
-	if (sensor->ctrls.error) {
-		dev_err(&client->dev, "%s Controls initialization failed (%d)\n",
-			__func__, sensor->ctrls.error);
-		v4l2_ctrl_handler_free(&sensor->ctrls);
+	/* By default, PIXEL_RATE is read only, but it does change per mode */
+	sensor->pixel_rate = v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,
+					       V4L2_CID_PIXEL_RATE,
+					       sensor->mode->pixel_rate,
+					       sensor->mode->pixel_rate, 1,
+					       sensor->mode->pixel_rate);
+	if (!sensor->pixel_rate)
+		goto handler_free;
+	sensor->pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY;
 
-		return sensor->ctrls.error;
-	}
+	if (sensor->ctrls.error)
+		goto handler_free;
 
 	sensor->sd.ctrl_handler = &sensor->ctrls;
 
 	return 0;
+
+handler_free:
+	dev_err(&client->dev, "%s Controls initialization failed (%d)\n",
+		__func__, sensor->ctrls.error);
+	v4l2_ctrl_handler_free(&sensor->ctrls);
+
+	return sensor->ctrls.error;
 }
 
 static int ov5647_parse_dt(struct ov5647 *sensor, struct device_node *np)
-- 
2.27.0


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

* [PATCH 23/25] media: ov5647: Support V4L2_CID_HBLANK control
  2020-06-23 10:07 [PATCH 00/25] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
                   ` (21 preceding siblings ...)
  2020-06-23 16:55 ` [PATCH 22/25] media: ov5647: Support V4L2_CID_PIXEL_RATE Jacopo Mondi
@ 2020-06-23 16:55 ` Jacopo Mondi
  2020-06-23 16:55 ` [PATCH 24/25] media: ov5647: Support V4L2_CID_VBLANK control Jacopo Mondi
                   ` (3 subsequent siblings)
  26 siblings, 0 replies; 56+ messages in thread
From: Jacopo Mondi @ 2020-06-23 16:55 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dave.stevenson, naush
  Cc: mrodin, hugues.fruchet, mripard, aford173, sudipi,
	andrew_gabbasov, erosca, linux-media, libcamera-devel,
	Jacopo Mondi

Add support for the V4L2_CID_HBLANK read-only control.

The implementation has been upported from RaspberryPi BSP commit:
commit d82f202156605 ("media: i2c: ov5647: Set V4L2_SUBDEV_FL_HAS_EVENTS flag")

Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
---
 drivers/media/i2c/ov5647.c | 26 +++++++++++++++++++++++++-
 1 file changed, 25 insertions(+), 1 deletion(-)

diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
index 218576a05e66b..3467a8090b38d 100644
--- a/drivers/media/i2c/ov5647.c
+++ b/drivers/media/i2c/ov5647.c
@@ -77,6 +77,7 @@ struct ov5647_mode {
 	struct v4l2_mbus_framefmt	format;
 	struct v4l2_rect		crop;
 	u64				pixel_rate;
+	int				hts;
 	struct regval_list		*reg_list;
 	unsigned int			num_regs;
 };
@@ -99,6 +100,7 @@ struct ov5647 {
 	struct ov5647_mode		*mode;
 	struct ov5647_mode		*current_mode;
 	struct v4l2_ctrl		*pixel_rate;
+	struct v4l2_ctrl		*hblank;
 };
 
 static inline struct ov5647 *to_sensor(struct v4l2_subdev *sd)
@@ -586,6 +588,7 @@ static struct ov5647_mode ov5647_sbggr8_modes[] = {
 			.height		= 960,
 		},
 		.pixel_rate	= 77291670,
+		.hts		= 1896,
 		.reg_list	= ov5647_640x480_sbggr8,
 		.num_regs	= ARRAY_SIZE(ov5647_640x480_sbggr8)
 	},
@@ -608,6 +611,7 @@ static struct ov5647_mode ov5647_sbggr10_modes[] = {
 			.height		= 1944
 		},
 		.pixel_rate	= 87500000,
+		.hts		= 2844,
 		.reg_list	= ov5647_2592x1944_sbggr10,
 		.num_regs	= ARRAY_SIZE(ov5647_2592x1944_sbggr10)
 	},
@@ -627,6 +631,7 @@ static struct ov5647_mode ov5647_sbggr10_modes[] = {
 			.height		= 1080,
 		},
 		.pixel_rate	= 81666700,
+		.hts		= 2416,
 		.reg_list	= ov5647_1080p30_sbggr10,
 		.num_regs	= ARRAY_SIZE(ov5647_1080p30_sbggr10)
 	},
@@ -646,6 +651,7 @@ static struct ov5647_mode ov5647_sbggr10_modes[] = {
 			.height		= 1944,
 		},
 		.pixel_rate	= 81666700,
+		.hts		= 1896,
 		.reg_list	= ov5647_2x2binned_sbggr10,
 		.num_regs	= ARRAY_SIZE(ov5647_2x2binned_sbggr10)
 	},
@@ -665,6 +671,7 @@ static struct ov5647_mode ov5647_sbggr10_modes[] = {
 			.height		= 1920,
 		},
 		.pixel_rate	= 55000000,
+		.hts		= 1852,
 		.reg_list	= ov5647_640x480_sbggr10,
 		.num_regs	= ARRAY_SIZE(ov5647_640x480_sbggr10)
 	},
@@ -1072,6 +1079,7 @@ static int ov5647_set_pad_fmt(struct v4l2_subdev *sd,
 	struct ov5647_mode *ov5647_mode_list;
 	struct ov5647_mode *mode;
 	unsigned int num_modes;
+	int hblank;
 
 	/*
 	 * Default mbus code MEDIA_BUS_FMT_SBGGR10_1X10 if the requested one
@@ -1105,6 +1113,9 @@ static int ov5647_set_pad_fmt(struct v4l2_subdev *sd,
 	__v4l2_ctrl_modify_range(sensor->pixel_rate, mode->pixel_rate,
 				 mode->pixel_rate, 1, mode->pixel_rate);
 
+	hblank = mode->hts - mode->format.width;
+	__v4l2_ctrl_modify_range(sensor->hblank, hblank, hblank, 1, hblank);
+
 	*fmt = mode->format;
 	mutex_unlock(&sensor->lock);
 
@@ -1309,6 +1320,9 @@ static int ov5647_s_ctrl(struct v4l2_ctrl *ctrl)
 	case V4L2_CID_PIXEL_RATE:
 		/* Read-only, but we adjust it based on mode. */
 		return 0;
+	case V4L2_CID_HBLANK:
+		/* Read-only, but we adjust it based on mode. */
+		return 0;
 	default:
 		dev_info(&client->dev,
 			 "Control (id:0x%x, val:0x%x) not supported\n",
@@ -1326,8 +1340,9 @@ static const struct v4l2_ctrl_ops ov5647_ctrl_ops = {
 static int ov5647_init_controls(struct ov5647 *sensor)
 {
 	struct i2c_client *client = v4l2_get_subdevdata(&sensor->sd);
+	int hblank;
 
-	v4l2_ctrl_handler_init(&sensor->ctrls, 6);
+	v4l2_ctrl_handler_init(&sensor->ctrls, 7);
 
 	v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,
 			  V4L2_CID_AUTOGAIN, 0, 1, 1, 0);
@@ -1357,6 +1372,15 @@ static int ov5647_init_controls(struct ov5647 *sensor)
 		goto handler_free;
 	sensor->pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY;
 
+	/* By default, HBLANK is read only, but it does change per mode */
+	hblank = sensor->mode->hts - sensor->mode->format.width;
+	sensor->hblank = v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,
+					   V4L2_CID_HBLANK, hblank, hblank, 1,
+					   hblank);
+	if (!sensor->hblank)
+		goto handler_free;
+	sensor->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
 	if (sensor->ctrls.error)
 		goto handler_free;
 
-- 
2.27.0


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

* [PATCH 24/25] media: ov5647: Support V4L2_CID_VBLANK control
  2020-06-23 10:07 [PATCH 00/25] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
                   ` (22 preceding siblings ...)
  2020-06-23 16:55 ` [PATCH 23/25] media: ov5647: Support V4L2_CID_HBLANK control Jacopo Mondi
@ 2020-06-23 16:55 ` Jacopo Mondi
  2020-06-23 16:55 ` [PATCH 25/25] media: ov5647: Advertise the correct exposure range Jacopo Mondi
                   ` (2 subsequent siblings)
  26 siblings, 0 replies; 56+ messages in thread
From: Jacopo Mondi @ 2020-06-23 16:55 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dave.stevenson, naush
  Cc: mrodin, hugues.fruchet, mripard, aford173, sudipi,
	andrew_gabbasov, erosca, linux-media, libcamera-devel,
	Dave Stevenson, Jacopo Mondi

From: Dave Stevenson <dave.stevenson@raspberrypi.com>

Adds vblank control to allow for frame rate control.

Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
---
 drivers/media/i2c/ov5647.c | 46 +++++++++++++++++++++++++++++++++++---
 1 file changed, 43 insertions(+), 3 deletions(-)

diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
index 3467a8090b38d..209218fb073d6 100644
--- a/drivers/media/i2c/ov5647.c
+++ b/drivers/media/i2c/ov5647.c
@@ -50,6 +50,8 @@
 #define OV5647_REG_AEC_AGC		0x3503
 #define OV5647_REG_GAIN_HI		0x350a
 #define OV5647_REG_GAIN_LO		0x350b
+#define OV5647_REG_VTS_HI		0x380e
+#define OV5647_REG_VTS_LO		0x380f
 #define OV5647_REG_FRAME_OFF_NUMBER	0x4202
 #define OV5647_REG_MIPI_CTRL00		0x4800
 #define OV5647_REG_MIPI_CTRL14		0x4814
@@ -68,6 +70,9 @@
 #define OV5647_PIXEL_ARRAY_WIDTH	2592U
 #define OV5647_PIXEL_ARRAY_HEIGHT	1944U
 
+#define OV5647_VBLANK_MIN		4
+#define OV5647_VTS_MAX			32767
+
 struct regval_list {
 	u16 addr;
 	u8 data;
@@ -78,6 +83,7 @@ struct ov5647_mode {
 	struct v4l2_rect		crop;
 	u64				pixel_rate;
 	int				hts;
+	int				vts;
 	struct regval_list		*reg_list;
 	unsigned int			num_regs;
 };
@@ -101,6 +107,7 @@ struct ov5647 {
 	struct ov5647_mode		*current_mode;
 	struct v4l2_ctrl		*pixel_rate;
 	struct v4l2_ctrl		*hblank;
+	struct v4l2_ctrl		*vblank;
 };
 
 static inline struct ov5647 *to_sensor(struct v4l2_subdev *sd)
@@ -152,8 +159,6 @@ static struct regval_list ov5647_640x480_sbggr8[] = {
 	{0x3b07, 0x0c},
 	{0x380c, 0x07},
 	{0x380d, 0x68},
-	{0x380e, 0x03},
-	{0x380f, 0xd8},
 	{0x3814, 0x31},
 	{0x3815, 0x31},
 	{0x3708, 0x64},
@@ -589,6 +594,7 @@ static struct ov5647_mode ov5647_sbggr8_modes[] = {
 		},
 		.pixel_rate	= 77291670,
 		.hts		= 1896,
+		.vts		= 0x3d8,
 		.reg_list	= ov5647_640x480_sbggr8,
 		.num_regs	= ARRAY_SIZE(ov5647_640x480_sbggr8)
 	},
@@ -612,6 +618,7 @@ static struct ov5647_mode ov5647_sbggr10_modes[] = {
 		},
 		.pixel_rate	= 87500000,
 		.hts		= 2844,
+		.vts		= 0x7b0,
 		.reg_list	= ov5647_2592x1944_sbggr10,
 		.num_regs	= ARRAY_SIZE(ov5647_2592x1944_sbggr10)
 	},
@@ -632,6 +639,7 @@ static struct ov5647_mode ov5647_sbggr10_modes[] = {
 		},
 		.pixel_rate	= 81666700,
 		.hts		= 2416,
+		.vts		= 0x450,
 		.reg_list	= ov5647_1080p30_sbggr10,
 		.num_regs	= ARRAY_SIZE(ov5647_1080p30_sbggr10)
 	},
@@ -652,6 +660,7 @@ static struct ov5647_mode ov5647_sbggr10_modes[] = {
 		},
 		.pixel_rate	= 81666700,
 		.hts		= 1896,
+		.vts		= 0x59b,
 		.reg_list	= ov5647_2x2binned_sbggr10,
 		.num_regs	= ARRAY_SIZE(ov5647_2x2binned_sbggr10)
 	},
@@ -672,6 +681,7 @@ static struct ov5647_mode ov5647_sbggr10_modes[] = {
 		},
 		.pixel_rate	= 55000000,
 		.hts		= 1852,
+		.vts		= 0x1f8,
 		.reg_list	= ov5647_640x480_sbggr10,
 		.num_regs	= ARRAY_SIZE(ov5647_640x480_sbggr10)
 	},
@@ -695,6 +705,22 @@ static const struct ov5647_format_list ov5647_formats[] = {
 #define OV5647_DEFAULT_MODE	(&ov5647_formats[0].modes[0])
 #define OV5647_DEFAULT_FORMAT	(ov5647_formats[0].modes[0].format)
 
+static int ov5647_write16(struct v4l2_subdev *sd, u16 reg, u16 val)
+{
+	unsigned char data[4] = { reg >> 8, reg & 0xff, val >> 8, val & 0xff};
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	int ret;
+
+	ret = i2c_master_send(client, data, 4);
+	if (ret < 0) {
+		dev_dbg(&client->dev, "%s: i2c write error, reg: %x\n",
+			__func__, reg);
+		return ret;
+	}
+
+	return 0;
+}
+
 static int ov5647_write(struct v4l2_subdev *sd, u16 reg, u8 val)
 {
 	unsigned char data[3] = { reg >> 8, reg & 0xff, val};
@@ -1116,6 +1142,11 @@ static int ov5647_set_pad_fmt(struct v4l2_subdev *sd,
 	hblank = mode->hts - mode->format.width;
 	__v4l2_ctrl_modify_range(sensor->hblank, hblank, hblank, 1, hblank);
 
+	__v4l2_ctrl_modify_range(sensor->vblank, OV5647_VBLANK_MIN,
+				 OV5647_VTS_MAX - mode->format.height,
+				 1, mode->vts - mode->format.height);
+	__v4l2_ctrl_s_ctrl(sensor->vblank, mode->vts - mode->format.height);
+
 	*fmt = mode->format;
 	mutex_unlock(&sensor->lock);
 
@@ -1323,6 +1354,9 @@ static int ov5647_s_ctrl(struct v4l2_ctrl *ctrl)
 	case V4L2_CID_HBLANK:
 		/* Read-only, but we adjust it based on mode. */
 		return 0;
+	case V4L2_CID_VBLANK:
+		return ov5647_write16(sd, OV5647_REG_VTS_HI,
+				      sensor->mode->format.height + ctrl->val);
 	default:
 		dev_info(&client->dev,
 			 "Control (id:0x%x, val:0x%x) not supported\n",
@@ -1342,7 +1376,7 @@ static int ov5647_init_controls(struct ov5647 *sensor)
 	struct i2c_client *client = v4l2_get_subdevdata(&sensor->sd);
 	int hblank;
 
-	v4l2_ctrl_handler_init(&sensor->ctrls, 7);
+	v4l2_ctrl_handler_init(&sensor->ctrls, 8);
 
 	v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,
 			  V4L2_CID_AUTOGAIN, 0, 1, 1, 0);
@@ -1381,6 +1415,12 @@ static int ov5647_init_controls(struct ov5647 *sensor)
 		goto handler_free;
 	sensor->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
 
+	sensor->vblank = v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,
+					   V4L2_CID_VBLANK, OV5647_VBLANK_MIN,
+					   OV5647_VTS_MAX - sensor->mode->format.height,
+					   1, sensor->mode->vts -
+					      sensor->mode->format.height);
+
 	if (sensor->ctrls.error)
 		goto handler_free;
 
-- 
2.27.0


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

* [PATCH 25/25] media: ov5647: Advertise the correct exposure range
  2020-06-23 10:07 [PATCH 00/25] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
                   ` (23 preceding siblings ...)
  2020-06-23 16:55 ` [PATCH 24/25] media: ov5647: Support V4L2_CID_VBLANK control Jacopo Mondi
@ 2020-06-23 16:55 ` Jacopo Mondi
  2020-06-29 17:33 ` [PATCH 00/25] media: ov5647: Support RaspberryPi Camera Module v1 Dafna Hirschfeld
  2020-07-10 15:59 ` Dafna Hirschfeld
  26 siblings, 0 replies; 56+ messages in thread
From: Jacopo Mondi @ 2020-06-23 16:55 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dave.stevenson, naush
  Cc: mrodin, hugues.fruchet, mripard, aford173, sudipi,
	andrew_gabbasov, erosca, linux-media, libcamera-devel,
	Dave Stevenson, Jacopo Mondi

From: Dave Stevenson <dave.stevenson@raspberrypi.com>

Exposure is clipped by the VTS of the mode, so it needs to be updated
when this is changed.

Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
---
 drivers/media/i2c/ov5647.c | 41 ++++++++++++++++++++++++++++++++------
 1 file changed, 35 insertions(+), 6 deletions(-)

diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
index 209218fb073d6..8f62415c07aad 100644
--- a/drivers/media/i2c/ov5647.c
+++ b/drivers/media/i2c/ov5647.c
@@ -73,6 +73,11 @@
 #define OV5647_VBLANK_MIN		4
 #define OV5647_VTS_MAX			32767
 
+#define OV5647_EXPOSURE_MIN		4
+#define OV5647_EXPOSURE_STEP		1
+#define OV5647_EXPOSURE_DEFAULT		1000
+#define OV5647_EXPOSURE_MAX		65535
+
 struct regval_list {
 	u16 addr;
 	u8 data;
@@ -108,6 +113,7 @@ struct ov5647 {
 	struct v4l2_ctrl		*pixel_rate;
 	struct v4l2_ctrl		*hblank;
 	struct v4l2_ctrl		*vblank;
+	struct v4l2_ctrl		*exposure;
 };
 
 static inline struct ov5647 *to_sensor(struct v4l2_subdev *sd)
@@ -1102,10 +1108,10 @@ static int ov5647_set_pad_fmt(struct v4l2_subdev *sd,
 {
 	struct v4l2_mbus_framefmt *fmt = &format->format;
 	struct ov5647 *sensor = to_sensor(sd);
+	int hblank, exposure_max, exposure_def;
 	struct ov5647_mode *ov5647_mode_list;
 	struct ov5647_mode *mode;
 	unsigned int num_modes;
-	int hblank;
 
 	/*
 	 * Default mbus code MEDIA_BUS_FMT_SBGGR10_1X10 if the requested one
@@ -1147,6 +1153,13 @@ static int ov5647_set_pad_fmt(struct v4l2_subdev *sd,
 				 1, mode->vts - mode->format.height);
 	__v4l2_ctrl_s_ctrl(sensor->vblank, mode->vts - mode->format.height);
 
+	exposure_max = mode->vts - 4;
+	exposure_def = exposure_max < OV5647_EXPOSURE_DEFAULT ? exposure_max
+							      : OV5647_EXPOSURE_DEFAULT;
+	__v4l2_ctrl_modify_range(sensor->exposure, sensor->exposure->minimum,
+				 exposure_max, sensor->exposure->step,
+				 exposure_def);
+
 	*fmt = mode->format;
 	mutex_unlock(&sensor->lock);
 
@@ -1329,6 +1342,18 @@ static int ov5647_s_ctrl(struct v4l2_ctrl *ctrl)
 
 	/* v4l2_ctrl_lock() locks our own mutex */
 
+	if (ctrl->id == V4L2_CID_VBLANK) {
+		int exposure_max, exposure_def;
+
+		/* Update max exposure while meeting expected vblanking */
+		exposure_max = sensor->mode->format.height + ctrl->val - 4;
+		exposure_def = exposure_max < OV5647_EXPOSURE_DEFAULT
+			     ? exposure_max : OV5647_EXPOSURE_DEFAULT;
+		__v4l2_ctrl_modify_range(sensor->exposure, sensor->exposure->minimum,
+					 exposure_max, sensor->exposure->step,
+					 exposure_def);
+	}
+
 	/*
 	 * If the device is not powered up by the host driver do
 	 * not apply any controls to H/W at this time. Instead
@@ -1374,9 +1399,9 @@ static const struct v4l2_ctrl_ops ov5647_ctrl_ops = {
 static int ov5647_init_controls(struct ov5647 *sensor)
 {
 	struct i2c_client *client = v4l2_get_subdevdata(&sensor->sd);
-	int hblank;
+	int hblank, exposure_max, exposure_def;
 
-	v4l2_ctrl_handler_init(&sensor->ctrls, 8);
+	v4l2_ctrl_handler_init(&sensor->ctrls, 9);
 
 	v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,
 			  V4L2_CID_AUTOGAIN, 0, 1, 1, 0);
@@ -1388,9 +1413,13 @@ static int ov5647_init_controls(struct ov5647 *sensor)
 			       V4L2_CID_EXPOSURE_AUTO, V4L2_EXPOSURE_MANUAL,
 			       0, V4L2_EXPOSURE_MANUAL);
 
-	/* min: 4 lines; max: 0xffff lines; default: 1000 lines. */
-	v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,
-			  V4L2_CID_EXPOSURE, 4, 65535, 1, 1000);
+	exposure_max = sensor->mode->vts - 4;
+	exposure_def = exposure_max < OV5647_EXPOSURE_DEFAULT ? exposure_max
+							      : OV5647_EXPOSURE_DEFAULT;
+	sensor->exposure = v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,
+					     V4L2_CID_EXPOSURE, OV5647_EXPOSURE_MIN,
+					     exposure_max, OV5647_EXPOSURE_STEP,
+					     exposure_def);
 
 	/* min: 16 = 1.0x; max (10 bits); default: 32 = 2.0x. */
 	v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,
-- 
2.27.0


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

* Re: [libcamera-devel] [PATCH 19/25] media: ov5647: Implement set_fmt pad operation
  2020-06-23 16:49 ` [PATCH 19/25] media: ov5647: Implement set_fmt pad operation Jacopo Mondi
@ 2020-06-29 16:54   ` Dafna Hirschfeld
  2020-06-30 10:13     ` Jacopo Mondi
  0 siblings, 1 reply; 56+ messages in thread
From: Dafna Hirschfeld @ 2020-06-29 16:54 UTC (permalink / raw)
  To: Jacopo Mondi, mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dave.stevenson, naush
  Cc: andrew_gabbasov, mrodin, mripard, libcamera-devel, sudipi,
	hugues.fruchet, erosca, aford173, linux-media



On 23.06.20 18:49, Jacopo Mondi wrote:
> Now that the driver supports more than a single mode, implement the
> .set_fmt pad operation and adjust the existing .get_fmt one to report
> the currently applied format.
> 
> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
> ---
>   drivers/media/i2c/ov5647.c | 67 +++++++++++++++++++++++++++++++++++---
>   1 file changed, 62 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
> index af9e6d43967d8..39e320f321bd8 100644
> --- a/drivers/media/i2c/ov5647.c
> +++ b/drivers/media/i2c/ov5647.c
> @@ -1016,15 +1016,72 @@ static int ov5647_enum_frame_size(struct v4l2_subdev *sd,
>   	return 0;
>   }
>   
> -static int ov5647_set_get_fmt(struct v4l2_subdev *sd,
> +static int ov5647_get_pad_fmt(struct v4l2_subdev *sd,
>   			      struct v4l2_subdev_pad_config *cfg,
>   			      struct v4l2_subdev_format *format)
>   {
>   	struct v4l2_mbus_framefmt *fmt = &format->format;
> +	struct v4l2_mbus_framefmt *sensor_format;
> +	struct ov5647 *sensor = to_sensor(sd);
>   
> -	/* Only one format is supported, so return that. */
> +	mutex_lock(&sensor->lock);
>   	memset(fmt, 0, sizeof(*fmt));
> -	*fmt = OV5647_DEFAULT_FORMAT;
> +
> +	switch (format->which) {
> +	case V4L2_SUBDEV_FORMAT_TRY:
> +		sensor_format = v4l2_subdev_get_try_format(sd, cfg, format->pad);
> +		break;
> +	default:
> +		sensor_format = &sensor->mode->format;
> +		break;
> +	}
> +
> +	*fmt = *sensor_format;
> +	mutex_unlock(&sensor->lock);
> +
> +	return 0;
> +}
> +
> +static int ov5647_set_pad_fmt(struct v4l2_subdev *sd,
> +			      struct v4l2_subdev_pad_config *cfg,
> +			      struct v4l2_subdev_format *format)
> +{
> +	struct v4l2_mbus_framefmt *fmt = &format->format;
> +	struct ov5647 *sensor = to_sensor(sd);
> +	struct ov5647_mode *ov5647_mode_list;
> +	struct ov5647_mode *mode;
> +	unsigned int num_modes;
> +
> +	/*
> +	 * Default mbus code MEDIA_BUS_FMT_SBGGR10_1X10 if the requested one
> +	 * is not supported.

In previous patch you added macros OV5647_DEFAULT_MODE, OV5647_DEFAULT_FORMAT
which comes from first format in the array 'ov5647_formats' which is MEDIA_BUS_FMT_SBGGR8_1X8.
But here you set the default format to MEDIA_BUS_FMT_SBGGR10_1X10

> +	 */
> +	if (fmt->code == MEDIA_BUS_FMT_SBGGR8_1X8) {
> +		ov5647_mode_list = ov5647_sbggr8_modes;
> +		num_modes = ARRAY_SIZE(ov5647_sbggr8_modes);
> +	} else {
> +		ov5647_mode_list = ov5647_sbggr10_modes;
> +		num_modes = ARRAY_SIZE(ov5647_sbggr10_modes);
> +	}
> +
> +	mode = v4l2_find_nearest_size(ov5647_mode_list, num_modes,
> +				      format.width, format.height,
> +				      fmt->width, fmt->height);
> +
> +	if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
> +		mutex_lock(&sensor->lock);
> +		*v4l2_subdev_get_try_format(sd, cfg, format->pad) = mode->format;
> +		*fmt = mode->format;
> +		mutex_unlock(&sensor->lock);
> +
> +		return 0;
> +	}
> +
> +	/* Update the sensor mode and apply at it at streamon time. */
> +	mutex_lock(&sensor->lock);
> +	sensor->mode = mode;
> +	*fmt = mode->format;
> +	mutex_unlock(&sensor->lock);
>   
>   	return 0;
>   }
> @@ -1068,8 +1125,8 @@ static int ov5647_get_selection(struct v4l2_subdev *sd,
>   static const struct v4l2_subdev_pad_ops ov5647_subdev_pad_ops = {
>   	.enum_mbus_code		= ov5647_enum_mbus_code,
>   	.enum_frame_size	= ov5647_enum_frame_size,
> -	.set_fmt		= ov5647_set_get_fmt,
> -	.get_fmt		= ov5647_set_get_fmt,
> +	.set_fmt		= ov5647_set_pad_fmt,
> +	.get_fmt		= ov5647_get_pad_fmt,
>   	.get_selection		= ov5647_get_selection,
>   };
>   
> 

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

* Re: [libcamera-devel] [PATCH 22/25] media: ov5647: Support V4L2_CID_PIXEL_RATE
  2020-06-23 16:55 ` [PATCH 22/25] media: ov5647: Support V4L2_CID_PIXEL_RATE Jacopo Mondi
@ 2020-06-29 17:01   ` Dafna Hirschfeld
  2020-06-29 21:25     ` Dave Stevenson
  0 siblings, 1 reply; 56+ messages in thread
From: Dafna Hirschfeld @ 2020-06-29 17:01 UTC (permalink / raw)
  To: Jacopo Mondi, mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dave.stevenson, naush
  Cc: andrew_gabbasov, mrodin, mripard, libcamera-devel, sudipi,
	hugues.fruchet, erosca, aford173, linux-media, Dafna Hirschfeld



On 23.06.20 18:55, Jacopo Mondi wrote:
> From: Dave Stevenson <dave.stevenson@raspberrypi.com>
> 
> Clients need to know the pixel rate in order to compute exposure
> and frame rate values. Advertise it.
> 
> Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
> ---
>   drivers/media/i2c/ov5647.c | 40 +++++++++++++++++++++++++++++++-------
>   1 file changed, 33 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
> index 35865e56de5f9..218576a05e66b 100644
> --- a/drivers/media/i2c/ov5647.c
> +++ b/drivers/media/i2c/ov5647.c
> @@ -76,6 +76,7 @@ struct regval_list {
>   struct ov5647_mode {
>   	struct v4l2_mbus_framefmt	format;
>   	struct v4l2_rect		crop;
> +	u64				pixel_rate;
>   	struct regval_list		*reg_list;
>   	unsigned int			num_regs;
>   };
> @@ -97,6 +98,7 @@ struct ov5647 {
>   	struct v4l2_ctrl_handler	ctrls;
>   	struct ov5647_mode		*mode;
>   	struct ov5647_mode		*current_mode;
> +	struct v4l2_ctrl		*pixel_rate;
>   };
>   
>   static inline struct ov5647 *to_sensor(struct v4l2_subdev *sd)
> @@ -583,6 +585,7 @@ static struct ov5647_mode ov5647_sbggr8_modes[] = {
>   			.width		= 1280,
>   			.height		= 960,
>   		},
> +		.pixel_rate	= 77291670,
>   		.reg_list	= ov5647_640x480_sbggr8,
>   		.num_regs	= ARRAY_SIZE(ov5647_640x480_sbggr8)
>   	},
> @@ -604,6 +607,7 @@ static struct ov5647_mode ov5647_sbggr10_modes[] = {
>   			.width		= 2592,
>   			.height		= 1944
>   		},
> +		.pixel_rate	= 87500000,
>   		.reg_list	= ov5647_2592x1944_sbggr10,
>   		.num_regs	= ARRAY_SIZE(ov5647_2592x1944_sbggr10)
>   	},
> @@ -622,6 +626,7 @@ static struct ov5647_mode ov5647_sbggr10_modes[] = {
>   			.width		= 1928,
>   			.height		= 1080,
>   		},
> +		.pixel_rate	= 81666700,
>   		.reg_list	= ov5647_1080p30_sbggr10,
>   		.num_regs	= ARRAY_SIZE(ov5647_1080p30_sbggr10)
>   	},
> @@ -640,6 +645,7 @@ static struct ov5647_mode ov5647_sbggr10_modes[] = {
>   			.width		= 2592,
>   			.height		= 1944,
>   		},
> +		.pixel_rate	= 81666700,
>   		.reg_list	= ov5647_2x2binned_sbggr10,
>   		.num_regs	= ARRAY_SIZE(ov5647_2x2binned_sbggr10)
>   	},
> @@ -658,6 +664,7 @@ static struct ov5647_mode ov5647_sbggr10_modes[] = {
>   			.width		= 2560,
>   			.height		= 1920,
>   		},
> +		.pixel_rate	= 55000000,
>   		.reg_list	= ov5647_640x480_sbggr10,
>   		.num_regs	= ARRAY_SIZE(ov5647_640x480_sbggr10)
>   	},
> @@ -1094,6 +1101,10 @@ static int ov5647_set_pad_fmt(struct v4l2_subdev *sd,
>   	/* Update the sensor mode and apply at it at streamon time. */
>   	mutex_lock(&sensor->lock);
>   	sensor->mode = mode;
> +
> +	__v4l2_ctrl_modify_range(sensor->pixel_rate, mode->pixel_rate,
> +				 mode->pixel_rate, 1, mode->pixel_rate);
> +
>   	*fmt = mode->format;
>   	mutex_unlock(&sensor->lock);
>   
> @@ -1295,6 +1306,9 @@ static int ov5647_s_ctrl(struct v4l2_ctrl *ctrl)
>   		return  ov5647_s_analogue_gain(sd, ctrl->val);
>   	case V4L2_CID_EXPOSURE:
>   		return ov5647_s_exposure(sd, ctrl->val);
> +	case V4L2_CID_PIXEL_RATE:
> +		/* Read-only, but we adjust it based on mode. */

Looking at other drivers, I see they don't handle read only controls
in s_ctrl cb. Also the docs (vidioc-queryctrl.rst) says that trying to set a read only control should
return EINVAL

Thanks,
Dafna

> +		return 0;
>   	default:
>   		dev_info(&client->dev,
>   			 "Control (id:0x%x, val:0x%x) not supported\n",
> @@ -1313,7 +1327,7 @@ static int ov5647_init_controls(struct ov5647 *sensor)
>   {
>   	struct i2c_client *client = v4l2_get_subdevdata(&sensor->sd);
>   
> -	v4l2_ctrl_handler_init(&sensor->ctrls, 5);
> +	v4l2_ctrl_handler_init(&sensor->ctrls, 6);
>   
>   	v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,
>   			  V4L2_CID_AUTOGAIN, 0, 1, 1, 0);
> @@ -1333,17 +1347,29 @@ static int ov5647_init_controls(struct ov5647 *sensor)
>   	v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,
>   			  V4L2_CID_ANALOGUE_GAIN, 16, 1023, 1, 32);
>   
> -	if (sensor->ctrls.error) {
> -		dev_err(&client->dev, "%s Controls initialization failed (%d)\n",
> -			__func__, sensor->ctrls.error);
> -		v4l2_ctrl_handler_free(&sensor->ctrls);
> +	/* By default, PIXEL_RATE is read only, but it does change per mode */
> +	sensor->pixel_rate = v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,
> +					       V4L2_CID_PIXEL_RATE,
> +					       sensor->mode->pixel_rate,
> +					       sensor->mode->pixel_rate, 1,
> +					       sensor->mode->pixel_rate);
> +	if (!sensor->pixel_rate)
> +		goto handler_free;
> +	sensor->pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY;
>   
> -		return sensor->ctrls.error;
> -	}
> +	if (sensor->ctrls.error)
> +		goto handler_free;
>   
>   	sensor->sd.ctrl_handler = &sensor->ctrls;
>   
>   	return 0;
> +
> +handler_free:
> +	dev_err(&client->dev, "%s Controls initialization failed (%d)\n",
> +		__func__, sensor->ctrls.error);
> +	v4l2_ctrl_handler_free(&sensor->ctrls);
> +
> +	return sensor->ctrls.error;
>   }
>   
>   static int ov5647_parse_dt(struct ov5647 *sensor, struct device_node *np)
> 

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

* Re: [PATCH 00/25] media: ov5647: Support RaspberryPi Camera Module v1
  2020-06-23 10:07 [PATCH 00/25] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
                   ` (24 preceding siblings ...)
  2020-06-23 16:55 ` [PATCH 25/25] media: ov5647: Advertise the correct exposure range Jacopo Mondi
@ 2020-06-29 17:33 ` Dafna Hirschfeld
  2020-06-29 18:08   ` Dafna Hirschfeld
  2020-07-10 15:59 ` Dafna Hirschfeld
  26 siblings, 1 reply; 56+ messages in thread
From: Dafna Hirschfeld @ 2020-06-29 17:33 UTC (permalink / raw)
  To: Jacopo Mondi, mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dave.stevenson, naush
  Cc: mrodin, hugues.fruchet, mripard, aford173, sudipi,
	andrew_gabbasov, erosca, linux-media, libcamera-devel,
	dafna Hirschfeld

Hi,
Thanks for the series,

I tried to apply it on master and found out that the set
is rebased on top of the patchset
"dt-bidings: media: ov5647 bindings"
so running 'git am' without the other set fails.
Maybe better to merge the two sets or mention it in the cover letter.

Thanks,
Dafna



On 23.06.20 12:07, Jacopo Mondi wrote:
> -------------------------------------------------------------------------------
> Second attempt after my ISP blocked the part of the first sending.
> Also removed Luis Oliveira email from the receiver list as it gets
> bounced back.
> 550 5.1.1 <lolivei@synopsys.com>... User unknown
> -------------------------------------------------------------------------------
> 
> Hello,
>    this series improves and expand the existing ov5647 sensor driver to
> the same feature level as found in RaspberryPi BSP.
> 
> It is based on recent media tree master and the sensor bindings conversion
> to dt-schema I sent out a few days ago:
> "[PATCH 0/2] dt-bidings: media: ov5647 bindings + small fix"
> 
> The first patches in the series has been sent by Roman as part of
> "[PATCH v2 0/6] ov5647 driver improvement"
> I took his patches in, addressed review comments and rebased on top
> of the new dt-schema bindings. I kept the extensive receiver list he had
> in his series for this reason.
> 
> The series continues by polishing and cleaning up the driver and expanding
> its functionalities to support multiple modes and image formats.
> 
> The series has been tested with libcamera and the driver functionalities
> compared with the BSP driver ones, and tested stand-alone by capturing
> raw frames with yavta.
> 
> Thanks
>     j
> 
> Dave Stevenson (8):
>    media: ov5647: Add support for PWDN GPIO.
>    media: ov5647: Add support for non-continuous clock mode
>    media: ov5647: Add set_fmt and get_fmt calls.
>    media: ov5647: Add support for get_selection()
>    media: ov5647: Set V4L2_SUBDEV_FL_HAS_EVENTS flag
>    media: ov5647: Support V4L2_CID_PIXEL_RATE
>    media: ov5647: Support V4L2_CID_VBLANK control
>    media: ov5647: Advertise the correct exposure range
> 
> David Plowman (1):
>    media: ov5647: Support gain, exposure and AWB controls
> 
> Jacopo Mondi (16):
>    dt-bindings: media: ov5647: Document pwdn-gpios
>    dt-bindings: media: ov5647: Document clock-noncontinuous
>    media: ov5647: Fix format initialization
>    media: ov5647: Fix style issues
>    media: ov5647: Replace license with SPDX identifier
>    media: ov5647: Fix return value from read/write
>    media: ov5647: Program mode at s_stream(1) time
>    media: ov5647: Implement enum_frame_size()
>    media: ov5647: Protect s_stream() with mutex
>    media: ov5647: Rationalize driver structure name
>    media: ov5647: Break out format handling
>    media: ov5647: Rename SBGGR8 VGA mode
>    media: ov5647: Add SGGBR10_1X10 modes
>    media: ov5647: Implement set_fmt pad operation
>    media: ov5647: Program mode only if it has changed
>    media: ov5647: Support V4L2_CID_HBLANK control
> 
>   .../devicetree/bindings/media/i2c/ov5647.yaml |   11 +
>   drivers/media/i2c/ov5647.c                    | 1267 +++++++++++++++--
>   2 files changed, 1126 insertions(+), 152 deletions(-)
> 
> --
> 2.27.0
> 

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

* Re: [PATCH 20/25] media: ov5647: Program mode only if it has changed
  2020-06-23 16:55 ` [PATCH 20/25] media: ov5647: Program mode only if it has changed Jacopo Mondi
@ 2020-06-29 17:48   ` Dafna Hirschfeld
  2020-06-30  7:43     ` Jacopo Mondi
  0 siblings, 1 reply; 56+ messages in thread
From: Dafna Hirschfeld @ 2020-06-29 17:48 UTC (permalink / raw)
  To: Jacopo Mondi, mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dave.stevenson, naush
  Cc: mrodin, hugues.fruchet, mripard, aford173, sudipi,
	andrew_gabbasov, erosca, linux-media, libcamera-devel,
	dafna Hirschfeld



On 23.06.20 18:55, Jacopo Mondi wrote:
> Store in the driver structure a pointer to the currently applied mode
> and program a new one at s_stream(1) time only if it has changed.

Hi,
I think this can be more readably implemented with a 'is_streaming' boolean
field.

Thanks,
Dafna

> 
> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
> ---
>   drivers/media/i2c/ov5647.c | 16 +++++++++++++++-
>   1 file changed, 15 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
> index 39e320f321bd8..ac114269e1c73 100644
> --- a/drivers/media/i2c/ov5647.c
> +++ b/drivers/media/i2c/ov5647.c
> @@ -96,6 +96,7 @@ struct ov5647 {
>   	bool				clock_ncont;
>   	struct v4l2_ctrl_handler	ctrls;
>   	struct ov5647_mode		*mode;
> +	struct ov5647_mode		*current_mode;
>   };
>   
>   static inline struct ov5647 *to_sensor(struct v4l2_subdev *sd)
> @@ -750,9 +751,13 @@ static int ov5647_set_virtual_channel(struct v4l2_subdev *sd, int channel)
>   static int ov5647_set_mode(struct v4l2_subdev *sd)
>   {
>   	struct i2c_client *client = v4l2_get_subdevdata(sd);
> +	struct ov5647 *sensor = to_sensor(sd);
>   	u8 resetval, rdval;
>   	int ret;
>   
> +	if (sensor->mode == sensor->current_mode)
> +		return 0;
> +
>   	ret = ov5647_read(sd, OV5647_SW_STANDBY, &rdval);
>   	if (ret < 0)
>   		return ret;
> @@ -778,6 +783,8 @@ static int ov5647_set_mode(struct v4l2_subdev *sd)
>   			return ret;
>   	}
>   
> +	sensor->current_mode = sensor->mode;
> +
>   	return 0;
>   }
>   
> @@ -816,6 +823,7 @@ static int ov5647_stream_on(struct v4l2_subdev *sd)
>   
>   static int ov5647_stream_off(struct v4l2_subdev *sd)
>   {
> +	struct ov5647 *sensor = to_sensor(sd);
>   	int ret;
>   
>   	ret = ov5647_write(sd, OV5647_REG_MIPI_CTRL00, MIPI_CTRL00_CLOCK_LANE_GATE |
> @@ -827,7 +835,13 @@ static int ov5647_stream_off(struct v4l2_subdev *sd)
>   	if (ret < 0)
>   		return ret;
>   
> -	return ov5647_write(sd, OV5640_REG_PAD_OUT, 0x01);
> +	ret = ov5647_write(sd, OV5640_REG_PAD_OUT, 0x01);
> +	if (ret < 0)
> +		return ret;
> +
> +	sensor->current_mode = NULL;
> +
> +	return 0;
>   }
>   
>   static int set_sw_standby(struct v4l2_subdev *sd, bool standby)
> 

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

* Re: [PATCH 00/25] media: ov5647: Support RaspberryPi Camera Module v1
  2020-06-29 17:33 ` [PATCH 00/25] media: ov5647: Support RaspberryPi Camera Module v1 Dafna Hirschfeld
@ 2020-06-29 18:08   ` Dafna Hirschfeld
  0 siblings, 0 replies; 56+ messages in thread
From: Dafna Hirschfeld @ 2020-06-29 18:08 UTC (permalink / raw)
  To: Jacopo Mondi, mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dave.stevenson, naush
  Cc: mrodin, hugues.fruchet, mripard, aford173, sudipi,
	andrew_gabbasov, erosca, linux-media, libcamera-devel,
	dafna Hirschfeld



On 29.06.20 19:33, Dafna Hirschfeld wrote:
> Hi,
> Thanks for the series,
> 
> I tried to apply it on master and found out that the set
> is rebased on top of the patchset
> "dt-bidings: media: ov5647 bindings"
> so running 'git am' without the other set fails.
> Maybe better to merge the two sets or mention it in the cover letter.
> 
> Thanks,
> Dafna
> 
> 
> 
> On 23.06.20 12:07, Jacopo Mondi wrote:
>> -------------------------------------------------------------------------------
>> Second attempt after my ISP blocked the part of the first sending.
>> Also removed Luis Oliveira email from the receiver list as it gets
>> bounced back.
>> 550 5.1.1 <lolivei@synopsys.com>... User unknown
>> -------------------------------------------------------------------------------
>>
>> Hello,
>>    this series improves and expand the existing ov5647 sensor driver to
>> the same feature level as found in RaspberryPi BSP.
>>
>> It is based on recent media tree master and the sensor bindings conversion
>> to dt-schema I sent out a few days ago:
>> "[PATCH 0/2] dt-bidings: media: ov5647 bindings + small fix"

oops, maybe I should better read the cover letter first,
sorry for the noise,

Thanks,
Dafna

>>
>> The first patches in the series has been sent by Roman as part of
>> "[PATCH v2 0/6] ov5647 driver improvement"
>> I took his patches in, addressed review comments and rebased on top
>> of the new dt-schema bindings. I kept the extensive receiver list he had
>> in his series for this reason.
>>
>> The series continues by polishing and cleaning up the driver and expanding
>> its functionalities to support multiple modes and image formats.
>>
>> The series has been tested with libcamera and the driver functionalities
>> compared with the BSP driver ones, and tested stand-alone by capturing
>> raw frames with yavta.
>>
>> Thanks
>>     j
>>
>> Dave Stevenson (8):
>>    media: ov5647: Add support for PWDN GPIO.
>>    media: ov5647: Add support for non-continuous clock mode
>>    media: ov5647: Add set_fmt and get_fmt calls.
>>    media: ov5647: Add support for get_selection()
>>    media: ov5647: Set V4L2_SUBDEV_FL_HAS_EVENTS flag
>>    media: ov5647: Support V4L2_CID_PIXEL_RATE
>>    media: ov5647: Support V4L2_CID_VBLANK control
>>    media: ov5647: Advertise the correct exposure range
>>
>> David Plowman (1):
>>    media: ov5647: Support gain, exposure and AWB controls
>>
>> Jacopo Mondi (16):
>>    dt-bindings: media: ov5647: Document pwdn-gpios
>>    dt-bindings: media: ov5647: Document clock-noncontinuous
>>    media: ov5647: Fix format initialization
>>    media: ov5647: Fix style issues
>>    media: ov5647: Replace license with SPDX identifier
>>    media: ov5647: Fix return value from read/write
>>    media: ov5647: Program mode at s_stream(1) time
>>    media: ov5647: Implement enum_frame_size()
>>    media: ov5647: Protect s_stream() with mutex
>>    media: ov5647: Rationalize driver structure name
>>    media: ov5647: Break out format handling
>>    media: ov5647: Rename SBGGR8 VGA mode
>>    media: ov5647: Add SGGBR10_1X10 modes
>>    media: ov5647: Implement set_fmt pad operation
>>    media: ov5647: Program mode only if it has changed
>>    media: ov5647: Support V4L2_CID_HBLANK control
>>
>>   .../devicetree/bindings/media/i2c/ov5647.yaml |   11 +
>>   drivers/media/i2c/ov5647.c                    | 1267 +++++++++++++++--
>>   2 files changed, 1126 insertions(+), 152 deletions(-)
>>
>> -- 
>> 2.27.0
>>

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

* Re: [libcamera-devel] [PATCH 22/25] media: ov5647: Support V4L2_CID_PIXEL_RATE
  2020-06-29 17:01   ` [libcamera-devel] " Dafna Hirschfeld
@ 2020-06-29 21:25     ` Dave Stevenson
  2020-06-30 15:13       ` Dave Stevenson
  0 siblings, 1 reply; 56+ messages in thread
From: Dave Stevenson @ 2020-06-29 21:25 UTC (permalink / raw)
  To: Dafna Hirschfeld
  Cc: Jacopo Mondi, Mauro Carvalho Chehab, Sakari Ailus, Hans Verkuil,
	Laurent Pinchart, Roman Kovalivskyi, Dave Stevenson,
	Naushir Patuck, andrew_gabbasov, mrodin, Maxime Ripard,
	libcamera-devel, sudipi, hugues.fruchet, erosca, aford173,
	Linux Media Mailing List

Hi Dafna

On Mon, 29 Jun 2020 at 18:01, Dafna Hirschfeld
<dafna.hirschfeld@collabora.com> wrote:
>
>
>
> On 23.06.20 18:55, Jacopo Mondi wrote:
> > From: Dave Stevenson <dave.stevenson@raspberrypi.com>
> >
> > Clients need to know the pixel rate in order to compute exposure
> > and frame rate values. Advertise it.
> >
> > Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
> > Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
> > ---
> >   drivers/media/i2c/ov5647.c | 40 +++++++++++++++++++++++++++++++-------
> >   1 file changed, 33 insertions(+), 7 deletions(-)
> >
> > diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
> > index 35865e56de5f9..218576a05e66b 100644
> > --- a/drivers/media/i2c/ov5647.c
> > +++ b/drivers/media/i2c/ov5647.c
> > @@ -76,6 +76,7 @@ struct regval_list {
> >   struct ov5647_mode {
> >       struct v4l2_mbus_framefmt       format;
> >       struct v4l2_rect                crop;
> > +     u64                             pixel_rate;
> >       struct regval_list              *reg_list;
> >       unsigned int                    num_regs;
> >   };
> > @@ -97,6 +98,7 @@ struct ov5647 {
> >       struct v4l2_ctrl_handler        ctrls;
> >       struct ov5647_mode              *mode;
> >       struct ov5647_mode              *current_mode;
> > +     struct v4l2_ctrl                *pixel_rate;
> >   };
> >
> >   static inline struct ov5647 *to_sensor(struct v4l2_subdev *sd)
> > @@ -583,6 +585,7 @@ static struct ov5647_mode ov5647_sbggr8_modes[] = {
> >                       .width          = 1280,
> >                       .height         = 960,
> >               },
> > +             .pixel_rate     = 77291670,
> >               .reg_list       = ov5647_640x480_sbggr8,
> >               .num_regs       = ARRAY_SIZE(ov5647_640x480_sbggr8)
> >       },
> > @@ -604,6 +607,7 @@ static struct ov5647_mode ov5647_sbggr10_modes[] = {
> >                       .width          = 2592,
> >                       .height         = 1944
> >               },
> > +             .pixel_rate     = 87500000,
> >               .reg_list       = ov5647_2592x1944_sbggr10,
> >               .num_regs       = ARRAY_SIZE(ov5647_2592x1944_sbggr10)
> >       },
> > @@ -622,6 +626,7 @@ static struct ov5647_mode ov5647_sbggr10_modes[] = {
> >                       .width          = 1928,
> >                       .height         = 1080,
> >               },
> > +             .pixel_rate     = 81666700,
> >               .reg_list       = ov5647_1080p30_sbggr10,
> >               .num_regs       = ARRAY_SIZE(ov5647_1080p30_sbggr10)
> >       },
> > @@ -640,6 +645,7 @@ static struct ov5647_mode ov5647_sbggr10_modes[] = {
> >                       .width          = 2592,
> >                       .height         = 1944,
> >               },
> > +             .pixel_rate     = 81666700,
> >               .reg_list       = ov5647_2x2binned_sbggr10,
> >               .num_regs       = ARRAY_SIZE(ov5647_2x2binned_sbggr10)
> >       },
> > @@ -658,6 +664,7 @@ static struct ov5647_mode ov5647_sbggr10_modes[] = {
> >                       .width          = 2560,
> >                       .height         = 1920,
> >               },
> > +             .pixel_rate     = 55000000,
> >               .reg_list       = ov5647_640x480_sbggr10,
> >               .num_regs       = ARRAY_SIZE(ov5647_640x480_sbggr10)
> >       },
> > @@ -1094,6 +1101,10 @@ static int ov5647_set_pad_fmt(struct v4l2_subdev *sd,
> >       /* Update the sensor mode and apply at it at streamon time. */
> >       mutex_lock(&sensor->lock);
> >       sensor->mode = mode;
> > +
> > +     __v4l2_ctrl_modify_range(sensor->pixel_rate, mode->pixel_rate,
> > +                              mode->pixel_rate, 1, mode->pixel_rate);
> > +
> >       *fmt = mode->format;
> >       mutex_unlock(&sensor->lock);
> >
> > @@ -1295,6 +1306,9 @@ static int ov5647_s_ctrl(struct v4l2_ctrl *ctrl)
> >               return  ov5647_s_analogue_gain(sd, ctrl->val);
> >       case V4L2_CID_EXPOSURE:
> >               return ov5647_s_exposure(sd, ctrl->val);
> > +     case V4L2_CID_PIXEL_RATE:
> > +             /* Read-only, but we adjust it based on mode. */
>
> Looking at other drivers, I see they don't handle read only controls
> in s_ctrl cb. Also the docs (vidioc-queryctrl.rst) says that trying to set a read only control should
> return EINVAL

It was a while ago that I looked at this, but my memory says that
without a handler here then the call to __v4l2_ctrl_modify_range to
update the value failed. The ranges and default were changed, but the
current value wasn't.

Checking now, yes, without returning 0 here,  __v4l2_ctrl_modify_range
returns -22 (-EINVAL) and v4l2-ctl --list-ctrls afterwards shows
Image Processing Controls

                     pixel_rate 0x009f0902 (int64)  : min=87500000
max=87500000 step=1 default=87500000 value=81666700 flags=read-only

A failure of the framework then and needs fixing there, or is it
correct for the driver to have to implement a set hander if it needs
to update the ranges?
A quick grep implies that ov5647 is the first driver that needs to
update V4L2_CID_PIXEL_RATE based on mode. I'll check in the morning if
things like V4L2_CID_HBLANK behave the same - it may be a control type
issue with 64 bit values.


Interesting that the docs say EINVAL as at least one path in the
framework appears to return -EACCES [1]
Checking it:
pi@raspberrypi:~ $ v4l2-ctl --set-ctrl pixel_rate=42
VIDIOC_S_EXT_CTRLS: failed: Permission denied
Error setting controls: Permission denied
which would imply -EACCES

I am testing on a 5.4 kernel rather than media_tree.git, but there
don't appear to be any significant differences in this area between
the two.

Cheers.
  Dave

[1] https://git.linuxtv.org/media_tree.git/tree/drivers/media/v4l2-core/v4l2-ctrls.c#n4224

> Thanks,
> Dafna
>
> > +             return 0;
> >       default:
> >               dev_info(&client->dev,
> >                        "Control (id:0x%x, val:0x%x) not supported\n",
> > @@ -1313,7 +1327,7 @@ static int ov5647_init_controls(struct ov5647 *sensor)
> >   {
> >       struct i2c_client *client = v4l2_get_subdevdata(&sensor->sd);
> >
> > -     v4l2_ctrl_handler_init(&sensor->ctrls, 5);
> > +     v4l2_ctrl_handler_init(&sensor->ctrls, 6);
> >
> >       v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,
> >                         V4L2_CID_AUTOGAIN, 0, 1, 1, 0);
> > @@ -1333,17 +1347,29 @@ static int ov5647_init_controls(struct ov5647 *sensor)
> >       v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,
> >                         V4L2_CID_ANALOGUE_GAIN, 16, 1023, 1, 32);
> >
> > -     if (sensor->ctrls.error) {
> > -             dev_err(&client->dev, "%s Controls initialization failed (%d)\n",
> > -                     __func__, sensor->ctrls.error);
> > -             v4l2_ctrl_handler_free(&sensor->ctrls);
> > +     /* By default, PIXEL_RATE is read only, but it does change per mode */
> > +     sensor->pixel_rate = v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,
> > +                                            V4L2_CID_PIXEL_RATE,
> > +                                            sensor->mode->pixel_rate,
> > +                                            sensor->mode->pixel_rate, 1,
> > +                                            sensor->mode->pixel_rate);
> > +     if (!sensor->pixel_rate)
> > +             goto handler_free;
> > +     sensor->pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY;
> >
> > -             return sensor->ctrls.error;
> > -     }
> > +     if (sensor->ctrls.error)
> > +             goto handler_free;
> >
> >       sensor->sd.ctrl_handler = &sensor->ctrls;
> >
> >       return 0;
> > +
> > +handler_free:
> > +     dev_err(&client->dev, "%s Controls initialization failed (%d)\n",
> > +             __func__, sensor->ctrls.error);
> > +     v4l2_ctrl_handler_free(&sensor->ctrls);
> > +
> > +     return sensor->ctrls.error;
> >   }
> >
> >   static int ov5647_parse_dt(struct ov5647 *sensor, struct device_node *np)
> >
> _______________________________________________
> libcamera-devel mailing list
> libcamera-devel@lists.libcamera.org
> https://lists.libcamera.org/listinfo/libcamera-devel

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

* Re: [PATCH 20/25] media: ov5647: Program mode only if it has changed
  2020-06-29 17:48   ` Dafna Hirschfeld
@ 2020-06-30  7:43     ` Jacopo Mondi
  2020-06-30  9:32       ` Dafna Hirschfeld
  0 siblings, 1 reply; 56+ messages in thread
From: Jacopo Mondi @ 2020-06-30  7:43 UTC (permalink / raw)
  To: Dafna Hirschfeld
  Cc: mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dave.stevenson, naush, mrodin, hugues.fruchet,
	mripard, aford173, sudipi, andrew_gabbasov, erosca, linux-media,
	libcamera-devel, dafna Hirschfeld

Hi Dafna,

On Mon, Jun 29, 2020 at 07:48:16PM +0200, Dafna Hirschfeld wrote:
>
>
> On 23.06.20 18:55, Jacopo Mondi wrote:
> > Store in the driver structure a pointer to the currently applied mode
> > and program a new one at s_stream(1) time only if it has changed.
>
> Hi,
> I think this can be more readably implemented with a 'is_streaming' boolean
> field.

How would you like to use an 'is_streaming' flag to decide if the
sensor mode has to be updated ?

Thanks
   j


>
> Thanks,
> Dafna
>
> >
> > Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
> > ---
> >   drivers/media/i2c/ov5647.c | 16 +++++++++++++++-
> >   1 file changed, 15 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
> > index 39e320f321bd8..ac114269e1c73 100644
> > --- a/drivers/media/i2c/ov5647.c
> > +++ b/drivers/media/i2c/ov5647.c
> > @@ -96,6 +96,7 @@ struct ov5647 {
> >   	bool				clock_ncont;
> >   	struct v4l2_ctrl_handler	ctrls;
> >   	struct ov5647_mode		*mode;
> > +	struct ov5647_mode		*current_mode;
> >   };
> >   static inline struct ov5647 *to_sensor(struct v4l2_subdev *sd)
> > @@ -750,9 +751,13 @@ static int ov5647_set_virtual_channel(struct v4l2_subdev *sd, int channel)
> >   static int ov5647_set_mode(struct v4l2_subdev *sd)
> >   {
> >   	struct i2c_client *client = v4l2_get_subdevdata(sd);
> > +	struct ov5647 *sensor = to_sensor(sd);
> >   	u8 resetval, rdval;
> >   	int ret;
> > +	if (sensor->mode == sensor->current_mode)
> > +		return 0;
> > +
> >   	ret = ov5647_read(sd, OV5647_SW_STANDBY, &rdval);
> >   	if (ret < 0)
> >   		return ret;
> > @@ -778,6 +783,8 @@ static int ov5647_set_mode(struct v4l2_subdev *sd)
> >   			return ret;
> >   	}
> > +	sensor->current_mode = sensor->mode;
> > +
> >   	return 0;
> >   }
> > @@ -816,6 +823,7 @@ static int ov5647_stream_on(struct v4l2_subdev *sd)
> >   static int ov5647_stream_off(struct v4l2_subdev *sd)
> >   {
> > +	struct ov5647 *sensor = to_sensor(sd);
> >   	int ret;
> >   	ret = ov5647_write(sd, OV5647_REG_MIPI_CTRL00, MIPI_CTRL00_CLOCK_LANE_GATE |
> > @@ -827,7 +835,13 @@ static int ov5647_stream_off(struct v4l2_subdev *sd)
> >   	if (ret < 0)
> >   		return ret;
> > -	return ov5647_write(sd, OV5640_REG_PAD_OUT, 0x01);
> > +	ret = ov5647_write(sd, OV5640_REG_PAD_OUT, 0x01);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	sensor->current_mode = NULL;
> > +
> > +	return 0;
> >   }
> >   static int set_sw_standby(struct v4l2_subdev *sd, bool standby)
> >

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

* Re: [PATCH 20/25] media: ov5647: Program mode only if it has changed
  2020-06-30  7:43     ` Jacopo Mondi
@ 2020-06-30  9:32       ` Dafna Hirschfeld
  2020-06-30 10:06         ` Jacopo Mondi
  0 siblings, 1 reply; 56+ messages in thread
From: Dafna Hirschfeld @ 2020-06-30  9:32 UTC (permalink / raw)
  To: Jacopo Mondi
  Cc: mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dave.stevenson, naush, mrodin, hugues.fruchet,
	mripard, aford173, sudipi, andrew_gabbasov, erosca, linux-media,
	libcamera-devel, dafna Hirschfeld



On 30.06.20 09:43, Jacopo Mondi wrote:
> Hi Dafna,
> 
> On Mon, Jun 29, 2020 at 07:48:16PM +0200, Dafna Hirschfeld wrote:
>>
>>
>> On 23.06.20 18:55, Jacopo Mondi wrote:
>>> Store in the driver structure a pointer to the currently applied mode
>>> and program a new one at s_stream(1) time only if it has changed.
>>
>> Hi,
>> I think this can be more readably implemented with a 'is_streaming' boolean
>> field.
> 
> How would you like to use an 'is_streaming' flag to decide if the
> sensor mode has to be updated ?

since 'current_mode' is set to NULL upon `ov5647_stream_off`
and you return from 'ov5647_set_stream' immediately if 'mode == current_mode'
it seem very similar to returning immediately from 'ov5647_set_stream' if the
device is currently streaming.

But actually in this patch it seems to be possible to change the mode
while streaming, if the callbacks are executed:

s_stream(1)
s_fmt
s_stream(1)

which is maybe a bug?

Thanks,
Dafna

> 
> Thanks
>     j
> 
> 
>>
>> Thanks,
>> Dafna
>>
>>>
>>> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
>>> ---
>>>    drivers/media/i2c/ov5647.c | 16 +++++++++++++++-
>>>    1 file changed, 15 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
>>> index 39e320f321bd8..ac114269e1c73 100644
>>> --- a/drivers/media/i2c/ov5647.c
>>> +++ b/drivers/media/i2c/ov5647.c
>>> @@ -96,6 +96,7 @@ struct ov5647 {
>>>    	bool				clock_ncont;
>>>    	struct v4l2_ctrl_handler	ctrls;
>>>    	struct ov5647_mode		*mode;
>>> +	struct ov5647_mode		*current_mode;
>>>    };
>>>    static inline struct ov5647 *to_sensor(struct v4l2_subdev *sd)
>>> @@ -750,9 +751,13 @@ static int ov5647_set_virtual_channel(struct v4l2_subdev *sd, int channel)
>>>    static int ov5647_set_mode(struct v4l2_subdev *sd)
>>>    {
>>>    	struct i2c_client *client = v4l2_get_subdevdata(sd);
>>> +	struct ov5647 *sensor = to_sensor(sd);
>>>    	u8 resetval, rdval;
>>>    	int ret;
>>> +	if (sensor->mode == sensor->current_mode)
>>> +		return 0;
>>> +
>>>    	ret = ov5647_read(sd, OV5647_SW_STANDBY, &rdval);
>>>    	if (ret < 0)
>>>    		return ret;
>>> @@ -778,6 +783,8 @@ static int ov5647_set_mode(struct v4l2_subdev *sd)
>>>    			return ret;
>>>    	}
>>> +	sensor->current_mode = sensor->mode;
>>> +
>>>    	return 0;
>>>    }
>>> @@ -816,6 +823,7 @@ static int ov5647_stream_on(struct v4l2_subdev *sd)
>>>    static int ov5647_stream_off(struct v4l2_subdev *sd)
>>>    {
>>> +	struct ov5647 *sensor = to_sensor(sd);
>>>    	int ret;
>>>    	ret = ov5647_write(sd, OV5647_REG_MIPI_CTRL00, MIPI_CTRL00_CLOCK_LANE_GATE |
>>> @@ -827,7 +835,13 @@ static int ov5647_stream_off(struct v4l2_subdev *sd)
>>>    	if (ret < 0)
>>>    		return ret;
>>> -	return ov5647_write(sd, OV5640_REG_PAD_OUT, 0x01);
>>> +	ret = ov5647_write(sd, OV5640_REG_PAD_OUT, 0x01);
>>> +	if (ret < 0)
>>> +		return ret;
>>> +
>>> +	sensor->current_mode = NULL;
>>> +
>>> +	return 0;
>>>    }
>>>    static int set_sw_standby(struct v4l2_subdev *sd, bool standby)
>>>

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

* Re: [PATCH 20/25] media: ov5647: Program mode only if it has changed
  2020-06-30  9:32       ` Dafna Hirschfeld
@ 2020-06-30 10:06         ` Jacopo Mondi
  2020-06-30 10:56           ` Dafna Hirschfeld
  0 siblings, 1 reply; 56+ messages in thread
From: Jacopo Mondi @ 2020-06-30 10:06 UTC (permalink / raw)
  To: Dafna Hirschfeld
  Cc: mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dave.stevenson, naush, mrodin, hugues.fruchet,
	mripard, aford173, sudipi, andrew_gabbasov, erosca, linux-media,
	libcamera-devel, dafna Hirschfeld

Hi Dafna,

On Tue, Jun 30, 2020 at 11:32:12AM +0200, Dafna Hirschfeld wrote:
>
>
> On 30.06.20 09:43, Jacopo Mondi wrote:
> > Hi Dafna,
> >
> > On Mon, Jun 29, 2020 at 07:48:16PM +0200, Dafna Hirschfeld wrote:
> > >
> > >
> > > On 23.06.20 18:55, Jacopo Mondi wrote:
> > > > Store in the driver structure a pointer to the currently applied mode
> > > > and program a new one at s_stream(1) time only if it has changed.
> > >
> > > Hi,
> > > I think this can be more readably implemented with a 'is_streaming' boolean
> > > field.
> >
> > How would you like to use an 'is_streaming' flag to decide if the
> > sensor mode has to be updated ?
>
> since 'current_mode' is set to NULL upon `ov5647_stream_off`
> and you return from 'ov5647_set_stream' immediately if 'mode == current_mode'
> it seem very similar to returning immediately from 'ov5647_set_stream' if the
> device is currently streaming.

No, the code returns immediately from ov5647_set_mode() if mode ==
current_mode. The modes comparison makes sure the sensor is not
reprogrammed if the mode hasn't changed. The remaning part of
s_stream() is executed regardless of the mode configuration. Am I
missing some part of the picture ?

>
> But actually in this patch it seems to be possible to change the mode
> while streaming, if the callbacks are executed:
>
> s_stream(1)
> s_fmt
> s_stream(1)
>
> which is maybe a bug?

The new format is stored in sensor->mode, and applied at the next
s_stream(1) operation if it differs from the already programmed one,
at least, this is how it is intended to work, have you found any
failing s_stream/set_fmt/s_stream which could be caused by a bug ?

Thanks
  j
>
> Thanks,
> Dafna
>
> >
> > Thanks
> >     j
> >
> >
> > >
> > > Thanks,
> > > Dafna
> > >
> > > >
> > > > Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
> > > > ---
> > > >    drivers/media/i2c/ov5647.c | 16 +++++++++++++++-
> > > >    1 file changed, 15 insertions(+), 1 deletion(-)
> > > >
> > > > diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
> > > > index 39e320f321bd8..ac114269e1c73 100644
> > > > --- a/drivers/media/i2c/ov5647.c
> > > > +++ b/drivers/media/i2c/ov5647.c
> > > > @@ -96,6 +96,7 @@ struct ov5647 {
> > > >    	bool				clock_ncont;
> > > >    	struct v4l2_ctrl_handler	ctrls;
> > > >    	struct ov5647_mode		*mode;
> > > > +	struct ov5647_mode		*current_mode;
> > > >    };
> > > >    static inline struct ov5647 *to_sensor(struct v4l2_subdev *sd)
> > > > @@ -750,9 +751,13 @@ static int ov5647_set_virtual_channel(struct v4l2_subdev *sd, int channel)
> > > >    static int ov5647_set_mode(struct v4l2_subdev *sd)
> > > >    {
> > > >    	struct i2c_client *client = v4l2_get_subdevdata(sd);
> > > > +	struct ov5647 *sensor = to_sensor(sd);
> > > >    	u8 resetval, rdval;
> > > >    	int ret;
> > > > +	if (sensor->mode == sensor->current_mode)
> > > > +		return 0;
> > > > +
> > > >    	ret = ov5647_read(sd, OV5647_SW_STANDBY, &rdval);
> > > >    	if (ret < 0)
> > > >    		return ret;
> > > > @@ -778,6 +783,8 @@ static int ov5647_set_mode(struct v4l2_subdev *sd)
> > > >    			return ret;
> > > >    	}
> > > > +	sensor->current_mode = sensor->mode;
> > > > +
> > > >    	return 0;
> > > >    }
> > > > @@ -816,6 +823,7 @@ static int ov5647_stream_on(struct v4l2_subdev *sd)
> > > >    static int ov5647_stream_off(struct v4l2_subdev *sd)
> > > >    {
> > > > +	struct ov5647 *sensor = to_sensor(sd);
> > > >    	int ret;
> > > >    	ret = ov5647_write(sd, OV5647_REG_MIPI_CTRL00, MIPI_CTRL00_CLOCK_LANE_GATE |
> > > > @@ -827,7 +835,13 @@ static int ov5647_stream_off(struct v4l2_subdev *sd)
> > > >    	if (ret < 0)
> > > >    		return ret;
> > > > -	return ov5647_write(sd, OV5640_REG_PAD_OUT, 0x01);
> > > > +	ret = ov5647_write(sd, OV5640_REG_PAD_OUT, 0x01);
> > > > +	if (ret < 0)
> > > > +		return ret;
> > > > +
> > > > +	sensor->current_mode = NULL;
> > > > +
> > > > +	return 0;
> > > >    }
> > > >    static int set_sw_standby(struct v4l2_subdev *sd, bool standby)
> > > >

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

* Re: [libcamera-devel] [PATCH 19/25] media: ov5647: Implement set_fmt pad operation
  2020-06-29 16:54   ` [libcamera-devel] " Dafna Hirschfeld
@ 2020-06-30 10:13     ` Jacopo Mondi
  2020-06-30 11:09       ` Dafna Hirschfeld
  0 siblings, 1 reply; 56+ messages in thread
From: Jacopo Mondi @ 2020-06-30 10:13 UTC (permalink / raw)
  To: Dafna Hirschfeld
  Cc: mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dave.stevenson, naush, andrew_gabbasov,
	mrodin, mripard, libcamera-devel, sudipi, hugues.fruchet, erosca,
	aford173, linux-media

Hi Dafna,

On Mon, Jun 29, 2020 at 06:54:43PM +0200, Dafna Hirschfeld wrote:
>
>
> On 23.06.20 18:49, Jacopo Mondi wrote:
> > Now that the driver supports more than a single mode, implement the
> > .set_fmt pad operation and adjust the existing .get_fmt one to report
> > the currently applied format.
> >
> > Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
> > ---
> >   drivers/media/i2c/ov5647.c | 67 +++++++++++++++++++++++++++++++++++---
> >   1 file changed, 62 insertions(+), 5 deletions(-)
> >
> > diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
> > index af9e6d43967d8..39e320f321bd8 100644
> > --- a/drivers/media/i2c/ov5647.c
> > +++ b/drivers/media/i2c/ov5647.c
> > @@ -1016,15 +1016,72 @@ static int ov5647_enum_frame_size(struct v4l2_subdev *sd,
> >   	return 0;
> >   }
> > -static int ov5647_set_get_fmt(struct v4l2_subdev *sd,
> > +static int ov5647_get_pad_fmt(struct v4l2_subdev *sd,
> >   			      struct v4l2_subdev_pad_config *cfg,
> >   			      struct v4l2_subdev_format *format)
> >   {
> >   	struct v4l2_mbus_framefmt *fmt = &format->format;
> > +	struct v4l2_mbus_framefmt *sensor_format;
> > +	struct ov5647 *sensor = to_sensor(sd);
> > -	/* Only one format is supported, so return that. */
> > +	mutex_lock(&sensor->lock);
> >   	memset(fmt, 0, sizeof(*fmt));
> > -	*fmt = OV5647_DEFAULT_FORMAT;
> > +
> > +	switch (format->which) {
> > +	case V4L2_SUBDEV_FORMAT_TRY:
> > +		sensor_format = v4l2_subdev_get_try_format(sd, cfg, format->pad);
> > +		break;
> > +	default:
> > +		sensor_format = &sensor->mode->format;
> > +		break;
> > +	}
> > +
> > +	*fmt = *sensor_format;
> > +	mutex_unlock(&sensor->lock);
> > +
> > +	return 0;
> > +}
> > +
> > +static int ov5647_set_pad_fmt(struct v4l2_subdev *sd,
> > +			      struct v4l2_subdev_pad_config *cfg,
> > +			      struct v4l2_subdev_format *format)
> > +{
> > +	struct v4l2_mbus_framefmt *fmt = &format->format;
> > +	struct ov5647 *sensor = to_sensor(sd);
> > +	struct ov5647_mode *ov5647_mode_list;
> > +	struct ov5647_mode *mode;
> > +	unsigned int num_modes;
> > +
> > +	/*
> > +	 * Default mbus code MEDIA_BUS_FMT_SBGGR10_1X10 if the requested one
> > +	 * is not supported.
>
> In previous patch you added macros OV5647_DEFAULT_MODE, OV5647_DEFAULT_FORMAT
> which comes from first format in the array 'ov5647_formats' which is MEDIA_BUS_FMT_SBGGR8_1X8.

Oh well, that's just an arbitrary selection of the format the sensor
is initialized with.

> But here you set the default format to MEDIA_BUS_FMT_SBGGR10_1X10
>

I chose the _1x10 version as it supports more resolution than the _1X8
one. The v4l2-spec says if the requested format is not supported the
closed possible match should be reported. It is easy to identify what
a closes possible match is when considering the image size, but for image
formats the "closes possible match" might be tricky to define.

I can change the sensor initial default state if you think that's the
case, but I don't think the initial configuration and the adjusted format
returned from s_stream() should be considered related. Do you agree or
is there any part of the specs I'm overlooking ?

Thanks
  j


> > +	 */
> > +	if (fmt->code == MEDIA_BUS_FMT_SBGGR8_1X8) {
> > +		ov5647_mode_list = ov5647_sbggr8_modes;
> > +		num_modes = ARRAY_SIZE(ov5647_sbggr8_modes);
> > +	} else {
> > +		ov5647_mode_list = ov5647_sbggr10_modes;
> > +		num_modes = ARRAY_SIZE(ov5647_sbggr10_modes);
> > +	}
> > +
> > +	mode = v4l2_find_nearest_size(ov5647_mode_list, num_modes,
> > +				      format.width, format.height,
> > +				      fmt->width, fmt->height);
> > +
> > +	if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
> > +		mutex_lock(&sensor->lock);
> > +		*v4l2_subdev_get_try_format(sd, cfg, format->pad) = mode->format;
> > +		*fmt = mode->format;
> > +		mutex_unlock(&sensor->lock);
> > +
> > +		return 0;
> > +	}
> > +
> > +	/* Update the sensor mode and apply at it at streamon time. */
> > +	mutex_lock(&sensor->lock);
> > +	sensor->mode = mode;
> > +	*fmt = mode->format;
> > +	mutex_unlock(&sensor->lock);
> >   	return 0;
> >   }
> > @@ -1068,8 +1125,8 @@ static int ov5647_get_selection(struct v4l2_subdev *sd,
> >   static const struct v4l2_subdev_pad_ops ov5647_subdev_pad_ops = {
> >   	.enum_mbus_code		= ov5647_enum_mbus_code,
> >   	.enum_frame_size	= ov5647_enum_frame_size,
> > -	.set_fmt		= ov5647_set_get_fmt,
> > -	.get_fmt		= ov5647_set_get_fmt,
> > +	.set_fmt		= ov5647_set_pad_fmt,
> > +	.get_fmt		= ov5647_get_pad_fmt,
> >   	.get_selection		= ov5647_get_selection,
> >   };
> >

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

* Re: [PATCH 20/25] media: ov5647: Program mode only if it has changed
  2020-06-30 10:06         ` Jacopo Mondi
@ 2020-06-30 10:56           ` Dafna Hirschfeld
  2020-06-30 12:05             ` Jacopo Mondi
  0 siblings, 1 reply; 56+ messages in thread
From: Dafna Hirschfeld @ 2020-06-30 10:56 UTC (permalink / raw)
  To: Jacopo Mondi
  Cc: mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dave.stevenson, naush, mrodin, hugues.fruchet,
	mripard, aford173, sudipi, andrew_gabbasov, erosca, linux-media,
	libcamera-devel, dafna Hirschfeld



On 30.06.20 12:06, Jacopo Mondi wrote:
> Hi Dafna,
> 
> On Tue, Jun 30, 2020 at 11:32:12AM +0200, Dafna Hirschfeld wrote:
>>
>>
>> On 30.06.20 09:43, Jacopo Mondi wrote:
>>> Hi Dafna,
>>>
>>> On Mon, Jun 29, 2020 at 07:48:16PM +0200, Dafna Hirschfeld wrote:
>>>>
>>>>
>>>> On 23.06.20 18:55, Jacopo Mondi wrote:
>>>>> Store in the driver structure a pointer to the currently applied mode
>>>>> and program a new one at s_stream(1) time only if it has changed.
>>>>
>>>> Hi,
>>>> I think this can be more readably implemented with a 'is_streaming' boolean
>>>> field.
>>>
>>> How would you like to use an 'is_streaming' flag to decide if the
>>> sensor mode has to be updated ?
>>
>> since 'current_mode' is set to NULL upon `ov5647_stream_off`
>> and you return from 'ov5647_set_stream' immediately if 'mode == current_mode'
>> it seem very similar to returning immediately from 'ov5647_set_stream' if the
>> device is currently streaming.
> 
> No, the code returns immediately from ov5647_set_mode() if mode ==
> current_mode. The modes comparison makes sure the sensor is not
> reprogrammed if the mode hasn't changed. The remaning part of
> s_stream() is executed regardless of the mode configuration. Am I
> missing some part of the picture ?
> 
>>
>> But actually in this patch it seems to be possible to change the mode
>> while streaming, if the callbacks are executed:
>>
>> s_stream(1)
>> s_fmt
>> s_stream(1)
>>
>> which is maybe a bug?
> 
> The new format is stored in sensor->mode, and applied at the next
> s_stream(1) operation if it differs from the already programmed one,
> at least, this is how it is intended to work, have you found any
> failing s_stream/set_fmt/s_stream which could be caused by a bug ?

What I meant is that there could be valid sequence of calls

s_stream(enable=1)
s_fmt
s_stream(enable=1)

For example if two video devices are connected to the sensor and they
stream simultaneously. There was a discussion about adding a code to the core
to follow the s_stream callback and call it only if the subdev is not streaming
but currently subdevs should support it themselves.


Thanks,
Dafna

> 
> Thanks
>    j
>>
>> Thanks,
>> Dafna
>>
>>>
>>> Thanks
>>>      j
>>>
>>>
>>>>
>>>> Thanks,
>>>> Dafna
>>>>
>>>>>
>>>>> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
>>>>> ---
>>>>>     drivers/media/i2c/ov5647.c | 16 +++++++++++++++-
>>>>>     1 file changed, 15 insertions(+), 1 deletion(-)
>>>>>
>>>>> diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
>>>>> index 39e320f321bd8..ac114269e1c73 100644
>>>>> --- a/drivers/media/i2c/ov5647.c
>>>>> +++ b/drivers/media/i2c/ov5647.c
>>>>> @@ -96,6 +96,7 @@ struct ov5647 {
>>>>>     	bool				clock_ncont;
>>>>>     	struct v4l2_ctrl_handler	ctrls;
>>>>>     	struct ov5647_mode		*mode;
>>>>> +	struct ov5647_mode		*current_mode;
>>>>>     };
>>>>>     static inline struct ov5647 *to_sensor(struct v4l2_subdev *sd)
>>>>> @@ -750,9 +751,13 @@ static int ov5647_set_virtual_channel(struct v4l2_subdev *sd, int channel)
>>>>>     static int ov5647_set_mode(struct v4l2_subdev *sd)
>>>>>     {
>>>>>     	struct i2c_client *client = v4l2_get_subdevdata(sd);
>>>>> +	struct ov5647 *sensor = to_sensor(sd);
>>>>>     	u8 resetval, rdval;
>>>>>     	int ret;
>>>>> +	if (sensor->mode == sensor->current_mode)
>>>>> +		return 0;
>>>>> +
>>>>>     	ret = ov5647_read(sd, OV5647_SW_STANDBY, &rdval);
>>>>>     	if (ret < 0)
>>>>>     		return ret;
>>>>> @@ -778,6 +783,8 @@ static int ov5647_set_mode(struct v4l2_subdev *sd)
>>>>>     			return ret;
>>>>>     	}
>>>>> +	sensor->current_mode = sensor->mode;
>>>>> +
>>>>>     	return 0;
>>>>>     }
>>>>> @@ -816,6 +823,7 @@ static int ov5647_stream_on(struct v4l2_subdev *sd)
>>>>>     static int ov5647_stream_off(struct v4l2_subdev *sd)
>>>>>     {
>>>>> +	struct ov5647 *sensor = to_sensor(sd);
>>>>>     	int ret;
>>>>>     	ret = ov5647_write(sd, OV5647_REG_MIPI_CTRL00, MIPI_CTRL00_CLOCK_LANE_GATE |
>>>>> @@ -827,7 +835,13 @@ static int ov5647_stream_off(struct v4l2_subdev *sd)
>>>>>     	if (ret < 0)
>>>>>     		return ret;
>>>>> -	return ov5647_write(sd, OV5640_REG_PAD_OUT, 0x01);
>>>>> +	ret = ov5647_write(sd, OV5640_REG_PAD_OUT, 0x01);
>>>>> +	if (ret < 0)
>>>>> +		return ret;
>>>>> +
>>>>> +	sensor->current_mode = NULL;
>>>>> +
>>>>> +	return 0;
>>>>>     }
>>>>>     static int set_sw_standby(struct v4l2_subdev *sd, bool standby)
>>>>>

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

* Re: [libcamera-devel] [PATCH 19/25] media: ov5647: Implement set_fmt pad operation
  2020-06-30 10:13     ` Jacopo Mondi
@ 2020-06-30 11:09       ` Dafna Hirschfeld
  0 siblings, 0 replies; 56+ messages in thread
From: Dafna Hirschfeld @ 2020-06-30 11:09 UTC (permalink / raw)
  To: Jacopo Mondi
  Cc: mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dave.stevenson, naush, andrew_gabbasov,
	mrodin, mripard, libcamera-devel, sudipi, hugues.fruchet, erosca,
	aford173, linux-media



On 30.06.20 12:13, Jacopo Mondi wrote:
> Hi Dafna,
> 
> On Mon, Jun 29, 2020 at 06:54:43PM +0200, Dafna Hirschfeld wrote:
>>
>>
>> On 23.06.20 18:49, Jacopo Mondi wrote:
>>> Now that the driver supports more than a single mode, implement the
>>> .set_fmt pad operation and adjust the existing .get_fmt one to report
>>> the currently applied format.
>>>
>>> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
>>> ---
>>>    drivers/media/i2c/ov5647.c | 67 +++++++++++++++++++++++++++++++++++---
>>>    1 file changed, 62 insertions(+), 5 deletions(-)
>>>
>>> diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
>>> index af9e6d43967d8..39e320f321bd8 100644
>>> --- a/drivers/media/i2c/ov5647.c
>>> +++ b/drivers/media/i2c/ov5647.c
>>> @@ -1016,15 +1016,72 @@ static int ov5647_enum_frame_size(struct v4l2_subdev *sd,
>>>    	return 0;
>>>    }
>>> -static int ov5647_set_get_fmt(struct v4l2_subdev *sd,
>>> +static int ov5647_get_pad_fmt(struct v4l2_subdev *sd,
>>>    			      struct v4l2_subdev_pad_config *cfg,
>>>    			      struct v4l2_subdev_format *format)
>>>    {
>>>    	struct v4l2_mbus_framefmt *fmt = &format->format;
>>> +	struct v4l2_mbus_framefmt *sensor_format;
>>> +	struct ov5647 *sensor = to_sensor(sd);
>>> -	/* Only one format is supported, so return that. */
>>> +	mutex_lock(&sensor->lock);
>>>    	memset(fmt, 0, sizeof(*fmt));
>>> -	*fmt = OV5647_DEFAULT_FORMAT;
>>> +
>>> +	switch (format->which) {
>>> +	case V4L2_SUBDEV_FORMAT_TRY:
>>> +		sensor_format = v4l2_subdev_get_try_format(sd, cfg, format->pad);
>>> +		break;
>>> +	default:
>>> +		sensor_format = &sensor->mode->format;
>>> +		break;
>>> +	}
>>> +
>>> +	*fmt = *sensor_format;
>>> +	mutex_unlock(&sensor->lock);
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static int ov5647_set_pad_fmt(struct v4l2_subdev *sd,
>>> +			      struct v4l2_subdev_pad_config *cfg,
>>> +			      struct v4l2_subdev_format *format)
>>> +{
>>> +	struct v4l2_mbus_framefmt *fmt = &format->format;
>>> +	struct ov5647 *sensor = to_sensor(sd);
>>> +	struct ov5647_mode *ov5647_mode_list;
>>> +	struct ov5647_mode *mode;
>>> +	unsigned int num_modes;
>>> +
>>> +	/*
>>> +	 * Default mbus code MEDIA_BUS_FMT_SBGGR10_1X10 if the requested one
>>> +	 * is not supported.
>>
>> In previous patch you added macros OV5647_DEFAULT_MODE, OV5647_DEFAULT_FORMAT
>> which comes from first format in the array 'ov5647_formats' which is MEDIA_BUS_FMT_SBGGR8_1X8.
> 
> Oh well, that's just an arbitrary selection of the format the sensor
> is initialized with.
> 
>> But here you set the default format to MEDIA_BUS_FMT_SBGGR10_1X10
>>
> 
> I chose the _1x10 version as it supports more resolution than the _1X8
> one. The v4l2-spec says if the requested format is not supported the
> closed possible match should be reported. It is easy to identify what
> a closes possible match is when considering the image size, but for image
> formats the "closes possible match" might be tricky to define.
> 
> I can change the sensor initial default state if you think that's the
> case, but I don't think the initial configuration and the adjusted format
> returned from s_stream() should be considered related. Do you agree or
> is there any part of the specs I'm overlooking ?

I also don't see it in the spec, but I think it is nicer that
s_fmt default to the initial value. This is also the first value
returned in the enumeration.

Thanks,
    d

> 
> Thanks
>    j
> 
> 
>>> +	 */
>>> +	if (fmt->code == MEDIA_BUS_FMT_SBGGR8_1X8) {
>>> +		ov5647_mode_list = ov5647_sbggr8_modes;
>>> +		num_modes = ARRAY_SIZE(ov5647_sbggr8_modes);
>>> +	} else {
>>> +		ov5647_mode_list = ov5647_sbggr10_modes;
>>> +		num_modes = ARRAY_SIZE(ov5647_sbggr10_modes);
>>> +	}
>>> +
>>> +	mode = v4l2_find_nearest_size(ov5647_mode_list, num_modes,
>>> +				      format.width, format.height,
>>> +				      fmt->width, fmt->height);
>>> +
>>> +	if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
>>> +		mutex_lock(&sensor->lock);
>>> +		*v4l2_subdev_get_try_format(sd, cfg, format->pad) = mode->format;
>>> +		*fmt = mode->format;
>>> +		mutex_unlock(&sensor->lock);
>>> +
>>> +		return 0;
>>> +	}
>>> +
>>> +	/* Update the sensor mode and apply at it at streamon time. */
>>> +	mutex_lock(&sensor->lock);
>>> +	sensor->mode = mode;
>>> +	*fmt = mode->format;
>>> +	mutex_unlock(&sensor->lock);
>>>    	return 0;
>>>    }
>>> @@ -1068,8 +1125,8 @@ static int ov5647_get_selection(struct v4l2_subdev *sd,
>>>    static const struct v4l2_subdev_pad_ops ov5647_subdev_pad_ops = {
>>>    	.enum_mbus_code		= ov5647_enum_mbus_code,
>>>    	.enum_frame_size	= ov5647_enum_frame_size,
>>> -	.set_fmt		= ov5647_set_get_fmt,
>>> -	.get_fmt		= ov5647_set_get_fmt,
>>> +	.set_fmt		= ov5647_set_pad_fmt,
>>> +	.get_fmt		= ov5647_get_pad_fmt,
>>>    	.get_selection		= ov5647_get_selection,
>>>    };
>>>

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

* Re: [PATCH 20/25] media: ov5647: Program mode only if it has changed
  2020-06-30 10:56           ` Dafna Hirschfeld
@ 2020-06-30 12:05             ` Jacopo Mondi
  2020-06-30 13:01               ` Dafna Hirschfeld
  0 siblings, 1 reply; 56+ messages in thread
From: Jacopo Mondi @ 2020-06-30 12:05 UTC (permalink / raw)
  To: Dafna Hirschfeld
  Cc: mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dave.stevenson, naush, mrodin, hugues.fruchet,
	mripard, aford173, sudipi, andrew_gabbasov, erosca, linux-media,
	libcamera-devel, dafna Hirschfeld

Hi Dafna,

On Tue, Jun 30, 2020 at 12:56:44PM +0200, Dafna Hirschfeld wrote:
>
>
> On 30.06.20 12:06, Jacopo Mondi wrote:
> > Hi Dafna,
> >
> > On Tue, Jun 30, 2020 at 11:32:12AM +0200, Dafna Hirschfeld wrote:
> > >
> > >
> > > On 30.06.20 09:43, Jacopo Mondi wrote:
> > > > Hi Dafna,
> > > >
> > > > On Mon, Jun 29, 2020 at 07:48:16PM +0200, Dafna Hirschfeld wrote:
> > > > >
> > > > >
> > > > > On 23.06.20 18:55, Jacopo Mondi wrote:
> > > > > > Store in the driver structure a pointer to the currently applied mode
> > > > > > and program a new one at s_stream(1) time only if it has changed.
> > > > >
> > > > > Hi,
> > > > > I think this can be more readably implemented with a 'is_streaming' boolean
> > > > > field.
> > > >
> > > > How would you like to use an 'is_streaming' flag to decide if the
> > > > sensor mode has to be updated ?
> > >
> > > since 'current_mode' is set to NULL upon `ov5647_stream_off`
> > > and you return from 'ov5647_set_stream' immediately if 'mode == current_mode'
> > > it seem very similar to returning immediately from 'ov5647_set_stream' if the
> > > device is currently streaming.
> >
> > No, the code returns immediately from ov5647_set_mode() if mode ==
> > current_mode. The modes comparison makes sure the sensor is not
> > reprogrammed if the mode hasn't changed. The remaning part of
> > s_stream() is executed regardless of the mode configuration. Am I
> > missing some part of the picture ?
> >
> > >
> > > But actually in this patch it seems to be possible to change the mode
> > > while streaming, if the callbacks are executed:
> > >
> > > s_stream(1)
> > > s_fmt
> > > s_stream(1)
> > >
> > > which is maybe a bug?
> >
> > The new format is stored in sensor->mode, and applied at the next
> > s_stream(1) operation if it differs from the already programmed one,
> > at least, this is how it is intended to work, have you found any
> > failing s_stream/set_fmt/s_stream which could be caused by a bug ?
>
> What I meant is that there could be valid sequence of calls
>
> s_stream(enable=1)
> s_fmt
> s_stream(enable=1)
>
> For example if two video devices are connected to the sensor and they
> stream simultaneously. There was a discussion about adding a code to the core

I'm not sure it is possible, given that the subdev has a single source
pad

> to follow the s_stream callback and call it only if the subdev is not streaming
> but currently subdevs should support it themselves.
>

Oh, so you're concerned about the fact userspace can call s_stream(1)
twice consecutively! it's indipendent from s_ftm if I got your point.

In this case a flag to control if the device is streaming already should
help, yes, I overlooked that indeed.

Thanks
  j

>
> Thanks,
> Dafna
>
> >
> > Thanks
> >    j
> > >
> > > Thanks,
> > > Dafna
> > >
> > > >
> > > > Thanks
> > > >      j
> > > >
> > > >
> > > > >
> > > > > Thanks,
> > > > > Dafna
> > > > >
> > > > > >
> > > > > > Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
> > > > > > ---
> > > > > >     drivers/media/i2c/ov5647.c | 16 +++++++++++++++-
> > > > > >     1 file changed, 15 insertions(+), 1 deletion(-)
> > > > > >
> > > > > > diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
> > > > > > index 39e320f321bd8..ac114269e1c73 100644
> > > > > > --- a/drivers/media/i2c/ov5647.c
> > > > > > +++ b/drivers/media/i2c/ov5647.c
> > > > > > @@ -96,6 +96,7 @@ struct ov5647 {
> > > > > >     	bool				clock_ncont;
> > > > > >     	struct v4l2_ctrl_handler	ctrls;
> > > > > >     	struct ov5647_mode		*mode;
> > > > > > +	struct ov5647_mode		*current_mode;
> > > > > >     };
> > > > > >     static inline struct ov5647 *to_sensor(struct v4l2_subdev *sd)
> > > > > > @@ -750,9 +751,13 @@ static int ov5647_set_virtual_channel(struct v4l2_subdev *sd, int channel)
> > > > > >     static int ov5647_set_mode(struct v4l2_subdev *sd)
> > > > > >     {
> > > > > >     	struct i2c_client *client = v4l2_get_subdevdata(sd);
> > > > > > +	struct ov5647 *sensor = to_sensor(sd);
> > > > > >     	u8 resetval, rdval;
> > > > > >     	int ret;
> > > > > > +	if (sensor->mode == sensor->current_mode)
> > > > > > +		return 0;
> > > > > > +
> > > > > >     	ret = ov5647_read(sd, OV5647_SW_STANDBY, &rdval);
> > > > > >     	if (ret < 0)
> > > > > >     		return ret;
> > > > > > @@ -778,6 +783,8 @@ static int ov5647_set_mode(struct v4l2_subdev *sd)
> > > > > >     			return ret;
> > > > > >     	}
> > > > > > +	sensor->current_mode = sensor->mode;
> > > > > > +
> > > > > >     	return 0;
> > > > > >     }
> > > > > > @@ -816,6 +823,7 @@ static int ov5647_stream_on(struct v4l2_subdev *sd)
> > > > > >     static int ov5647_stream_off(struct v4l2_subdev *sd)
> > > > > >     {
> > > > > > +	struct ov5647 *sensor = to_sensor(sd);
> > > > > >     	int ret;
> > > > > >     	ret = ov5647_write(sd, OV5647_REG_MIPI_CTRL00, MIPI_CTRL00_CLOCK_LANE_GATE |
> > > > > > @@ -827,7 +835,13 @@ static int ov5647_stream_off(struct v4l2_subdev *sd)
> > > > > >     	if (ret < 0)
> > > > > >     		return ret;
> > > > > > -	return ov5647_write(sd, OV5640_REG_PAD_OUT, 0x01);
> > > > > > +	ret = ov5647_write(sd, OV5640_REG_PAD_OUT, 0x01);
> > > > > > +	if (ret < 0)
> > > > > > +		return ret;
> > > > > > +
> > > > > > +	sensor->current_mode = NULL;
> > > > > > +
> > > > > > +	return 0;
> > > > > >     }
> > > > > >     static int set_sw_standby(struct v4l2_subdev *sd, bool standby)
> > > > > >

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

* Re: [PATCH 20/25] media: ov5647: Program mode only if it has changed
  2020-06-30 12:05             ` Jacopo Mondi
@ 2020-06-30 13:01               ` Dafna Hirschfeld
  2020-06-30 14:53                 ` [libcamera-devel] " Dave Stevenson
  2020-07-01  7:25                 ` Laurent Pinchart
  0 siblings, 2 replies; 56+ messages in thread
From: Dafna Hirschfeld @ 2020-06-30 13:01 UTC (permalink / raw)
  To: Jacopo Mondi
  Cc: mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dave.stevenson, naush, mrodin, hugues.fruchet,
	mripard, aford173, sudipi, andrew_gabbasov, erosca, linux-media,
	libcamera-devel, dafna Hirschfeld

Hi,


On 30.06.20 14:05, Jacopo Mondi wrote:
> Hi Dafna,
> 
> On Tue, Jun 30, 2020 at 12:56:44PM +0200, Dafna Hirschfeld wrote:
>>
>>
>> On 30.06.20 12:06, Jacopo Mondi wrote:
>>> Hi Dafna,
>>>
>>> On Tue, Jun 30, 2020 at 11:32:12AM +0200, Dafna Hirschfeld wrote:
>>>>
>>>>
>>>> On 30.06.20 09:43, Jacopo Mondi wrote:
>>>>> Hi Dafna,
>>>>>
>>>>> On Mon, Jun 29, 2020 at 07:48:16PM +0200, Dafna Hirschfeld wrote:
>>>>>>
>>>>>>
>>>>>> On 23.06.20 18:55, Jacopo Mondi wrote:
>>>>>>> Store in the driver structure a pointer to the currently applied mode
>>>>>>> and program a new one at s_stream(1) time only if it has changed.
>>>>>>
>>>>>> Hi,
>>>>>> I think this can be more readably implemented with a 'is_streaming' boolean
>>>>>> field.
>>>>>
>>>>> How would you like to use an 'is_streaming' flag to decide if the
>>>>> sensor mode has to be updated ?
>>>>
>>>> since 'current_mode' is set to NULL upon `ov5647_stream_off`
>>>> and you return from 'ov5647_set_stream' immediately if 'mode == current_mode'
>>>> it seem very similar to returning immediately from 'ov5647_set_stream' if the
>>>> device is currently streaming.
>>>
>>> No, the code returns immediately from ov5647_set_mode() if mode ==
>>> current_mode. The modes comparison makes sure the sensor is not
>>> reprogrammed if the mode hasn't changed. The remaning part of
>>> s_stream() is executed regardless of the mode configuration. Am I
>>> missing some part of the picture ?
>>>
>>>>
>>>> But actually in this patch it seems to be possible to change the mode
>>>> while streaming, if the callbacks are executed:
>>>>
>>>> s_stream(1)
>>>> s_fmt
>>>> s_stream(1)
>>>>
>>>> which is maybe a bug?
>>>
>>> The new format is stored in sensor->mode, and applied at the next
>>> s_stream(1) operation if it differs from the already programmed one,
>>> at least, this is how it is intended to work, have you found any
>>> failing s_stream/set_fmt/s_stream which could be caused by a bug ?
>>
>> What I meant is that there could be valid sequence of calls
>>
>> s_stream(enable=1)
>> s_fmt
>> s_stream(enable=1)
>>
>> For example if two video devices are connected to the sensor and they
>> stream simultaneously. There was a discussion about adding a code to the core
> 
> I'm not sure it is possible, given that the subdev has a single source
> pad

Video devices should not be connected directly to the sensor, they can also
be connected to the sensor through an isp entity that is connected to the sensor
from one side and to two video devices from the other side.

Thanks,
D

> 
>> to follow the s_stream callback and call it only if the subdev is not streaming
>> but currently subdevs should support it themselves.
>>
> 
> Oh, so you're concerned about the fact userspace can call s_stream(1)
> twice consecutively! it's indipendent from s_ftm if I got your point.
> 
> In this case a flag to control if the device is streaming already should
> help, yes, I overlooked that indeed.
> 
> Thanks
>    j
> 
>>
>> Thanks,
>> Dafna
>>
>>>
>>> Thanks
>>>     j
>>>>
>>>> Thanks,
>>>> Dafna
>>>>
>>>>>
>>>>> Thanks
>>>>>       j
>>>>>
>>>>>
>>>>>>
>>>>>> Thanks,
>>>>>> Dafna
>>>>>>
>>>>>>>
>>>>>>> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
>>>>>>> ---
>>>>>>>      drivers/media/i2c/ov5647.c | 16 +++++++++++++++-
>>>>>>>      1 file changed, 15 insertions(+), 1 deletion(-)
>>>>>>>
>>>>>>> diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
>>>>>>> index 39e320f321bd8..ac114269e1c73 100644
>>>>>>> --- a/drivers/media/i2c/ov5647.c
>>>>>>> +++ b/drivers/media/i2c/ov5647.c
>>>>>>> @@ -96,6 +96,7 @@ struct ov5647 {
>>>>>>>      	bool				clock_ncont;
>>>>>>>      	struct v4l2_ctrl_handler	ctrls;
>>>>>>>      	struct ov5647_mode		*mode;
>>>>>>> +	struct ov5647_mode		*current_mode;
>>>>>>>      };
>>>>>>>      static inline struct ov5647 *to_sensor(struct v4l2_subdev *sd)
>>>>>>> @@ -750,9 +751,13 @@ static int ov5647_set_virtual_channel(struct v4l2_subdev *sd, int channel)
>>>>>>>      static int ov5647_set_mode(struct v4l2_subdev *sd)
>>>>>>>      {
>>>>>>>      	struct i2c_client *client = v4l2_get_subdevdata(sd);
>>>>>>> +	struct ov5647 *sensor = to_sensor(sd);
>>>>>>>      	u8 resetval, rdval;
>>>>>>>      	int ret;
>>>>>>> +	if (sensor->mode == sensor->current_mode)
>>>>>>> +		return 0;
>>>>>>> +
>>>>>>>      	ret = ov5647_read(sd, OV5647_SW_STANDBY, &rdval);
>>>>>>>      	if (ret < 0)
>>>>>>>      		return ret;
>>>>>>> @@ -778,6 +783,8 @@ static int ov5647_set_mode(struct v4l2_subdev *sd)
>>>>>>>      			return ret;
>>>>>>>      	}
>>>>>>> +	sensor->current_mode = sensor->mode;
>>>>>>> +
>>>>>>>      	return 0;
>>>>>>>      }
>>>>>>> @@ -816,6 +823,7 @@ static int ov5647_stream_on(struct v4l2_subdev *sd)
>>>>>>>      static int ov5647_stream_off(struct v4l2_subdev *sd)
>>>>>>>      {
>>>>>>> +	struct ov5647 *sensor = to_sensor(sd);
>>>>>>>      	int ret;
>>>>>>>      	ret = ov5647_write(sd, OV5647_REG_MIPI_CTRL00, MIPI_CTRL00_CLOCK_LANE_GATE |
>>>>>>> @@ -827,7 +835,13 @@ static int ov5647_stream_off(struct v4l2_subdev *sd)
>>>>>>>      	if (ret < 0)
>>>>>>>      		return ret;
>>>>>>> -	return ov5647_write(sd, OV5640_REG_PAD_OUT, 0x01);
>>>>>>> +	ret = ov5647_write(sd, OV5640_REG_PAD_OUT, 0x01);
>>>>>>> +	if (ret < 0)
>>>>>>> +		return ret;
>>>>>>> +
>>>>>>> +	sensor->current_mode = NULL;
>>>>>>> +
>>>>>>> +	return 0;
>>>>>>>      }
>>>>>>>      static int set_sw_standby(struct v4l2_subdev *sd, bool standby)
>>>>>>>

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

* Re: [libcamera-devel] [PATCH 20/25] media: ov5647: Program mode only if it has changed
  2020-06-30 13:01               ` Dafna Hirschfeld
@ 2020-06-30 14:53                 ` Dave Stevenson
  2020-06-30 15:11                   ` Dafna Hirschfeld
  2020-07-01  7:25                 ` Laurent Pinchart
  1 sibling, 1 reply; 56+ messages in thread
From: Dave Stevenson @ 2020-06-30 14:53 UTC (permalink / raw)
  To: Dafna Hirschfeld
  Cc: Jacopo Mondi, andrew_gabbasov, Dave Stevenson, mrodin, erosca,
	Maxime Ripard, Roman Kovalivskyi, libcamera-devel,
	Linux Media Mailing List, Sakari Ailus, hugues.fruchet,
	Mauro Carvalho Chehab, aford173, sudipi

Hi Dafna

On Tue, 30 Jun 2020 at 14:01, Dafna Hirschfeld
<dafna.hirschfeld@collabora.com> wrote:
>
> Hi,
>
>
> On 30.06.20 14:05, Jacopo Mondi wrote:
> > Hi Dafna,
> >
> > On Tue, Jun 30, 2020 at 12:56:44PM +0200, Dafna Hirschfeld wrote:
> >>
> >>
> >> On 30.06.20 12:06, Jacopo Mondi wrote:
> >>> Hi Dafna,
> >>>
> >>> On Tue, Jun 30, 2020 at 11:32:12AM +0200, Dafna Hirschfeld wrote:
> >>>>
> >>>>
> >>>> On 30.06.20 09:43, Jacopo Mondi wrote:
> >>>>> Hi Dafna,
> >>>>>
> >>>>> On Mon, Jun 29, 2020 at 07:48:16PM +0200, Dafna Hirschfeld wrote:
> >>>>>>
> >>>>>>
> >>>>>> On 23.06.20 18:55, Jacopo Mondi wrote:
> >>>>>>> Store in the driver structure a pointer to the currently applied mode
> >>>>>>> and program a new one at s_stream(1) time only if it has changed.
> >>>>>>
> >>>>>> Hi,
> >>>>>> I think this can be more readably implemented with a 'is_streaming' boolean
> >>>>>> field.
> >>>>>
> >>>>> How would you like to use an 'is_streaming' flag to decide if the
> >>>>> sensor mode has to be updated ?
> >>>>
> >>>> since 'current_mode' is set to NULL upon `ov5647_stream_off`
> >>>> and you return from 'ov5647_set_stream' immediately if 'mode == current_mode'
> >>>> it seem very similar to returning immediately from 'ov5647_set_stream' if the
> >>>> device is currently streaming.
> >>>
> >>> No, the code returns immediately from ov5647_set_mode() if mode ==
> >>> current_mode. The modes comparison makes sure the sensor is not
> >>> reprogrammed if the mode hasn't changed. The remaning part of
> >>> s_stream() is executed regardless of the mode configuration. Am I
> >>> missing some part of the picture ?
> >>>
> >>>>
> >>>> But actually in this patch it seems to be possible to change the mode
> >>>> while streaming, if the callbacks are executed:
> >>>>
> >>>> s_stream(1)
> >>>> s_fmt
> >>>> s_stream(1)
> >>>>
> >>>> which is maybe a bug?
> >>>
> >>> The new format is stored in sensor->mode, and applied at the next
> >>> s_stream(1) operation if it differs from the already programmed one,
> >>> at least, this is how it is intended to work, have you found any
> >>> failing s_stream/set_fmt/s_stream which could be caused by a bug ?
> >>
> >> What I meant is that there could be valid sequence of calls
> >>
> >> s_stream(enable=1)
> >> s_fmt
> >> s_stream(enable=1)
> >>
> >> For example if two video devices are connected to the sensor and they
> >> stream simultaneously. There was a discussion about adding a code to the core
> >
> > I'm not sure it is possible, given that the subdev has a single source
> > pad
>
> Video devices should not be connected directly to the sensor,

That's an odd statement as it is exactly the situation we have on the
Pi. The CSI2 receiver writes data to RAM, therefore it is a video
device.
Did you intend to say that it isn't necessarily connected directly to
the sensor?

> they can also
> be connected to the sensor through an isp entity that is connected to the sensor
> from one side and to two video devices from the other side.

It's true that some platforms will route the received CSI2 data
straight through the ISP, and only write the processed image(s) to
RAM. If there are multiple output video devices from the ISP then yes
they will VIDIOC_STREAMON at different points.
However is it really valid to call s_stream(1) on the sensor subdev
for each of them? Doesn't that mean you really need refcounting of the
number of s_stream(1)'s (and s_stream(0)'s) within each sensor driver,
so that it only actually stops streaming on the last s_stream(0), not
the first. A simple boolean isn't sufficient, otherwise
VIDIOC_STREAMON(NODE_A);
VIDIOC_STREAMON(NODE_B);
VIDIOC_STREAMOFF(NODE_B);
leaves you with no data from NODE_A even though it has never called
VIDIOC_STREAMOFF.

Anyway this patch was to remove excess writing of the mode registers if you did
s_fmt
s_stream(1)
s_stream(0)
s_stream(1)

The driver uses the s_power call rather than pm_runtime as that was an
acceptable approach when it was written in 2017, so the power, and
hence register settings, can be maintained between multiple s_stream
calls.

  Dave

> Thanks,
> D
>
> >
> >> to follow the s_stream callback and call it only if the subdev is not streaming
> >> but currently subdevs should support it themselves.
> >>
> >
> > Oh, so you're concerned about the fact userspace can call s_stream(1)
> > twice consecutively! it's indipendent from s_ftm if I got your point.
> >
> > In this case a flag to control if the device is streaming already should
> > help, yes, I overlooked that indeed.
> >
> > Thanks
> >    j
> >
> >>
> >> Thanks,
> >> Dafna
> >>
> >>>
> >>> Thanks
> >>>     j
> >>>>
> >>>> Thanks,
> >>>> Dafna
> >>>>
> >>>>>
> >>>>> Thanks
> >>>>>       j
> >>>>>
> >>>>>
> >>>>>>
> >>>>>> Thanks,
> >>>>>> Dafna
> >>>>>>
> >>>>>>>
> >>>>>>> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
> >>>>>>> ---
> >>>>>>>      drivers/media/i2c/ov5647.c | 16 +++++++++++++++-
> >>>>>>>      1 file changed, 15 insertions(+), 1 deletion(-)
> >>>>>>>
> >>>>>>> diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
> >>>>>>> index 39e320f321bd8..ac114269e1c73 100644
> >>>>>>> --- a/drivers/media/i2c/ov5647.c
> >>>>>>> +++ b/drivers/media/i2c/ov5647.c
> >>>>>>> @@ -96,6 +96,7 @@ struct ov5647 {
> >>>>>>>         bool                            clock_ncont;
> >>>>>>>         struct v4l2_ctrl_handler        ctrls;
> >>>>>>>         struct ov5647_mode              *mode;
> >>>>>>> +       struct ov5647_mode              *current_mode;
> >>>>>>>      };
> >>>>>>>      static inline struct ov5647 *to_sensor(struct v4l2_subdev *sd)
> >>>>>>> @@ -750,9 +751,13 @@ static int ov5647_set_virtual_channel(struct v4l2_subdev *sd, int channel)
> >>>>>>>      static int ov5647_set_mode(struct v4l2_subdev *sd)
> >>>>>>>      {
> >>>>>>>         struct i2c_client *client = v4l2_get_subdevdata(sd);
> >>>>>>> +       struct ov5647 *sensor = to_sensor(sd);
> >>>>>>>         u8 resetval, rdval;
> >>>>>>>         int ret;
> >>>>>>> +       if (sensor->mode == sensor->current_mode)
> >>>>>>> +               return 0;
> >>>>>>> +
> >>>>>>>         ret = ov5647_read(sd, OV5647_SW_STANDBY, &rdval);
> >>>>>>>         if (ret < 0)
> >>>>>>>                 return ret;
> >>>>>>> @@ -778,6 +783,8 @@ static int ov5647_set_mode(struct v4l2_subdev *sd)
> >>>>>>>                         return ret;
> >>>>>>>         }
> >>>>>>> +       sensor->current_mode = sensor->mode;
> >>>>>>> +
> >>>>>>>         return 0;
> >>>>>>>      }
> >>>>>>> @@ -816,6 +823,7 @@ static int ov5647_stream_on(struct v4l2_subdev *sd)
> >>>>>>>      static int ov5647_stream_off(struct v4l2_subdev *sd)
> >>>>>>>      {
> >>>>>>> +       struct ov5647 *sensor = to_sensor(sd);
> >>>>>>>         int ret;
> >>>>>>>         ret = ov5647_write(sd, OV5647_REG_MIPI_CTRL00, MIPI_CTRL00_CLOCK_LANE_GATE |
> >>>>>>> @@ -827,7 +835,13 @@ static int ov5647_stream_off(struct v4l2_subdev *sd)
> >>>>>>>         if (ret < 0)
> >>>>>>>                 return ret;
> >>>>>>> -       return ov5647_write(sd, OV5640_REG_PAD_OUT, 0x01);
> >>>>>>> +       ret = ov5647_write(sd, OV5640_REG_PAD_OUT, 0x01);
> >>>>>>> +       if (ret < 0)
> >>>>>>> +               return ret;
> >>>>>>> +
> >>>>>>> +       sensor->current_mode = NULL;
> >>>>>>> +
> >>>>>>> +       return 0;
> >>>>>>>      }
> >>>>>>>      static int set_sw_standby(struct v4l2_subdev *sd, bool standby)
> >>>>>>>
> _______________________________________________
> libcamera-devel mailing list
> libcamera-devel@lists.libcamera.org
> https://lists.libcamera.org/listinfo/libcamera-devel

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

* Re: [libcamera-devel] [PATCH 20/25] media: ov5647: Program mode only if it has changed
  2020-06-30 14:53                 ` [libcamera-devel] " Dave Stevenson
@ 2020-06-30 15:11                   ` Dafna Hirschfeld
  0 siblings, 0 replies; 56+ messages in thread
From: Dafna Hirschfeld @ 2020-06-30 15:11 UTC (permalink / raw)
  To: Dave Stevenson
  Cc: Jacopo Mondi, andrew_gabbasov, Dave Stevenson, mrodin, erosca,
	Maxime Ripard, Roman Kovalivskyi, libcamera-devel,
	Linux Media Mailing List, Sakari Ailus, hugues.fruchet,
	Mauro Carvalho Chehab, aford173, sudipi



On 30.06.20 16:53, Dave Stevenson wrote:
> Hi Dafna
> 
> On Tue, 30 Jun 2020 at 14:01, Dafna Hirschfeld
> <dafna.hirschfeld@collabora.com> wrote:
>>
>> Hi,
>>
>>
>> On 30.06.20 14:05, Jacopo Mondi wrote:
>>> Hi Dafna,
>>>
>>> On Tue, Jun 30, 2020 at 12:56:44PM +0200, Dafna Hirschfeld wrote:
>>>>
>>>>
>>>> On 30.06.20 12:06, Jacopo Mondi wrote:
>>>>> Hi Dafna,
>>>>>
>>>>> On Tue, Jun 30, 2020 at 11:32:12AM +0200, Dafna Hirschfeld wrote:
>>>>>>
>>>>>>
>>>>>> On 30.06.20 09:43, Jacopo Mondi wrote:
>>>>>>> Hi Dafna,
>>>>>>>
>>>>>>> On Mon, Jun 29, 2020 at 07:48:16PM +0200, Dafna Hirschfeld wrote:
>>>>>>>>
>>>>>>>>
>>>>>>>> On 23.06.20 18:55, Jacopo Mondi wrote:
>>>>>>>>> Store in the driver structure a pointer to the currently applied mode
>>>>>>>>> and program a new one at s_stream(1) time only if it has changed.
>>>>>>>>
>>>>>>>> Hi,
>>>>>>>> I think this can be more readably implemented with a 'is_streaming' boolean
>>>>>>>> field.
>>>>>>>
>>>>>>> How would you like to use an 'is_streaming' flag to decide if the
>>>>>>> sensor mode has to be updated ?
>>>>>>
>>>>>> since 'current_mode' is set to NULL upon `ov5647_stream_off`
>>>>>> and you return from 'ov5647_set_stream' immediately if 'mode == current_mode'
>>>>>> it seem very similar to returning immediately from 'ov5647_set_stream' if the
>>>>>> device is currently streaming.
>>>>>
>>>>> No, the code returns immediately from ov5647_set_mode() if mode ==
>>>>> current_mode. The modes comparison makes sure the sensor is not
>>>>> reprogrammed if the mode hasn't changed. The remaning part of
>>>>> s_stream() is executed regardless of the mode configuration. Am I
>>>>> missing some part of the picture ?
>>>>>
>>>>>>
>>>>>> But actually in this patch it seems to be possible to change the mode
>>>>>> while streaming, if the callbacks are executed:
>>>>>>
>>>>>> s_stream(1)
>>>>>> s_fmt
>>>>>> s_stream(1)
>>>>>>
>>>>>> which is maybe a bug?
>>>>>
>>>>> The new format is stored in sensor->mode, and applied at the next
>>>>> s_stream(1) operation if it differs from the already programmed one,
>>>>> at least, this is how it is intended to work, have you found any
>>>>> failing s_stream/set_fmt/s_stream which could be caused by a bug ?
>>>>
>>>> What I meant is that there could be valid sequence of calls
>>>>
>>>> s_stream(enable=1)
>>>> s_fmt
>>>> s_stream(enable=1)
>>>>
>>>> For example if two video devices are connected to the sensor and they
>>>> stream simultaneously. There was a discussion about adding a code to the core
>>>
>>> I'm not sure it is possible, given that the subdev has a single source
>>> pad
>>
>> Video devices should not be connected directly to the sensor,
> 
> That's an odd statement as it is exactly the situation we have on the
> Pi. The CSI2 receiver writes data to RAM, therefore it is a video
> device.
> Did you intend to say that it isn't necessarily connected directly to
> the sensor?
Yes, sorry, I meant, "they don't have to" (but they can).

> 
>> they can also
>> be connected to the sensor through an isp entity that is connected to the sensor
>> from one side and to two video devices from the other side.
> 
> It's true that some platforms will route the received CSI2 data
> straight through the ISP, and only write the processed image(s) to
> RAM. If there are multiple output video devices from the ISP then yes
> they will VIDIOC_STREAMON at different points.
> However is it really valid to call s_stream(1) on the sensor subdev
> for each of them? Doesn't that mean you really need refcounting of the
> number of s_stream(1)'s (and s_stream(0)'s) within each sensor driver,
> so that it only actually stops streaming on the last s_stream(0), not
> the first. A simple boolean isn't sufficient, otherwise
> VIDIOC_STREAMON(NODE_A);
> VIDIOC_STREAMON(NODE_B);
> VIDIOC_STREAMOFF(NODE_B);
> leaves you with no data from NODE_A even though it has never called
> VIDIOC_STREAMOFF.

oh, right, there was a proposal to add functions that do it with refcounting

https://patchwork.kernel.org/project/linux-media/list/?series=271153

Dafna


> 
> Anyway this patch was to remove excess writing of the mode registers if you did
> s_fmt
> s_stream(1)
> s_stream(0)
> s_stream(1)
> 
> The driver uses the s_power call rather than pm_runtime as that was an
> acceptable approach when it was written in 2017, so the power, and
> hence register settings, can be maintained between multiple s_stream
> calls.
> 
>    Dave
> 
>> Thanks,
>> D
>>
>>>
>>>> to follow the s_stream callback and call it only if the subdev is not streaming
>>>> but currently subdevs should support it themselves.
>>>>
>>>
>>> Oh, so you're concerned about the fact userspace can call s_stream(1)
>>> twice consecutively! it's indipendent from s_ftm if I got your point.
>>>
>>> In this case a flag to control if the device is streaming already should
>>> help, yes, I overlooked that indeed.
>>>
>>> Thanks
>>>     j
>>>
>>>>
>>>> Thanks,
>>>> Dafna
>>>>
>>>>>
>>>>> Thanks
>>>>>      j
>>>>>>
>>>>>> Thanks,
>>>>>> Dafna
>>>>>>
>>>>>>>
>>>>>>> Thanks
>>>>>>>        j
>>>>>>>
>>>>>>>
>>>>>>>>
>>>>>>>> Thanks,
>>>>>>>> Dafna
>>>>>>>>
>>>>>>>>>
>>>>>>>>> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
>>>>>>>>> ---
>>>>>>>>>       drivers/media/i2c/ov5647.c | 16 +++++++++++++++-
>>>>>>>>>       1 file changed, 15 insertions(+), 1 deletion(-)
>>>>>>>>>
>>>>>>>>> diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
>>>>>>>>> index 39e320f321bd8..ac114269e1c73 100644
>>>>>>>>> --- a/drivers/media/i2c/ov5647.c
>>>>>>>>> +++ b/drivers/media/i2c/ov5647.c
>>>>>>>>> @@ -96,6 +96,7 @@ struct ov5647 {
>>>>>>>>>          bool                            clock_ncont;
>>>>>>>>>          struct v4l2_ctrl_handler        ctrls;
>>>>>>>>>          struct ov5647_mode              *mode;
>>>>>>>>> +       struct ov5647_mode              *current_mode;
>>>>>>>>>       };
>>>>>>>>>       static inline struct ov5647 *to_sensor(struct v4l2_subdev *sd)
>>>>>>>>> @@ -750,9 +751,13 @@ static int ov5647_set_virtual_channel(struct v4l2_subdev *sd, int channel)
>>>>>>>>>       static int ov5647_set_mode(struct v4l2_subdev *sd)
>>>>>>>>>       {
>>>>>>>>>          struct i2c_client *client = v4l2_get_subdevdata(sd);
>>>>>>>>> +       struct ov5647 *sensor = to_sensor(sd);
>>>>>>>>>          u8 resetval, rdval;
>>>>>>>>>          int ret;
>>>>>>>>> +       if (sensor->mode == sensor->current_mode)
>>>>>>>>> +               return 0;
>>>>>>>>> +
>>>>>>>>>          ret = ov5647_read(sd, OV5647_SW_STANDBY, &rdval);
>>>>>>>>>          if (ret < 0)
>>>>>>>>>                  return ret;
>>>>>>>>> @@ -778,6 +783,8 @@ static int ov5647_set_mode(struct v4l2_subdev *sd)
>>>>>>>>>                          return ret;
>>>>>>>>>          }
>>>>>>>>> +       sensor->current_mode = sensor->mode;
>>>>>>>>> +
>>>>>>>>>          return 0;
>>>>>>>>>       }
>>>>>>>>> @@ -816,6 +823,7 @@ static int ov5647_stream_on(struct v4l2_subdev *sd)
>>>>>>>>>       static int ov5647_stream_off(struct v4l2_subdev *sd)
>>>>>>>>>       {
>>>>>>>>> +       struct ov5647 *sensor = to_sensor(sd);
>>>>>>>>>          int ret;
>>>>>>>>>          ret = ov5647_write(sd, OV5647_REG_MIPI_CTRL00, MIPI_CTRL00_CLOCK_LANE_GATE |
>>>>>>>>> @@ -827,7 +835,13 @@ static int ov5647_stream_off(struct v4l2_subdev *sd)
>>>>>>>>>          if (ret < 0)
>>>>>>>>>                  return ret;
>>>>>>>>> -       return ov5647_write(sd, OV5640_REG_PAD_OUT, 0x01);
>>>>>>>>> +       ret = ov5647_write(sd, OV5640_REG_PAD_OUT, 0x01);
>>>>>>>>> +       if (ret < 0)
>>>>>>>>> +               return ret;
>>>>>>>>> +
>>>>>>>>> +       sensor->current_mode = NULL;
>>>>>>>>> +
>>>>>>>>> +       return 0;
>>>>>>>>>       }
>>>>>>>>>       static int set_sw_standby(struct v4l2_subdev *sd, bool standby)
>>>>>>>>>
>> _______________________________________________
>> libcamera-devel mailing list
>> libcamera-devel@lists.libcamera.org
>> https://lists.libcamera.org/listinfo/libcamera-devel

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

* Re: [libcamera-devel] [PATCH 22/25] media: ov5647: Support V4L2_CID_PIXEL_RATE
  2020-06-29 21:25     ` Dave Stevenson
@ 2020-06-30 15:13       ` Dave Stevenson
  2020-07-01  7:21         ` Laurent Pinchart
  0 siblings, 1 reply; 56+ messages in thread
From: Dave Stevenson @ 2020-06-30 15:13 UTC (permalink / raw)
  To: Dafna Hirschfeld
  Cc: Jacopo Mondi, Mauro Carvalho Chehab, Sakari Ailus, Hans Verkuil,
	Laurent Pinchart, Roman Kovalivskyi, Dave Stevenson,
	Naushir Patuck, andrew_gabbasov, mrodin, Maxime Ripard,
	libcamera-devel, sudipi, hugues.fruchet, erosca, aford173,
	Linux Media Mailing List

On Mon, 29 Jun 2020 at 22:25, Dave Stevenson
<dave.stevenson@raspberrypi.com> wrote:
>
> Hi Dafna
>
> On Mon, 29 Jun 2020 at 18:01, Dafna Hirschfeld
> <dafna.hirschfeld@collabora.com> wrote:
> >
> >
> >
> > On 23.06.20 18:55, Jacopo Mondi wrote:
> > > From: Dave Stevenson <dave.stevenson@raspberrypi.com>
> > >
> > > Clients need to know the pixel rate in order to compute exposure
> > > and frame rate values. Advertise it.
> > >
> > > Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
> > > Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
> > > ---
> > >   drivers/media/i2c/ov5647.c | 40 +++++++++++++++++++++++++++++++-------
> > >   1 file changed, 33 insertions(+), 7 deletions(-)
> > >
> > > diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
> > > index 35865e56de5f9..218576a05e66b 100644
> > > --- a/drivers/media/i2c/ov5647.c
> > > +++ b/drivers/media/i2c/ov5647.c
> > > @@ -76,6 +76,7 @@ struct regval_list {
> > >   struct ov5647_mode {
> > >       struct v4l2_mbus_framefmt       format;
> > >       struct v4l2_rect                crop;
> > > +     u64                             pixel_rate;
> > >       struct regval_list              *reg_list;
> > >       unsigned int                    num_regs;
> > >   };
> > > @@ -97,6 +98,7 @@ struct ov5647 {
> > >       struct v4l2_ctrl_handler        ctrls;
> > >       struct ov5647_mode              *mode;
> > >       struct ov5647_mode              *current_mode;
> > > +     struct v4l2_ctrl                *pixel_rate;
> > >   };
> > >
> > >   static inline struct ov5647 *to_sensor(struct v4l2_subdev *sd)
> > > @@ -583,6 +585,7 @@ static struct ov5647_mode ov5647_sbggr8_modes[] = {
> > >                       .width          = 1280,
> > >                       .height         = 960,
> > >               },
> > > +             .pixel_rate     = 77291670,
> > >               .reg_list       = ov5647_640x480_sbggr8,
> > >               .num_regs       = ARRAY_SIZE(ov5647_640x480_sbggr8)
> > >       },
> > > @@ -604,6 +607,7 @@ static struct ov5647_mode ov5647_sbggr10_modes[] = {
> > >                       .width          = 2592,
> > >                       .height         = 1944
> > >               },
> > > +             .pixel_rate     = 87500000,
> > >               .reg_list       = ov5647_2592x1944_sbggr10,
> > >               .num_regs       = ARRAY_SIZE(ov5647_2592x1944_sbggr10)
> > >       },
> > > @@ -622,6 +626,7 @@ static struct ov5647_mode ov5647_sbggr10_modes[] = {
> > >                       .width          = 1928,
> > >                       .height         = 1080,
> > >               },
> > > +             .pixel_rate     = 81666700,
> > >               .reg_list       = ov5647_1080p30_sbggr10,
> > >               .num_regs       = ARRAY_SIZE(ov5647_1080p30_sbggr10)
> > >       },
> > > @@ -640,6 +645,7 @@ static struct ov5647_mode ov5647_sbggr10_modes[] = {
> > >                       .width          = 2592,
> > >                       .height         = 1944,
> > >               },
> > > +             .pixel_rate     = 81666700,
> > >               .reg_list       = ov5647_2x2binned_sbggr10,
> > >               .num_regs       = ARRAY_SIZE(ov5647_2x2binned_sbggr10)
> > >       },
> > > @@ -658,6 +664,7 @@ static struct ov5647_mode ov5647_sbggr10_modes[] = {
> > >                       .width          = 2560,
> > >                       .height         = 1920,
> > >               },
> > > +             .pixel_rate     = 55000000,
> > >               .reg_list       = ov5647_640x480_sbggr10,
> > >               .num_regs       = ARRAY_SIZE(ov5647_640x480_sbggr10)
> > >       },
> > > @@ -1094,6 +1101,10 @@ static int ov5647_set_pad_fmt(struct v4l2_subdev *sd,
> > >       /* Update the sensor mode and apply at it at streamon time. */
> > >       mutex_lock(&sensor->lock);
> > >       sensor->mode = mode;
> > > +
> > > +     __v4l2_ctrl_modify_range(sensor->pixel_rate, mode->pixel_rate,
> > > +                              mode->pixel_rate, 1, mode->pixel_rate);
> > > +
> > >       *fmt = mode->format;
> > >       mutex_unlock(&sensor->lock);
> > >
> > > @@ -1295,6 +1306,9 @@ static int ov5647_s_ctrl(struct v4l2_ctrl *ctrl)
> > >               return  ov5647_s_analogue_gain(sd, ctrl->val);
> > >       case V4L2_CID_EXPOSURE:
> > >               return ov5647_s_exposure(sd, ctrl->val);
> > > +     case V4L2_CID_PIXEL_RATE:
> > > +             /* Read-only, but we adjust it based on mode. */
> >
> > Looking at other drivers, I see they don't handle read only controls
> > in s_ctrl cb. Also the docs (vidioc-queryctrl.rst) says that trying to set a read only control should
> > return EINVAL
>
> It was a while ago that I looked at this, but my memory says that
> without a handler here then the call to __v4l2_ctrl_modify_range to
> update the value failed. The ranges and default were changed, but the
> current value wasn't.
>
> Checking now, yes, without returning 0 here,  __v4l2_ctrl_modify_range
> returns -22 (-EINVAL) and v4l2-ctl --list-ctrls afterwards shows
> Image Processing Controls
>
>                      pixel_rate 0x009f0902 (int64)  : min=87500000
> max=87500000 step=1 default=87500000 value=81666700 flags=read-only
>
> A failure of the framework then and needs fixing there, or is it
> correct for the driver to have to implement a set hander if it needs
> to update the ranges?
> A quick grep implies that ov5647 is the first driver that needs to
> update V4L2_CID_PIXEL_RATE based on mode. I'll check in the morning if
> things like V4L2_CID_HBLANK behave the same - it may be a control type
> issue with 64 bit values.

Just following this up, it's not a 64 bit control thing, it's any read
only control won't update the current value if you
use__v4l2_ctrl_modify_range. That's why the patch adding
V4L2_CID_HBLANK has to do the same thing.
I've just tried it on imx219 and it works fine.....

The answer is down to "modern" sensor drivers using pm_runtime having a line
    if (pm_runtime_get_if_in_use(&client->dev) == 0)
        return 0;
in their s_ctrl function. So whenever the sensor isn't streaming,
which has to be the case for setting modes, gets a 0 return value from
the s_ctrl call even though the control is invalid.
That does seem to be a failure within the ctrl core then. Effectively
other drivers do have this handling in, but via a different route.

Hans or Sakari may have ideas on how they would like to see the core
v4l2-ctrls code fixing to cover this. try_or_set_cluster is called
from too many places for me to know whether it is safe to just skip
the s_ctrl call for read only controls.

  Dave

> Interesting that the docs say EINVAL as at least one path in the
> framework appears to return -EACCES [1]
> Checking it:
> pi@raspberrypi:~ $ v4l2-ctl --set-ctrl pixel_rate=42
> VIDIOC_S_EXT_CTRLS: failed: Permission denied
> Error setting controls: Permission denied
> which would imply -EACCES
>
> I am testing on a 5.4 kernel rather than media_tree.git, but there
> don't appear to be any significant differences in this area between
> the two.
>
> Cheers.
>   Dave
>
> [1] https://git.linuxtv.org/media_tree.git/tree/drivers/media/v4l2-core/v4l2-ctrls.c#n4224
>
> > Thanks,
> > Dafna
> >
> > > +             return 0;
> > >       default:
> > >               dev_info(&client->dev,
> > >                        "Control (id:0x%x, val:0x%x) not supported\n",
> > > @@ -1313,7 +1327,7 @@ static int ov5647_init_controls(struct ov5647 *sensor)
> > >   {
> > >       struct i2c_client *client = v4l2_get_subdevdata(&sensor->sd);
> > >
> > > -     v4l2_ctrl_handler_init(&sensor->ctrls, 5);
> > > +     v4l2_ctrl_handler_init(&sensor->ctrls, 6);
> > >
> > >       v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,
> > >                         V4L2_CID_AUTOGAIN, 0, 1, 1, 0);
> > > @@ -1333,17 +1347,29 @@ static int ov5647_init_controls(struct ov5647 *sensor)
> > >       v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,
> > >                         V4L2_CID_ANALOGUE_GAIN, 16, 1023, 1, 32);
> > >
> > > -     if (sensor->ctrls.error) {
> > > -             dev_err(&client->dev, "%s Controls initialization failed (%d)\n",
> > > -                     __func__, sensor->ctrls.error);
> > > -             v4l2_ctrl_handler_free(&sensor->ctrls);
> > > +     /* By default, PIXEL_RATE is read only, but it does change per mode */
> > > +     sensor->pixel_rate = v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,
> > > +                                            V4L2_CID_PIXEL_RATE,
> > > +                                            sensor->mode->pixel_rate,
> > > +                                            sensor->mode->pixel_rate, 1,
> > > +                                            sensor->mode->pixel_rate);
> > > +     if (!sensor->pixel_rate)
> > > +             goto handler_free;
> > > +     sensor->pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY;
> > >
> > > -             return sensor->ctrls.error;
> > > -     }
> > > +     if (sensor->ctrls.error)
> > > +             goto handler_free;
> > >
> > >       sensor->sd.ctrl_handler = &sensor->ctrls;
> > >
> > >       return 0;
> > > +
> > > +handler_free:
> > > +     dev_err(&client->dev, "%s Controls initialization failed (%d)\n",
> > > +             __func__, sensor->ctrls.error);
> > > +     v4l2_ctrl_handler_free(&sensor->ctrls);
> > > +
> > > +     return sensor->ctrls.error;
> > >   }
> > >
> > >   static int ov5647_parse_dt(struct ov5647 *sensor, struct device_node *np)
> > >
> > _______________________________________________
> > libcamera-devel mailing list
> > libcamera-devel@lists.libcamera.org
> > https://lists.libcamera.org/listinfo/libcamera-devel

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

* Re: [libcamera-devel] [PATCH 22/25] media: ov5647: Support V4L2_CID_PIXEL_RATE
  2020-06-30 15:13       ` Dave Stevenson
@ 2020-07-01  7:21         ` Laurent Pinchart
  0 siblings, 0 replies; 56+ messages in thread
From: Laurent Pinchart @ 2020-07-01  7:21 UTC (permalink / raw)
  To: Dave Stevenson
  Cc: Dafna Hirschfeld, Jacopo Mondi, Mauro Carvalho Chehab,
	Sakari Ailus, Hans Verkuil, Roman Kovalivskyi, Dave Stevenson,
	Naushir Patuck, andrew_gabbasov, mrodin, Maxime Ripard,
	libcamera-devel, sudipi, hugues.fruchet, erosca, aford173,
	Linux Media Mailing List

Hi Dave,

(Question for Hans below)

On Tue, Jun 30, 2020 at 04:13:29PM +0100, Dave Stevenson wrote:
> On Mon, 29 Jun 2020 at 22:25, Dave Stevenson wrote:
> > On Mon, 29 Jun 2020 at 18:01, Dafna Hirschfeld wrote:
> > > On 23.06.20 18:55, Jacopo Mondi wrote:
> > > > From: Dave Stevenson <dave.stevenson@raspberrypi.com>
> > > >
> > > > Clients need to know the pixel rate in order to compute exposure
> > > > and frame rate values. Advertise it.
> > > >
> > > > Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
> > > > Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
> > > > ---
> > > >   drivers/media/i2c/ov5647.c | 40 +++++++++++++++++++++++++++++++-------
> > > >   1 file changed, 33 insertions(+), 7 deletions(-)
> > > >
> > > > diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
> > > > index 35865e56de5f9..218576a05e66b 100644
> > > > --- a/drivers/media/i2c/ov5647.c
> > > > +++ b/drivers/media/i2c/ov5647.c
> > > > @@ -76,6 +76,7 @@ struct regval_list {
> > > >   struct ov5647_mode {
> > > >       struct v4l2_mbus_framefmt       format;
> > > >       struct v4l2_rect                crop;
> > > > +     u64                             pixel_rate;
> > > >       struct regval_list              *reg_list;
> > > >       unsigned int                    num_regs;
> > > >   };
> > > > @@ -97,6 +98,7 @@ struct ov5647 {
> > > >       struct v4l2_ctrl_handler        ctrls;
> > > >       struct ov5647_mode              *mode;
> > > >       struct ov5647_mode              *current_mode;
> > > > +     struct v4l2_ctrl                *pixel_rate;
> > > >   };
> > > >
> > > >   static inline struct ov5647 *to_sensor(struct v4l2_subdev *sd)
> > > > @@ -583,6 +585,7 @@ static struct ov5647_mode ov5647_sbggr8_modes[] = {
> > > >                       .width          = 1280,
> > > >                       .height         = 960,
> > > >               },
> > > > +             .pixel_rate     = 77291670,
> > > >               .reg_list       = ov5647_640x480_sbggr8,
> > > >               .num_regs       = ARRAY_SIZE(ov5647_640x480_sbggr8)
> > > >       },
> > > > @@ -604,6 +607,7 @@ static struct ov5647_mode ov5647_sbggr10_modes[] = {
> > > >                       .width          = 2592,
> > > >                       .height         = 1944
> > > >               },
> > > > +             .pixel_rate     = 87500000,
> > > >               .reg_list       = ov5647_2592x1944_sbggr10,
> > > >               .num_regs       = ARRAY_SIZE(ov5647_2592x1944_sbggr10)
> > > >       },
> > > > @@ -622,6 +626,7 @@ static struct ov5647_mode ov5647_sbggr10_modes[] = {
> > > >                       .width          = 1928,
> > > >                       .height         = 1080,
> > > >               },
> > > > +             .pixel_rate     = 81666700,
> > > >               .reg_list       = ov5647_1080p30_sbggr10,
> > > >               .num_regs       = ARRAY_SIZE(ov5647_1080p30_sbggr10)
> > > >       },
> > > > @@ -640,6 +645,7 @@ static struct ov5647_mode ov5647_sbggr10_modes[] = {
> > > >                       .width          = 2592,
> > > >                       .height         = 1944,
> > > >               },
> > > > +             .pixel_rate     = 81666700,
> > > >               .reg_list       = ov5647_2x2binned_sbggr10,
> > > >               .num_regs       = ARRAY_SIZE(ov5647_2x2binned_sbggr10)
> > > >       },
> > > > @@ -658,6 +664,7 @@ static struct ov5647_mode ov5647_sbggr10_modes[] = {
> > > >                       .width          = 2560,
> > > >                       .height         = 1920,
> > > >               },
> > > > +             .pixel_rate     = 55000000,
> > > >               .reg_list       = ov5647_640x480_sbggr10,
> > > >               .num_regs       = ARRAY_SIZE(ov5647_640x480_sbggr10)
> > > >       },
> > > > @@ -1094,6 +1101,10 @@ static int ov5647_set_pad_fmt(struct v4l2_subdev *sd,
> > > >       /* Update the sensor mode and apply at it at streamon time. */
> > > >       mutex_lock(&sensor->lock);
> > > >       sensor->mode = mode;
> > > > +
> > > > +     __v4l2_ctrl_modify_range(sensor->pixel_rate, mode->pixel_rate,
> > > > +                              mode->pixel_rate, 1, mode->pixel_rate);
> > > > +
> > > >       *fmt = mode->format;
> > > >       mutex_unlock(&sensor->lock);
> > > >
> > > > @@ -1295,6 +1306,9 @@ static int ov5647_s_ctrl(struct v4l2_ctrl *ctrl)
> > > >               return  ov5647_s_analogue_gain(sd, ctrl->val);
> > > >       case V4L2_CID_EXPOSURE:
> > > >               return ov5647_s_exposure(sd, ctrl->val);
> > > > +     case V4L2_CID_PIXEL_RATE:
> > > > +             /* Read-only, but we adjust it based on mode. */
> > >
> > > Looking at other drivers, I see they don't handle read only controls
> > > in s_ctrl cb. Also the docs (vidioc-queryctrl.rst) says that trying to set a read only control should
> > > return EINVAL
> >
> > It was a while ago that I looked at this, but my memory says that
> > without a handler here then the call to __v4l2_ctrl_modify_range to
> > update the value failed. The ranges and default were changed, but the
> > current value wasn't.
> >
> > Checking now, yes, without returning 0 here,  __v4l2_ctrl_modify_range
> > returns -22 (-EINVAL) and v4l2-ctl --list-ctrls afterwards shows
> > Image Processing Controls
> >
> >                      pixel_rate 0x009f0902 (int64)  : min=87500000
> > max=87500000 step=1 default=87500000 value=81666700 flags=read-only
> >
> > A failure of the framework then and needs fixing there, or is it
> > correct for the driver to have to implement a set hander if it needs
> > to update the ranges?
> > A quick grep implies that ov5647 is the first driver that needs to
> > update V4L2_CID_PIXEL_RATE based on mode. I'll check in the morning if
> > things like V4L2_CID_HBLANK behave the same - it may be a control type
> > issue with 64 bit values.
> 
> Just following this up, it's not a 64 bit control thing, it's any read
> only control won't update the current value if you
> use__v4l2_ctrl_modify_range. That's why the patch adding
> V4L2_CID_HBLANK has to do the same thing.
> I've just tried it on imx219 and it works fine.....
> 
> The answer is down to "modern" sensor drivers using pm_runtime having a line
>     if (pm_runtime_get_if_in_use(&client->dev) == 0)
>         return 0;
> in their s_ctrl function. So whenever the sensor isn't streaming,
> which has to be the case for setting modes, gets a 0 return value from
> the s_ctrl call even though the control is invalid.
> That does seem to be a failure within the ctrl core then. Effectively
> other drivers do have this handling in, but via a different route.
> 
> Hans or Sakari may have ideas on how they would like to see the core
> v4l2-ctrls code fixing to cover this. try_or_set_cluster is called
> from too many places for me to know whether it is safe to just skip
> the s_ctrl call for read only controls.

I think the control framework shouldn't call .s_ctrl() for read-only
controls. If it's read-only the __v4l2_ctrl_modify_range() is supposed
to originate from the same driver, so any specific driver-side handling
can be handled before or after calling __v4l2_ctrl_modify_range().

A better helper function to update the value of a read-only control may
be a good idea. I may also have bypassed __v4l2_ctrl_modify_range()
completely and set the value manually in the corresponding v4l2_ctrl
instance, but I understand that this would be called a hack. I know we
would lose support for control events in that case, but for
V4L2_CID_PIXEL_RATE I don't think this is a problem. Control events are
actually annoying to use synchronously, if you want to know what other
controls have been impacted by a VIDIOC_S_CTRL call, userspace code to
handle this through control events would be a bit cumbersome.

> > Interesting that the docs say EINVAL as at least one path in the
> > framework appears to return -EACCES [1]
> > Checking it:
> > pi@raspberrypi:~ $ v4l2-ctl --set-ctrl pixel_rate=42
> > VIDIOC_S_EXT_CTRLS: failed: Permission denied
> > Error setting controls: Permission denied
> > which would imply -EACCES
> >
> > I am testing on a 5.4 kernel rather than media_tree.git, but there
> > don't appear to be any significant differences in this area between
> > the two.
> >
> > [1] https://git.linuxtv.org/media_tree.git/tree/drivers/media/v4l2-core/v4l2-ctrls.c#n4224
> >
> > > > +             return 0;
> > > >       default:
> > > >               dev_info(&client->dev,
> > > >                        "Control (id:0x%x, val:0x%x) not supported\n",
> > > > @@ -1313,7 +1327,7 @@ static int ov5647_init_controls(struct ov5647 *sensor)
> > > >   {
> > > >       struct i2c_client *client = v4l2_get_subdevdata(&sensor->sd);
> > > >
> > > > -     v4l2_ctrl_handler_init(&sensor->ctrls, 5);
> > > > +     v4l2_ctrl_handler_init(&sensor->ctrls, 6);
> > > >
> > > >       v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,
> > > >                         V4L2_CID_AUTOGAIN, 0, 1, 1, 0);
> > > > @@ -1333,17 +1347,29 @@ static int ov5647_init_controls(struct ov5647 *sensor)
> > > >       v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,
> > > >                         V4L2_CID_ANALOGUE_GAIN, 16, 1023, 1, 32);
> > > >
> > > > -     if (sensor->ctrls.error) {
> > > > -             dev_err(&client->dev, "%s Controls initialization failed (%d)\n",
> > > > -                     __func__, sensor->ctrls.error);
> > > > -             v4l2_ctrl_handler_free(&sensor->ctrls);
> > > > +     /* By default, PIXEL_RATE is read only, but it does change per mode */
> > > > +     sensor->pixel_rate = v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,
> > > > +                                            V4L2_CID_PIXEL_RATE,
> > > > +                                            sensor->mode->pixel_rate,
> > > > +                                            sensor->mode->pixel_rate, 1,
> > > > +                                            sensor->mode->pixel_rate);
> > > > +     if (!sensor->pixel_rate)
> > > > +             goto handler_free;
> > > > +     sensor->pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY;
> > > >
> > > > -             return sensor->ctrls.error;
> > > > -     }
> > > > +     if (sensor->ctrls.error)
> > > > +             goto handler_free;
> > > >
> > > >       sensor->sd.ctrl_handler = &sensor->ctrls;
> > > >
> > > >       return 0;
> > > > +
> > > > +handler_free:
> > > > +     dev_err(&client->dev, "%s Controls initialization failed (%d)\n",
> > > > +             __func__, sensor->ctrls.error);
> > > > +     v4l2_ctrl_handler_free(&sensor->ctrls);
> > > > +
> > > > +     return sensor->ctrls.error;
> > > >   }
> > > >
> > > >   static int ov5647_parse_dt(struct ov5647 *sensor, struct device_node *np)

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH 20/25] media: ov5647: Program mode only if it has changed
  2020-06-30 13:01               ` Dafna Hirschfeld
  2020-06-30 14:53                 ` [libcamera-devel] " Dave Stevenson
@ 2020-07-01  7:25                 ` Laurent Pinchart
  2020-07-03 12:21                   ` Jacopo Mondi
  1 sibling, 1 reply; 56+ messages in thread
From: Laurent Pinchart @ 2020-07-01  7:25 UTC (permalink / raw)
  To: Dafna Hirschfeld
  Cc: Jacopo Mondi, mchehab, sakari.ailus, hverkuil, roman.kovalivskyi,
	dave.stevenson, naush, mrodin, hugues.fruchet, mripard, aford173,
	sudipi, andrew_gabbasov, erosca, linux-media, libcamera-devel,
	dafna Hirschfeld

Hi Dafna,

On Tue, Jun 30, 2020 at 03:01:21PM +0200, Dafna Hirschfeld wrote:
> On 30.06.20 14:05, Jacopo Mondi wrote:
> > On Tue, Jun 30, 2020 at 12:56:44PM +0200, Dafna Hirschfeld wrote:
> >> On 30.06.20 12:06, Jacopo Mondi wrote:
> >>> On Tue, Jun 30, 2020 at 11:32:12AM +0200, Dafna Hirschfeld wrote:
> >>>> On 30.06.20 09:43, Jacopo Mondi wrote:
> >>>>> On Mon, Jun 29, 2020 at 07:48:16PM +0200, Dafna Hirschfeld wrote:
> >>>>>> On 23.06.20 18:55, Jacopo Mondi wrote:
> >>>>>>> Store in the driver structure a pointer to the currently applied mode
> >>>>>>> and program a new one at s_stream(1) time only if it has changed.
> >>>>>>
> >>>>>> Hi,
> >>>>>> I think this can be more readably implemented with a 'is_streaming' boolean
> >>>>>> field.
> >>>>>
> >>>>> How would you like to use an 'is_streaming' flag to decide if the
> >>>>> sensor mode has to be updated ?
> >>>>
> >>>> since 'current_mode' is set to NULL upon `ov5647_stream_off`
> >>>> and you return from 'ov5647_set_stream' immediately if 'mode == current_mode'
> >>>> it seem very similar to returning immediately from 'ov5647_set_stream' if the
> >>>> device is currently streaming.
> >>>
> >>> No, the code returns immediately from ov5647_set_mode() if mode ==
> >>> current_mode. The modes comparison makes sure the sensor is not
> >>> reprogrammed if the mode hasn't changed. The remaning part of
> >>> s_stream() is executed regardless of the mode configuration. Am I
> >>> missing some part of the picture ?
> >>>
> >>>> But actually in this patch it seems to be possible to change the mode
> >>>> while streaming, if the callbacks are executed:
> >>>>
> >>>> s_stream(1)
> >>>> s_fmt
> >>>> s_stream(1)
> >>>>
> >>>> which is maybe a bug?
> >>>
> >>> The new format is stored in sensor->mode, and applied at the next
> >>> s_stream(1) operation if it differs from the already programmed one,
> >>> at least, this is how it is intended to work, have you found any
> >>> failing s_stream/set_fmt/s_stream which could be caused by a bug ?
> >>
> >> What I meant is that there could be valid sequence of calls
> >>
> >> s_stream(enable=1)
> >> s_fmt
> >> s_stream(enable=1)
> >>
> >> For example if two video devices are connected to the sensor and they
> >> stream simultaneously. There was a discussion about adding a code to the core
> > 
> > I'm not sure it is possible, given that the subdev has a single source
> > pad
> 
> Video devices should not be connected directly to the sensor, they can also
> be connected to the sensor through an isp entity that is connected to the sensor
> from one side and to two video devices from the other side.

I don't think it should be the job of the sensor driver to handle this.
A sensor can be streaming or not streaming, and a .s_stream(1) call
while already streaming shouldn't happen. It's the job of the ISP driver
(with help from core code) to ensure this won't happen. Otherwise we
would have to protect against that case in all sensor drivers,
duplicating code in many places and opening the door to bugs. Subdev
drivers should be as simple as possible.

> >> to follow the s_stream callback and call it only if the subdev is not streaming
> >> but currently subdevs should support it themselves.
> > 
> > Oh, so you're concerned about the fact userspace can call s_stream(1)
> > twice consecutively! it's indipendent from s_ftm if I got your point.
> > 
> > In this case a flag to control if the device is streaming already should
> > help, yes, I overlooked that indeed.
> > 
> >>>>>>> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
> >>>>>>> ---
> >>>>>>>      drivers/media/i2c/ov5647.c | 16 +++++++++++++++-
> >>>>>>>      1 file changed, 15 insertions(+), 1 deletion(-)
> >>>>>>>
> >>>>>>> diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
> >>>>>>> index 39e320f321bd8..ac114269e1c73 100644
> >>>>>>> --- a/drivers/media/i2c/ov5647.c
> >>>>>>> +++ b/drivers/media/i2c/ov5647.c
> >>>>>>> @@ -96,6 +96,7 @@ struct ov5647 {
> >>>>>>>      	bool				clock_ncont;
> >>>>>>>      	struct v4l2_ctrl_handler	ctrls;
> >>>>>>>      	struct ov5647_mode		*mode;
> >>>>>>> +	struct ov5647_mode		*current_mode;
> >>>>>>>      };
> >>>>>>>      static inline struct ov5647 *to_sensor(struct v4l2_subdev *sd)
> >>>>>>> @@ -750,9 +751,13 @@ static int ov5647_set_virtual_channel(struct v4l2_subdev *sd, int channel)
> >>>>>>>      static int ov5647_set_mode(struct v4l2_subdev *sd)
> >>>>>>>      {
> >>>>>>>      	struct i2c_client *client = v4l2_get_subdevdata(sd);
> >>>>>>> +	struct ov5647 *sensor = to_sensor(sd);
> >>>>>>>      	u8 resetval, rdval;
> >>>>>>>      	int ret;
> >>>>>>> +	if (sensor->mode == sensor->current_mode)
> >>>>>>> +		return 0;
> >>>>>>> +
> >>>>>>>      	ret = ov5647_read(sd, OV5647_SW_STANDBY, &rdval);
> >>>>>>>      	if (ret < 0)
> >>>>>>>      		return ret;
> >>>>>>> @@ -778,6 +783,8 @@ static int ov5647_set_mode(struct v4l2_subdev *sd)
> >>>>>>>      			return ret;
> >>>>>>>      	}
> >>>>>>> +	sensor->current_mode = sensor->mode;
> >>>>>>> +
> >>>>>>>      	return 0;
> >>>>>>>      }
> >>>>>>> @@ -816,6 +823,7 @@ static int ov5647_stream_on(struct v4l2_subdev *sd)
> >>>>>>>      static int ov5647_stream_off(struct v4l2_subdev *sd)
> >>>>>>>      {
> >>>>>>> +	struct ov5647 *sensor = to_sensor(sd);
> >>>>>>>      	int ret;
> >>>>>>>      	ret = ov5647_write(sd, OV5647_REG_MIPI_CTRL00, MIPI_CTRL00_CLOCK_LANE_GATE |
> >>>>>>> @@ -827,7 +835,13 @@ static int ov5647_stream_off(struct v4l2_subdev *sd)
> >>>>>>>      	if (ret < 0)
> >>>>>>>      		return ret;
> >>>>>>> -	return ov5647_write(sd, OV5640_REG_PAD_OUT, 0x01);
> >>>>>>> +	ret = ov5647_write(sd, OV5640_REG_PAD_OUT, 0x01);
> >>>>>>> +	if (ret < 0)
> >>>>>>> +		return ret;
> >>>>>>> +
> >>>>>>> +	sensor->current_mode = NULL;
> >>>>>>> +
> >>>>>>> +	return 0;
> >>>>>>>      }
> >>>>>>>      static int set_sw_standby(struct v4l2_subdev *sd, bool standby)
> >>>>>>>

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH 20/25] media: ov5647: Program mode only if it has changed
  2020-07-01  7:25                 ` Laurent Pinchart
@ 2020-07-03 12:21                   ` Jacopo Mondi
  2020-07-03 16:33                     ` Laurent Pinchart
  0 siblings, 1 reply; 56+ messages in thread
From: Jacopo Mondi @ 2020-07-03 12:21 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Dafna Hirschfeld, mchehab, sakari.ailus, hverkuil,
	roman.kovalivskyi, dave.stevenson, naush, mrodin, hugues.fruchet,
	mripard, aford173, sudipi, andrew_gabbasov, erosca, linux-media,
	libcamera-devel, dafna Hirschfeld

Hello,

On Wed, Jul 01, 2020 at 10:25:54AM +0300, Laurent Pinchart wrote:
> Hi Dafna,
>
> On Tue, Jun 30, 2020 at 03:01:21PM +0200, Dafna Hirschfeld wrote:
> > On 30.06.20 14:05, Jacopo Mondi wrote:
> > > On Tue, Jun 30, 2020 at 12:56:44PM +0200, Dafna Hirschfeld wrote:
> > >> On 30.06.20 12:06, Jacopo Mondi wrote:
> > >>> On Tue, Jun 30, 2020 at 11:32:12AM +0200, Dafna Hirschfeld wrote:
> > >>>> On 30.06.20 09:43, Jacopo Mondi wrote:
> > >>>>> On Mon, Jun 29, 2020 at 07:48:16PM +0200, Dafna Hirschfeld wrote:
> > >>>>>> On 23.06.20 18:55, Jacopo Mondi wrote:
> > >>>>>>> Store in the driver structure a pointer to the currently applied mode
> > >>>>>>> and program a new one at s_stream(1) time only if it has changed.
> > >>>>>>
> > >>>>>> Hi,
> > >>>>>> I think this can be more readably implemented with a 'is_streaming' boolean
> > >>>>>> field.
> > >>>>>
> > >>>>> How would you like to use an 'is_streaming' flag to decide if the
> > >>>>> sensor mode has to be updated ?
> > >>>>
> > >>>> since 'current_mode' is set to NULL upon `ov5647_stream_off`
> > >>>> and you return from 'ov5647_set_stream' immediately if 'mode == current_mode'
> > >>>> it seem very similar to returning immediately from 'ov5647_set_stream' if the
> > >>>> device is currently streaming.
> > >>>
> > >>> No, the code returns immediately from ov5647_set_mode() if mode ==
> > >>> current_mode. The modes comparison makes sure the sensor is not
> > >>> reprogrammed if the mode hasn't changed. The remaning part of
> > >>> s_stream() is executed regardless of the mode configuration. Am I
> > >>> missing some part of the picture ?
> > >>>
> > >>>> But actually in this patch it seems to be possible to change the mode
> > >>>> while streaming, if the callbacks are executed:
> > >>>>
> > >>>> s_stream(1)
> > >>>> s_fmt
> > >>>> s_stream(1)
> > >>>>
> > >>>> which is maybe a bug?
> > >>>
> > >>> The new format is stored in sensor->mode, and applied at the next
> > >>> s_stream(1) operation if it differs from the already programmed one,
> > >>> at least, this is how it is intended to work, have you found any
> > >>> failing s_stream/set_fmt/s_stream which could be caused by a bug ?
> > >>
> > >> What I meant is that there could be valid sequence of calls
> > >>
> > >> s_stream(enable=1)
> > >> s_fmt
> > >> s_stream(enable=1)
> > >>
> > >> For example if two video devices are connected to the sensor and they
> > >> stream simultaneously. There was a discussion about adding a code to the core
> > >
> > > I'm not sure it is possible, given that the subdev has a single source
> > > pad
> >
> > Video devices should not be connected directly to the sensor, they can also
> > be connected to the sensor through an isp entity that is connected to the sensor
> > from one side and to two video devices from the other side.
>
> I don't think it should be the job of the sensor driver to handle this.
> A sensor can be streaming or not streaming, and a .s_stream(1) call
> while already streaming shouldn't happen. It's the job of the ISP driver
> (with help from core code) to ensure this won't happen. Otherwise we
> would have to protect against that case in all sensor drivers,
> duplicating code in many places and opening the door to bugs. Subdev
> drivers should be as simple as possible.
>

Most of the sensor driver I've briefly looked at implement a simple
check to avoid double stream(1) but they do not implement any form of
refcounting. I think that does more harm than good to be honest, as it
would hide  potential problematic start stream sequences, but would
stop the sensor at the first stream(0), leaving one of the multiple
receivers stuck.

I would prefer avoid doing this here.

However the driver already refcounting on s_power(), which if I'm not
mistaken could be avoided, as bridges should use
v4l2_pipeline_pm_get(), which already does refcounting, if I'm not
mistaken.

To me, grasping how s_stream() and s_start() work for real is still hard,
as those are the only two operation propagated along the pipeline by
briges, even for MC platforms, and it seems looking at the existing
driver, the confusion is big, as all of them handle things slightly
differently :/


> > >> to follow the s_stream callback and call it only if the subdev is not streaming
> > >> but currently subdevs should support it themselves.
> > >
> > > Oh, so you're concerned about the fact userspace can call s_stream(1)
> > > twice consecutively! it's indipendent from s_ftm if I got your point.
> > >
> > > In this case a flag to control if the device is streaming already should
> > > help, yes, I overlooked that indeed.
> > >
> > >>>>>>> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
> > >>>>>>> ---
> > >>>>>>>      drivers/media/i2c/ov5647.c | 16 +++++++++++++++-
> > >>>>>>>      1 file changed, 15 insertions(+), 1 deletion(-)
> > >>>>>>>
> > >>>>>>> diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
> > >>>>>>> index 39e320f321bd8..ac114269e1c73 100644
> > >>>>>>> --- a/drivers/media/i2c/ov5647.c
> > >>>>>>> +++ b/drivers/media/i2c/ov5647.c
> > >>>>>>> @@ -96,6 +96,7 @@ struct ov5647 {
> > >>>>>>>      	bool				clock_ncont;
> > >>>>>>>      	struct v4l2_ctrl_handler	ctrls;
> > >>>>>>>      	struct ov5647_mode		*mode;
> > >>>>>>> +	struct ov5647_mode		*current_mode;
> > >>>>>>>      };
> > >>>>>>>      static inline struct ov5647 *to_sensor(struct v4l2_subdev *sd)
> > >>>>>>> @@ -750,9 +751,13 @@ static int ov5647_set_virtual_channel(struct v4l2_subdev *sd, int channel)
> > >>>>>>>      static int ov5647_set_mode(struct v4l2_subdev *sd)
> > >>>>>>>      {
> > >>>>>>>      	struct i2c_client *client = v4l2_get_subdevdata(sd);
> > >>>>>>> +	struct ov5647 *sensor = to_sensor(sd);
> > >>>>>>>      	u8 resetval, rdval;
> > >>>>>>>      	int ret;
> > >>>>>>> +	if (sensor->mode == sensor->current_mode)
> > >>>>>>> +		return 0;
> > >>>>>>> +
> > >>>>>>>      	ret = ov5647_read(sd, OV5647_SW_STANDBY, &rdval);
> > >>>>>>>      	if (ret < 0)
> > >>>>>>>      		return ret;
> > >>>>>>> @@ -778,6 +783,8 @@ static int ov5647_set_mode(struct v4l2_subdev *sd)
> > >>>>>>>      			return ret;
> > >>>>>>>      	}
> > >>>>>>> +	sensor->current_mode = sensor->mode;
> > >>>>>>> +
> > >>>>>>>      	return 0;
> > >>>>>>>      }
> > >>>>>>> @@ -816,6 +823,7 @@ static int ov5647_stream_on(struct v4l2_subdev *sd)
> > >>>>>>>      static int ov5647_stream_off(struct v4l2_subdev *sd)
> > >>>>>>>      {
> > >>>>>>> +	struct ov5647 *sensor = to_sensor(sd);
> > >>>>>>>      	int ret;
> > >>>>>>>      	ret = ov5647_write(sd, OV5647_REG_MIPI_CTRL00, MIPI_CTRL00_CLOCK_LANE_GATE |
> > >>>>>>> @@ -827,7 +835,13 @@ static int ov5647_stream_off(struct v4l2_subdev *sd)
> > >>>>>>>      	if (ret < 0)
> > >>>>>>>      		return ret;
> > >>>>>>> -	return ov5647_write(sd, OV5640_REG_PAD_OUT, 0x01);
> > >>>>>>> +	ret = ov5647_write(sd, OV5640_REG_PAD_OUT, 0x01);
> > >>>>>>> +	if (ret < 0)
> > >>>>>>> +		return ret;
> > >>>>>>> +
> > >>>>>>> +	sensor->current_mode = NULL;
> > >>>>>>> +
> > >>>>>>> +	return 0;
> > >>>>>>>      }
> > >>>>>>>      static int set_sw_standby(struct v4l2_subdev *sd, bool standby)
> > >>>>>>>
>
> --
> Regards,
>
> Laurent Pinchart

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

* Re: [PATCH 20/25] media: ov5647: Program mode only if it has changed
  2020-07-03 12:21                   ` Jacopo Mondi
@ 2020-07-03 16:33                     ` Laurent Pinchart
  0 siblings, 0 replies; 56+ messages in thread
From: Laurent Pinchart @ 2020-07-03 16:33 UTC (permalink / raw)
  To: Jacopo Mondi
  Cc: Dafna Hirschfeld, mchehab, sakari.ailus, hverkuil,
	roman.kovalivskyi, dave.stevenson, naush, mrodin, hugues.fruchet,
	mripard, aford173, sudipi, andrew_gabbasov, erosca, linux-media,
	libcamera-devel, dafna Hirschfeld

Hi Jacopo,

On Fri, Jul 03, 2020 at 02:21:50PM +0200, Jacopo Mondi wrote:
> On Wed, Jul 01, 2020 at 10:25:54AM +0300, Laurent Pinchart wrote:
> > On Tue, Jun 30, 2020 at 03:01:21PM +0200, Dafna Hirschfeld wrote:
> >> On 30.06.20 14:05, Jacopo Mondi wrote:
> >>> On Tue, Jun 30, 2020 at 12:56:44PM +0200, Dafna Hirschfeld wrote:
> >>>> On 30.06.20 12:06, Jacopo Mondi wrote:
> >>>>> On Tue, Jun 30, 2020 at 11:32:12AM +0200, Dafna Hirschfeld wrote:
> >>>>>> On 30.06.20 09:43, Jacopo Mondi wrote:
> >>>>>>> On Mon, Jun 29, 2020 at 07:48:16PM +0200, Dafna Hirschfeld wrote:
> >>>>>>>> On 23.06.20 18:55, Jacopo Mondi wrote:
> >>>>>>>>> Store in the driver structure a pointer to the currently applied mode
> >>>>>>>>> and program a new one at s_stream(1) time only if it has changed.
> >>>>>>>>
> >>>>>>>> Hi,
> >>>>>>>> I think this can be more readably implemented with a 'is_streaming' boolean
> >>>>>>>> field.
> >>>>>>>
> >>>>>>> How would you like to use an 'is_streaming' flag to decide if the
> >>>>>>> sensor mode has to be updated ?
> >>>>>>
> >>>>>> since 'current_mode' is set to NULL upon `ov5647_stream_off`
> >>>>>> and you return from 'ov5647_set_stream' immediately if 'mode == current_mode'
> >>>>>> it seem very similar to returning immediately from 'ov5647_set_stream' if the
> >>>>>> device is currently streaming.
> >>>>>
> >>>>> No, the code returns immediately from ov5647_set_mode() if mode ==
> >>>>> current_mode. The modes comparison makes sure the sensor is not
> >>>>> reprogrammed if the mode hasn't changed. The remaning part of
> >>>>> s_stream() is executed regardless of the mode configuration. Am I
> >>>>> missing some part of the picture ?
> >>>>>
> >>>>>> But actually in this patch it seems to be possible to change the mode
> >>>>>> while streaming, if the callbacks are executed:
> >>>>>>
> >>>>>> s_stream(1)
> >>>>>> s_fmt
> >>>>>> s_stream(1)
> >>>>>>
> >>>>>> which is maybe a bug?
> >>>>>
> >>>>> The new format is stored in sensor->mode, and applied at the next
> >>>>> s_stream(1) operation if it differs from the already programmed one,
> >>>>> at least, this is how it is intended to work, have you found any
> >>>>> failing s_stream/set_fmt/s_stream which could be caused by a bug ?
> >>>>
> >>>> What I meant is that there could be valid sequence of calls
> >>>>
> >>>> s_stream(enable=1)
> >>>> s_fmt
> >>>> s_stream(enable=1)
> >>>>
> >>>> For example if two video devices are connected to the sensor and they
> >>>> stream simultaneously. There was a discussion about adding a code to the core
> >>>
> >>> I'm not sure it is possible, given that the subdev has a single source
> >>> pad
> >>
> >> Video devices should not be connected directly to the sensor, they can also
> >> be connected to the sensor through an isp entity that is connected to the sensor
> >> from one side and to two video devices from the other side.
> >
> > I don't think it should be the job of the sensor driver to handle this.
> > A sensor can be streaming or not streaming, and a .s_stream(1) call
> > while already streaming shouldn't happen. It's the job of the ISP driver
> > (with help from core code) to ensure this won't happen. Otherwise we
> > would have to protect against that case in all sensor drivers,
> > duplicating code in many places and opening the door to bugs. Subdev
> > drivers should be as simple as possible.
> 
> Most of the sensor driver I've briefly looked at implement a simple
> check to avoid double stream(1) but they do not implement any form of
> refcounting. I think that does more harm than good to be honest, as it
> would hide  potential problematic start stream sequences, but would
> stop the sensor at the first stream(0), leaving one of the multiple
> receivers stuck.
> 
> I would prefer avoid doing this here.
> 
> However the driver already refcounting on s_power(), which if I'm not
> mistaken could be avoided, as bridges should use
> v4l2_pipeline_pm_get(), which already does refcounting, if I'm not
> mistaken.

.s_power() can also be called when opening the subdev device node from
userspace, through sd->internal_ops->open(). In new drivers, I'd
recommend implementing .s_power() based on runtime PM, with .s_power(1)
calling pm_runtime_get_sync() and .s_power(0) calling pm_runtime_put().
.s_stream() should call the runtime PM functions too. That way all the
refcounting will be handled by runtime PM.

.s_stream() should not be refcounted, the caller should ensure that a
started sensor doesn't get started again and that a stopped sensor
doesn't receive a .s_stream(0) call.

> To me, grasping how s_stream() and s_start() work for real is still hard,
> as those are the only two operation propagated along the pipeline by
> briges, even for MC platforms, and it seems looking at the existing
> driver, the confusion is big, as all of them handle things slightly
> differently :/

None of this has ever been really documented, and APIs have evolved over
time without fixing drivers, hence today's mess.

> >>>> to follow the s_stream callback and call it only if the subdev is not streaming
> >>>> but currently subdevs should support it themselves.
> >>>
> >>> Oh, so you're concerned about the fact userspace can call s_stream(1)
> >>> twice consecutively! it's indipendent from s_ftm if I got your point.
> >>>
> >>> In this case a flag to control if the device is streaming already should
> >>> help, yes, I overlooked that indeed.
> >>>
> >>>>>>>>> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
> >>>>>>>>> ---
> >>>>>>>>>      drivers/media/i2c/ov5647.c | 16 +++++++++++++++-
> >>>>>>>>>      1 file changed, 15 insertions(+), 1 deletion(-)
> >>>>>>>>>
> >>>>>>>>> diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
> >>>>>>>>> index 39e320f321bd8..ac114269e1c73 100644
> >>>>>>>>> --- a/drivers/media/i2c/ov5647.c
> >>>>>>>>> +++ b/drivers/media/i2c/ov5647.c
> >>>>>>>>> @@ -96,6 +96,7 @@ struct ov5647 {
> >>>>>>>>>      	bool				clock_ncont;
> >>>>>>>>>      	struct v4l2_ctrl_handler	ctrls;
> >>>>>>>>>      	struct ov5647_mode		*mode;
> >>>>>>>>> +	struct ov5647_mode		*current_mode;
> >>>>>>>>>      };
> >>>>>>>>>      static inline struct ov5647 *to_sensor(struct v4l2_subdev *sd)
> >>>>>>>>> @@ -750,9 +751,13 @@ static int ov5647_set_virtual_channel(struct v4l2_subdev *sd, int channel)
> >>>>>>>>>      static int ov5647_set_mode(struct v4l2_subdev *sd)
> >>>>>>>>>      {
> >>>>>>>>>      	struct i2c_client *client = v4l2_get_subdevdata(sd);
> >>>>>>>>> +	struct ov5647 *sensor = to_sensor(sd);
> >>>>>>>>>      	u8 resetval, rdval;
> >>>>>>>>>      	int ret;
> >>>>>>>>> +	if (sensor->mode == sensor->current_mode)
> >>>>>>>>> +		return 0;
> >>>>>>>>> +
> >>>>>>>>>      	ret = ov5647_read(sd, OV5647_SW_STANDBY, &rdval);
> >>>>>>>>>      	if (ret < 0)
> >>>>>>>>>      		return ret;
> >>>>>>>>> @@ -778,6 +783,8 @@ static int ov5647_set_mode(struct v4l2_subdev *sd)
> >>>>>>>>>      			return ret;
> >>>>>>>>>      	}
> >>>>>>>>> +	sensor->current_mode = sensor->mode;
> >>>>>>>>> +
> >>>>>>>>>      	return 0;
> >>>>>>>>>      }
> >>>>>>>>> @@ -816,6 +823,7 @@ static int ov5647_stream_on(struct v4l2_subdev *sd)
> >>>>>>>>>      static int ov5647_stream_off(struct v4l2_subdev *sd)
> >>>>>>>>>      {
> >>>>>>>>> +	struct ov5647 *sensor = to_sensor(sd);
> >>>>>>>>>      	int ret;
> >>>>>>>>>      	ret = ov5647_write(sd, OV5647_REG_MIPI_CTRL00, MIPI_CTRL00_CLOCK_LANE_GATE |
> >>>>>>>>> @@ -827,7 +835,13 @@ static int ov5647_stream_off(struct v4l2_subdev *sd)
> >>>>>>>>>      	if (ret < 0)
> >>>>>>>>>      		return ret;
> >>>>>>>>> -	return ov5647_write(sd, OV5640_REG_PAD_OUT, 0x01);
> >>>>>>>>> +	ret = ov5647_write(sd, OV5640_REG_PAD_OUT, 0x01);
> >>>>>>>>> +	if (ret < 0)
> >>>>>>>>> +		return ret;
> >>>>>>>>> +
> >>>>>>>>> +	sensor->current_mode = NULL;
> >>>>>>>>> +
> >>>>>>>>> +	return 0;
> >>>>>>>>>      }
> >>>>>>>>>      static int set_sw_standby(struct v4l2_subdev *sd, bool standby)
> >>>>>>>>>

-- 
Regards,

Laurent Pinchart

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

* Re: [libcamera-devel] [PATCH 16/25] media: ov5647: Add support for get_selection()
  2020-06-23 16:49 ` [PATCH 16/25] media: ov5647: Add support for get_selection() Jacopo Mondi
@ 2020-07-09 19:56   ` Dafna Hirschfeld
  0 siblings, 0 replies; 56+ messages in thread
From: Dafna Hirschfeld @ 2020-07-09 19:56 UTC (permalink / raw)
  To: Jacopo Mondi, mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dave.stevenson, naush
  Cc: andrew_gabbasov, mrodin, mripard, libcamera-devel, sudipi,
	hugues.fruchet, erosca, aford173, linux-media



On 23.06.20 18:49, Jacopo Mondi wrote:
> From: Dave Stevenson <dave.stevenson@raspberrypi.com>
> 
> Support the get_selection() pad operation to report the device
> full pixel array size, the currently applied analogue crop rectangle and
> the active pixel array dimensions.
> 
> Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
> ---
>   drivers/media/i2c/ov5647.c | 95 ++++++++++++++++++++++++++++----------
>   1 file changed, 71 insertions(+), 24 deletions(-)
> 
> diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
> index a801ed0249aad..3757f0b10fe93 100644
> --- a/drivers/media/i2c/ov5647.c
> +++ b/drivers/media/i2c/ov5647.c
> @@ -59,25 +59,14 @@
>   #define VAL_TERM 0xfe
>   #define REG_DLY  0xffff
>   
> -#define OV5647_ROW_START		0x01
> -#define OV5647_ROW_START_MIN		0
> -#define OV5647_ROW_START_MAX		2004
> -#define OV5647_ROW_START_DEF		54
> -
> -#define OV5647_COLUMN_START		0x02
> -#define OV5647_COLUMN_START_MIN		0
> -#define OV5647_COLUMN_START_MAX		2750
> -#define OV5647_COLUMN_START_DEF		16
> -
> -#define OV5647_WINDOW_HEIGHT		0x03
> -#define OV5647_WINDOW_HEIGHT_MIN	2
> -#define OV5647_WINDOW_HEIGHT_MAX	2006
> -#define OV5647_WINDOW_HEIGHT_DEF	1944
> -
> -#define OV5647_WINDOW_WIDTH		0x04
> -#define OV5647_WINDOW_WIDTH_MIN		2
> -#define OV5647_WINDOW_WIDTH_MAX		2752
> -#define OV5647_WINDOW_WIDTH_DEF		2592
> +/* OV5647 native and active pixel array size */
> +#define OV5647_NATIVE_WIDTH		2624U
> +#define OV5647_NATIVE_HEIGHT		1956U
> +
> +#define OV5647_PIXEL_ARRAY_LEFT		16U
> +#define OV5647_PIXEL_ARRAY_TOP		16U
> +#define OV5647_PIXEL_ARRAY_WIDTH	2592U
> +#define OV5647_PIXEL_ARRAY_HEIGHT	1944U
>   
>   struct regval_list {
>   	u16 addr;
> @@ -86,6 +75,7 @@ struct regval_list {
>   
>   struct ov5647_mode {
>   	struct v4l2_mbus_framefmt	format;
> +	struct v4l2_rect		crop;
>   	struct regval_list		*reg_list;
>   	unsigned int			num_regs;
>   };
> @@ -224,6 +214,12 @@ static struct ov5647_mode ov5647_8bit_modes[] = {
>   			.width		= 640,
>   			.height		= 480
>   		},
> +		.crop = {
> +			.left		= 0,
> +			.top		= 0,
> +			.width		= 1280,
> +			.height		= 960,
> +		},
>   		.reg_list	= ov5647_640x480,
>   		.num_regs	= ARRAY_SIZE(ov5647_640x480)
>   	},
> @@ -412,7 +408,7 @@ static int set_sw_standby(struct v4l2_subdev *sd, bool standby)
>   static int ov5647_sensor_power(struct v4l2_subdev *sd, int on)
>   {
>   	struct i2c_client *client = v4l2_get_subdevdata(sd);
> -	struct ov5647 *ov5647 = to_state(sd);
> +	struct ov5647 *sensor = to_sensor(sd);

Hi,
This is a compilation fix that was introduced in patch
'media: ov5647: Rationalize driver structure name'

Thanks,
Dafna

>   	int ret = 0;
>   
>   	mutex_lock(&sensor->lock);
> @@ -507,6 +503,20 @@ static const struct v4l2_subdev_core_ops ov5647_subdev_core_ops = {
>   #endif
>   };
>   
> +static const struct v4l2_rect *
> +__ov5647_get_pad_crop(struct ov5647 *ov5647, struct v4l2_subdev_pad_config *cfg,
> +		      unsigned int pad, enum v4l2_subdev_format_whence which)
> +{
> +	switch (which) {
> +	case V4L2_SUBDEV_FORMAT_TRY:
> +		return v4l2_subdev_get_try_crop(&ov5647->sd, cfg, pad);
> +	case V4L2_SUBDEV_FORMAT_ACTIVE:
> +		return &ov5647->mode->crop;
> +	}
> +
> +	return NULL;
> +}
> +
>   static int ov5647_s_stream(struct v4l2_subdev *sd, int enable)
>   {
>   	struct ov5647 *sensor = to_sensor(sd);
> @@ -577,11 +587,48 @@ static int ov5647_set_get_fmt(struct v4l2_subdev *sd,
>   	return 0;
>   }
>   
> +static int ov5647_get_selection(struct v4l2_subdev *sd,
> +				struct v4l2_subdev_pad_config *cfg,
> +				struct v4l2_subdev_selection *sel)
> +{
> +	switch (sel->target) {
> +	case V4L2_SEL_TGT_CROP: {
> +		struct ov5647 *sensor = to_sensor(sd);
> +
> +		mutex_lock(&sensor->lock);
> +		sel->r = *__ov5647_get_pad_crop(sensor, cfg, sel->pad,
> +						sel->which);
> +		mutex_unlock(&sensor->lock);
> +
> +		return 0;
> +	}
> +
> +	case V4L2_SEL_TGT_NATIVE_SIZE:
> +		sel->r.top = 0;
> +		sel->r.left = 0;
> +		sel->r.width = OV5647_NATIVE_WIDTH;
> +		sel->r.height = OV5647_NATIVE_HEIGHT;
> +
> +		return 0;
> +
> +	case V4L2_SEL_TGT_CROP_DEFAULT:
> +		sel->r.top = OV5647_PIXEL_ARRAY_TOP;
> +		sel->r.left = OV5647_PIXEL_ARRAY_LEFT;
> +		sel->r.width = OV5647_PIXEL_ARRAY_WIDTH;
> +		sel->r.height = OV5647_PIXEL_ARRAY_HEIGHT;
> +
> +		return 0;
> +	}
> +
> +	return -EINVAL;
> +}
> +
>   static const struct v4l2_subdev_pad_ops ov5647_subdev_pad_ops = {
>   	.enum_mbus_code		= ov5647_enum_mbus_code,
>   	.enum_frame_size	= ov5647_enum_frame_size,
>   	.set_fmt		= ov5647_set_get_fmt,
>   	.get_fmt		= ov5647_set_get_fmt,
> +	.get_selection		= ov5647_get_selection,
>   };
>   
>   static const struct v4l2_subdev_ops ov5647_subdev_ops = {
> @@ -626,10 +673,10 @@ static int ov5647_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
>   	struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(sd, fh->pad, 0);
>   	struct v4l2_rect *crop = v4l2_subdev_get_try_crop(sd, fh->pad, 0);
>   
> -	crop->left = OV5647_COLUMN_START_DEF;
> -	crop->top = OV5647_ROW_START_DEF;
> -	crop->width = OV5647_WINDOW_WIDTH_DEF;
> -	crop->height = OV5647_WINDOW_HEIGHT_DEF;
> +	crop->left = OV5647_PIXEL_ARRAY_LEFT;
> +	crop->top = OV5647_PIXEL_ARRAY_TOP;
> +	crop->width = OV5647_PIXEL_ARRAY_WIDTH;
> +	crop->height = OV5647_PIXEL_ARRAY_HEIGHT;
>   
>   	*format = OV5647_DEFAULT_FORMAT;
>   
> 

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

* Re: [libcamera-devel] [PATCH 03/25] media: ov5647: Add support for PWDN GPIO.
  2020-06-23 10:07 ` [PATCH 03/25] media: ov5647: Add support for PWDN GPIO Jacopo Mondi
@ 2020-07-09 20:04   ` Dafna Hirschfeld
  2020-07-14 12:45     ` Jacopo Mondi
  0 siblings, 1 reply; 56+ messages in thread
From: Dafna Hirschfeld @ 2020-07-09 20:04 UTC (permalink / raw)
  To: Jacopo Mondi, mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dave.stevenson, naush
  Cc: mrodin, hugues.fruchet, mripard, aford173, sudipi,
	andrew_gabbasov, erosca, linux-media, libcamera-devel



On 23.06.20 12:07, Jacopo Mondi wrote:
> From: Dave Stevenson <dave.stevenson@raspberrypi.org>
> 
> Add support for an optional GPIO connected to PWDN on the sensor. This
> allows the use of hardware standby mode where internal device clock
> and circuit activities are halted.
> 
> Please note that power is off when PWDN is high.
> 
> Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
> Signed-off-by: Roman Kovalivskyi <roman.kovalivskyi@globallogic.com>
> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
> ---
>   drivers/media/i2c/ov5647.c | 28 ++++++++++++++++++++++++++++
>   1 file changed, 28 insertions(+)
> 
> diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
> index e7d2e5b4ad4b9..105ff7f899b34 100644
> --- a/drivers/media/i2c/ov5647.c
> +++ b/drivers/media/i2c/ov5647.c
> @@ -21,6 +21,7 @@
>   
>   #include <linux/clk.h>
>   #include <linux/delay.h>
> +#include <linux/gpio/consumer.h>
>   #include <linux/i2c.h>
>   #include <linux/init.h>
>   #include <linux/io.h>
> @@ -35,6 +36,13 @@
>   
>   #define SENSOR_NAME "ov5647"
>   
> +/*
> + * From the datasheet, "20ms after PWDN goes low or 20ms after RESETB goes
> + * high if reset is inserted after PWDN goes high, host can access sensor's
> + * SCCB to initialize sensor."
> + */
> +#define PWDN_ACTIVE_DELAY_MS	20
> +
>   #define MIPI_CTRL00_CLOCK_LANE_GATE		BIT(5)
>   #define MIPI_CTRL00_BUS_IDLE			BIT(2)
>   #define MIPI_CTRL00_CLOCK_LANE_DISABLE		BIT(0)
> @@ -86,6 +94,7 @@ struct ov5647 {
>   	unsigned int			height;
>   	int				power_count;
>   	struct clk			*xclk;
> +	struct gpio_desc		*pwdn;
>   };
>   
>   static inline struct ov5647 *to_state(struct v4l2_subdev *sd)
> @@ -355,6 +364,11 @@ static int ov5647_sensor_power(struct v4l2_subdev *sd, int on)
>   	if (on && !ov5647->power_count)	{
>   		dev_dbg(&client->dev, "OV5647 power on\n");
>   
> +		if (ov5647->pwdn) {
> +			gpiod_set_value_cansleep(ov5647->pwdn, 0);
> +			msleep(PWDN_ACTIVE_DELAY_MS);
> +		}
> +
>   		ret = clk_prepare_enable(ov5647->xclk);
>   		if (ret < 0) {
>   			dev_err(&client->dev, "clk prepare enable failed\n");
> @@ -392,6 +406,8 @@ static int ov5647_sensor_power(struct v4l2_subdev *sd, int on)
>   			dev_dbg(&client->dev, "soft stby failed\n");
>   
>   		clk_disable_unprepare(ov5647->xclk);
> +
> +		gpiod_set_value_cansleep(ov5647->pwdn, 1);
>   	}
>   
>   	/* Update the power count. */
> @@ -581,6 +597,10 @@ static int ov5647_probe(struct i2c_client *client)
>   		return -EINVAL;
>   	}
>   
> +	/* Request the power down GPIO asserted */
> +	sensor->pwdn = devm_gpiod_get_optional(&client->dev, "pwdn",
> +					       GPIOD_OUT_HIGH);

Hi,
I see that other drivers check for error from 'devm_gpiod_get_optional'
using 'IS_ERR'

Thanks,
Dafna

> +
>   	mutex_init(&sensor->lock);
>   
>   	sd = &sensor->sd;
> @@ -594,7 +614,15 @@ static int ov5647_probe(struct i2c_client *client)
>   	if (ret < 0)
>   		goto mutex_remove;
>   
> +	if (sensor->pwdn) {
> +		gpiod_set_value_cansleep(sensor->pwdn, 0);
> +		msleep(PWDN_ACTIVE_DELAY_MS);
> +	}
> +
>   	ret = ov5647_detect(sd);
> +
> +	gpiod_set_value_cansleep(sensor->pwdn, 1);
> +
>   	if (ret < 0)
>   		goto error;
>   
> 

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

* Re: [PATCH 00/25] media: ov5647: Support RaspberryPi Camera Module v1
  2020-06-23 10:07 [PATCH 00/25] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
                   ` (25 preceding siblings ...)
  2020-06-29 17:33 ` [PATCH 00/25] media: ov5647: Support RaspberryPi Camera Module v1 Dafna Hirschfeld
@ 2020-07-10 15:59 ` Dafna Hirschfeld
  2020-07-14 12:48   ` Jacopo Mondi
  26 siblings, 1 reply; 56+ messages in thread
From: Dafna Hirschfeld @ 2020-07-10 15:59 UTC (permalink / raw)
  To: Jacopo Mondi, mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dave.stevenson, naush
  Cc: andrew_gabbasov, mrodin, mripard, libcamera-devel, sudipi,
	hugues.fruchet, erosca, aford173, linux-media



On 23.06.20 12:07, Jacopo Mondi wrote:
> -------------------------------------------------------------------------------
> Second attempt after my ISP blocked the part of the first sending.
> Also removed Luis Oliveira email from the receiver list as it gets
> bounced back.
> 550 5.1.1 <lolivei@synopsys.com>... User unknown
> -------------------------------------------------------------------------------
> 
> Hello,
>    this series improves and expand the existing ov5647 sensor driver to
> the same feature level as found in RaspberryPi BSP.
> 
> It is based on recent media tree master and the sensor bindings conversion
> to dt-schema I sent out a few days ago:
> "[PATCH 0/2] dt-bidings: media: ov5647 bindings + small fix"
> 
> The first patches in the series has been sent by Roman as part of
> "[PATCH v2 0/6] ov5647 driver improvement"
> I took his patches in, addressed review comments and rebased on top
> of the new dt-schema bindings. I kept the extensive receiver list he had
> in his series for this reason.
> 
> The series continues by polishing and cleaning up the driver and expanding
> its functionalities to support multiple modes and image formats.
> 
> The series has been tested with libcamera and the driver functionalities
> compared with the BSP driver ones, and tested stand-alone by capturing
> raw frames with yavta.

Hi,
Tested it on rock-pi 4 board with rkisp1 driver for the isp,
using the command 'cam -c 1 -C --file="/tmp/libcamframe#.data" -s width=800,height=600'
from libcamera.

This the branch: https://gitlab.collabora.com/dafna/linux/-/tree/test-ov5647-10-jul
The top commit is the ov5647 dts node:
https://gitlab.collabora.com/dafna/linux/-/commit/6aa58e6c5378dc20fce9fcc0ef68916ae3fa7b22

Tested-by: Dafna Hirschfeld <dafna.hirschfeld@collabora.com>

> 
> Thanks
>     j
> 
> Dave Stevenson (8):
>    media: ov5647: Add support for PWDN GPIO.
>    media: ov5647: Add support for non-continuous clock mode
>    media: ov5647: Add set_fmt and get_fmt calls.
>    media: ov5647: Add support for get_selection()
>    media: ov5647: Set V4L2_SUBDEV_FL_HAS_EVENTS flag
>    media: ov5647: Support V4L2_CID_PIXEL_RATE
>    media: ov5647: Support V4L2_CID_VBLANK control
>    media: ov5647: Advertise the correct exposure range
> 
> David Plowman (1):
>    media: ov5647: Support gain, exposure and AWB controls
> 
> Jacopo Mondi (16):
>    dt-bindings: media: ov5647: Document pwdn-gpios
>    dt-bindings: media: ov5647: Document clock-noncontinuous
>    media: ov5647: Fix format initialization
>    media: ov5647: Fix style issues
>    media: ov5647: Replace license with SPDX identifier
>    media: ov5647: Fix return value from read/write
>    media: ov5647: Program mode at s_stream(1) time
>    media: ov5647: Implement enum_frame_size()
>    media: ov5647: Protect s_stream() with mutex
>    media: ov5647: Rationalize driver structure name
>    media: ov5647: Break out format handling
>    media: ov5647: Rename SBGGR8 VGA mode
>    media: ov5647: Add SGGBR10_1X10 modes
>    media: ov5647: Implement set_fmt pad operation
>    media: ov5647: Program mode only if it has changed
>    media: ov5647: Support V4L2_CID_HBLANK control
> 
>   .../devicetree/bindings/media/i2c/ov5647.yaml |   11 +
>   drivers/media/i2c/ov5647.c                    | 1267 +++++++++++++++--
>   2 files changed, 1126 insertions(+), 152 deletions(-)
> 
> --
> 2.27.0
> 
> _______________________________________________
> libcamera-devel mailing list
> libcamera-devel@lists.libcamera.org
> https://lists.libcamera.org/listinfo/libcamera-devel
> 

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

* Re: [libcamera-devel] [PATCH 03/25] media: ov5647: Add support for PWDN GPIO.
  2020-07-09 20:04   ` [libcamera-devel] " Dafna Hirschfeld
@ 2020-07-14 12:45     ` Jacopo Mondi
  0 siblings, 0 replies; 56+ messages in thread
From: Jacopo Mondi @ 2020-07-14 12:45 UTC (permalink / raw)
  To: Dafna Hirschfeld
  Cc: mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dave.stevenson, naush, mrodin, hugues.fruchet,
	mripard, aford173, sudipi, andrew_gabbasov, erosca, linux-media,
	libcamera-devel

Hi Dafna,

On Thu, Jul 09, 2020 at 10:04:14PM +0200, Dafna Hirschfeld wrote:
>
>
> On 23.06.20 12:07, Jacopo Mondi wrote:
> > From: Dave Stevenson <dave.stevenson@raspberrypi.org>
> >
> > Add support for an optional GPIO connected to PWDN on the sensor. This
> > allows the use of hardware standby mode where internal device clock
> > and circuit activities are halted.
> >
> > Please note that power is off when PWDN is high.
> >
> > Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
> > Signed-off-by: Roman Kovalivskyi <roman.kovalivskyi@globallogic.com>
> > Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
> > ---
> >   drivers/media/i2c/ov5647.c | 28 ++++++++++++++++++++++++++++
> >   1 file changed, 28 insertions(+)
> >
> > diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
> > index e7d2e5b4ad4b9..105ff7f899b34 100644
> > --- a/drivers/media/i2c/ov5647.c
> > +++ b/drivers/media/i2c/ov5647.c
> > @@ -21,6 +21,7 @@
> >   #include <linux/clk.h>
> >   #include <linux/delay.h>
> > +#include <linux/gpio/consumer.h>
> >   #include <linux/i2c.h>
> >   #include <linux/init.h>
> >   #include <linux/io.h>
> > @@ -35,6 +36,13 @@
> >   #define SENSOR_NAME "ov5647"
> > +/*
> > + * From the datasheet, "20ms after PWDN goes low or 20ms after RESETB goes
> > + * high if reset is inserted after PWDN goes high, host can access sensor's
> > + * SCCB to initialize sensor."
> > + */
> > +#define PWDN_ACTIVE_DELAY_MS	20
> > +
> >   #define MIPI_CTRL00_CLOCK_LANE_GATE		BIT(5)
> >   #define MIPI_CTRL00_BUS_IDLE			BIT(2)
> >   #define MIPI_CTRL00_CLOCK_LANE_DISABLE		BIT(0)
> > @@ -86,6 +94,7 @@ struct ov5647 {
> >   	unsigned int			height;
> >   	int				power_count;
> >   	struct clk			*xclk;
> > +	struct gpio_desc		*pwdn;
> >   };
> >   static inline struct ov5647 *to_state(struct v4l2_subdev *sd)
> > @@ -355,6 +364,11 @@ static int ov5647_sensor_power(struct v4l2_subdev *sd, int on)
> >   	if (on && !ov5647->power_count)	{
> >   		dev_dbg(&client->dev, "OV5647 power on\n");
> > +		if (ov5647->pwdn) {
> > +			gpiod_set_value_cansleep(ov5647->pwdn, 0);
> > +			msleep(PWDN_ACTIVE_DELAY_MS);
> > +		}
> > +
> >   		ret = clk_prepare_enable(ov5647->xclk);
> >   		if (ret < 0) {
> >   			dev_err(&client->dev, "clk prepare enable failed\n");
> > @@ -392,6 +406,8 @@ static int ov5647_sensor_power(struct v4l2_subdev *sd, int on)
> >   			dev_dbg(&client->dev, "soft stby failed\n");
> >   		clk_disable_unprepare(ov5647->xclk);
> > +
> > +		gpiod_set_value_cansleep(ov5647->pwdn, 1);
> >   	}
> >   	/* Update the power count. */
> > @@ -581,6 +597,10 @@ static int ov5647_probe(struct i2c_client *client)
> >   		return -EINVAL;
> >   	}
> > +	/* Request the power down GPIO asserted */
> > +	sensor->pwdn = devm_gpiod_get_optional(&client->dev, "pwdn",
> > +					       GPIOD_OUT_HIGH);
>
> Hi,
> I see that other drivers check for error from 'devm_gpiod_get_optional'
> using 'IS_ERR'

Thanks for noticing. It's probably worth adding a check for this.
I'll fix in v2.

Thanks
  j

>
> Thanks,
> Dafna
>
> > +
> >   	mutex_init(&sensor->lock);
> >   	sd = &sensor->sd;
> > @@ -594,7 +614,15 @@ static int ov5647_probe(struct i2c_client *client)
> >   	if (ret < 0)
> >   		goto mutex_remove;
> > +	if (sensor->pwdn) {
> > +		gpiod_set_value_cansleep(sensor->pwdn, 0);
> > +		msleep(PWDN_ACTIVE_DELAY_MS);
> > +	}
> > +
> >   	ret = ov5647_detect(sd);
> > +
> > +	gpiod_set_value_cansleep(sensor->pwdn, 1);
> > +
> >   	if (ret < 0)
> >   		goto error;
> >

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

* Re: [PATCH 00/25] media: ov5647: Support RaspberryPi Camera Module v1
  2020-07-10 15:59 ` Dafna Hirschfeld
@ 2020-07-14 12:48   ` Jacopo Mondi
  0 siblings, 0 replies; 56+ messages in thread
From: Jacopo Mondi @ 2020-07-14 12:48 UTC (permalink / raw)
  To: Dafna Hirschfeld
  Cc: mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dave.stevenson, naush, andrew_gabbasov,
	mrodin, mripard, libcamera-devel, sudipi, hugues.fruchet, erosca,
	aford173, linux-media

Hi Dafna,

On Fri, Jul 10, 2020 at 05:59:56PM +0200, Dafna Hirschfeld wrote:
>
>
> On 23.06.20 12:07, Jacopo Mondi wrote:
> > -------------------------------------------------------------------------------
> > Second attempt after my ISP blocked the part of the first sending.
> > Also removed Luis Oliveira email from the receiver list as it gets
> > bounced back.
> > 550 5.1.1 <lolivei@synopsys.com>... User unknown
> > -------------------------------------------------------------------------------
> >
> > Hello,
> >    this series improves and expand the existing ov5647 sensor driver to
> > the same feature level as found in RaspberryPi BSP.
> >
> > It is based on recent media tree master and the sensor bindings conversion
> > to dt-schema I sent out a few days ago:
> > "[PATCH 0/2] dt-bidings: media: ov5647 bindings + small fix"
> >
> > The first patches in the series has been sent by Roman as part of
> > "[PATCH v2 0/6] ov5647 driver improvement"
> > I took his patches in, addressed review comments and rebased on top
> > of the new dt-schema bindings. I kept the extensive receiver list he had
> > in his series for this reason.
> >
> > The series continues by polishing and cleaning up the driver and expanding
> > its functionalities to support multiple modes and image formats.
> >
> > The series has been tested with libcamera and the driver functionalities
> > compared with the BSP driver ones, and tested stand-alone by capturing
> > raw frames with yavta.
>
> Hi,
> Tested it on rock-pi 4 board with rkisp1 driver for the isp,
> using the command 'cam -c 1 -C --file="/tmp/libcamframe#.data" -s width=800,height=600'
> from libcamera.
>
> This the branch: https://gitlab.collabora.com/dafna/linux/-/tree/test-ov5647-10-jul
> The top commit is the ov5647 dts node:
> https://gitlab.collabora.com/dafna/linux/-/commit/6aa58e6c5378dc20fce9fcc0ef68916ae3fa7b22
>
> Tested-by: Dafna Hirschfeld <dafna.hirschfeld@collabora.com>
>

Thanks for having validated the driver on a platform different from
the one I've tested with.

I'll collect your tag in the next version.

Thanks
  j

> >
> > Thanks
> >     j
> >
> > Dave Stevenson (8):
> >    media: ov5647: Add support for PWDN GPIO.
> >    media: ov5647: Add support for non-continuous clock mode
> >    media: ov5647: Add set_fmt and get_fmt calls.
> >    media: ov5647: Add support for get_selection()
> >    media: ov5647: Set V4L2_SUBDEV_FL_HAS_EVENTS flag
> >    media: ov5647: Support V4L2_CID_PIXEL_RATE
> >    media: ov5647: Support V4L2_CID_VBLANK control
> >    media: ov5647: Advertise the correct exposure range
> >
> > David Plowman (1):
> >    media: ov5647: Support gain, exposure and AWB controls
> >
> > Jacopo Mondi (16):
> >    dt-bindings: media: ov5647: Document pwdn-gpios
> >    dt-bindings: media: ov5647: Document clock-noncontinuous
> >    media: ov5647: Fix format initialization
> >    media: ov5647: Fix style issues
> >    media: ov5647: Replace license with SPDX identifier
> >    media: ov5647: Fix return value from read/write
> >    media: ov5647: Program mode at s_stream(1) time
> >    media: ov5647: Implement enum_frame_size()
> >    media: ov5647: Protect s_stream() with mutex
> >    media: ov5647: Rationalize driver structure name
> >    media: ov5647: Break out format handling
> >    media: ov5647: Rename SBGGR8 VGA mode
> >    media: ov5647: Add SGGBR10_1X10 modes
> >    media: ov5647: Implement set_fmt pad operation
> >    media: ov5647: Program mode only if it has changed
> >    media: ov5647: Support V4L2_CID_HBLANK control
> >
> >   .../devicetree/bindings/media/i2c/ov5647.yaml |   11 +
> >   drivers/media/i2c/ov5647.c                    | 1267 +++++++++++++++--
> >   2 files changed, 1126 insertions(+), 152 deletions(-)
> >
> > --
> > 2.27.0
> >
> > _______________________________________________
> > libcamera-devel mailing list
> > libcamera-devel@lists.libcamera.org
> > https://lists.libcamera.org/listinfo/libcamera-devel
> >

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

* Re: [PATCH 15/25] media: ov5647: Break out format handling
  2020-06-23 16:42 ` [PATCH 15/25] media: ov5647: Break out format handling Jacopo Mondi
@ 2020-07-31 11:44   ` Sakari Ailus
  0 siblings, 0 replies; 56+ messages in thread
From: Sakari Ailus @ 2020-07-31 11:44 UTC (permalink / raw)
  To: Jacopo Mondi
  Cc: mchehab, hverkuil, laurent.pinchart, roman.kovalivskyi,
	dave.stevenson, naush, mrodin, hugues.fruchet, mripard, aford173,
	sudipi, andrew_gabbasov, erosca, linux-media, libcamera-devel

Hi Jacopo,

Btw. I've bounced the two DT binding patches to DT list + Rob. Please
remember that in v2 if there are changes.

On Tue, Jun 23, 2020 at 06:42:24PM +0200, Jacopo Mondi wrote:
> Break format handling out from the main driver structure.
> 
> This commit prepares for the introduction of more sensor formats and
> resolutions by instrumenting the existing operation to work on multiple
> modes instead of assuming a single one supported.
> 
> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
> ---
>  drivers/media/i2c/ov5647.c | 84 +++++++++++++++++++++++++++-----------
>  1 file changed, 61 insertions(+), 23 deletions(-)
> 
> diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
> index 03f4f1a257ecd..a801ed0249aad 100644
> --- a/drivers/media/i2c/ov5647.c
> +++ b/drivers/media/i2c/ov5647.c
> @@ -84,18 +84,28 @@ struct regval_list {
>  	u8 data;
>  };
>  
> +struct ov5647_mode {
> +	struct v4l2_mbus_framefmt	format;
> +	struct regval_list		*reg_list;
> +	unsigned int			num_regs;
> +};
> +
> +struct ov5647_format_list {
> +	unsigned int			mbus_code;
> +	struct ov5647_mode		*modes;
> +	unsigned int			num_modes;
> +};
> +
>  struct ov5647 {
>  	struct v4l2_subdev		sd;
>  	struct media_pad		pad;
>  	struct mutex			lock;
> -	struct v4l2_mbus_framefmt	format;
> -	unsigned int			width;
> -	unsigned int			height;
>  	int				power_count;
>  	struct clk			*xclk;
>  	struct gpio_desc		*pwdn;
>  	bool				clock_ncont;
>  	struct v4l2_ctrl_handler	ctrls;
> +	struct ov5647_mode		*mode;
>  };
>  
>  static inline struct ov5647 *to_sensor(struct v4l2_subdev *sd)
> @@ -205,6 +215,33 @@ static struct regval_list ov5647_640x480[] = {
>  	{0x0100, 0x01},
>  };
>  
> +static struct ov5647_mode ov5647_8bit_modes[] = {

const

> +	{
> +		.format	= {
> +			.code		= MEDIA_BUS_FMT_SBGGR8_1X8,
> +			.colorspace	= V4L2_COLORSPACE_SRGB,
> +			.field		= V4L2_FIELD_NONE,
> +			.width		= 640,
> +			.height		= 480
> +		},
> +		.reg_list	= ov5647_640x480,
> +		.num_regs	= ARRAY_SIZE(ov5647_640x480)
> +	},
> +};
> +
> +static const struct ov5647_format_list ov5647_formats[] = {
> +	{
> +		.mbus_code	= MEDIA_BUS_FMT_SBGGR8_1X8,
> +		.modes		= ov5647_8bit_modes,
> +		.num_modes	= ARRAY_SIZE(ov5647_8bit_modes),
> +	},
> +};
> +
> +#define OV5647_NUM_FORMATS	(ARRAY_SIZE(ov5647_formats))

Please use ARRAY_SIZE() directly, you don't need a macro here.

> +
> +#define OV5647_DEFAULT_MODE	(&ov5647_formats[0].modes[0])
> +#define OV5647_DEFAULT_FORMAT	(ov5647_formats[0].modes[0].format)
> +
>  static int ov5647_write(struct v4l2_subdev *sd, u16 reg, u8 val)
>  {
>  	unsigned char data[3] = { reg >> 8, reg & 0xff, val};
> @@ -282,8 +319,7 @@ static int ov5647_set_mode(struct v4l2_subdev *sd)
>  	if (ret < 0)
>  		return ret;
>  
> -	ret = ov5647_write_array(sd, ov5647_640x480,
> -				 ARRAY_SIZE(ov5647_640x480));
> +	ret = ov5647_write_array(sd, sensor->mode->reg_list, sensor->mode->num_regs);

No need for a line over 80.

>  	if (ret < 0) {
>  		dev_err(&client->dev, "write sensor default regs error\n");
>  		return ret;
> @@ -494,10 +530,10 @@ static int ov5647_enum_mbus_code(struct v4l2_subdev *sd,
>  				 struct v4l2_subdev_pad_config *cfg,
>  				 struct v4l2_subdev_mbus_code_enum *code)
>  {
> -	if (code->index > 0)
> +	if (code->index >= OV5647_NUM_FORMATS)
>  		return -EINVAL;
>  
> -	code->code = MEDIA_BUS_FMT_SBGGR8_1X8;
> +	code->code = ov5647_formats[code->index].mbus_code;
>  
>  	return 0;
>  }
> @@ -506,16 +542,24 @@ static int ov5647_enum_frame_size(struct v4l2_subdev *sd,
>  				  struct v4l2_subdev_pad_config *cfg,
>  				  struct v4l2_subdev_frame_size_enum *fse)
>  {
> -	if (fse->index)
> +	const struct v4l2_mbus_framefmt *fmt;
> +	unsigned int i = 0;
> +
> +	for (; i < OV5647_NUM_FORMATS; ++i) {
> +		if (ov5647_formats[i].mbus_code == fse->code)
> +			break;
> +	}
> +	if (i == OV5647_NUM_FORMATS)
>  		return -EINVAL;
>  
> -	if (fse->code != MEDIA_BUS_FMT_SBGGR8_1X8)
> +	if (fse->index >= ov5647_formats[i].num_modes)
>  		return -EINVAL;
>  
> -	fse->min_width = 640;
> -	fse->max_width = 640;
> -	fse->min_height = 480;
> -	fse->max_height = 480;
> +	fmt = &ov5647_formats[i].modes[fse->index].format;
> +	fse->min_width = fmt->width;
> +	fse->max_width = fmt->width;
> +	fse->min_height = fmt->height;
> +	fse->max_height = fmt->height;
>  
>  	return 0;
>  }
> @@ -528,11 +572,7 @@ static int ov5647_set_get_fmt(struct v4l2_subdev *sd,
>  
>  	/* Only one format is supported, so return that. */
>  	memset(fmt, 0, sizeof(*fmt));
> -	fmt->code = MEDIA_BUS_FMT_SBGGR8_1X8;
> -	fmt->colorspace = V4L2_COLORSPACE_SRGB;
> -	fmt->field = V4L2_FIELD_NONE;
> -	fmt->width = 640;
> -	fmt->height = 480;
> +	*fmt = OV5647_DEFAULT_FORMAT;
>  
>  	return 0;
>  }
> @@ -591,11 +631,7 @@ static int ov5647_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
>  	crop->width = OV5647_WINDOW_WIDTH_DEF;
>  	crop->height = OV5647_WINDOW_HEIGHT_DEF;
>  
> -	format->code = MEDIA_BUS_FMT_SBGGR8_1X8;
> -	format->width = 640;
> -	format->height = 480;
> -	format->field = V4L2_FIELD_NONE;
> -	format->colorspace = V4L2_COLORSPACE_SRGB;
> +	*format = OV5647_DEFAULT_FORMAT;
>  
>  	return 0;
>  }
> @@ -813,6 +849,8 @@ static int ov5647_probe(struct i2c_client *client)
>  
>  	mutex_init(&sensor->lock);
>  
> +	sensor->mode = OV5647_DEFAULT_MODE;

You could do this without the macro, too.

> +
>  	ret = ov5647_init_controls(sensor);
>  	if (ret)
>  		goto mutex_destroy;

-- 
Kind regards,

Sakari Ailus

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

* Re: [PATCH 11/25] media: ov5647: Implement enum_frame_size()
  2020-06-23 16:42 ` [PATCH 11/25] media: ov5647: Implement enum_frame_size() Jacopo Mondi
@ 2020-08-18  7:33   ` Sakari Ailus
  2020-08-18  7:38     ` Sakari Ailus
  0 siblings, 1 reply; 56+ messages in thread
From: Sakari Ailus @ 2020-08-18  7:33 UTC (permalink / raw)
  To: Jacopo Mondi
  Cc: mchehab, hverkuil, laurent.pinchart, roman.kovalivskyi,
	dave.stevenson, naush, mrodin, hugues.fruchet, mripard, aford173,
	sudipi, andrew_gabbasov, erosca, linux-media, libcamera-devel

Hi Jacopo,

On Tue, Jun 23, 2020 at 06:42:20PM +0200, Jacopo Mondi wrote:
> Implement the .enum_frame_size subdev pad operation.
> 
> As the driver only supports one format and one resolution at the moment
> the implementation is trivial.
> 
> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
> ---
>  drivers/media/i2c/ov5647.c | 25 ++++++++++++++++++++++---
>  1 file changed, 22 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
> index bb9ff77f49fe0..859cc5b0d14a3 100644
> --- a/drivers/media/i2c/ov5647.c
> +++ b/drivers/media/i2c/ov5647.c
> @@ -482,6 +482,24 @@ static int ov5647_enum_mbus_code(struct v4l2_subdev *sd,
>  	return 0;
>  }
>  
> +static int ov5647_enum_frame_size(struct v4l2_subdev *sd,
> +				  struct v4l2_subdev_pad_config *cfg,
> +				  struct v4l2_subdev_frame_size_enum *fse)
> +{
> +	if (fse->index)
> +		return -EINVAL;
> +
> +	if (fse->code != MEDIA_BUS_FMT_SBGGR8_1X8)
> +		return -EINVAL;
> +
> +	fse->min_width = 640;
> +	fse->max_width = 640;
> +	fse->min_height = 480;
> +	fse->max_height = 480;

Could this be somehow connected to the mode used? Or at least use a macro
defined close to the mode? This seems to be a 1,3 MP sensor and the driver
only supports VGA...

> +
> +	return 0;
> +}
> +
>  static int ov5647_set_get_fmt(struct v4l2_subdev *sd,
>  			      struct v4l2_subdev_pad_config *cfg,
>  			      struct v4l2_subdev_format *format)
> @@ -500,9 +518,10 @@ static int ov5647_set_get_fmt(struct v4l2_subdev *sd,
>  }
>  
>  static const struct v4l2_subdev_pad_ops ov5647_subdev_pad_ops = {
> -	.enum_mbus_code = ov5647_enum_mbus_code,
> -	.set_fmt =	  ov5647_set_get_fmt,
> -	.get_fmt =	  ov5647_set_get_fmt,
> +	.enum_mbus_code		= ov5647_enum_mbus_code,
> +	.enum_frame_size	= ov5647_enum_frame_size,
> +	.set_fmt		= ov5647_set_get_fmt,
> +	.get_fmt		= ov5647_set_get_fmt,
>  };
>  
>  static const struct v4l2_subdev_ops ov5647_subdev_ops = {
> -- 
> 2.27.0
> 

-- 
Sakari Ailus

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

* Re: [PATCH 11/25] media: ov5647: Implement enum_frame_size()
  2020-08-18  7:33   ` Sakari Ailus
@ 2020-08-18  7:38     ` Sakari Ailus
  0 siblings, 0 replies; 56+ messages in thread
From: Sakari Ailus @ 2020-08-18  7:38 UTC (permalink / raw)
  To: Jacopo Mondi
  Cc: mchehab, hverkuil, laurent.pinchart, roman.kovalivskyi,
	dave.stevenson, naush, mrodin, hugues.fruchet, mripard, aford173,
	sudipi, andrew_gabbasov, erosca, linux-media, libcamera-devel

> Could this be somehow connected to the mode used? Or at least use a macro
> defined close to the mode? This seems to be a 1,3 MP sensor and the driver
> only supports VGA...

Please ignore the comment. I see it's actually addressed by the next patch.

-- 
Sakari Ailus

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

* [PATCH 01/25] dt-bindings: media: ov5647: Document pwdn-gpios
  2020-06-22 17:18 Jacopo Mondi
@ 2020-06-22 17:18 ` Jacopo Mondi
  0 siblings, 0 replies; 56+ messages in thread
From: Jacopo Mondi @ 2020-06-22 17:18 UTC (permalink / raw)
  To: lolivei, mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dave.stevenson, naush
  Cc: Jacopo Mondi, mrodin, hugues.fruchet, mripard, aford173, sudipi,
	andrew_gabbasov, erosca, linux-media, libcamera-devel

Document in dt-schema bindings for the ov5647 sensor the optional
'pwdn-gpios' property.

Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
---
 Documentation/devicetree/bindings/media/i2c/ov5647.yaml | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Documentation/devicetree/bindings/media/i2c/ov5647.yaml b/Documentation/devicetree/bindings/media/i2c/ov5647.yaml
index 067e222e0c7c3..58d64a69e9640 100644
--- a/Documentation/devicetree/bindings/media/i2c/ov5647.yaml
+++ b/Documentation/devicetree/bindings/media/i2c/ov5647.yaml
@@ -25,6 +25,10 @@ properties:
     description: Reference to the xclk clock
     maxItems: 1
 
+  pwdn-gpios:
+    description: Reference to the GPIO connected to the pwdn pin. Active high.
+    maxItems: 1
+
   port:
     type: object
     description: |-
@@ -61,6 +65,7 @@ additionalProperties: false
 
 examples:
   - |
+    #include <dt-bindings/gpio/gpio.h>
 
     i2c {
         #address-cells = <1>;
@@ -70,6 +75,7 @@ examples:
             compatible = "ovti,ov5647";
             reg = <0x36>;
             clocks = <&camera_clk>;
+            pwdn-gpios = <&pioE 29 GPIO_ACTIVE_HIGH>;
 
             port {
                 camera_out: endpoint {
-- 
2.27.0


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

end of thread, back to index

Thread overview: 56+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-06-23 10:07 [PATCH 00/25] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
2020-06-23 10:07 ` [PATCH 01/25] dt-bindings: media: ov5647: Document pwdn-gpios Jacopo Mondi
2020-06-23 10:07 ` [PATCH 02/25] dt-bindings: media: ov5647: Document clock-noncontinuous Jacopo Mondi
2020-06-23 10:07 ` [PATCH 03/25] media: ov5647: Add support for PWDN GPIO Jacopo Mondi
2020-07-09 20:04   ` [libcamera-devel] " Dafna Hirschfeld
2020-07-14 12:45     ` Jacopo Mondi
2020-06-23 10:07 ` [PATCH 04/25] media: ov5647: Add support for non-continuous clock mode Jacopo Mondi
2020-06-23 10:07 ` [PATCH 05/25] media: ov5647: Add set_fmt and get_fmt calls Jacopo Mondi
2020-06-23 10:07 ` [PATCH 06/25] media: ov5647: Fix format initialization Jacopo Mondi
2020-06-23 10:07 ` [PATCH 07/25] media: ov5647: Fix style issues Jacopo Mondi
2020-06-23 10:07 ` [PATCH 08/25] media: ov5647: Replace license with SPDX identifier Jacopo Mondi
2020-06-23 10:07 ` [PATCH 09/25] media: ov5647: Fix return value from read/write Jacopo Mondi
2020-06-23 10:08 ` [PATCH 10/25] media: ov5647: Program mode at s_stream(1) time Jacopo Mondi
2020-06-23 16:42 ` [PATCH 11/25] media: ov5647: Implement enum_frame_size() Jacopo Mondi
2020-08-18  7:33   ` Sakari Ailus
2020-08-18  7:38     ` Sakari Ailus
2020-06-23 16:42 ` [PATCH 12/25] media: ov5647: Protect s_stream() with mutex Jacopo Mondi
2020-06-23 16:42 ` [PATCH 13/25] media: ov5647: Support gain, exposure and AWB controls Jacopo Mondi
2020-06-23 16:42 ` [PATCH 14/25] media: ov5647: Rationalize driver structure name Jacopo Mondi
2020-06-23 16:42 ` [PATCH 15/25] media: ov5647: Break out format handling Jacopo Mondi
2020-07-31 11:44   ` Sakari Ailus
2020-06-23 16:49 ` [PATCH 16/25] media: ov5647: Add support for get_selection() Jacopo Mondi
2020-07-09 19:56   ` [libcamera-devel] " Dafna Hirschfeld
2020-06-23 16:49 ` [PATCH 17/25] media: ov5647: Rename SBGGR8 VGA mode Jacopo Mondi
2020-06-23 16:49 ` [PATCH 18/25] media: ov5647: Add SGGBR10_1X10 modes Jacopo Mondi
2020-06-23 16:49 ` [PATCH 19/25] media: ov5647: Implement set_fmt pad operation Jacopo Mondi
2020-06-29 16:54   ` [libcamera-devel] " Dafna Hirschfeld
2020-06-30 10:13     ` Jacopo Mondi
2020-06-30 11:09       ` Dafna Hirschfeld
2020-06-23 16:55 ` [PATCH 20/25] media: ov5647: Program mode only if it has changed Jacopo Mondi
2020-06-29 17:48   ` Dafna Hirschfeld
2020-06-30  7:43     ` Jacopo Mondi
2020-06-30  9:32       ` Dafna Hirschfeld
2020-06-30 10:06         ` Jacopo Mondi
2020-06-30 10:56           ` Dafna Hirschfeld
2020-06-30 12:05             ` Jacopo Mondi
2020-06-30 13:01               ` Dafna Hirschfeld
2020-06-30 14:53                 ` [libcamera-devel] " Dave Stevenson
2020-06-30 15:11                   ` Dafna Hirschfeld
2020-07-01  7:25                 ` Laurent Pinchart
2020-07-03 12:21                   ` Jacopo Mondi
2020-07-03 16:33                     ` Laurent Pinchart
2020-06-23 16:55 ` [PATCH 21/25] media: ov5647: Set V4L2_SUBDEV_FL_HAS_EVENTS flag Jacopo Mondi
2020-06-23 16:55 ` [PATCH 22/25] media: ov5647: Support V4L2_CID_PIXEL_RATE Jacopo Mondi
2020-06-29 17:01   ` [libcamera-devel] " Dafna Hirschfeld
2020-06-29 21:25     ` Dave Stevenson
2020-06-30 15:13       ` Dave Stevenson
2020-07-01  7:21         ` Laurent Pinchart
2020-06-23 16:55 ` [PATCH 23/25] media: ov5647: Support V4L2_CID_HBLANK control Jacopo Mondi
2020-06-23 16:55 ` [PATCH 24/25] media: ov5647: Support V4L2_CID_VBLANK control Jacopo Mondi
2020-06-23 16:55 ` [PATCH 25/25] media: ov5647: Advertise the correct exposure range Jacopo Mondi
2020-06-29 17:33 ` [PATCH 00/25] media: ov5647: Support RaspberryPi Camera Module v1 Dafna Hirschfeld
2020-06-29 18:08   ` Dafna Hirschfeld
2020-07-10 15:59 ` Dafna Hirschfeld
2020-07-14 12:48   ` Jacopo Mondi
  -- strict thread matches above, loose matches on Subject: below --
2020-06-22 17:18 Jacopo Mondi
2020-06-22 17:18 ` [PATCH 01/25] dt-bindings: media: ov5647: Document pwdn-gpios Jacopo Mondi

Linux-Media Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/linux-media/0 linux-media/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 linux-media linux-media/ https://lore.kernel.org/linux-media \
		linux-media@vger.kernel.org
	public-inbox-index linux-media

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kernel.vger.linux-media


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git