linux/drivers/media/tuners/r820t.c

// SPDX-License-Identifier: GPL-2.0
// Rafael Micro R820T driver
//
// Copyright (C) 2013 Mauro Carvalho Chehab
//
// This driver was written from scratch, based on an existing driver
// that it is part of rtl-sdr git tree, released under GPLv2:
//	https://groups.google.com/forum/#!topic/ultra-cheap-sdr/Y3rBEOFtHug
//	https://github.com/n1gp/gr-baz
//
// From what I understood from the threads, the original driver was converted
// to userspace from a Realtek tree. I couldn't find the original tree.
// However, the original driver look awkward on my eyes. So, I decided to
// write a new version from it from the scratch, while trying to reproduce
// everything found there.
//
// TODO:
//	After locking, the original driver seems to have some routines to
//		improve reception. This was not implemented here yet.
//
//	RF Gain set/get is not implemented.

#define pr_fmt(fmt)

#include <linux/videodev2.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/bitrev.h>

#include "tuner-i2c.h"
#include "r820t.h"

/*
 * FIXME: I think that there are only 32 registers, but better safe than
 *	  sorry. After finishing the driver, we may review it.
 */
#define REG_SHADOW_START
#define NUM_REGS
#define NUM_IMR
#define IMR_TRIAL

#define VER_NUM

static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC();

static int no_imr_cal;
module_param(no_imr_cal, int, 0444);
MODULE_PARM_DESC();


/*
 * enums and structures
 */

enum xtal_cap_value {};

struct r820t_sect_type {};

struct r820t_priv {};

struct r820t_freq_range {};

#define VCO_POWER_REF
#define DIP_FREQ

/*
 * Static constants
 */

static LIST_HEAD(hybrid_tuner_instance_list);
static DEFINE_MUTEX(r820t_list_mutex);

/* Those initial values start from REG_SHADOW_START */
static const u8 r820t_init_array[NUM_REGS] =;

/* Tuner frequency ranges */
static const struct r820t_freq_range freq_ranges[] =;

static int r820t_xtal_capacitor[][2] =;

static const char *r820t_chip_enum_to_str(enum r820t_chip chip)
{}

/*
 * I2C read/write code and shadow registers logic
 */
static void shadow_store(struct r820t_priv *priv, u8 reg, const u8 *val,
			 int len)
{}

static int r820t_write(struct r820t_priv *priv, u8 reg, const u8 *val,
		       int len)
{}

static inline int r820t_write_reg(struct r820t_priv *priv, u8 reg, u8 val)
{}

static int r820t_read_cache_reg(struct r820t_priv *priv, int reg)
{}

static inline int r820t_write_reg_mask(struct r820t_priv *priv, u8 reg, u8 val,
				u8 bit_mask)
{}

static int r820t_read(struct r820t_priv *priv, u8 reg, u8 *val, int len)
{}

/*
 * r820t tuning logic
 */

static int r820t_set_mux(struct r820t_priv *priv, u32 freq)
{}

static int r820t_set_pll(struct r820t_priv *priv, enum v4l2_tuner_type type,
			 u32 freq)
{}

static int r820t_sysfreq_sel(struct r820t_priv *priv, u32 freq,
			     enum v4l2_tuner_type type,
			     v4l2_std_id std,
			     u32 delsys)
{}

static int r820t_set_tv_standard(struct r820t_priv *priv,
				 unsigned bw,
				 enum v4l2_tuner_type type,
				 v4l2_std_id std, u32 delsys)

{}

static int r820t_read_gain(struct r820t_priv *priv)
{}

#if 0
/* FIXME: This routine requires more testing */

/*
 * measured with a Racal 6103E GSM test set at 928 MHz with -60 dBm
 * input power, for raw results see:
 *	http://steve-m.de/projects/rtl-sdr/gain_measurement/r820t/
 */

static const int r820t_lna_gain_steps[]  = {
	0, 9, 13, 40, 38, 13, 31, 22, 26, 31, 26, 14, 19, 5, 35, 13
};

static const int r820t_mixer_gain_steps[]  = {
	0, 5, 10, 10, 19, 9, 10, 25, 17, 10, 8, 16, 13, 6, 3, -8
};

