linux/drivers/media/pci/tw686x/tw686x-core.c

// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (C) 2015 VanguardiaSur - www.vanguardiasur.com.ar
 *
 * Based on original driver by Krzysztof Ha?asa:
 * Copyright (C) 2015 Industrial Research Institute for Automation
 * and Measurements PIAP
 *
 * Notes
 * -----
 *
 * 1. Under stress-testing, it has been observed that the PCIe link
 * goes down, without reason. Therefore, the driver takes special care
 * to allow device hot-unplugging.
 *
 * 2. TW686X devices are capable of setting a few different DMA modes,
 * including: scatter-gather, field and frame modes. However,
 * under stress testings it has been found that the machine can
 * freeze completely if DMA registers are programmed while streaming
 * is active.
 *
 * Therefore, driver implements a dma_mode called 'memcpy' which
 * avoids cycling the DMA buffers, and insteads allocates extra DMA buffers
 * and then copies into vmalloc'ed user buffers.
 *
 * In addition to this, when streaming is on, the driver tries to access
 * hardware registers as infrequently as possible. This is done by using
 * a timer to limit the rate at which DMA is reset on DMA channels error.
 */

#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci_ids.h>
#include <linux/slab.h>
#include <linux/timer.h>

#include "tw686x.h"
#include "tw686x-regs.h"

/*
 * This module parameter allows to control the DMA_TIMER_INTERVAL value.
 * The DMA_TIMER_INTERVAL register controls the minimum DMA interrupt
 * time span (iow, the maximum DMA interrupt rate) thus allowing for
 * IRQ coalescing.
 *
 * The chip datasheet does not mention a time unit for this value, so
 * users wanting fine-grain control over the interrupt rate should
 * determine the desired value through testing.
 */
static u32 dma_interval =;
module_param(dma_interval, int, 0444);
MODULE_PARM_DESC();

static unsigned int dma_mode =;
static const char *dma_mode_name(unsigned int mode)
{}

static int tw686x_dma_mode_get(char *buffer, const struct kernel_param *kp)
{}

static int tw686x_dma_mode_set(const char *val, const struct kernel_param *kp)
{}
module_param_call();
MODULE_PARM_DESC();

void tw686x_disable_channel(struct tw686x_dev *dev, unsigned int channel)
{}

void tw686x_enable_channel(struct tw686x_dev *dev, unsigned int channel)
{}

/*
 * The purpose of this awful hack is to avoid enabling the DMA
 * channels "too fast" which makes some TW686x devices very
 * angry and freeze the CPU (see note 1).
 */
static void tw686x_dma_delay(struct timer_list *t)
{}

static void tw686x_reset_channels(struct tw686x_dev *dev, unsigned int ch_mask)
{}

static irqreturn_t tw686x_irq(int irq, void *dev_id)
{}

static void tw686x_dev_release(struct v4l2_device *v4l2_dev)
{}

static int tw686x_probe(struct pci_dev *pci_dev,
			const struct pci_device_id *pci_id)
{}

static void tw686x_remove(struct pci_dev *pci_dev)
{}

/*
 * On TW6864 and TW6868, all channels share the pair of video DMA SG tables,
 * with 10-bit start_idx and end_idx determining start and end of frame buffer
 * for particular channel.
 * TW6868 with all its 8 channels would be problematic (only 127 SG entries per
 * channel) but we support only 4 channels on this chip anyway (the first
 * 4 channels are driven with internal video decoder, the other 4 would require
 * an external TW286x part).
 *
 * On TW6865 and TW6869, each channel has its own DMA SG table, with indexes
 * starting with 0. Both chips have complete sets of internal video decoders
 * (respectively 4 or 8-channel).
 *
 * All chips have separate SG tables for two video frames.
 */

/* driver_data is number of A/V channels */
static const struct pci_device_id tw686x_pci_tbl[] =;
MODULE_DEVICE_TABLE(pci, tw686x_pci_tbl);

static struct pci_driver tw686x_pci_driver =;
module_pci_driver();

MODULE_DESCRIPTION();
MODULE_AUTHOR();
MODULE_AUTHOR();
MODULE_LICENSE();