aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/brcm2708/patches-4.19/950-0325-media-bcm2835-unicam-Power-on-subdev-on-open-release.patch
blob: 3acdacecd21eea04048d6e72a7b58cdc6fec9023 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
From 14dccf96c00c9c1cd18843e5a4bb37e12eebe01e Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.org>
Date: Tue, 29 Jan 2019 15:56:10 +0000
Subject: [PATCH 325/773] media:bcm2835-unicam: Power on subdev on
 open/release, not streaming

The driver was powering on the source subdevice as part of STREAMON,
and powering it off in STREAMOFF. This isn't so great if there is a
significant amount of setup required for your device.

Copy the approach taken in the Atmel ISC driver where s_power(1) is called
on first file handle open, and s_power(0) is called on the last release.

See https://www.raspberrypi.org/forums/viewtopic.php?f=43&t=232437

Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
---
 .../media/platform/bcm2835/bcm2835-unicam.c   | 68 +++++++++++++++----
 1 file changed, 54 insertions(+), 14 deletions(-)

--- a/drivers/media/platform/bcm2835/bcm2835-unicam.c
+++ b/drivers/media/platform/bcm2835/bcm2835-unicam.c
@@ -1237,11 +1237,6 @@ static int unicam_start_streaming(struct
 		unicam_err(dev, "Failed to enable CSI clock: %d\n", ret);
 		goto err_pm_put;
 	}
-	ret = v4l2_subdev_call(dev->sensor, core, s_power, 1);
-	if (ret < 0 && ret != -ENOIOCTLCMD) {
-		unicam_err(dev, "power on failed in subdev\n");
-		goto err_clock_unprepare;
-	}
 	dev->streaming = 1;
 
 	unicam_start_rx(dev, addr);
@@ -1256,8 +1251,6 @@ static int unicam_start_streaming(struct
 
 err_disable_unicam:
 	unicam_disable(dev);
-	v4l2_subdev_call(dev->sensor, core, s_power, 0);
-err_clock_unprepare:
 	clk_disable_unprepare(dev->clock);
 err_pm_put:
 	unicam_runtime_put(dev);
@@ -1306,11 +1299,6 @@ static void unicam_stop_streaming(struct
 	dev->next_frm = NULL;
 	spin_unlock_irqrestore(&dev->dma_queue_lock, flags);
 
-	if (v4l2_subdev_has_op(dev->sensor, core, s_power)) {
-		if (v4l2_subdev_call(dev->sensor, core, s_power, 0) < 0)
-			unicam_err(dev, "power off failed in subdev\n");
-	}
-
 	clk_disable_unprepare(dev->clock);
 	unicam_runtime_put(dev);
 }
@@ -1543,11 +1531,63 @@ static const struct vb2_ops unicam_video
 	.stop_streaming		= unicam_stop_streaming,
 };
 
+/*
+ * unicam_open : This function is based on the v4l2_fh_open helper function.
+ * It has been augmented to handle sensor subdevice power management,
+ */
+static int unicam_open(struct file *file)
+{
+	struct unicam_device *dev = video_drvdata(file);
+	int ret;
+
+	mutex_lock(&dev->lock);
+
+	ret = v4l2_fh_open(file);
+	if (ret) {
+		unicam_err(dev, "v4l2_fh_open failed\n");
+		goto unlock;
+	}
+
+	if (!v4l2_fh_is_singular_file(file))
+		goto unlock;
+
+	ret = v4l2_subdev_call(dev->sensor, core, s_power, 1);
+	if (ret < 0 && ret != -ENOIOCTLCMD) {
+		v4l2_fh_release(file);
+		goto unlock;
+	}
+
+unlock:
+	mutex_unlock(&dev->lock);
+	return ret;
+}
+
+static int unicam_release(struct file *file)
+{
+	struct unicam_device *dev = video_drvdata(file);
+	struct v4l2_subdev *sd = dev->sensor;
+	bool fh_singular;
+	int ret;
+
+	mutex_lock(&dev->lock);
+
+	fh_singular = v4l2_fh_is_singular_file(file);
+
+	ret = _vb2_fop_release(file, NULL);
+
+	if (fh_singular)
+		v4l2_subdev_call(sd, core, s_power, 0);
+
+	mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
 /* unicam capture driver file operations */
 static const struct v4l2_file_operations unicam_fops = {
 	.owner		= THIS_MODULE,
-	.open           = v4l2_fh_open,
-	.release        = vb2_fop_release,
+	.open           = unicam_open,
+	.release        = unicam_release,
 	.read		= vb2_fop_read,
 	.poll		= vb2_fop_poll,
 	.unlocked_ioctl	= video_ioctl2,