]> Git Repo - linux.git/blob - drivers/media/pci/mgb4/mgb4_trigger.c
Linux 6.14-rc3
[linux.git] / drivers / media / pci / mgb4 / mgb4_trigger.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2021-2023 Digiteq Automotive
4  *     author: Martin Tuma <[email protected]>
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 }
This page took 0.041419 seconds and 4 git commands to generate.