// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Support for NXT2002 and NXT2004 - VSB/QAM
*
* Copyright (C) 2005 Kirk Lapray <kirk.lapray@gmail.com>
* Copyright (C) 2006-2014 Michael Krufky <mkrufky@linuxtv.org>
* based on nxt2002 by Taylor Jacob <rtjacob@earthlink.net>
* and nxt2004 by Jean-Francois Thibert <jeanfrancois@sagetv.com>
*/
/*
* NOTES ABOUT THIS DRIVER
*
* This Linux driver supports:
* B2C2/BBTI Technisat Air2PC - ATSC (NXT2002)
* AverTVHD MCE A180 (NXT2004)
* ATI HDTV Wonder (NXT2004)
*
* This driver needs external firmware. Please use the command
* "<kerneldir>/scripts/get_dvb_firmware nxt2002" or
* "<kerneldir>/scripts/get_dvb_firmware nxt2004" to
* download/extract the appropriate firmware, and then copy it to
* /usr/lib/hotplug/firmware/ or /lib/firmware/
* (depending on configuration of firmware hotplug).
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
/* Max transfer size done by I2C transfer functions */
#define MAX_XFER_SIZE 256
#define NXT2002_DEFAULT_FIRMWARE "dvb-fe-nxt2002.fw"
#define NXT2004_DEFAULT_FIRMWARE "dvb-fe-nxt2004.fw"
#define CRC_CCIT_MASK 0x1021
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <media/dvb_frontend.h>
#include "nxt200x.h"
struct nxt200x_state {
struct i2c_adapter* i2c;
const struct nxt200x_config* config;
struct dvb_frontend frontend;
/* demodulator private data */
nxt_chip_type demod_chip;
u8 initialised:1;
};
static int debug;
#define dprintk(args...) do { if (debug) pr_debug(args); } while (0)
static int i2c_writebytes (struct nxt200x_state* state, u8 addr, u8 *buf, u8 len)
{
int err;
struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = len };
if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
pr_warn("%s: i2c write error (addr 0x%02x, err == %i)\n",
__func__, addr, err);
return -EREMOTEIO;
}
return 0;
}
static int i2c_readbytes(struct nxt200x_state *state, u8 addr, u8 *buf, u8 len)
{
int err;
struct i2c_msg msg = { .addr = addr, .flags = I2C_M_RD, .buf = buf, .len = len };
if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
pr_warn("%s: i2c read error (addr 0x%02x, err == %i)\n",
__func__, addr, err);
return -EREMOTEIO;
}
return 0;
}
static int nxt200x_writebytes (struct nxt200x_state* state, u8 reg,
const u8 *buf, u8 len)
{
u8 buf2[MAX_XFER_SIZE];
int err;
struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf2, .len = len + 1 };
if (1 + len > sizeof(buf2)) {
pr_warn("%s: i2c wr reg=%04x: len=%d is too big!\n",
__func__, reg, len);
return -EINVAL;
}
buf2[0] = reg;
memcpy(&buf2[1], buf, len);
if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
pr_warn("%s: i2c write error (addr 0x%02x, err == %i)\n",
__func__, state->config->demod_address, err);
return -EREMOTEIO;
}
return 0;
}
static int nxt200x_readbytes(struct nxt200x_state *state, u8 reg, u8 *buf, u8 len)
{
u8 reg2 [] = { reg };
struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = reg2, .len = 1 },
{ .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = buf, .len