File Index
Files and directories
Sign in
FILE

mgb4_trigger.c

File preview with syntax highlighting.

linux-6.19.14/drivers/media/pci/mgb4/mgb4_trigger.c C
  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
 24struct trigger_data {
 25	struct mgb4_dev *mgbdev;
 26	struct iio_trigger *trig;
 27};
 28
 29static 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
 47static 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
 61static const struct iio_trigger_ops trigger_ops = {
 62	.set_trigger_state = &trigger_set_state,
 63};
 64
 65static 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
 82static const struct iio_chan_spec trigger_channels[] = {
 83	TRIGGER_CHANNEL(0),
 84	IIO_CHAN_SOFT_TIMESTAMP(1),
 85};
 86
 87static 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
108static 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, IRQF_NO_THREAD,
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
133error_free_irq:
134	free_irq(irq, st->trig);
135error_free_trig:
136	iio_trigger_free(st->trig);
137
138	return ret;
139}
140
141static 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
150struct 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
191error_buffer:
192	iio_triggered_buffer_cleanup(indio_dev);
193error_trigger:
194	remove_trigger(indio_dev, irq);
195error_alloc:
196	iio_device_free(indio_dev);
197
198	return NULL;
199}
200
201void 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}
~/ Read-only file preview.