// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Mirics MSi2500 driver
* Mirics MSi3101 SDR Dongle driver
*
* Copyright (C) 2013 Antti Palosaari <crope@iki.fi>
*
* That driver is somehow based of pwc driver:
* (C) 1999-2004 Nemosoft Unv.
* (C) 2004-2006 Luc Saillard (luc@saillard.org)
* (C) 2011 Hans de Goede <hdegoede@redhat.com>
*/
#include <linux/module.h>
#include <linux/slab.h>
#include <asm/div64.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-event.h>
#include <linux/usb.h>
#include <media/videobuf2-v4l2.h>
#include <media/videobuf2-vmalloc.h>
#include <linux/spi/spi.h>
static bool msi2500_emulated_fmt;
module_param_named(emulated_formats, msi2500_emulated_fmt, bool, 0644);
MODULE_PARM_DESC(emulated_formats, "enable emulated formats (disappears in future)");
/*
* iConfiguration 0
* bInterfaceNumber 0
* bAlternateSetting 1
* bNumEndpoints 1
* bEndpointAddress 0x81 EP 1 IN
* bmAttributes 1
* Transfer Type Isochronous
* wMaxPacketSize 0x1400 3x 1024 bytes
* bInterval 1
*/
#define MAX_ISO_BUFS (8)
#define ISO_FRAMES_PER_DESC (8)
#define ISO_MAX_FRAME_SIZE (3 * 1024)
#define ISO_BUFFER_SIZE (ISO_FRAMES_PER_DESC * ISO_MAX_FRAME_SIZE)
#define MAX_ISOC_ERRORS 20
/*
* TODO: These formats should be moved to V4L2 API. Formats are currently
* disabled from formats[] table, not visible to userspace.
*/
/* signed 12-bit */
#define MSI2500_PIX_FMT_SDR_S12 v4l2_fourcc('D', 'S', '1', '2')
/* Mirics MSi2500 format 384 */
#define MSI2500_PIX_FMT_SDR_MSI2500_384 v4l2_fourcc('M', '3', '8', '4')
static const struct v4l2_frequency_band bands[] = {
{
.tuner = 0,
.type = V4L2_TUNER_ADC,
.index = 0,
.capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS,
.rangelow = 1200000,
.rangehigh = 15000000,
},
};
/* stream formats */
struct msi2500_format {
u32 pixelformat;
u32 buffersize;
};
/* format descriptions for capture and preview */
static struct msi2500_format formats[] = {
{
.pixelformat = V4L2_SDR_FMT_CS8,
.buffersize = 3 * 1008,
#if 0
}, {
.pixelformat = MSI2500_PIX_FMT_SDR_MSI2500_384,
}, {
.pixelformat = MSI2500_PIX_FMT_SDR_S12,
#endif
}, {
.pixelformat = V4L2_SDR_FMT_CS14LE,
.buffersize = 3 * 1008,
}, {
.pixelformat = V4L2_SDR_FMT_CU8,
.buffersize = 3 * 1008,
}, {
.pixelformat = V4L2_SDR_FMT_CU16LE,
.buffersize = 3 * 1008,
},
};
static const unsigned int NUM_FORMATS = ARRAY_SIZE(formats);
/* intermediate buffers with raw data from the USB device */
struct msi2500_frame_buf {
/* common v4l buffer stuff -- must be first */
struct vb2_v4l2_buffer vb;
struct list_head list;
};
struct msi2500_dev {
struct device *dev;
struct video_device vdev;
struct v4l2_device v4l2_dev;
struct v4l2_subdev *v4l2_subdev;
struct spi_master *master;
/* videobuf2 queue and queued buffers list */
struct vb2_queue vb_queue;
struct list_head queued_bufs;
spinlock_t queued_bufs_lock; /* Protects queued_bufs */
/* Note if taking both locks v4l2_lock must always be locked first! */
struct mutex v4l2_lock; /* Protects everything else */
struct mutex vb_queue_lock; /* Protects vb_queue and capt_file */
/* Pointer to our usb_device, will be NULL after unplug */
struct usb_device *udev; /* Both mutexes most be hold when setting! */
unsigned int f_adc;
u32 pixelformat;
u32 buffersize;
unsigned