All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 00/29]  media: ov5647: Support RaspberryPi Camera Module v1
@ 2020-11-09 16:49 Jacopo Mondi
  2020-11-09 16:49 ` [PATCH v3 01/29] media: ov5647: Add support for PWDN GPIO Jacopo Mondi
                   ` (29 more replies)
  0 siblings, 30 replies; 37+ messages in thread
From: Jacopo Mondi @ 2020-11-09 16:49 UTC (permalink / raw)
  To: linux-media
  Cc: Jacopo Mondi, mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dafna.hirschfeld, dave.stevenson, naush,
	erosca

Third iteration following:
v2: https://patchwork.linuxtv.org/project/linux-media/list/?series=3782
v1: https://patchwork.linuxtv.org/project/linux-media/list/?series=2765

Major changes are:
- Address Dave's comments
  - Remove superseded patch:
    "media: ov5647: Program mode only if it has changed"
  - Remove Raw Bayer pattern from mode names
  - Remove cosmetic re-flow of register-value tables

- Address Hans' comment:
  - Add support for V4L2_SEL_TGT_CROP_BOUNDS
  - Redefine the CROP rectangle relatively to the native pixel array as per
    "[PATCH 4/4] media: i2c: imx219: Selection compliance fixes"

- New patches:
  - media: ov5647: Support VIDIOC_SUBSCRIBE_EVENT
  Fix v4l2-compliance error:
  fail: v4l2-test-controls.cpp(823): subscribe event for control 'User Controls' failed

  - media: ov5647: Remove 640x480 SBGGR8 mode
  The 640x480 8-bit mode is broken, at least when capturing on RaspberryPi4.
  As the receiver works when capturing in 8-bit mode with other sensors, it
  might be legit to think the mode is broken. As I've no way to fix it, it's
  probably better to remove it completely.


v4l2-compliance output:
-------------------------------------------------------------------------------
v4l2-compliance 1.21.0-4679, 32 bits, 32-bit time_t
v4l2-compliance SHA: 225c6c2a17be 2020-10-30 15:13:07

Compliance test for device /dev/v4l-subdev0:


Required ioctls:

Allow for multiple opens:
	test second /dev/v4l-subdev0 open: OK
	test for unlimited opens: OK

	test invalid ioctls: OK
Debug ioctls:
	test VIDIOC_LOG_STATUS: OK (Not Supported)

Input ioctls:
	test VIDIOC_G/S_TUNER/ENUM_FREQ_BANDS: OK (Not Supported)
	test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
	test VIDIOC_S_HW_FREQ_SEEK: OK (Not Supported)
	test VIDIOC_ENUMAUDIO: OK (Not Supported)
	test VIDIOC_G/S/ENUMINPUT: OK (Not Supported)
	test VIDIOC_G/S_AUDIO: OK (Not Supported)
	Inputs: 0 Audio Inputs: 0 Tuners: 0

Output ioctls:
	test VIDIOC_G/S_MODULATOR: OK (Not Supported)
	test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
	test VIDIOC_ENUMAUDOUT: OK (Not Supported)
	test VIDIOC_G/S/ENUMOUTPUT: OK (Not Supported)
	test VIDIOC_G/S_AUDOUT: OK (Not Supported)
	Outputs: 0 Audio Outputs: 0 Modulators: 0

Input/Output configuration ioctls:
	test VIDIOC_ENUM/G/S/QUERY_STD: OK (Not Supported)
	test VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: OK (Not Supported)
	test VIDIOC_DV_TIMINGS_CAP: OK (Not Supported)
	test VIDIOC_G/S_EDID: OK (Not Supported)

Control ioctls:
	test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: OK
	test VIDIOC_QUERYCTRL: OK
	test VIDIOC_G/S_CTRL: OK
	test VIDIOC_G/S/TRY_EXT_CTRLS: OK
	test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: OK
	test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
	Standard Controls: 12 Private Controls: 0

Format ioctls:
	test VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: OK (Not Supported)
	test VIDIOC_G/S_PARM: OK (Not Supported)
	test VIDIOC_G_FBUF: OK (Not Supported)
	test VIDIOC_G_FMT: OK (Not Supported)
	test VIDIOC_TRY_FMT: OK (Not Supported)
	test VIDIOC_S_FMT: OK (Not Supported)
	test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)
	test Cropping: OK (Not Supported)
	test Composing: OK (Not Supported)
	test Scaling: OK (Not Supported)

Codec ioctls:
	test VIDIOC_(TRY_)ENCODER_CMD: OK (Not Supported)
	test VIDIOC_G_ENC_INDEX: OK (Not Supported)
	test VIDIOC_(TRY_)DECODER_CMD: OK (Not Supported)

Buffer ioctls:
	test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK (Not Supported)
	test VIDIOC_EXPBUF: OK (Not Supported)
	test Requests: OK (Not Supported)

Total for device /dev/v4l-subdev0: 41, Succeeded: 41, Failed: 0, Warnings: 0
-------------------------------------------------------------------------------

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 (20):
  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: Use SBGGR10_1X10 640x480 as default
  media: ov5647: Implement set_fmt pad operation
  media: ov5647: Support V4L2_CID_HBLANK control
  media: ov5647: Use pm_runtime infrastructure
  media: ov5647: Rework s_stream() operation
  media: ov5647: Apply controls only when powered
  media: ov5647: Constify oe_enable/disable reglist
  media: ov5647: Support VIDIOC_SUBSCRIBE_EVENT
  media: ov5647: Remove 640x480 SBGGR8 mode

 drivers/media/i2c/ov5647.c | 1290 ++++++++++++++++++++++++++++++------
 1 file changed, 1079 insertions(+), 211 deletions(-)

--
2.29.1


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

* [PATCH v3 01/29] media: ov5647: Add support for PWDN GPIO.
  2020-11-09 16:49 [PATCH v3 00/29] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
@ 2020-11-09 16:49 ` Jacopo Mondi
  2020-11-09 16:49 ` [PATCH v3 02/29] media: ov5647: Add support for non-continuous clock mode Jacopo Mondi
                   ` (28 subsequent siblings)
  29 siblings, 0 replies; 37+ messages in thread
From: Jacopo Mondi @ 2020-11-09 16:49 UTC (permalink / raw)
  To: linux-media
  Cc: Jacopo Mondi, mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dafna.hirschfeld, dave.stevenson, naush,
	erosca

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 | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
index e7d2e5b4ad4b9..5dde138763eb0 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,14 @@ 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);
+	if (IS_ERR(sensor->pwdn)) {
+		dev_err(dev, "Failed to get 'pwdn' gpio\n");
+		return -EINVAL;
+	}
+
 	mutex_init(&sensor->lock);
 
 	sd = &sensor->sd;
@@ -594,7 +618,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.29.1


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

* [PATCH v3 02/29] media: ov5647: Add support for non-continuous clock mode
  2020-11-09 16:49 [PATCH v3 00/29] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
  2020-11-09 16:49 ` [PATCH v3 01/29] media: ov5647: Add support for PWDN GPIO Jacopo Mondi
@ 2020-11-09 16:49 ` Jacopo Mondi
  2020-11-09 16:49 ` [PATCH v3 03/29] media: ov5647: Add set_fmt and get_fmt calls Jacopo Mondi
                   ` (27 subsequent siblings)
  29 siblings, 0 replies; 37+ messages in thread
From: Jacopo Mondi @ 2020-11-09 16:49 UTC (permalink / raw)
  To: linux-media
  Cc: Jacopo Mondi, mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dafna.hirschfeld, dave.stevenson, naush,
	erosca

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 5dde138763eb0..ccb56f9b09fd4 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.29.1


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

* [PATCH v3 03/29] media: ov5647: Add set_fmt and get_fmt calls.
  2020-11-09 16:49 [PATCH v3 00/29] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
  2020-11-09 16:49 ` [PATCH v3 01/29] media: ov5647: Add support for PWDN GPIO Jacopo Mondi
  2020-11-09 16:49 ` [PATCH v3 02/29] media: ov5647: Add support for non-continuous clock mode Jacopo Mondi
@ 2020-11-09 16:49 ` Jacopo Mondi
  2020-11-09 16:49 ` [PATCH v3 04/29] media: ov5647: Fix format initialization Jacopo Mondi
                   ` (26 subsequent siblings)
  29 siblings, 0 replies; 37+ messages in thread
From: Jacopo Mondi @ 2020-11-09 16:49 UTC (permalink / raw)
  To: linux-media
  Cc: Jacopo Mondi, mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dafna.hirschfeld, dave.stevenson, naush,
	erosca

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 ccb56f9b09fd4..9093a1ca7bce2 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.29.1


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

* [PATCH v3 04/29] media: ov5647: Fix format initialization
  2020-11-09 16:49 [PATCH v3 00/29] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
                   ` (2 preceding siblings ...)
  2020-11-09 16:49 ` [PATCH v3 03/29] media: ov5647: Add set_fmt and get_fmt calls Jacopo Mondi
@ 2020-11-09 16:49 ` Jacopo Mondi
  2020-11-09 16:49 ` [PATCH v3 05/29] media: ov5647: Fix style issues Jacopo Mondi
                   ` (25 subsequent siblings)
  29 siblings, 0 replies; 37+ messages in thread
From: Jacopo Mondi @ 2020-11-09 16:49 UTC (permalink / raw)
  To: linux-media
  Cc: Jacopo Mondi, mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dafna.hirschfeld, dave.stevenson, naush,
	erosca

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 9093a1ca7bce2..04551ed683df3 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.29.1


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

* [PATCH v3 05/29] media: ov5647: Fix style issues
  2020-11-09 16:49 [PATCH v3 00/29] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
                   ` (3 preceding siblings ...)
  2020-11-09 16:49 ` [PATCH v3 04/29] media: ov5647: Fix format initialization Jacopo Mondi
@ 2020-11-09 16:49 ` Jacopo Mondi
  2020-11-09 16:49 ` [PATCH v3 06/29] media: ov5647: Replace license with SPDX identifier Jacopo Mondi
                   ` (24 subsequent siblings)
  29 siblings, 0 replies; 37+ messages in thread
From: Jacopo Mondi @ 2020-11-09 16:49 UTC (permalink / raw)
  To: linux-media
  Cc: Jacopo Mondi, mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dafna.hirschfeld, dave.stevenson, naush,
	erosca

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 04551ed683df3..f9bae58c5d311 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,9 +620,8 @@ 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);
 	if (IS_ERR(sensor->pwdn)) {
 		dev_err(dev, "Failed to get 'pwdn' gpio\n");
 		return -EINVAL;
@@ -643,14 +631,14 @@ static int ov5647_probe(struct i2c_client *client)
 
 	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);
@@ -658,22 +646,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;
 }
 
@@ -692,7 +681,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);
 
@@ -707,7 +696,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.29.1


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

* [PATCH v3 06/29] media: ov5647: Replace license with SPDX identifier
  2020-11-09 16:49 [PATCH v3 00/29] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
                   ` (4 preceding siblings ...)
  2020-11-09 16:49 ` [PATCH v3 05/29] media: ov5647: Fix style issues Jacopo Mondi
