summaryrefslogtreecommitdiffstats
path: root/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0479-media-soc_camera-rcar_csi2-add-interrupts.patch
blob: 960da09469dfcaa462896a221ccade07b8244994 (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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
From 0812102bc301699c607229cb86b2bc8d385aef2f Mon Sep 17 00:00:00 2001
From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
Date: Wed, 19 Feb 2020 02:26:11 +0300
Subject: [PATCH] media: soc_camera: rcar_csi2: add interrupts

This enables interrupts from RCAR CSI2 and grab timestamp
of received frames (EOF)

Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
---
 drivers/media/platform/soc_camera/rcar_csi2.c | 58 ++++++++++++++++++++++++++-
 1 file changed, 57 insertions(+), 1 deletion(-)

diff --git a/drivers/media/platform/soc_camera/rcar_csi2.c b/drivers/media/platform/soc_camera/rcar_csi2.c
index ffb28c7..ca47ba3 100644
--- a/drivers/media/platform/soc_camera/rcar_csi2.c
+++ b/drivers/media/platform/soc_camera/rcar_csi2.c
@@ -200,6 +200,7 @@ struct rcar_csi2_link_config {
 	unsigned long vcdt;
 	unsigned long vcdt2;
 	unsigned int csi_rate;
+	unsigned int use_interrupts;
 };
 
 #define INIT_RCAR_CSI2_LINK_CONFIG(m) \
@@ -228,6 +229,8 @@ struct rcar_csi2 {
 	unsigned int			csi_rate;
 	spinlock_t			lock;
 	atomic_t			use_count;
+	unsigned int			use_interrupts;
+	u64				timestamp[4];
 };
 
 static int dump = 0;
@@ -434,6 +437,7 @@ static irqreturn_t rcar_csi2_irq(int irq, void *data)
 	struct rcar_csi2 *priv = data;
 	u32 int_status;
 	unsigned int handled = 0;
+	u64 ts;
 
 	spin_lock(&priv->lock);
 
@@ -441,6 +445,26 @@ static irqreturn_t rcar_csi2_irq(int irq, void *data)
 	if (!int_status)
 		goto done;
 
+	/* update timestamp on EOF for remote */
+	ts = ktime_get_ns();
+
+	if (int_status & RCAR_CSI2_INTSTATE_VD4_END) {
+		priv->timestamp[3] = ts;
+		//printk("eof vc3\n");
+	}
+	if (int_status & RCAR_CSI2_INTSTATE_VD3_END) {
+		priv->timestamp[2] = ts;
+		//printk("eof vc2\n");
+	}
+	if (int_status & RCAR_CSI2_INTSTATE_VD2_END) {
+		priv->timestamp[1] = ts;
+		//printk("eof vc1\n");
+	}
+	if (int_status & RCAR_CSI2_INTSTATE_VD1_END) {
+		priv->timestamp[0] = ts;
+		//printk("eof vc0\n");
+	}
+
 	/* ack interrupts */
 	iowrite32(int_status, priv->base + RCAR_CSI2_INTSTATE);
 	handled = 1;
@@ -456,6 +480,10 @@ static void rcar_csi2_hwdeinit(struct rcar_csi2 *priv)
 {
 	iowrite32(0, priv->base + RCAR_CSI2_PHYCNT);
 
+	/* mask interrupts */
+	iowrite32(~0U, priv->base + RCAR_CSI2_INTCLOSE);
+	/* ack interrupts */
+	iowrite32(~0U, priv->base + RCAR_CSI2_INTSTATE);
 	/* reset CSI2 hardware */
 	iowrite32(0x00000001, priv->base + RCAR_CSI2_SRST);
 	udelay(5);
@@ -550,6 +578,18 @@ static int rcar_csi2_hwinit(struct rcar_csi2 *priv)
 	dev_dbg(&priv->pdev->dev, "CSI2 VCDT2: 0x%x\n",
 			 ioread32(priv->base + RCAR_CSI2_VCDT2));
 
+	if (priv->use_interrupts) {
+		/* EOF only interrupts */
+		tmp = RCAR_CSI2_INTSTATE_VD1_END | RCAR_CSI2_INTSTATE_VD2_END |
+		      RCAR_CSI2_INTSTATE_VD3_END | RCAR_CSI2_INTSTATE_VD4_END;
+		/* unmask interrupts */
+		iowrite32(~tmp, priv->base + RCAR_CSI2_INTCLOSE);
+		/* ack all interrupts */
+		iowrite32(~0U, priv->base + RCAR_CSI2_INTSTATE);
+		/* enable interrupts */
+		iowrite32(tmp, priv->base + RCAR_CSI2_INTEN);
+	}
+
 	/* wait until video decoder power off */
 	msleep(10);
 	{
@@ -608,8 +648,21 @@ static int rcar_csi2_s_power(struct v4l2_subdev *sd, int on)
 	return ret;
 }
 
+static long rcar_csi2_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+	struct rcar_csi2 *priv = v4l2_get_subdevdata(sd);
+
+	if (cmd > 4 || !priv->use_interrupts)
+		return -EINVAL;
+
+	*(u64 *)arg = priv->timestamp[cmd];
+
+	return 0;
+}
+
 static struct v4l2_subdev_core_ops rcar_csi2_subdev_core_ops = {
 	.s_power	= rcar_csi2_s_power,
+	.ioctl		= rcar_csi2_ioctl,
 };
 
 static struct v4l2_subdev_ops rcar_csi2_subdev_ops = {
@@ -660,6 +713,9 @@ static int rcar_csi2_parse_dt(struct device_node *np,
 		printk(KERN_ERR "csi-rate not set\n");
 		return ret;
 	}
+	config->use_interrupts = 0;
+	if (of_property_read_bool(endpoint, "use-interrupts"))
+		config->use_interrupts = 1;
 	of_node_put(endpoint);
 
 	config->lanes = bus_cfg.bus.mipi_csi2.num_data_lanes;
@@ -730,7 +786,6 @@ static int rcar_csi2_probe(struct platform_device *pdev)
 		return -ENOMEM;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	/* Interrupt unused so far */
 	irq = platform_get_irq(pdev, 0);
 
 	if (!res || (int)irq <= 0) {
@@ -754,6 +809,7 @@ static int rcar_csi2_probe(struct platform_device *pdev)
 	priv->vcdt = link_config.vcdt;
 	priv->vcdt2 = link_config.vcdt2;
 	priv->csi_rate = link_config.csi_rate;
+	priv->use_interrupts = link_config.use_interrupts;
 	atomic_set(&priv->use_count, 0);
 
 	platform_set_drvdata(pdev, priv);
-- 
2.7.4