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