@ 2020-11-09 16:49 ` Jacopo Mondi
  2020-11-09 16:49 ` [PATCH v3 07/29] media: ov5647: Fix return value from read/write Jacopo Mondi
                   ` (23 subsequent siblings)
  29 siblings, 0 replies; 37+ messages in thread
From: Jacopo Mondi @ 2020-11-09 16:49 UTC (permalink / raw)
  To: linux-media
  Cc: Jacopo Mondi, mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dafna.hirschfeld, dave.stevenson, naush,
	erosca

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 f9bae58c5d311..9bf27e6280bd2 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.29.1


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

* [PATCH v3 07/29] media: ov5647: Fix return value from read/write
  2020-11-09 16:49 [PATCH v3 00/29] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
                   ` (5 preceding siblings ...)
  2020-11-09 16:49 ` [PATCH v3 06/29] media: ov5647: Replace license with SPDX identifier Jacopo Mondi
@ 2020-11-09 16:49 ` Jacopo Mondi
  2020-11-09 16:49 ` [PATCH v3 08/29] media: ov5647: Program mode at s_stream(1) time Jacopo Mondi
                   ` (22 subsequent siblings)
  29 siblings, 0 replies; 37+ messages in thread
From: Jacopo Mondi @ 2020-11-09 16:49 UTC (permalink / raw)
  To: linux-media
  Cc: Jacopo Mondi, mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dafna.hirschfeld, dave.stevenson, naush,
	erosca

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 9bf27e6280bd2..c04ef44ccf2ab 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.29.1


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

* [PATCH v3 08/29] media: ov5647: Program mode at s_stream(1) time
  2020-11-09 16:49 [PATCH v3 00/29] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
                   ` (6 preceding siblings ...)
  2020-11-09 16:49 ` [PATCH v3 07/29] media: ov5647: Fix return value from read/write Jacopo Mondi
@ 2020-11-09 16:49 ` Jacopo Mondi
  2020-11-09 16:49 ` [PATCH v3 09/29] media: ov5647: Implement enum_frame_size() Jacopo Mondi
                   ` (21 subsequent siblings)
  29 siblings, 0 replies; 37+ messages in thread
From: Jacopo Mondi @ 2020-11-09 16:49 UTC (permalink / raw)
  To: linux-media
  Cc: Jacopo Mondi, mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dafna.hirschfeld, dave.stevenson, naush,
	erosca

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 c04ef44ccf2ab..b9f19165b3491 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.29.1


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

* [PATCH v3 09/29] media: ov5647: Implement enum_frame_size()
  2020-11-09 16:49 [PATCH v3 00/29] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
                   ` (7 preceding siblings ...)
  2020-11-09 16:49 ` [PATCH v3 08/29] media: ov5647: Program mode at s_stream(1) time Jacopo Mondi
@ 2020-11-09 16:49 ` Jacopo Mondi
  2020-11-09 16:49 ` [PATCH v3 10/29] media: ov5647: Protect s_stream() with mutex Jacopo Mondi
                   ` (20 subsequent siblings)
  29 siblings, 0 replies; 37+ messages in thread
From: Jacopo Mondi @ 2020-11-09 16:49 UTC (permalink / raw)
  To: linux-media
  Cc: Jacopo Mondi, mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dafna.hirschfeld, dave.stevenson, naush,
	erosca

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 b9f19165b3491..f18e3ad342ebf 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.29.1


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

* [PATCH v3 10/29] media: ov5647: Protect s_stream() with mutex
  2020-11-09 16:49 [PATCH v3 00/29] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
                   ` (8 preceding siblings ...)
  2020-11-09 16:49 ` [PATCH v3 09/29] media: ov5647: Implement enum_frame_size() Jacopo Mondi
@ 2020-11-09 16:49 ` Jacopo Mondi
  2020-11-09 16:49 ` [PATCH v3 11/29] media: ov5647: Support gain, exposure and AWB controls Jacopo Mondi
                   ` (19 subsequent siblings)
  29 siblings, 0 replies; 37+ messages in thread
From: Jacopo Mondi @ 2020-11-09 16:49 UTC (permalink / raw)
  To: linux-media
  Cc: Jacopo Mondi, mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dafna.hirschfeld, dave.stevenson, naush,
	erosca

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 f18e3ad342ebf..d386791f87500 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.29.1


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

* [PATCH v3 11/29] media: ov5647: Support gain, exposure and AWB controls
  2020-11-09 16:49 [PATCH v3 00/29] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
                   ` (9 preceding siblings ...)
  2020-11-09 16:49 ` [PATCH v3 10/29] media: ov5647: Protect s_stream() with mutex Jacopo Mondi
@ 2020-11-09 16:49 ` Jacopo Mondi
  2020-11-09 16:49 ` [PATCH v3 12/29] media: ov5647: Rationalize driver structure name Jacopo Mondi
                   ` (18 subsequent siblings)
  29 siblings, 0 replies; 37+ messages in thread
From: Jacopo Mondi @ 2020-11-09 16:49 UTC (permalink / raw)
  To: linux-media
  Cc: Jacopo Mondi, mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dafna.hirschfeld, dave.stevenson, naush,
	erosca, David Plowman

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 d386791f87500..4a009848cefc8 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 = {
@@ -658,6 +817,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;
@@ -667,7 +830,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);
@@ -689,6 +852,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);
 
@@ -702,6 +867,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.29.1


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

* [PATCH v3 12/29] media: ov5647: Rationalize driver structure name
  2020-11-09 16:49 [PATCH v3 00/29] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
                   ` (10 preceding siblings ...)
  2020-11-09 16:49 ` [PATCH v3 11/29] media: ov5647: Support gain, exposure and AWB controls Jacopo Mondi
@ 2020-11-09 16:49 ` Jacopo Mondi
  2020-11-09 16:49 ` [PATCH v3 13/29] media: ov5647: Break out format handling Jacopo Mondi
                   ` (17 subsequent siblings)
  29 siblings, 0 replies; 37+ messages in thread
From: Jacopo Mondi @ 2020-11-09 16:49 UTC (permalink / raw)
  To: linux-media
  Cc: Jacopo Mondi, mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dafna.hirschfeld, dave.stevenson, naush,
	erosca

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 | 46 +++++++++++++++++++-------------------
 1 file changed, 23 insertions(+), 23 deletions(-)

diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
index 4a009848cefc8..91193706b6fe1 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;
 
@@ -376,20 +376,20 @@ 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(&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);
@@ -863,13 +863,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.29.1


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

* [PATCH v3 13/29] media: ov5647: Break out format handling
  2020-11-09 16:49 [PATCH v3 00/29] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
                   ` (11 preceding siblings ...)
  2020-11-09 16:49 ` [PATCH v3 12/29] media: ov5647: Rationalize driver structure name Jacopo Mondi
@ 2020-11-09 16:49 ` Jacopo Mondi
  2020-11-18 20:18   ` Sakari Ailus
  2020-11-09 16:49 ` [PATCH v3 14/29] media: ov5647: Add support for get_selection() Jacopo Mondi
                   ` (16 subsequent siblings)
  29 siblings, 1 reply; 37+ messages in thread
From: Jacopo Mondi @ 2020-11-09 16:49 UTC (permalink / raw)
  To: linux-media
  Cc: Jacopo Mondi, mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dafna.hirschfeld, dave.stevenson, naush,
	erosca

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 | 90 +++++++++++++++++++++++++++-----------
 1 file changed, 65 insertions(+), 25 deletions(-)

diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
index 91193706b6fe1..d41c11afe1216 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;
+	const struct regval_list	*reg_list;
+	unsigned int			num_regs;
+};
+
+struct ov5647_format_list {
+	unsigned int			mbus_code;
+	const 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;
+	const struct ov5647_mode	*mode;
 };
 
 static inline struct ov5647 *to_sensor(struct v4l2_subdev *sd)
@@ -115,7 +125,7 @@ static struct regval_list sensor_oe_enable_regs[] = {
 	{0x3002, 0xe4},
 };
 
-static struct regval_list ov5647_640x480[] = {
+static const struct regval_list ov5647_640x480[] = {
 	{0x0100, 0x00},
 	{0x0103, 0x01},
 	{0x3034, 0x08},
@@ -205,6 +215,33 @@ static struct regval_list ov5647_640x480[] = {
 	{0x0100, 0x01},
 };
 
+static const 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};
@@ -245,7 +282,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)
+			      const struct regval_list *regs, int array_size)
 {
 	int i, ret;
 
@@ -275,6 +312,7 @@ 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;
 
@@ -282,8 +320,8 @@ 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 +532,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 +544,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 +574,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 +633,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;
 }
@@ -817,6 +855,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.29.1


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

* [PATCH v3 14/29] media: ov5647: Add support for get_selection()
  2020-11-09 16:49 [PATCH v3 00/29] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
                   ` (12 preceding siblings ...)
  2020-11-09 16:49 ` [PATCH v3 13/29] media: ov5647: Break out format handling Jacopo Mondi
@ 2020-11-09 16:49 ` Jacopo Mondi
  2020-11-09 16:49 ` [PATCH v3 15/29] media: ov5647: Rename SBGGR8 VGA mode Jacopo Mondi
                   ` (15 subsequent siblings)
  29 siblings, 0 replies; 37+ messages in thread
From: Jacopo Mondi @ 2020-11-09 16:49 UTC (permalink / raw)
  To: linux-media
  Cc: Jacopo Mondi, mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dafna.hirschfeld, dave.stevenson, naush,
	erosca, Dave Stevenson

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 | 94 ++++++++++++++++++++++++++++----------
 1 file changed, 71 insertions(+), 23 deletions(-)

diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
index d41c11afe1216..624f3cf9a79c9 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;
 	const struct regval_list	*reg_list;
 	unsigned int			num_regs;
 };
@@ -224,6 +214,12 @@ static const struct ov5647_mode ov5647_8bit_modes[] = {
 			.width		= 640,
 			.height		= 480
 		},
+		.crop = {
+			.left		= OV5647_PIXEL_ARRAY_LEFT,
+			.top		= OV5647_PIXEL_ARRAY_TOP,
+			.width		= 1280,
+			.height		= 960,
+		},
 		.reg_list	= ov5647_640x480,
 		.num_regs	= ARRAY_SIZE(ov5647_640x480)
 	},
