// SPDX-License-Identifier: GPL-2.0-or-later
/*
* netup_unidvb_core.c
*
* Main module for NetUP Universal Dual DVB-CI
*
* Copyright (C) 2014 NetUP Inc.
* Copyright (C) 2014 Sergey Kozlov <serjk@netup.ru>
* Copyright (C) 2014 Abylay Ospan <aospan@netup.ru>
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kmod.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/list.h>
#include <media/videobuf2-v4l2.h>
#include <media/videobuf2-vmalloc.h>
#include "netup_unidvb.h"
#include "cxd2841er.h"
#include "horus3a.h"
#include "ascot2e.h"
#include "helene.h"
#include "lnbh25.h"
static int spi_enable;
module_param(spi_enable, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
MODULE_DESCRIPTION("Driver for NetUP Dual Universal DVB CI PCIe card");
MODULE_AUTHOR("info@netup.ru");
MODULE_VERSION(NETUP_UNIDVB_VERSION);
MODULE_LICENSE("GPL");
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
/* Avalon-MM PCI-E registers */
#define AVL_PCIE_IENR 0x50
#define AVL_PCIE_ISR 0x40
#define AVL_IRQ_ENABLE 0x80
#define AVL_IRQ_ASSERTED 0x80
/* GPIO registers */
#define GPIO_REG_IO 0x4880
#define GPIO_REG_IO_TOGGLE 0x4882
#define GPIO_REG_IO_SET 0x4884
#define GPIO_REG_IO_CLEAR 0x4886
/* GPIO bits */
#define GPIO_FEA_RESET (1 << 0)
#define GPIO_FEB_RESET (1 << 1)
#define GPIO_RFA_CTL (1 << 2)
#define GPIO_RFB_CTL (1 << 3)
#define GPIO_FEA_TU_RESET (1 << 4)
#define GPIO_FEB_TU_RESET (1 << 5)
/* DMA base address */
#define NETUP_DMA0_ADDR 0x4900
#define NETUP_DMA1_ADDR 0x4940
/* 8 DMA blocks * 128 packets * 188 bytes*/
#define NETUP_DMA_BLOCKS_COUNT 8
#define NETUP_DMA_PACKETS_COUNT 128
/* DMA status bits */
#define BIT_DMA_RUN 1
#define BIT_DMA_ERROR 2
#define BIT_DMA_IRQ 0x200
/**
* struct netup_dma_regs - the map of DMA module registers
* @ctrlstat_set: Control register, write to set control bits
* @ctrlstat_clear: Control register, write to clear control bits
* @start_addr_lo: DMA ring buffer start address, lower part
* @start_addr_hi: DMA ring buffer start address, higher part
* @size: DMA ring buffer size register
* * Bits [0-7]: DMA packet size, 188 bytes
* * Bits [16-23]: packets count in block, 128 packets
* * Bits [24-31]: blocks count, 8 blocks
* @timeout: DMA timeout in units of 8ns
* For example, value of 375000000 equals to 3 sec
* @curr_addr_lo: Current ring buffer head address, lower part
* @curr_addr_hi: Current ring buffer head address, higher part
* @stat_pkt_received: Statistic register, not tested
* @stat_pkt_accepted: Statistic register, not tested
* @stat_pkt_overruns: Statistic register, not tested
* @stat_pkt_underruns: Statistic register, not tested
* @stat_fifo_overruns: Statistic register, not tested
*/
struct netup_dma_regs {
__le32 ctrlstat_set;
__le32 ctrlstat_clear;
__le32 start_addr_lo;
__le32 start_addr_hi;
__le32 size;
__le32 timeout;
__le32 curr_addr_lo;
__le32 curr_addr_hi;
__le32 stat_pkt_received;
__le32 stat_pkt_accepted;
__le32 stat_pkt_overruns;
__le32 stat_pkt_underruns;
__le32 stat_fifo_overruns;
} __packed __aligned(1);
struct netup_unidvb_buffer {
struct vb2_v4l2_buffer vb;
struct list_head list;
u32 size;
};
static int netup_unidvb_tuner_ctrl(void *priv, int is_dvb_tc);
static void netup_unidvb_queue_cleanup(struct netup_dma *dma);
static struct cxd2841er_config demod_config = {
.i2c_addr = 0xc8,
.xtal = SONY_XTAL_24000,
.flags = CXD2841ER_USE_GATECTRL | CXD2841ER_ASCOT
};
static struct horus3a_config horus3a_conf = {
.i2c_address = 0xc0,
.xtal_freq_mhz = 16,
.set_tuner_callback = netup_unidvb_tuner_ctrl
};
static struct ascot2e_config ascot2e_conf = {
.i2c_address = 0xc2,
.set_tuner_callback = netup_unidvb_tuner_ctrl
};
static struct helene_config helene_conf = {
.i2c_address = 0xc0,
.xtal = SONY_HELENE_XTAL_24000,
.set_tuner_callback = netup_unidvb_tuner_ctrl
};
static struct lnbh25_config lnbh25_conf = {
.i2c_address = 0x10,
.data2_config = LNBH25_TEN | LNBH25_EXTM
};
static int netup_unidvb_tuner_ctrl(void *priv, int is_dvb_tc)
{
u8 reg, mask;
struct netup_dma *dma = priv;
struct netup_unidvb_dev *ndev;
if (!priv)
return -EINVAL;
ndev = dma->ndev;
dev_dbg(&ndev->pci_dev->dev, "%s(): num %d is_dvb_tc %d\n",
__func__, dma->num, is_dvb_tc);
reg = readb(ndev->bmmio0 + GPIO_REG_IO);
mask = (dma->num == 0) ? GPIO_RFA_CTL : GPIO_RFB_CTL;
/* inverted tuner control in hw rev. 1.4 */
if (ndev->rev == NETUP_HW_REV_1_4)
is_dvb_tc = !is_dvb_tc;
if (!is_dvb_tc)
reg |= mask;
else
reg &= ~mask;
writeb(reg, ndev->bmmio0 + GPIO_REG_IO);
return 0;
}
static void netup_unidvb_dev_enable(struct netup_unidvb_dev *ndev)
{
u16 gpio_reg;
/* enable PCI-E interrupts */
writel(AVL_IRQ_ENABLE, ndev->bmmio0 + AVL_PCIE_IENR);
/* unreset frontends bits[0:1] */
writeb(0x00, ndev->bmmio0 + GPIO_REG_IO);
msleep(100);
gpio_reg