xref: /linux/drivers/media/pci/mgb4/mgb4_trigger.c (revision d30c1683aaecb93d2ab95685dc4300a33d3cea7a)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2021-2023 Digiteq Automotive
4  *     author: Martin Tuma <martin.tuma@digiteqautomotive.com>
5  *
6  * This module handles the IIO trigger device. The card has two signal inputs
7  * for event triggers that can be used to record events related to the video
8  * stream. A standard linux IIO device with triggered buffer capability is
9  * created and configured that can be used to fetch the events with the same
10  * clock source as the video frames.
11  */
12 
13 #include <linux/iio/iio.h>
14 #include <linux/iio/buffer.h>
15 #include <linux/iio/trigger.h>
16 #include <linux/iio/trigger_consumer.h>
17 #include <linux/iio/triggered_buffer.h>
18 #include <linux/pci.h>
19 #include <linux/dma/amd_xdma.h>
20 #include <linux/types.h>
21 #include "mgb4_core.h"
22 #include "mgb4_trigger.h"
23 
24 struct trigger_data {
25 	struct mgb4_dev *mgbdev;
26 	struct iio_trigger *trig;
27 };
28 
29 static int trigger_read_raw(struct iio_dev *indio_dev,
30 			    struct iio_chan_spec const *chan, int *val,
31 			    int *val2, long mask)
32 {
33 	struct trigger_data *st = iio_priv(indio_dev);
34 
35 	switch (mask) {
36 	case IIO_CHAN_INFO_RAW:
37 		if (iio_buffer_enabled(indio_dev))
38 			return -EBUSY;
39 		*val = mgb4_read_reg(&st->mgbdev->video, 0xA0);
40 
41 		return IIO_VAL_INT;
42 	}
43 
44 	return -EINVAL;
45 }
46 
47 static int trigger_set_state(struct iio_trigger *trig, bool state)
48 {
49 	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
50 	struct trigger_data *st = iio_priv(indio_dev);
51 	int irq = xdma_get_user_irq(st->mgbdev->xdev, 11);
52 
53 	if (state)
54 		xdma_enable_user_irq(st->mgbdev->xdev, irq);
55 	else
56 		xdma_disable_user_irq(st->mgbdev->xdev, irq);
57 
58 	return 0;
59 }
60 
61 static const struct iio_trigger_ops trigger_ops = {
62 	.set_trigger_state = &trigger_set_state,
63 };
64 
65 static const struct iio_info trigger_info = {
66 	.read_raw         = trigger_read_raw,
67 };
68 
69 #define TRIGGER_CHANNEL(_si) {                    \
70 	.type = IIO_ACTIVITY,                         \
71 	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
72 	.scan_index = _si,                            \
73 	.scan_type = {                                \
74 		.sign = 'u',                              \
75 		.realbits = 32,                           \
76 		.storagebits = 32,                        \
77 		.shift = 0,                               \
78 		.endianness = IIO_CPU                     \
79 	},                                            \
80 }
81 
82 static const struct iio_chan_spec trigger_channels[] = {
83 	TRIGGER_CHANNEL(0),
84 	IIO_CHAN_SOFT_TIMESTAMP(1),
85 };
86 
87 static irqreturn_t trigger_handler(int irq, void *p)
88 {
89 	struct iio_poll_func *pf = p;
90 	struct iio_dev *indio_dev = pf->indio_dev;
91 	struct trigger_data *st = iio_priv(indio_dev);
92 	struct {
93 		u32 data;
94 		aligned_s64 ts;
95 	} scan = { };
96 
97 	scan.data = mgb4_read_reg(&st->mgbdev->video, 0xA0);
98 	mgb4_write_reg(&st->mgbdev->video, 0xA0, scan.data);
99 
100 	iio_push_to_buffers_with_ts(indio_dev, &scan, sizeof(scan), pf->timestamp);
101 	iio_trigger_notify_done(indio_dev->trig);
102 
103 	mgb4_write_reg(&st->mgbdev->video, 0xB4, 1U << 11);
104 
105 	return IRQ_HANDLED;
106 }
107 
108 static int probe_trigger(struct iio_dev *indio_dev, int irq)
109 {
110 	int ret;
111 	struct trigger_data *st = iio_priv(indio_dev);
112 
113 	st->trig = iio_trigger_alloc(&st->mgbdev->pdev->dev, "%s-dev%d",
114 				     indio_dev->name, iio_device_id(indio_dev));
115 	if (!st->trig)
116 		return -ENOMEM;
117 
118 	ret = request_irq(irq, &iio_trigger_generic_data_rdy_poll, 0,
119 			  "mgb4-trigger", st->trig);
120 	if (ret)
121 		goto error_free_trig;
122 
123 	st->trig->ops = &trigger_ops;
124 	iio_trigger_set_drvdata(st->trig, indio_dev);
125 	ret = iio_trigger_register(st->trig);
126 	if (ret)
127 		goto error_free_irq;
128 
129 	indio_dev->trig = iio_trigger_get(st->trig);
130 
131 	return 0;
132 
133 error_free_irq:
134 	free_irq(irq, st->trig);
135 error_free_trig:
136 	iio_trigger_free(st->trig);
137 
138 	return ret;
139 }
140 
141 static void remove_trigger(struct iio_dev *indio_dev, int irq)
142 {
143 	struct trigger_data *st = iio_priv(indio_dev);
144 
145 	iio_trigger_unregister(st->trig);
146 	free_irq(irq, st->trig);
147 	iio_trigger_free(st->trig);
148 }
149 
150 struct iio_dev *mgb4_trigger_create(struct mgb4_dev *mgbdev)
151 {
152 	struct iio_dev *indio_dev;
153 	struct trigger_data *data;
154 	struct pci_dev *pdev = mgbdev->pdev;
155 	struct device *dev = &pdev->dev;
156 	int rv, irq;
157 
158 	indio_dev = iio_device_alloc(dev, sizeof(*data));
159 	if (!indio_dev)
160 		return NULL;
161 
162 	indio_dev->info = &trigger_info;
163 	indio_dev->name = "mgb4";
164 	indio_dev->modes = INDIO_DIRECT_MODE;
165 	indio_dev->channels = trigger_channels;
166 	indio_dev->num_channels = ARRAY_SIZE(trigger_channels);
167 
168 	data = iio_priv(indio_dev);
169 	data->mgbdev = mgbdev;
170 
171 	irq = xdma_get_user_irq(mgbdev->xdev, 11);
172 	rv = probe_trigger(indio_dev, irq);
173 	if (rv < 0) {
174 		dev_err(dev, "iio triggered setup failed\n");
175 		goto error_alloc;
176 	}
177 	rv = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
178 					trigger_handler, NULL);
179 	if (rv < 0) {
180 		dev_err(dev, "iio triggered buffer setup failed\n");
181 		goto error_trigger;
182 	}
183 	rv = iio_device_register(indio_dev);
184 	if (rv < 0) {
185 		dev_err(dev, "iio device register failed\n");
186 		goto error_buffer;
187 	}
188 
189 	return indio_dev;
190 
191 error_buffer:
192 	iio_triggered_buffer_cleanup(indio_dev);
193 error_trigger:
194 	remove_trigger(indio_dev, irq);
195 error_alloc:
196 	iio_device_free(indio_dev);
197 
198 	return NULL;
199 }
200 
201 void mgb4_trigger_free(struct iio_dev *indio_dev)
202 {
203 	struct trigger_data *st = iio_priv(indio_dev);
204 
205 	iio_device_unregister(indio_dev);
206 	iio_triggered_buffer_cleanup(indio_dev);
207 	remove_trigger(indio_dev, xdma_get_user_irq(st->mgbdev->xdev, 11));
208 	iio_device_free(indio_dev);
209 }
210