@@ -509,6 +505,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);
@@ -579,11 +589,49 @@ 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:
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+		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 = {
@@ -628,10 +676,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.29.1


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

* [PATCH v3 15/29] media: ov5647: Rename SBGGR8 VGA mode
  2020-11-09 16:49 [PATCH v3 00/29] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
                   ` (13 preceding siblings ...)
  2020-11-09 16:49 ` [PATCH v3 14/29] media: ov5647: Add support for get_selection() Jacopo Mondi
@ 2020-11-09 16:49 ` Jacopo Mondi
  2020-11-09 16:49 ` [PATCH v3 16/29] media: ov5647: Add SGGBR10_1X10 modes Jacopo Mondi
                   ` (14 subsequent siblings)
  29 siblings, 0 replies; 37+ messages in thread
From: Jacopo Mondi @ 2020-11-09 16:49 UTC (permalink / raw)
  To: linux-media
  Cc: Jacopo Mondi, mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dafna.hirschfeld, dave.stevenson, naush,
	erosca

Before adding new modes, rename the only existing one to report
the bit depth 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 624f3cf9a79c9..6cb45c1ac9d44 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 const struct regval_list ov5647_640x480[] = {
+static const struct regval_list ov5647_640x480_8bpp[] = {
 	{0x0100, 0x00},
 	{0x0103, 0x01},
 	{0x3034, 0x08},
@@ -205,7 +205,8 @@ static const struct regval_list ov5647_640x480[] = {
 	{0x0100, 0x01},
 };
 
-static const struct ov5647_mode ov5647_8bit_modes[] = {
+static const struct ov5647_mode ov5647_8bpp_modes[] = {
+	/* 8-bit VGA mode: Uncentred crop 2x2 binned 1296x972 image. */
 	{
 		.format	= {
 			.code		= MEDIA_BUS_FMT_SBGGR8_1X8,
@@ -220,16 +221,16 @@ static const struct ov5647_mode ov5647_8bit_modes[] = {
 			.width		= 1280,
 			.height		= 960,
 		},
-		.reg_list	= ov5647_640x480,
-		.num_regs	= ARRAY_SIZE(ov5647_640x480)
+		.reg_list	= ov5647_640x480_8bpp,
+		.num_regs	= ARRAY_SIZE(ov5647_640x480_8bpp)
 	},
 };
 
 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_8bpp_modes,
+		.num_modes	= ARRAY_SIZE(ov5647_8bpp_modes),
 	},
 };
 
-- 
2.29.1


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

* [PATCH v3 16/29] media: ov5647: Add SGGBR10_1X10 modes
  2020-11-09 16:49 [PATCH v3 00/29] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
                   ` (14 preceding siblings ...)
  2020-11-09 16:49 ` [PATCH v3 15/29] media: ov5647: Rename SBGGR8 VGA mode Jacopo Mondi
@ 2020-11-09 16:49 ` Jacopo Mondi
  2020-11-09 16:49 ` [PATCH v3 17/29] media: ov5647: Use SBGGR10_1X10 640x480 as default Jacopo Mondi
                   ` (13 subsequent siblings)
  29 siblings, 0 replies; 37+ messages in thread
From: Jacopo Mondi @ 2020-11-09 16:49 UTC (permalink / raw)
  To: linux-media
  Cc: Jacopo Mondi, mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dafna.hirschfeld, dave.stevenson, naush,
	erosca

Add 4 additional sensor modes in SBGGR10_1X10 format.

Add the following resolutions:
- 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 6cb45c1ac9d44..a282dc7267ad8 100644
--- a/drivers/media/i2c/ov5647.c
+++ b/drivers/media/i2c/ov5647.c
@@ -205,6 +205,367 @@ static const struct regval_list ov5647_640x480_8bpp[] = {
 	{0x0100, 0x01},
 };
 
+static struct regval_list ov5647_2592x1944_10bpp[] = {
+	{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_10bpp[] = {
+	{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_10bpp[] = {
+	{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_10bpp[] = {
+	{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 const struct ov5647_mode ov5647_8bpp_modes[] = {
 	/* 8-bit VGA mode: Uncentred crop 2x2 binned 1296x972 image. */
 	{
@@ -226,12 +587,92 @@ static const struct ov5647_mode ov5647_8bpp_modes[] = {
 	},
 };
 
+static const struct ov5647_mode ov5647_10bpp_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		= OV5647_PIXEL_ARRAY_LEFT,
+			.top		= OV5647_PIXEL_ARRAY_TOP,
+			.width		= 2592,
+			.height		= 1944
+		},
+		.reg_list	= ov5647_2592x1944_10bpp,
+		.num_regs	= ARRAY_SIZE(ov5647_2592x1944_10bpp)
+	},
+	/* 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 + OV5647_PIXEL_ARRAY_LEFT,
+			.top		= 434 + OV5647_PIXEL_ARRAY_TOP,
+			.width		= 1928,
+			.height		= 1080,
+		},
+		.reg_list	= ov5647_1080p30_10bpp,
+		.num_regs	= ARRAY_SIZE(ov5647_1080p30_10bpp)
+	},
+	/* 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		= OV5647_PIXEL_ARRAY_LEFT,
+			.top		= OV5647_PIXEL_ARRAY_TOP,
+			.width		= 2592,
+			.height		= 1944,
+		},
+		.reg_list	= ov5647_2x2binned_10bpp,
+		.num_regs	= ARRAY_SIZE(ov5647_2x2binned_10bpp)
+	},
+	/* 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 + OV5647_PIXEL_ARRAY_LEFT,
+			.top		= OV5647_PIXEL_ARRAY_TOP,
+			.width		= 2560,
+			.height		= 1920,
+		},
+		.reg_list	= ov5647_640x480_10bpp,
+		.num_regs	= ARRAY_SIZE(ov5647_640x480_10bpp)
+	},
+};
+
 static const struct ov5647_format_list ov5647_formats[] = {
 	{
 		.mbus_code	= MEDIA_BUS_FMT_SBGGR8_1X8,
 		.modes		= ov5647_8bpp_modes,
 		.num_modes	= ARRAY_SIZE(ov5647_8bpp_modes),
 	},
+	{
+		.mbus_code	= MEDIA_BUS_FMT_SBGGR10_1X10,
+		.modes		= ov5647_10bpp_modes,
+		.num_modes	= ARRAY_SIZE(ov5647_10bpp_modes),
+	},
 };
 
 #define OV5647_NUM_FORMATS	(ARRAY_SIZE(ov5647_formats))
-- 
2.29.1


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

* [PATCH v3 17/29] media: ov5647: Use SBGGR10_1X10 640x480 as default
  2020-11-09 16:49 [PATCH v3 00/29] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
                   ` (15 preceding siblings ...)
  2020-11-09 16:49 ` [PATCH v3 16/29] media: ov5647: Add SGGBR10_1X10 modes Jacopo Mondi
@ 2020-11-09 16:49 ` Jacopo Mondi
  2020-11-09 16:49 ` [PATCH v3 18/29] media: ov5647: Implement set_fmt pad operation Jacopo Mondi
                   ` (12 subsequent siblings)
  29 siblings, 0 replies; 37+ messages in thread
From: Jacopo Mondi @ 2020-11-09 16:49 UTC (permalink / raw)
  To: linux-media
  Cc: Jacopo Mondi, mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dafna.hirschfeld, dave.stevenson, naush,
	erosca

The SBGGR10_1X10 formats supports more resolutions than SBGGR8_1X8.
Make it the default sensor format and set 2x2 binned 640x480 resolution
as default sensor size as it maximizes the FOV and framerate.

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

diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
index a282dc7267ad8..c65aacc0e04d3 100644
--- a/drivers/media/i2c/ov5647.c
+++ b/drivers/media/i2c/ov5647.c
@@ -677,8 +677,9 @@ static const struct ov5647_format_list ov5647_formats[] = {
 
 #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)
+/* Default sensor mode is 2x2 binned 640x480 SBGGR10_1X10. */
+#define OV5647_DEFAULT_MODE	(&ov5647_formats[1].modes[3])
+#define OV5647_DEFAULT_FORMAT	(ov5647_formats[1].modes[3].format)
 
 static int ov5647_write(struct v4l2_subdev *sd, u16 reg, u8 val)
 {
@@ -1024,7 +1025,6 @@ 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. */
 	memset(fmt, 0, sizeof(*fmt));
 	*fmt = OV5647_DEFAULT_FORMAT;
 
-- 
2.29.1


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

* [PATCH v3 18/29] media: ov5647: Implement set_fmt pad operation
  2020-11-09 16:49 [PATCH v3 00/29] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
                   ` (16 preceding siblings ...)
  2020-11-09 16:49 ` [PATCH v3 17/29] media: ov5647: Use SBGGR10_1X10 640x480 as default Jacopo Mondi
@ 2020-11-09 16:49 ` Jacopo Mondi
  2020-11-18 20:42   ` Sakari Ailus
  2020-11-09 16:49 ` [PATCH v3 19/29] media: ov5647: Set V4L2_SUBDEV_FL_HAS_EVENTS flag Jacopo Mondi
                   ` (11 subsequent siblings)
  29 siblings, 1 reply; 37+ messages in thread
From: Jacopo Mondi @ 2020-11-09 16:49 UTC (permalink / raw)
  To: linux-media
  Cc: Jacopo Mondi, mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dafna.hirschfeld, dave.stevenson, naush,
	erosca

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 | 66 +++++++++++++++++++++++++++++++++++---
 1 file changed, 62 insertions(+), 4 deletions(-)

diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
index c65aacc0e04d3..68eab61d53493 100644
--- a/drivers/media/i2c/ov5647.c
+++ b/drivers/media/i2c/ov5647.c
@@ -1019,14 +1019,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;
+	const struct v4l2_mbus_framefmt *sensor_format;
+	struct ov5647 *sensor = to_sensor(sd);
 
 	memset(fmt, 0, sizeof(*fmt));
-	*fmt = OV5647_DEFAULT_FORMAT;
+
+	mutex_lock(&sensor->lock);
+	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;
+	const struct ov5647_mode *ov5647_mode_list;
+	struct ov5647 *sensor = to_sensor(sd);
+	const 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_8bpp_modes;
+		num_modes = ARRAY_SIZE(ov5647_8bpp_modes);
+	} else {
+		ov5647_mode_list = ov5647_10bpp_modes;
+		num_modes = ARRAY_SIZE(ov5647_10bpp_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;
 }
@@ -1071,8 +1129,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.29.1


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

* [PATCH v3 19/29] media: ov5647: Set V4L2_SUBDEV_FL_HAS_EVENTS flag
  2020-11-09 16:49 [PATCH v3 00/29] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
                   ` (17 preceding siblings ...)
  2020-11-09 16:49 ` [PATCH v3 18/29] media: ov5647: Implement set_fmt pad operation Jacopo Mondi
@ 2020-11-09 16:49 ` Jacopo Mondi
  2020-11-09 16:49 ` [PATCH v3 20/29] media: ov5647: Support V4L2_CID_PIXEL_RATE Jacopo Mondi
                   ` (10 subsequent siblings)
  29 siblings, 0 replies; 37+ messages in thread
From: Jacopo Mondi @ 2020-11-09 16:49 UTC (permalink / raw)
  To: linux-media
  Cc: Jacopo Mondi, mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dafna.hirschfeld, dave.stevenson, naush,
	erosca, Dave Stevenson

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 68eab61d53493..66556690dcffb 100644
--- a/drivers/media/i2c/ov5647.c
+++ b/drivers/media/i2c/ov5647.c
@@ -1412,7 +1412,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.29.1


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

* [PATCH v3 20/29] media: ov5647: Support V4L2_CID_PIXEL_RATE
  2020-11-09 16:49 [PATCH v3 00/29] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
                   ` (18 preceding siblings ...)
  2020-11-09 16:49 ` [PATCH v3 19/29] media: ov5647: Set V4L2_SUBDEV_FL_HAS_EVENTS flag Jacopo Mondi
@ 2020-11-09 16:49 ` Jacopo Mondi
  2020-11-18 20:43   ` Sakari Ailus
  2020-11-09 16:49 ` [PATCH v3 21/29] media: ov5647: Support V4L2_CID_HBLANK control Jacopo Mondi
                   ` (9 subsequent siblings)
  29 siblings, 1 reply; 37+ messages in thread
From: Jacopo Mondi @ 2020-11-09 16:49 UTC (permalink / raw)
  To: linux-media
  Cc: Jacopo Mondi, mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dafna.hirschfeld, dave.stevenson, naush,
	erosca, Dave Stevenson

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 66556690dcffb..01978491b97f4 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;
 	const struct regval_list	*reg_list;
 	unsigned int			num_regs;
 };
@@ -96,6 +97,7 @@ struct ov5647 {
 	bool				clock_ncont;
 	struct v4l2_ctrl_handler	ctrls;
 	const struct ov5647_mode	*mode;
+	struct v4l2_ctrl		*pixel_rate;
 };
 
 static inline struct ov5647 *to_sensor(struct v4l2_subdev *sd)
@@ -582,6 +584,7 @@ static const struct ov5647_mode ov5647_8bpp_modes[] = {
 			.width		= 1280,
 			.height		= 960,
 		},
+		.pixel_rate	= 77291670,
 		.reg_list	= ov5647_640x480_8bpp,
 		.num_regs	= ARRAY_SIZE(ov5647_640x480_8bpp)
 	},
@@ -603,6 +606,7 @@ static const struct ov5647_mode ov5647_10bpp_modes[] = {
 			.width		= 2592,
 			.height		= 1944
 		},
+		.pixel_rate	= 87500000,
 		.reg_list	= ov5647_2592x1944_10bpp,
 		.num_regs	= ARRAY_SIZE(ov5647_2592x1944_10bpp)
 	},
@@ -621,6 +625,7 @@ static const struct ov5647_mode ov5647_10bpp_modes[] = {
 			.width		= 1928,
 			.height		= 1080,
 		},
+		.pixel_rate	= 81666700,
 		.reg_list	= ov5647_1080p30_10bpp,
 		.num_regs	= ARRAY_SIZE(ov5647_1080p30_10bpp)
 	},
@@ -639,6 +644,7 @@ static const struct ov5647_mode ov5647_10bpp_modes[] = {
 			.width		= 2592,
 			.height		= 1944,
 		},
+		.pixel_rate	= 81666700,
 		.reg_list	= ov5647_2x2binned_10bpp,
 		.num_regs	= ARRAY_SIZE(ov5647_2x2binned_10bpp)
 	},
@@ -657,6 +663,7 @@ static const struct ov5647_mode ov5647_10bpp_modes[] = {
 			.width		= 2560,
 			.height		= 1920,
 		},
+		.pixel_rate	= 55000000,
 		.reg_list	= ov5647_640x480_10bpp,
 		.num_regs	= ARRAY_SIZE(ov5647_640x480_10bpp)
 	},
@@ -1083,6 +1090,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);
 
@@ -1285,6 +1296,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",
@@ -1303,7 +1317,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);
@@ -1323,17 +1337,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.29.1


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

* [PATCH v3 21/29] media: ov5647: Support V4L2_CID_HBLANK control
  2020-11-09 16:49 [PATCH v3 00/29] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
                   ` (19 preceding siblings ...)
  2020-11-09 16:49 ` [PATCH v3 20/29] media: ov5647: Support V4L2_CID_PIXEL_RATE Jacopo Mondi
@ 2020-11-09 16:49 ` Jacopo Mondi
  2020-11-09 16:49 ` [PATCH v3 22/29] media: ov5647: Support V4L2_CID_VBLANK control Jacopo Mondi
                   ` (8 subsequent siblings)
  29 siblings, 0 replies; 37+ messages in thread
From: Jacopo Mondi @ 2020-11-09 16:49 UTC (permalink / raw)
  To: linux-media
  Cc: Jacopo Mondi, mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dafna.hirschfeld, dave.stevenson, naush,
	erosca

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 01978491b97f4..0c46a8605835c 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;
 	const struct regval_list	*reg_list;
 	unsigned int			num_regs;
 };
@@ -98,6 +99,7 @@ struct ov5647 {
 	struct v4l2_ctrl_handler	ctrls;
 	const struct ov5647_mode	*mode;
 	struct v4l2_ctrl		*pixel_rate;
+	struct v4l2_ctrl		*hblank;
 };
 
 static inline struct ov5647 *to_sensor(struct v4l2_subdev *sd)
@@ -585,6 +587,7 @@ static const struct ov5647_mode ov5647_8bpp_modes[] = {
 			.height		= 960,
 		},
 		.pixel_rate	= 77291670,
+		.hts		= 1896,
 		.reg_list	= ov5647_640x480_8bpp,
 		.num_regs	= ARRAY_SIZE(ov5647_640x480_8bpp)
 	},
@@ -607,6 +610,7 @@ static const struct ov5647_mode ov5647_10bpp_modes[] = {
 			.height		= 1944
 		},
 		.pixel_rate	= 87500000,
+		.hts		= 2844,
 		.reg_list	= ov5647_2592x1944_10bpp,
 		.num_regs	= ARRAY_SIZE(ov5647_2592x1944_10bpp)
 	},
@@ -626,6 +630,7 @@ static const struct ov5647_mode ov5647_10bpp_modes[] = {
 			.height		= 1080,
 		},
 		.pixel_rate	= 81666700,
+		.hts		= 2416,
 		.reg_list	= ov5647_1080p30_10bpp,
 		.num_regs	= ARRAY_SIZE(ov5647_1080p30_10bpp)
 	},
@@ -645,6 +650,7 @@ static const struct ov5647_mode ov5647_10bpp_modes[] = {
 			.height		= 1944,
 		},
 		.pixel_rate	= 81666700,
+		.hts		= 1896,
 		.reg_list	= ov5647_2x2binned_10bpp,
 		.num_regs	= ARRAY_SIZE(ov5647_2x2binned_10bpp)
 	},
@@ -664,6 +670,7 @@ static const struct ov5647_mode ov5647_10bpp_modes[] = {
 			.height		= 1920,
 		},
 		.pixel_rate	= 55000000,
+		.hts		= 1852,
 		.reg_list	= ov5647_640x480_10bpp,
 		.num_regs	= ARRAY_SIZE(ov5647_640x480_10bpp)
 	},
@@ -1061,6 +1068,7 @@ static int ov5647_set_pad_fmt(struct v4l2_subdev *sd,
 	struct ov5647 *sensor = to_sensor(sd);
 	const struct ov5647_mode *mode;
 	unsigned int num_modes;
+	int hblank;
 
 	/*
 	 * Default mbus code MEDIA_BUS_FMT_SBGGR10_1X10 if the requested one
@@ -1094,6 +1102,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);
 
@@ -1299,6 +1310,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",
@@ -1316,8 +1330,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);
@@ -1347,6 +1362,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.29.1


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

* [PATCH v3 22/29] media: ov5647: Support V4L2_CID_VBLANK control
  2020-11-09 16:49 [PATCH v3 00/29] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
                   ` (20 preceding siblings ...)
  2020-11-09 16:49 ` [PATCH v3 21/29] media: ov5647: Support V4L2_CID_HBLANK control Jacopo Mondi
@ 2020-11-09 16:49 ` Jacopo Mondi
  2020-11-09 16:49 ` [PATCH v3 23/29] media: ov5647: Advertise the correct exposure range Jacopo Mondi
                   ` (7 subsequent siblings)
  29 siblings, 0 replies; 37+ messages in thread
From: Jacopo Mondi @ 2020-11-09 16:49 UTC (permalink / raw)
  To: linux-media
  Cc: Jacopo Mondi, mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dafna.hirschfeld, dave.stevenson, naush,
	erosca, Dave Stevenson

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 0c46a8605835c..50edb19a933fb 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;
 	const struct regval_list	*reg_list;
 	unsigned int			num_regs;
 };
@@ -100,6 +106,7 @@ struct ov5647 {
 	const struct ov5647_mode	*mode;
 	struct v4l2_ctrl		*pixel_rate;
 	struct v4l2_ctrl		*hblank;
+	struct v4l2_ctrl		*vblank;
 };
 
 static inline struct ov5647 *to_sensor(struct v4l2_subdev *sd)
@@ -151,8 +158,6 @@ static const struct regval_list ov5647_640x480_8bpp[] = {
 	{0x3b07, 0x0c},
 	{0x380c, 0x07},
 	{0x380d, 0x68},
-	{0x380e, 0x03},
-	{0x380f, 0xd8},
 	{0x3814, 0x31},
 	{0x3815, 0x31},
 	{0x3708, 0x64},
@@ -588,6 +593,7 @@ static const struct ov5647_mode ov5647_8bpp_modes[] = {
 		},
 		.pixel_rate	= 77291670,
 		.hts		= 1896,
+		.vts		= 0x3d8,
 		.reg_list	= ov5647_640x480_8bpp,
 		.num_regs	= ARRAY_SIZE(ov5647_640x480_8bpp)
 	},
@@ -611,6 +617,7 @@ static const struct ov5647_mode ov5647_10bpp_modes[] = {
 		},
 		.pixel_rate	= 87500000,
 		.hts		= 2844,
+		.vts		= 0x7b0,
 		.reg_list	= ov5647_2592x1944_10bpp,
 		.num_regs	= ARRAY_SIZE(ov5647_2592x1944_10bpp)
 	},
@@ -631,6 +638,7 @@ static const struct ov5647_mode ov5647_10bpp_modes[] = {
 		},
 		.pixel_rate	= 81666700,
 		.hts		= 2416,
+		.vts		= 0x450,
 		.reg_list	= ov5647_1080p30_10bpp,
 		.num_regs	= ARRAY_SIZE(ov5647_1080p30_10bpp)
 	},
@@ -651,6 +659,7 @@ static const struct ov5647_mode ov5647_10bpp_modes[] = {
 		},
 		.pixel_rate	= 81666700,
 		.hts		= 1896,
+		.vts		= 0x59b,
 		.reg_list	= ov5647_2x2binned_10bpp,
 		.num_regs	= ARRAY_SIZE(ov5647_2x2binned_10bpp)
 	},
@@ -671,6 +680,7 @@ static const struct ov5647_mode ov5647_10bpp_modes[] = {
 		},
 		.pixel_rate	= 55000000,
 		.hts		= 1852,
+		.vts		= 0x1f8,
 		.reg_list	= ov5647_640x480_10bpp,
 		.num_regs	= ARRAY_SIZE(ov5647_640x480_10bpp)
 	},
@@ -695,6 +705,22 @@ static const struct ov5647_format_list ov5647_formats[] = {
 #define OV5647_DEFAULT_MODE	(&ov5647_formats[1].modes[3])
 #define OV5647_DEFAULT_FORMAT	(ov5647_formats[1].modes[3].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};
@@ -1105,6 +1131,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);
 
@@ -1313,6 +1344,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",
@@ -1332,7 +1366,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);
@@ -1371,6 +1405,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.29.1


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

* [PATCH v3 23/29] media: ov5647: Advertise the correct exposure range
  2020-11-09 16:49 [PATCH v3 00/29] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
                   ` (21 preceding siblings ...)
  2020-11-09 16:49 ` [PATCH v3 22/29] media: ov5647: Support V4L2_CID_VBLANK control Jacopo Mondi
@ 2020-11-09 16:49 ` Jacopo Mondi
  2020-11-09 16:49 ` [PATCH v3 24/29] media: ov5647: Use pm_runtime infrastructure Jacopo Mondi
                   ` (6 subsequent siblings)
  29 siblings, 0 replies; 37+ messages in thread
From: Jacopo Mondi @ 2020-11-09 16:49 UTC (permalink / raw)
  To: linux-media
  Cc: Jacopo Mondi, mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dafna.hirschfeld, dave.stevenson, naush,
	erosca, Dave Stevenson

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 | 39 +++++++++++++++++++++++++++++++++-----
 1 file changed, 34 insertions(+), 5 deletions(-)

diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
index 50edb19a933fb..7745a85ef4f02 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;
@@ -107,6 +112,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)
@@ -1092,9 +1098,9 @@ static int ov5647_set_pad_fmt(struct v4l2_subdev *sd,
 	struct v4l2_mbus_framefmt *fmt = &format->format;
 	const struct ov5647_mode *ov5647_mode_list;
 	struct ov5647 *sensor = to_sensor(sd);
+	int hblank, exposure_max, exposure_def;
 	const struct ov5647_mode *mode;
 	unsigned int num_modes;
-	int hblank;
 
 	/*
 	 * Default mbus code MEDIA_BUS_FMT_SBGGR10_1X10 if the requested one
@@ -1136,6 +1142,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);
 
@@ -1319,6 +1332,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
@@ -1364,7 +1389,7 @@ 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);
 
@@ -1378,9 +1403,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.29.1


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

* [PATCH v3 24/29] media: ov5647: Use pm_runtime infrastructure
  2020-11-09 16:49 [PATCH v3 00/29] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
                   ` (22 preceding siblings ...)
  2020-11-09 16:49 ` [PATCH v3 23/29] media: ov5647: Advertise the correct exposure range Jacopo Mondi
@ 2020-11-09 16:49 ` Jacopo Mondi
  2020-11-09 16:49 ` [PATCH v3 25/29] media: ov5647: Rework s_stream() operation Jacopo Mondi
                   ` (5 subsequent siblings)
  29 siblings, 0 replies; 37+ messages in thread
From: Jacopo Mondi @ 2020-11-09 16:49 UTC (permalink / raw)
  To: linux-media
  Cc: Jacopo Mondi, mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dafna.hirschfeld, dave.stevenson, naush,
	erosca

Use the pm_runtime framework to replace the legacy s_power() operation.

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

diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
index 7745a85ef4f02..ff265506a4c85 100644
--- a/drivers/media/i2c/ov5647.c
+++ b/drivers/media/i2c/ov5647.c
@@ -19,6 +19,7 @@
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/of_graph.h>
+#include <linux/pm_runtime.h>
 #include <linux/slab.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-ctrls.h>
@@ -879,86 +880,75 @@ static int ov5647_stream_off(struct v4l2_subdev *sd)
 	return ov5647_write(sd, OV5640_REG_PAD_OUT, 0x01);
 }
 
-static int set_sw_standby(struct v4l2_subdev *sd, bool standby)
+static int ov5647_power_on(struct device *dev)
 {
+	struct ov5647 *sensor = dev_get_drvdata(dev);
 	int ret;
-	u8 rdval;
 
-	ret = ov5647_read(sd, OV5647_SW_STANDBY, &rdval);
-	if (ret < 0)
-		return ret;
+	dev_dbg(dev, "OV5647 power on\n");
 
-	if (standby)
-		rdval &= ~0x01;
-	else
-		rdval |= 0x01;
-
-	return ov5647_write(sd, OV5647_SW_STANDBY, rdval);
-}
+	if (sensor->pwdn) {
+		gpiod_set_value_cansleep(sensor->pwdn, 0);
+		msleep(PWDN_ACTIVE_DELAY_MS);
+	}
 
-static int ov5647_sensor_power(struct v4l2_subdev *sd, int on)
-{
-	struct i2c_client *client = v4l2_get_subdevdata(sd);
-	struct ov5647 *sensor = to_sensor(sd);
-	int ret = 0;
+	ret = clk_prepare_enable(sensor->xclk);
+	if (ret < 0) {
+		dev_err(dev, "clk prepare enable failed\n");
+		goto error_pwdn;
+	}
 
-	mutex_lock(&sensor->lock);
+	ret = ov5647_write_array(&sensor->sd, sensor_oe_enable_regs,
+				 ARRAY_SIZE(sensor_oe_enable_regs));
+	if (ret < 0) {
+		dev_err(dev, "write sensor_oe_enable_regs error\n");
+		goto error_clk_disable;
+	}
 
-	if (on && !sensor->power_count)	{
-		dev_dbg(&client->dev, "OV5647 power on\n");
+	/* Stream off to coax lanes into LP-11 state. */
+	ret = ov5647_stream_off(&sensor->sd);
+	if (ret < 0) {
+		dev_err(dev, "camera not available, check power\n");
+		goto error_clk_disable;
+	}
 
-		if (sensor->pwdn) {
-			gpiod_set_value_cansleep(sensor->pwdn, 0);
-			msleep(PWDN_ACTIVE_DELAY_MS);
-		}
+	return 0;
 
-		ret = clk_prepare_enable(sensor->xclk);
-		if (ret < 0) {
-			dev_err(&client->dev, "clk prepare enable failed\n");
-			goto out;
-		}
+error_clk_disable:
+	clk_disable_unprepare(sensor->xclk);
+error_pwdn:
+	gpiod_set_value_cansleep(sensor->pwdn, 1);
 
-		ret = ov5647_write_array(sd, sensor_oe_enable_regs,
-					 ARRAY_SIZE(sensor_oe_enable_regs));
-		if (ret < 0) {
-			clk_disable_unprepare(sensor->xclk);
-			dev_err(&client->dev,
-				"write sensor_oe_enable_regs error\n");
-			goto out;
-		}
+	return ret;
+}
 
-		/* Stream off to coax lanes into LP-11 state. */
-		ret = ov5647_stream_off(sd);
-		if (ret < 0) {
-			clk_disable_unprepare(sensor->xclk);
-			dev_err(&client->dev,
-				"Camera not available, check Power\n");
-			goto out;
-		}
-	} else if (!on && sensor->power_count == 1) {
-		dev_dbg(&client->dev, "OV5647 power off\n");
+static int ov5647_power_off(struct device *dev)
+{
+	struct ov5647 *sensor = dev_get_drvdata(dev);
+	u8 rdval;
+	int ret;
 
-		ret = ov5647_write_array(sd, sensor_oe_disable_regs,
-					 ARRAY_SIZE(sensor_oe_disable_regs));
-		if (ret < 0)
-			dev_dbg(&client->dev, "disable oe failed\n");
+	dev_dbg(dev, "OV5647 power off\n");
 
-		ret = set_sw_standby(sd, true);
-		if (ret < 0)
-			dev_dbg(&client->dev, "soft stby failed\n");
+	ret = ov5647_write_array(&sensor->sd, sensor_oe_disable_regs,
+				 ARRAY_SIZE(sensor_oe_disable_regs));
+	if (ret < 0)
+		dev_dbg(dev, "disable oe failed\n");
 
-		clk_disable_unprepare(sensor->xclk);
-		gpiod_set_value_cansleep(sensor->pwdn, 1);
-	}
+	/* Enter software standby */
+	ret = ov5647_read(&sensor->sd, OV5647_SW_STANDBY, &rdval);
+	if (ret < 0)
+		dev_dbg(dev, "software standby failed\n");
 
-	/* Update the power count. */
-	sensor->power_count += on ? 1 : -1;
-	WARN_ON(sensor->power_count < 0);
+	rdval &= ~0x01;
+	ret = ov5647_write(&sensor->sd, OV5647_SW_STANDBY, rdval);
+	if (ret < 0)
+		dev_dbg(dev, "software standby failed\n");
 
-out:
-	mutex_unlock(&sensor->lock);
+	clk_disable_unprepare(sensor->xclk);
+	gpiod_set_value_cansleep(sensor->pwdn, 1);
 
-	return ret;
+	return 0;
 }
 
 #ifdef CONFIG_VIDEO_ADV_DEBUG
@@ -987,7 +977,6 @@ static int ov5647_sensor_set_register(struct v4l2_subdev *sd,
 
 /* 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
 	.g_register		= ov5647_sensor_get_register,
 	.s_register		= ov5647_sensor_set_register,
@@ -1539,24 +1528,29 @@ static int ov5647_probe(struct i2c_client *client)
 	if (ret < 0)
 		goto ctrl_handler_free;
 
-	if (sensor->pwdn) {
-		gpiod_set_value_cansleep(sensor->pwdn, 0);
-		msleep(PWDN_ACTIVE_DELAY_MS);
-	}
+	ret = ov5647_power_on(dev);
+	if (ret)
+		goto entity_cleanup;
 
 	ret = ov5647_detect(sd);
-	gpiod_set_value_cansleep(sensor->pwdn, 1);
 	if (ret < 0)
-		goto entity_cleanup;
+		goto power_off;
 
 	ret = v4l2_async_register_subdev(sd);
 	if (ret < 0)
-		goto entity_cleanup;
+		goto power_off;
+
+	/* Enable runtime PM and turn off the device */
+	pm_runtime_set_active(dev);
+	pm_runtime_enable(dev);
+	pm_runtime_idle(dev);
 
 	dev_dbg(dev, "OmniVision OV5647 camera driver probed\n");
 
 	return 0;
 
+power_off:
+	ov5647_power_off(dev);
 entity_cleanup:
 	media_entity_cleanup(&sd->entity);
 ctrl_handler_free:
@@ -1576,11 +1570,16 @@ static int ov5647_remove(struct i2c_client *client)
 	media_entity_cleanup(&sensor->sd.entity);
 	v4l2_ctrl_handler_free(&sensor->ctrls);
 	v4l2_device_unregister_subdev(sd);
+	pm_runtime_disable(&client->dev);
 	mutex_destroy(&sensor->lock);
 
 	return 0;
 }
 
+static const struct dev_pm_ops ov5647_pm_ops = {
+	SET_RUNTIME_PM_OPS(ov5647_power_off, ov5647_power_on, NULL)
+};
+
 static const struct i2c_device_id ov5647_id[] = {
 	{ "ov5647", 0 },
 	{ /* sentinel */ }
@@ -1599,6 +1598,7 @@ static struct i2c_driver ov5647_driver = {
 	.driver = {
 		.of_match_table = of_match_ptr(ov5647_of_match),
 		.name	= "ov5647",
+		.pm	= &ov5647_pm_ops,
 	},
 	.probe_new	= ov5647_probe,
 	.remove		= ov5647_remove,
-- 
2.29.1


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

* [PATCH v3 25/29] media: ov5647: Rework s_stream() operation
  2020-11-09 16:49 [PATCH v3 00/29] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
                   ` (23 preceding siblings ...)
  2020-11-09 16:49 ` [PATCH v3 24/29] media: ov5647: Use pm_runtime infrastructure Jacopo Mondi
@ 2020-11-09 16:49 ` Jacopo Mondi
  2020-11-09 16:49 ` [PATCH v3 26/29] media: ov5647: Apply controls only when powered Jacopo Mondi
                   ` (4 subsequent siblings)
  29 siblings, 0 replies; 37+ messages in thread
From: Jacopo Mondi @ 2020-11-09 16:49 UTC (permalink / raw)
  To: linux-media
  Cc: Jacopo Mondi, mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dafna.hirschfeld, dave.stevenson, naush,
	erosca

Rework the s_stream() operation to turn the sensor on and
off at stream enable/disable time using the pm_runtime infrastructure.

Protect the stream on/off from being called multiple times in
sequence with a 'streaming' flag.

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

diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
index ff265506a4c85..dc24afbb7cfd0 100644
--- a/drivers/media/i2c/ov5647.c
+++ b/drivers/media/i2c/ov5647.c
@@ -114,6 +114,7 @@ struct ov5647 {
 	struct v4l2_ctrl		*hblank;
 	struct v4l2_ctrl		*vblank;
 	struct v4l2_ctrl		*exposure;
+	bool				streaming;
 };
 
 static inline struct ov5647 *to_sensor(struct v4l2_subdev *sd)
@@ -999,14 +1000,42 @@ __ov5647_get_pad_crop(struct ov5647 *ov5647, struct v4l2_subdev_pad_config *cfg,
 
 static int ov5647_s_stream(struct v4l2_subdev *sd, int enable)
 {
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
 	struct ov5647 *sensor = to_sensor(sd);
 	int ret;
 
 	mutex_lock(&sensor->lock);
-	if (enable)
+	if (sensor->streaming == enable) {
+		mutex_unlock(&sensor->lock);
+		return 0;
+	}
+
+	if (enable) {
+		ret = pm_runtime_get_sync(&client->dev);
+		if (ret < 0)
+			goto error_unlock;
+
 		ret = ov5647_stream_on(sd);
-	else
+		if (ret < 0) {
+			dev_err(&client->dev, "stream start failed: %d\n", ret);
+			goto error_unlock;
+		}
+	} else {
 		ret = ov5647_stream_off(sd);
+		if (ret < 0) {
+			dev_err(&client->dev, "stream stop failed: %d\n", ret);
+			goto error_unlock;
+		}
+		pm_runtime_put(&client->dev);
+	}
+
+	sensor->streaming = enable;
+	mutex_unlock(&sensor->lock);
+
+	return 0;
+
+error_unlock:
+	pm_runtime_put(&client->dev);
 	mutex_unlock(&sensor->lock);
 
 	return ret;
-- 
2.29.1


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

* [PATCH v3 26/29] media: ov5647: Apply controls only when powered
  2020-11-09 16:49 [PATCH v3 00/29] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
                   ` (24 preceding siblings ...)
  2020-11-09 16:49 ` [PATCH v3 25/29] media: ov5647: Rework s_stream() operation Jacopo Mondi
@ 2020-11-09 16:49 ` Jacopo Mondi
  2020-11-09 16:49 ` [PATCH v3 27/29] media: ov5647: Constify oe_enable/disable reglist Jacopo Mondi
                   ` (3 subsequent siblings)
  29 siblings, 0 replies; 37+ messages in thread
From: Jacopo Mondi @ 2020-11-09 16:49 UTC (permalink / raw)
  To: linux-media
  Cc: Jacopo Mondi, mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dafna.hirschfeld, dave.stevenson, naush,
	erosca

Use pm_runtime_get_if_in_use() in s_ctrl to apply controls
only when the device is powered on.

Rework the control set function to balance the
pm_runtime_get_if_in_use() call with
pm_runtime_put() at the end of the function.

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

diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
index dc24afbb7cfd0..ef6c7b1e12490 100644
--- a/drivers/media/i2c/ov5647.c
+++ b/drivers/media/i2c/ov5647.c
@@ -104,7 +104,6 @@ struct ov5647 {
 	struct v4l2_subdev		sd;
 	struct media_pad		pad;
 	struct mutex			lock;
-	int				power_count;
 	struct clk			*xclk;
 	struct gpio_desc		*pwdn;
 	bool				clock_ncont;
@@ -1347,6 +1346,8 @@ static int ov5647_s_ctrl(struct v4l2_ctrl *ctrl)
 					    struct ov5647, ctrls);
 	struct v4l2_subdev *sd = &sensor->sd;
 	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	int ret = 0;
+
 
 	/* v4l2_ctrl_lock() locks our own mutex */
 
@@ -1363,33 +1364,40 @@ static int ov5647_s_ctrl(struct v4l2_ctrl *ctrl)
 	}
 
 	/*
-	 * 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 the device is not powered up 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)
+	if (pm_runtime_get_if_in_use(&client->dev) == 0)
 		return 0;
 
 	switch (ctrl->id) {
 	case V4L2_CID_AUTO_WHITE_BALANCE:
-		return ov5647_s_auto_white_balance(sd, ctrl->val);
+		ret = ov5647_s_auto_white_balance(sd, ctrl->val);
+		break;
 	case V4L2_CID_AUTOGAIN:
-		return ov5647_s_autogain(sd, ctrl->val);
+		ret = ov5647_s_autogain(sd, ctrl->val);
+		break;
 	case V4L2_CID_EXPOSURE_AUTO:
-		return ov5647_s_exposure_auto(sd, ctrl->val);
+		ret = ov5647_s_exposure_auto(sd, ctrl->val);
+		break;
 	case V4L2_CID_ANALOGUE_GAIN:
-		return  ov5647_s_analogue_gain(sd, ctrl->val);
+		ret =  ov5647_s_analogue_gain(sd, ctrl->val);
+		break;
 	case V4L2_CID_EXPOSURE:
-		return ov5647_s_exposure(sd, ctrl->val);
+		ret = ov5647_s_exposure(sd, ctrl->val);
+		break;
+	case V4L2_CID_VBLANK:
+		ret = ov5647_write16(sd, OV5647_REG_VTS_HI,
+				     sensor->mode->format.height + ctrl->val);
+		break;
+
+	/* Read-only, but we adjust it based on mode. */
 	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;
-	case V4L2_CID_VBLANK:
-		return ov5647_write16(sd, OV5647_REG_VTS_HI,
-				      sensor->mode->format.height + ctrl->val);
+		break;
+
 	default:
 		dev_info(&client->dev,
 			 "Control (id:0x%x, val:0x%x) not supported\n",
@@ -1397,7 +1405,9 @@ static int ov5647_s_ctrl(struct v4l2_ctrl *ctrl)
 		return -EINVAL;
 	}
 
-	return 0;
+	pm_runtime_put(&client->dev);
+
+	return ret;
 }
 
 static const struct v4l2_ctrl_ops ov5647_ctrl_ops = {
-- 
2.29.1


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

* [PATCH v3 27/29] media: ov5647: Constify oe_enable/disable reglist
  2020-11-09 16:49 [PATCH v3 00/29] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
                   ` (25 preceding siblings ...)
  2020-11-09 16:49 ` [PATCH v3 26/29] media: ov5647: Apply controls only when powered Jacopo Mondi
@ 2020-11-09 16:49 ` Jacopo Mondi
  2020-11-09 16:49 ` [PATCH v3 28/29] media: ov5647: Support VIDIOC_SUBSCRIBE_EVENT Jacopo Mondi
                   ` (2 subsequent siblings)
  29 siblings, 0 replies; 37+ messages in thread
From: Jacopo Mondi @ 2020-11-09 16:49 UTC (permalink / raw)
  To: linux-media
  Cc: Jacopo Mondi, mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dafna.hirschfeld, dave.stevenson, naush,
	erosca

Make the two register-value lists const.

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

diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
index ef6c7b1e12490..afb8173458bbe 100644
--- a/drivers/media/i2c/ov5647.c
+++ b/drivers/media/i2c/ov5647.c
@@ -121,13 +121,13 @@ static inline struct ov5647 *to_sensor(struct v4l2_subdev *sd)
 	return container_of(sd, struct ov5647, sd);
 }
 
-static struct regval_list sensor_oe_disable_regs[] = {
+static const struct regval_list sensor_oe_disable_regs[] = {
 	{0x3000, 0x00},
 	{0x3001, 0x00},
 	{0x3002, 0x00},
 };
 
-static struct regval_list sensor_oe_enable_regs[] = {
+static const struct regval_list sensor_oe_enable_regs[] = {
 	{0x3000, 0x0f},
 	{0x3001, 0xff},
 	{0x3002, 0xe4},
-- 
2.29.1


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

* [PATCH v3 28/29] media: ov5647: Support VIDIOC_SUBSCRIBE_EVENT
  2020-11-09 16:49 [PATCH v3 00/29] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
                   ` (26 preceding siblings ...)
  2020-11-09 16:49 ` [PATCH v3 27/29] media: ov5647: Constify oe_enable/disable reglist Jacopo Mondi
@ 2020-11-09 16:49 ` Jacopo Mondi
  2020-11-09 16:49 ` [PATCH v3 29/29] media: ov5647: Remove 640x480 SBGGR8 mode Jacopo Mondi
  2020-11-18 20:50 ` [PATCH v3 00/29] media: ov5647: Support RaspberryPi Camera Module v1 Sakari Ailus
  29 siblings, 0 replies; 37+ messages in thread
From: Jacopo Mondi @ 2020-11-09 16:49 UTC (permalink / raw)
  To: linux-media
  Cc: Jacopo Mondi, mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dafna.hirschfeld, dave.stevenson, naush,
	erosca

The driver reports the V4L2_SUBDEV_FL_HAS_EVENTS flag but does not
support subscribing and unsubscribing to events.

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

diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
index afb8173458bbe..5235045ef0012 100644
--- a/drivers/media/i2c/ov5647.c
+++ b/drivers/media/i2c/ov5647.c
@@ -24,6 +24,7 @@
 #include <linux/videodev2.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
 #include <media/v4l2-fwnode.h>
 #include <media/v4l2-image-sizes.h>
 #include <media/v4l2-mediabus.h>
@@ -977,6 +978,8 @@ static int ov5647_sensor_set_register(struct v4l2_subdev *sd,
 
 /* Subdev core operations registration */
 static const struct v4l2_subdev_core_ops ov5647_subdev_core_ops = {
+	.subscribe_event	= v4l2_ctrl_subdev_subscribe_event,
+	.unsubscribe_event	= v4l2_event_subdev_unsubscribe,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 	.g_register		= ov5647_sensor_get_register,
 	.s_register		= ov5647_sensor_set_register,
-- 
2.29.1


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

* [PATCH v3 29/29] media: ov5647: Remove 640x480 SBGGR8 mode
  2020-11-09 16:49 [PATCH v3 00/29] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
                   ` (27 preceding siblings ...)
  2020-11-09 16:49 ` [PATCH v3 28/29] media: ov5647: Support VIDIOC_SUBSCRIBE_EVENT Jacopo Mondi
@ 2020-11-09 16:49 ` Jacopo Mondi
  2020-11-18 20:48   ` Sakari Ailus
  2020-11-18 20:50 ` [PATCH v3 00/29] media: ov5647: Support RaspberryPi Camera Module v1 Sakari Ailus
  29 siblings, 1 reply; 37+ messages in thread
From: Jacopo Mondi @ 2020-11-09 16:49 UTC (permalink / raw)
  To: linux-media
  Cc: Jacopo Mondi, mchehab, sakari.ailus, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dafna.hirschfeld, dave.stevenson, naush,
	erosca

Capturing in 640x480 SBGGR8_1X8 hangs the system when capturing
with the unicam driver on RaspberryPi 4 platform.

Remove it.

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

diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
index 5235045ef0012..43bebf1f36f8d 100644
--- a/drivers/media/i2c/ov5647.c
+++ b/drivers/media/i2c/ov5647.c
@@ -134,94 +134,6 @@ static const struct regval_list sensor_oe_enable_regs[] = {
 	{0x3002, 0xe4},
 };
 
-static const struct regval_list ov5647_640x480_8bpp[] = {
-	{0x0100, 0x00},
-	{0x0103, 0x01},
-	{0x3034, 0x08},
-	{0x3035, 0x21},
-	{0x3036, 0x46},
-	{0x303c, 0x11},
-	{0x3106, 0xf5},
-	{0x3821, 0x07},
-	{0x3820, 0x41},
-	{0x3827, 0xec},
-	{0x370c, 0x0f},
-	{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},
-	{0x380c, 0x07},
-	{0x380d, 0x68},
-	{0x3814, 0x31},
-	{0x3815, 0x31},
-	{0x3708, 0x64},
-	{0x3709, 0x52},
-	{0x3808, 0x02},
-	{0x3809, 0x80},
-	{0x380a, 0x01},
-	{0x380b, 0xe0},
-	{0x3801, 0x00},
-	{0x3802, 0x00},
-	{0x3803, 0x00},
-	{0x3804, 0x0a},
-	{0x3805, 0x3f},
-	{0x3806, 0x07},
-	{0x3807, 0xa1},
-	{0x3811, 0x08},
-	{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, 0x27},
-	{0x3a0a, 0x00},
-	{0x3a0b, 0xf6},
-	{0x3a0d, 0x04},
-	{0x3a0e, 0x03},
-	{0x3a0f, 0x58},
-	{0x3a10, 0x50},
-	{0x3a1b, 0x58},
-	{0x3a1e, 0x50},
-	{0x3a11, 0x60},
-	{0x3a1f, 0x28},
-	{0x4001, 0x02},
-	{0x4004, 0x02},
-	{0x4000, 0x09},
-	{0x4837, 0x24},
-	{0x4050, 0x6e},
-	{0x4051, 0x8f},
-	{0x0100, 0x01},
-};
-
 static struct regval_list ov5647_2592x1944_10bpp[] = {
 	{0x0100, 0x00},
 	{0x0103, 0x01},
@@ -583,30 +495,6 @@ static struct regval_list ov5647_640x480_10bpp[] = {
 	{0x0100, 0x01},
 };
 
-static const struct ov5647_mode ov5647_8bpp_modes[] = {
-	/* 8-bit VGA mode: Uncentred crop 2x2 binned 1296x972 image. */
-	{
-		.format	= {
-			.code		= MEDIA_BUS_FMT_SBGGR8_1X8,
-			.colorspace	= V4L2_COLORSPACE_SRGB,
-			.field		= V4L2_FIELD_NONE,
-			.width		= 640,
-			.height		= 480
-		},
-		.crop = {
-			.left		= OV5647_PIXEL_ARRAY_LEFT,
-			.top		= OV5647_PIXEL_ARRAY_TOP,
-			.width		= 1280,
-			.height		= 960,
-		},
-		.pixel_rate	= 77291670,
-		.hts		= 1896,
-		.vts		= 0x3d8,
-		.reg_list	= ov5647_640x480_8bpp,
-		.num_regs	= ARRAY_SIZE(ov5647_640x480_8bpp)
-	},
-};
-
 static const struct ov5647_mode ov5647_10bpp_modes[] = {
 	/* 2592x1944 full resolution full FOV 10-bit mode. */
 	{
@@ -695,23 +583,17 @@ static const struct ov5647_mode ov5647_10bpp_modes[] = {
 };
 
 static const struct ov5647_format_list ov5647_formats[] = {
-	{
-		.mbus_code	= MEDIA_BUS_FMT_SBGGR8_1X8,
-		.modes		= ov5647_8bpp_modes,
-		.num_modes	= ARRAY_SIZE(ov5647_8bpp_modes),
-	},
 	{
 		.mbus_code	= MEDIA_BUS_FMT_SBGGR10_1X10,
 		.modes		= ov5647_10bpp_modes,
 		.num_modes	= ARRAY_SIZE(ov5647_10bpp_modes),
 	},
 };
-
 #define OV5647_NUM_FORMATS	(ARRAY_SIZE(ov5647_formats))
 
 /* Default sensor mode is 2x2 binned 640x480 SBGGR10_1X10. */
-#define OV5647_DEFAULT_MODE	(&ov5647_formats[1].modes[3])
-#define OV5647_DEFAULT_FORMAT	(ov5647_formats[1].modes[3].format)
+#define OV5647_DEFAULT_MODE	(&ov5647_formats[0].modes[3])
+#define OV5647_DEFAULT_FORMAT	(ov5647_formats[0].modes[3].format)
 
 static int ov5647_write16(struct v4l2_subdev *sd, u16 reg, u16 val)
 {
@@ -1116,25 +998,12 @@ static int ov5647_set_pad_fmt(struct v4l2_subdev *sd,
 			      struct v4l2_subdev_format *format)
 {
 	struct v4l2_mbus_framefmt *fmt = &format->format;
-	const struct ov5647_mode *ov5647_mode_list;
 	struct ov5647 *sensor = to_sensor(sd);
 	int hblank, exposure_max, exposure_def;
 	const 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_8bpp_modes;
-		num_modes = ARRAY_SIZE(ov5647_8bpp_modes);
-	} else {
-		ov5647_mode_list = ov5647_10bpp_modes;
-		num_modes = ARRAY_SIZE(ov5647_10bpp_modes);
-	}
 
-	mode = v4l2_find_nearest_size(ov5647_mode_list, num_modes,
+	mode = v4l2_find_nearest_size(ov5647_10bpp_modes,
+				      ARRAY_SIZE(ov5647_10bpp_modes),
 				      format.width, format.height,
 				      fmt->width, fmt->height);
 
-- 
2.29.1


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

* Re: [PATCH v3 13/29] media: ov5647: Break out format handling
  2020-11-09 16:49 ` [PATCH v3 13/29] media: ov5647: Break out format handling Jacopo Mondi
@ 2020-11-18 20:18   ` Sakari Ailus
  0 siblings, 0 replies; 37+ messages in thread
From: Sakari Ailus @ 2020-11-18 20:18 UTC (permalink / raw)
  To: Jacopo Mondi
  Cc: linux-media, mchehab, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dafna.hirschfeld, dave.stevenson, naush,
	erosca

Hi Jacopo,

On Mon, Nov 09, 2020 at 05:49:18PM +0100, 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 | 90 +++++++++++++++++++++++++++-----------
>  1 file changed, 65 insertions(+), 25 deletions(-)
> 
> diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
> index 91193706b6fe1..d41c11afe1216 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;
> +	const struct regval_list	*reg_list;
> +	unsigned int			num_regs;
> +};
> +
> +struct ov5647_format_list {
> +	unsigned int			mbus_code;
> +	const 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;
> +	const struct ov5647_mode	*mode;
>  };
>  
>  static inline struct ov5647 *to_sensor(struct v4l2_subdev *sd)
> @@ -115,7 +125,7 @@ static struct regval_list sensor_oe_enable_regs[] = {
>  	{0x3002, 0xe4},
>  };
>  
> -static struct regval_list ov5647_640x480[] = {
> +static const struct regval_list ov5647_640x480[] = {
>  	{0x0100, 0x00},
>  	{0x0103, 0x01},
>  	{0x3034, 0x08},
> @@ -205,6 +215,33 @@ static struct regval_list ov5647_640x480[] = {
>  	{0x0100, 0x01},
>  };
>  
> +static const 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};
> @@ -245,7 +282,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)
> +			      const struct regval_list *regs, int array_size)
>  {
>  	int i, ret;
>  
> @@ -275,6 +312,7 @@ 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;
>  
> @@ -282,8 +320,8 @@ 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 +532,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 +544,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 +574,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;

With this change, the memset above becomes redundant.

>  
>  	return 0;
>  }
> @@ -591,11 +633,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;
>  }
> @@ -817,6 +855,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;

-- 
Regards,

Sakari Ailus

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

* Re: [PATCH v3 18/29] media: ov5647: Implement set_fmt pad operation
  2020-11-09 16:49 ` [PATCH v3 18/29] media: ov5647: Implement set_fmt pad operation Jacopo Mondi
@ 2020-11-18 20:42   ` Sakari Ailus
  2020-11-19 11:39     ` Jacopo Mondi
  0 siblings, 1 reply; 37+ messages in thread
From: Sakari Ailus @ 2020-11-18 20:42 UTC (permalink / raw)
  To: Jacopo Mondi
  Cc: linux-media, mchehab, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dafna.hirschfeld, dave.stevenson, naush,
	erosca

Hi Jacopo,

On Mon, Nov 09, 2020 at 05:49:23PM +0100, 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 | 66 +++++++++++++++++++++++++++++++++++---
>  1 file changed, 62 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
> index c65aacc0e04d3..68eab61d53493 100644
> --- a/drivers/media/i2c/ov5647.c
> +++ b/drivers/media/i2c/ov5647.c
> @@ -1019,14 +1019,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;
> +	const struct v4l2_mbus_framefmt *sensor_format;
> +	struct ov5647 *sensor = to_sensor(sd);
>  
>  	memset(fmt, 0, sizeof(*fmt));
> -	*fmt = OV5647_DEFAULT_FORMAT;
> +
> +	mutex_lock(&sensor->lock);
> +	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;
> +	const struct ov5647_mode *ov5647_mode_list;
> +	struct ov5647 *sensor = to_sensor(sd);
> +	const 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_8bpp_modes;
> +		num_modes = ARRAY_SIZE(ov5647_8bpp_modes);
> +	} else {
> +		ov5647_mode_list = ov5647_10bpp_modes;
> +		num_modes = ARRAY_SIZE(ov5647_10bpp_modes);
> +	}

It'd be nicer if you could obtain the above information from an array where
there's entry for each format. The above checks have a tendency to repeat
themselves in a number of places.

> +
> +	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;
>  }
> @@ -1071,8 +1129,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,
>  };
>  

-- 
Sakari Ailus

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

* Re: [PATCH v3 20/29] media: ov5647: Support V4L2_CID_PIXEL_RATE
  2020-11-09 16:49 ` [PATCH v3 20/29] media: ov5647: Support V4L2_CID_PIXEL_RATE Jacopo Mondi
@ 2020-11-18 20:43   ` Sakari Ailus
  0 siblings, 0 replies; 37+ messages in thread
From: Sakari Ailus @ 2020-11-18 20:43 UTC (permalink / raw)
  To: Jacopo Mondi
  Cc: linux-media, mchehab, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dafna.hirschfeld, dave.stevenson, naush,
	erosca, Dave Stevenson

Hi Jacopo,

On Mon, Nov 09, 2020 at 05:49:25PM +0100, 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 66556690dcffb..01978491b97f4 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;
>  	const struct regval_list	*reg_list;
>  	unsigned int			num_regs;
>  };
> @@ -96,6 +97,7 @@ struct ov5647 {
>  	bool				clock_ncont;
>  	struct v4l2_ctrl_handler	ctrls;
>  	const struct ov5647_mode	*mode;
> +	struct v4l2_ctrl		*pixel_rate;
>  };
>  
>  static inline struct ov5647 *to_sensor(struct v4l2_subdev *sd)
> @@ -582,6 +584,7 @@ static const struct ov5647_mode ov5647_8bpp_modes[] = {
>  			.width		= 1280,
>  			.height		= 960,
>  		},
> +		.pixel_rate	= 77291670,
>  		.reg_list	= ov5647_640x480_8bpp,
>  		.num_regs	= ARRAY_SIZE(ov5647_640x480_8bpp)
>  	},
> @@ -603,6 +606,7 @@ static const struct ov5647_mode ov5647_10bpp_modes[] = {
>  			.width		= 2592,
>  			.height		= 1944
>  		},
> +		.pixel_rate	= 87500000,
>  		.reg_list	= ov5647_2592x1944_10bpp,
>  		.num_regs	= ARRAY_SIZE(ov5647_2592x1944_10bpp)
>  	},
> @@ -621,6 +625,7 @@ static const struct ov5647_mode ov5647_10bpp_modes[] = {
>  			.width		= 1928,
>  			.height		= 1080,
>  		},
> +		.pixel_rate	= 81666700,
>  		.reg_list	= ov5647_1080p30_10bpp,
>  		.num_regs	= ARRAY_SIZE(ov5647_1080p30_10bpp)
>  	},
> @@ -639,6 +644,7 @@ static const struct ov5647_mode ov5647_10bpp_modes[] = {
>  			.width		= 2592,
>  			.height		= 1944,
>  		},
> +		.pixel_rate	= 81666700,
>  		.reg_list	= ov5647_2x2binned_10bpp,
>  		.num_regs	= ARRAY_SIZE(ov5647_2x2binned_10bpp)
>  	},
> @@ -657,6 +663,7 @@ static const struct ov5647_mode ov5647_10bpp_modes[] = {
>  			.width		= 2560,
>  			.height		= 1920,
>  		},
> +		.pixel_rate	= 55000000,
>  		.reg_list	= ov5647_640x480_10bpp,
>  		.num_regs	= ARRAY_SIZE(ov5647_640x480_10bpp)
>  	},
> @@ -1083,6 +1090,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);
>  
> @@ -1285,6 +1296,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",
> @@ -1303,7 +1317,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);
> @@ -1323,17 +1337,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;