static int r820t_set_gain_mode(struct r820t_priv *priv,
			       bool set_manual_gain,
			       int gain)
{
	int rc;

	if (set_manual_gain) {
		int i, total_gain = 0;
		uint8_t mix_index = 0, lna_index = 0;
		u8 data[4];

		/* LNA auto off */
		rc = r820t_write_reg_mask(priv, 0x05, 0x10, 0x10);
		if (rc < 0)
			return rc;

		 /* Mixer auto off */
		rc = r820t_write_reg_mask(priv, 0x07, 0, 0x10);
		if (rc < 0)
			return rc;

		rc = r820t_read(priv, 0x00, data, sizeof(data));
		if (rc < 0)
			return rc;

		/* set fixed VGA gain for now (16.3 dB) */
		rc = r820t_write_reg_mask(priv, 0x0c, 0x08, 0x9f);
		if (rc < 0)
			return rc;

		for (i = 0; i < 15; i++) {
			if (total_gain >= gain)
				break;

			total_gain += r820t_lna_gain_steps[++lna_index];

			if (total_gain >= gain)
				break;

			total_gain += r820t_mixer_gain_steps[++mix_index];
		}

		/* set LNA gain */
		rc = r820t_write_reg_mask(priv, 0x05, lna_index, 0x0f);
		if (rc < 0)
			return rc;

		/* set Mixer gain */
		rc = r820t_write_reg_mask(priv, 0x07, mix_index, 0x0f);
		if (rc < 0)
			return rc;
	} else {
		/* LNA */
		rc = r820t_write_reg_mask(priv, 0x05, 0, 0x10);
		if (rc < 0)
			return rc;

		/* Mixer */
		rc = r820t_write_reg_mask(priv, 0x07, 0x10, 0x10);
		if (rc < 0)
			return rc;

		/* set fixed VGA gain for now (26.5 dB) */
		rc = r820t_write_reg_mask(priv, 0x0c, 0x0b, 0x9f);
		if (rc < 0)
			return rc;
	}

	return 0;
}
#endif

static int generic_set_freq(struct dvb_frontend *fe,
			    u32 freq /* in HZ */,
			    unsigned bw,
			    enum v4l2_tuner_type type,
			    v4l2_std_id std, u32 delsys)
{}

/*
 * r820t standby logic
 */

static int r820t_standby(struct r820t_priv *priv)
{}

/*
 * r820t device init logic
 */

static int r820t_xtal_check(struct r820t_priv *priv)
{}

static int r820t_imr_prepare(struct r820t_priv *priv)
{}

static int r820t_multi_read(struct r820t_priv *priv)
{}

static int r820t_imr_cross(struct r820t_priv *priv,
			   struct r820t_sect_type iq_point[3],
			   u8 *x_direct)
{}

static void r820t_compre_cor(struct r820t_sect_type iq[3])
{}

static int r820t_compre_step(struct r820t_priv *priv,
			     struct r820t_sect_type iq[3], u8 reg)
{}

static int r820t_iq_tree(struct r820t_priv *priv,
			 struct r820t_sect_type iq[3],
			 u8 fix_val, u8 var_val, u8 fix_reg)
{}

static int r820t_section(struct r820t_priv *priv,
			 struct r820t_sect_type *iq_point)
{}

static int r820t_vga_adjust(struct r820t_priv *priv)
{}

static int r820t_iq(struct r820t_priv *priv, struct r820t_sect_type *iq_pont)
{}

static int r820t_f_imr(struct r820t_priv *priv, struct r820t_sect_type *iq_pont)
{}

static int r820t_imr(struct r820t_priv *priv, unsigned imr_mem, bool im_flag)
{}

static int r820t_imr_callibrate(struct r820t_priv *priv)
{}

#if 0
/* Not used, for now */
static int r820t_gpio(struct r820t_priv *priv, bool enable)
{
	return r820t_write_reg_mask(priv, 0x0f, enable ? 1 : 0, 0x01);
}
#endif

/*
 *  r820t frontend operations and tuner attach code
 *
 * All driver locks and i2c control are only in this part of the code
 */

static int r820t_init(struct dvb_frontend *fe)
{}

static int r820t_sleep(struct dvb_frontend *fe)
{}

static int r820t_set_analog_freq(struct dvb_frontend *fe,
				 struct analog_parameters *p)
{}

static int r820t_set_params(struct dvb_frontend *fe)
{}

static int r820t_signal(struct dvb_frontend *fe, u16 *strength)
{}

static int r820t_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
{}

static void r820t_release(struct dvb_frontend *fe)
{}

static const struct dvb_tuner_ops r820t_tuner_ops =;

struct dvb_frontend *r820t_attach(struct dvb_frontend *fe,
				  struct i2c_adapter *i2c,
				  const struct r820t_config *cfg)
{}
EXPORT_SYMBOL_GPL();

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