You can drop the check and move the assignment below after the handler
error check.

> +	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,

Sakari Ailus

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

* Re: [PATCH v3 29/29] media: ov5647: Remove 640x480 SBGGR8 mode
  2020-11-09 16:49 ` [PATCH v3 29/29] media: ov5647: Remove 640x480 SBGGR8 mode Jacopo Mondi
@ 2020-11-18 20:48   ` Sakari Ailus
  2020-11-19 10:07     ` Jacopo Mondi
  0 siblings, 1 reply; 37+ messages in thread
From: Sakari Ailus @ 2020-11-18 20:48 UTC (permalink / raw)
  To: Jacopo Mondi
  Cc: linux-media, mchehab, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dafna.hirschfeld, dave.stevenson, naush,
	erosca

Hi Jacopo,

On Mon, Nov 09, 2020 at 05:49:34PM +0100, Jacopo Mondi wrote:
> Capturing in 640x480 SBGGR8_1X8 hangs the system when capturing
> with the unicam driver on RaspberryPi 4 platform.
> 
> Remove it.

Is this somehow a property of the sensor driver? Is the sensor driver in
use somewhere else where this configuration could be useful? Can other 8
bpp configurations captured with the Unicam driver?

-- 
Regards,

Sakari Ailus

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

* Re: [PATCH v3 00/29]  media: ov5647: Support RaspberryPi Camera Module v1
  2020-11-09 16:49 [PATCH v3 00/29] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
                   ` (28 preceding siblings ...)
  2020-11-09 16:49 ` [PATCH v3 29/29] media: ov5647: Remove 640x480 SBGGR8 mode Jacopo Mondi
@ 2020-11-18 20:50 ` Sakari Ailus
  29 siblings, 0 replies; 37+ messages in thread
From: Sakari Ailus @ 2020-11-18 20:50 UTC (permalink / raw)
  To: Jacopo Mondi
  Cc: linux-media, mchehab, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dafna.hirschfeld, dave.stevenson, naush,
	erosca

Hi Jacopo,

On Mon, Nov 09, 2020 at 05:49:05PM +0100, Jacopo Mondi wrote:
> Third iteration following:
> v2: https://patchwork.linuxtv.org/project/linux-media/list/?series=3782
> v1: https://patchwork.linuxtv.org/project/linux-media/list/?series=2765

Thanks for the update. This set really improves the driver in many ways.

I had a few small comments on specific patches. Also, in general, please
try to maintain coding style, 80 characters per line in particular ---
unless there are tangible reasons to do otherwise.

-- 
Kind regards,

Sakari Ailus

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

* Re: [PATCH v3 29/29] media: ov5647: Remove 640x480 SBGGR8 mode
  2020-11-18 20:48   ` Sakari Ailus
@ 2020-11-19 10:07     ` Jacopo Mondi
  0 siblings, 0 replies; 37+ messages in thread
From: Jacopo Mondi @ 2020-11-19 10:07 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, mchehab, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dafna.hirschfeld, dave.stevenson, naush,
	erosca

Hi Sakari,

On Wed, Nov 18, 2020 at 10:48:13PM +0200, Sakari Ailus wrote:
> Hi Jacopo,
>
> On Mon, Nov 09, 2020 at 05:49:34PM +0100, Jacopo Mondi wrote:
> > Capturing in 640x480 SBGGR8_1X8 hangs the system when capturing
> > with the unicam driver on RaspberryPi 4 platform.
> >
> > Remove it.
>
> Is this somehow a property of the sensor driver? Is the sensor driver in

More than a property I would say a failure of the sensor driver :)
> use somewhere else where this configuration could be useful? Can other 8

I'm not sure in which other platforms the 8bpp mode has been tested
with

> bpp configurations captured with the Unicam driver?

But unicam can capture 8bpp modes with imx219 (just tested) and
imx477 according to Dave


>
> --
> Regards,
>
> Sakari Ailus

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

* Re: [PATCH v3 18/29] media: ov5647: Implement set_fmt pad operation
  2020-11-18 20:42   ` Sakari Ailus
@ 2020-11-19 11:39     ` Jacopo Mondi
  0 siblings, 0 replies; 37+ messages in thread
From: Jacopo Mondi @ 2020-11-19 11:39 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, mchehab, hverkuil, laurent.pinchart,
	roman.kovalivskyi, dafna.hirschfeld, dave.stevenson, naush,
	erosca

Hi Sakari,

On Wed, Nov 18, 2020 at 10:42:35PM +0200, Sakari Ailus wrote:
> Hi Jacopo,
>
> On Mon, Nov 09, 2020 at 05:49:23PM +0100, 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 | 66 +++++++++++++++++++++++++++++++++++---
> >  1 file changed, 62 insertions(+), 4 deletions(-)
> >
> > diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
> > index c65aacc0e04d3..68eab61d53493 100644
> > --- a/drivers/media/i2c/ov5647.c
> > +++ b/drivers/media/i2c/ov5647.c
> > @@ -1019,14 +1019,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;
> > +	const struct v4l2_mbus_framefmt *sensor_format;
> > +	struct ov5647 *sensor = to_sensor(sd);
> >
> >  	memset(fmt, 0, sizeof(*fmt));
> > -	*fmt = OV5647_DEFAULT_FORMAT;
> > +
> > +	mutex_lock(&sensor->lock);
> > +	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;
> > +	const struct ov5647_mode *ov5647_mode_list;
> > +	struct ov5647 *sensor = to_sensor(sd);
> > +	const 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_8bpp_modes;
> > +		num_modes = ARRAY_SIZE(ov5647_8bpp_modes);
> > +	} else {
> > +		ov5647_mode_list = ov5647_10bpp_modes;
> > +		num_modes = ARRAY_SIZE(ov5647_10bpp_modes);
> > +	}
>
> It'd be nicer if you could obtain the above information from an array where
> there's entry for each format. The above checks have a tendency to repeat
> themselves in a number of places.
>

Indeed I could replace this with a for loop like it's done in
enum_frame_sizes...

I'll fix

> > +
> > +	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;
> >  }
> > @@ -1071,8 +1129,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,
> >  };
> >
>
> --
> Sakari Ailus

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

end of thread, other threads:[~2020-11-19 11:40 UTC | newest]

Thread overview: 37+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-11-09 16:49 [PATCH v3 00/29] media: ov5647: Support RaspberryPi Camera Module v1 Jacopo Mondi
2020-11-09 16:49 ` [PATCH v3 01/29] media: ov5647: Add support for PWDN GPIO Jacopo Mondi
2020-11-09 16:49 ` [PATCH v3 02/29] media: ov5647: Add support for non-continuous clock mode Jacopo Mondi
2020-11-09 16:49 ` [PATCH v3 03/29] media: ov5647: Add set_fmt and get_fmt calls Jacopo Mondi
2020-11-09 16:49 ` [PATCH v3 04/29] media: ov5647: Fix format initialization Jacopo Mondi
2020-11-09 16:49 ` [PATCH v3 05/29] media: ov5647: Fix style issues Jacopo Mondi
2020-11-09 16:49 ` [PATCH v3 06/29] media: ov5647: Replace license with SPDX identifier Jacopo Mondi
2020-11-09 16:49 ` [PATCH v3 07/29] media: ov5647: Fix return value from read/write Jacopo Mondi
2020-11-09 16:49 ` [PATCH v3 08/29] media: ov5647: Program mode at s_stream(1) time Jacopo Mondi
2020-11-09 16:49 ` [PATCH v3 09/29] media: ov5647: Implement enum_frame_size() Jacopo Mondi
2020-11-09 16:49 ` [PATCH v3 10/29] media: ov5647: Protect s_stream() with mutex Jacopo Mondi
2020-11-09 16:49 ` [PATCH v3 11/29] media: ov5647: Support gain, exposure and AWB controls Jacopo Mondi
2020-11-09 16:49 ` [PATCH v3 12/29] media: ov5647: Rationalize driver structure name Jacopo Mondi
2020-11-09 16:49 ` [PATCH v3 13/29] media: ov5647: Break out format handling Jacopo Mondi
2020-11-18 20:18   ` Sakari Ailus
2020-11-09 16:49 ` [PATCH v3 14/29] media: ov5647: Add support for get_selection() Jacopo Mondi
2020-11-09 16:49 ` [PATCH v3 15/29] media: ov5647: Rename SBGGR8 VGA mode Jacopo Mondi
2020-11-09 16:49 ` [PATCH v3 16/29] media: ov5647: Add SGGBR10_1X10 modes Jacopo Mondi
2020-11-09 16:49 ` [PATCH v3 17/29] media: ov5647: Use SBGGR10_1X10 640x480 as default Jacopo Mondi
2020-11-09 16:49 ` [PATCH v3 18/29] media: ov5647: Implement set_fmt pad operation Jacopo Mondi
2020-11-18 20:42   ` Sakari Ailus
2020-11-19 11:39     ` Jacopo Mondi
2020-11-09 16:49 ` [PATCH v3 19/29] media: ov5647: Set V4L2_SUBDEV_FL_HAS_EVENTS flag Jacopo Mondi
2020-11-09 16:49 ` [PATCH v3 20/29] media: ov5647: Support V4L2_CID_PIXEL_RATE Jacopo Mondi
2020-11-18 20:43   ` Sakari Ailus
2020-11-09 16:49 ` [PATCH v3 21/29] media: ov5647: Support V4L2_CID_HBLANK control Jacopo Mondi
2020-11-09 16:49 ` [PATCH v3 22/29] media: ov5647: Support V4L2_CID_VBLANK control Jacopo Mondi
2020-11-09 16:49 ` [PATCH v3 23/29] media: ov5647: Advertise the correct exposure range Jacopo Mondi
2020-11-09 16:49 ` [PATCH v3 24/29] media: ov5647: Use pm_runtime infrastructure Jacopo Mondi
2020-11-09 16:49 ` [PATCH v3 25/29] media: ov5647: Rework s_stream() operation Jacopo Mondi
2020-11-09 16:49 ` [PATCH v3 26/29] media: ov5647: Apply controls only when powered Jacopo Mondi
2020-11-09 16:49 ` [PATCH v3 27/29] media: ov5647: Constify oe_enable/disable reglist Jacopo Mondi
2020-11-09 16:49 ` [PATCH v3 28/29] media: ov5647: Support VIDIOC_SUBSCRIBE_EVENT Jacopo Mondi
2020-11-09 16:49 ` [PATCH v3 29/29] media: ov5647: Remove 640x480 SBGGR8 mode Jacopo Mondi
2020-11-18 20:48   ` Sakari Ailus
2020-11-19 10:07     ` Jacopo Mondi
2020-11-18 20:50 ` [PATCH v3 00/29] media: ov5647: Support RaspberryPi Camera Module v1 Sakari Ailus

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.