/*
 * Realtek RTL2830 demodulator driver
 *
 * Copyright (c) 2008 Realtek
 * Copyright (c) 2008 Jan Hoogenraad, Barnaby Shearer, Andy Hasper
 * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
 *
 *    This program is free software; you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation; either version 2 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with this program; if not, write to the Free Software
 *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *
 * Thanks to Realtek for a lot of support we received !
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/string.h>
#include <linux/slab.h>
#include "compat.h"
#include <asm/div64.h>

#include "dvb_frontend.h"
#include "rtl2830_priv.h"
#include "rtl2830.h"

/* include Realtek RTL2830 example driver */
#include "foundation.c"
#include "demod_rtl2830.h"
#include "demod_rtl2830.c"

#define UPDATE_PROCEDURE_PERIOD	500   /* 500ms */

static int rtl2830_debug = 1;
module_param_named(debug, rtl2830_debug, int, 0644);
MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");

struct rtl2830_state {
	struct i2c_adapter *i2c;
	struct dvb_frontend frontend;
	struct rtl2830_config config;

	/* Realtek RTL2830 example driver modules */
	BASE_INTERFACE_MODULE *pBaseInterface;
	BASE_INTERFACE_MODULE BaseInterfaceModuleMemory;
	DVBT_DEMOD_MODULE *pDemod;
	DVBT_DEMOD_MODULE DvbtDemodModuleMemory;
	I2C_BRIDGE_MODULE I2cBridgeModuleMemory;

	unsigned long next_statistics_check;
	u8 sleep:1;
};

static u8 regmask[8] = {0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff};

/* write multiple registers */
static int rtl2830_write_regs2(struct rtl2830_state *state, u8 page, u8 reg,
	const u8 *val, u8 len)
{
//RTL2832U len: 64 OK - 65 NOK
	u8 buf[2+len];
	struct i2c_msg msg = {
		.addr = state->config.demod_address,
		.flags = 0,
		.len = sizeof(buf),
		.buf = buf};

	buf[0] = page;
	buf[1] = reg;
	memcpy(&buf[2], val, len);

	if (i2c_transfer(state->i2c, &msg, 1) != 1) {
		warn("I2C write failed reg:%02x len:%d", reg, len);
		return -EREMOTEIO;
	}

	return 0;
}

static int rtl2830_write_regs(struct rtl2830_state *state, u8 page, u8 reg,
	const u8 *val, u8 len2)
{
	int ret;
	u8 i, packets, remainder, len;
	#define FW_PACKET_MAX_DATA  8
/*
len2 = 34
packets = 4
remainder = 2
i = 0, 1, 2, 3, 4
IF (i = 4 = packets) THEN len = 2
*/
	packets = len2 / FW_PACKET_MAX_DATA;
	remainder = len2 % FW_PACKET_MAX_DATA;
	len = FW_PACKET_MAX_DATA;
	for (i = 0; (i <= packets && remainder); i++) {
		if (i == packets)  /* set size of the last packet */
			len = remainder;

//		deb_info("%s: i:%d len:%d reg:%02x\n", __func__, i, len, reg);
		ret = rtl2830_write_regs2(state, page, reg, &val[(i * FW_PACKET_MAX_DATA)], len);
		reg += FW_PACKET_MAX_DATA;

		if (ret) {
			err("firmware download failed at %d with %d", i, ret);
		}
	}

	return 0;
}


/* read multiple registers */
static int rtl2830_read_regs(struct rtl2830_state *state, u8 page, u8 reg,
	u8 *val, u8 len)
{
	u8 obuf[2] = {page, reg};
	struct i2c_msg msg[2] = {
		{
			.addr = state->config.demod_address,
			.flags = 0,
			.len = sizeof(obuf),
			.buf = obuf
		}, {
			.addr = state->config.demod_address,
			.flags = I2C_M_RD,
			.len = len,
			.buf = val
		}
	};

	if (i2c_transfer(state->i2c, msg, 2) != 2) {
		warn("I2C read failed reg:%02x", reg);
		return -EREMOTEIO;
	}
	return 0;
}

static int rtl2830_write_reg_bits(struct rtl2830_state *state, u8 page, u8 reg,
	u8 pos, u8 len, u8 val)
{
	int ret;
	u8 tmp, mask;

	ret = rtl2830_read_regs(state, page, reg, &tmp, 1);
	if (ret)
		return ret;

	mask = regmask[len - 1] << pos;
	tmp = (tmp & ~mask) | ((val << pos) & mask);

	return rtl2830_write_regs(state, page, reg, &tmp, 1);
}

static int rtl2830_demod_write_register_bytes(DVBT_DEMOD_MODULE *pDemod,
	unsigned char PageNo, unsigned char RegStartAddr,
	const unsigned char *pWritingBytes, unsigned char ByteNum)
{
	struct rtl2830_state *state;
	int ret;

	if (PageNo > 4)
		goto error;

	/* get pointer to state */
	pDemod->pBaseInterface->GetUserDefinedDataPointer(pDemod->
		pBaseInterface, (void *) &state);

	ret = rtl2830_write_regs(state, PageNo, RegStartAddr, pWritingBytes,
		ByteNum);
	if (ret)
		goto error;

	return FUNCTION_SUCCESS;
error:
	return FUNCTION_ERROR;
}

static int rtl2830_demod_read_register_bytes(DVBT_DEMOD_MODULE *pDemod,
	unsigned char PageNo, unsigned char RegStartAddr,
	unsigned char *pReadingBytes, unsigned char ByteNum)
{
	struct rtl2830_state *state;
	int ret;

	if (PageNo > 4)
		goto error;

	/* get pointer to state */
	pDemod->pBaseInterface->GetUserDefinedDataPointer(pDemod->
		pBaseInterface, (void *) &state);

	ret = rtl2830_read_regs(state, PageNo, RegStartAddr, pReadingBytes,
		ByteNum);
	if (ret)
		goto error;

	return FUNCTION_SUCCESS;
error:
	return FUNCTION_ERROR;
}

static void rtl2830_platform_wait(BASE_INTERFACE_MODULE *pBaseInterface,
	unsigned long time)
{
	msleep(time);
	return;
}

#if 0
// Demod register bit names
enum DVBT_REG_BIT_NAME
{
	// Software reset register
	DVBT_SOFT_RST,

	// Tuner I2C forwording register
	DVBT_IIC_REPEAT,


	// Registers for initializing
	DVBT_TR_WAIT_MIN_8K,
	DVBT_RSD_BER_FAIL_VAL,
	DVBT_EN_BK_TRK,
	DVBT_REG_PI,

	DVBT_REG_PFREQ_1_0,				// For RTL2830 only
	DVBT_PD_DA8,					// For RTL2830 only
	DVBT_LOCK_TH,					// For RTL2830 only
	DVBT_BER_PASS_SCAL,				// For RTL2830 only
	DVBT_CE_FFSM_BYPASS,			// For RTL2830 only
	DVBT_ALPHAIIR_N,				// For RTL2830 only
	DVBT_ALPHAIIR_DIF,				// For RTL2830 only
	DVBT_EN_TRK_SPAN,				// For RTL2830 only
	DVBT_LOCK_TH_LEN,				// For RTL2830 only
	DVBT_CCI_THRE,					// For RTL2830 only
	DVBT_CCI_MON_SCAL,				// For RTL2830 only
	DVBT_CCI_M0,					// For RTL2830 only
	DVBT_CCI_M1,					// For RTL2830 only
	DVBT_CCI_M2,					// For RTL2830 only
	DVBT_CCI_M3,					// For RTL2830 only
	DVBT_SPEC_INIT_0,				// For RTL2830 only
	DVBT_SPEC_INIT_1,				// For RTL2830 only
	DVBT_SPEC_INIT_2,				// For RTL2830 only

	DVBT_AD_EN_REG,					// For RTL2832 only
	DVBT_AD_EN_REG1,				// For RTL2832 only
	DVBT_EN_BBIN,					// For RTL2832 only
	DVBT_MGD_THD0,					// For RTL2832 only
	DVBT_MGD_THD1,					// For RTL2832 only
	DVBT_MGD_THD2,					// For RTL2832 only
	DVBT_MGD_THD3,					// For RTL2832 only
	DVBT_MGD_THD4,					// For RTL2832 only
	DVBT_MGD_THD5,					// For RTL2832 only
	DVBT_MGD_THD6,					// For RTL2832 only
	DVBT_MGD_THD7,					// For RTL2832 only
	DVBT_EN_CACQ_NOTCH,				// For RTL2832 only
	DVBT_AD_AV_REF,					// For RTL2832 only
	DVBT_PIP_ON,					// For RTL2832 only
	DVBT_SCALE1_B92,				// For RTL2832 only
	DVBT_SCALE1_B93,				// For RTL2832 only
	DVBT_SCALE1_BA7,				// For RTL2832 only
	DVBT_SCALE1_BA9,				// For RTL2832 only
	DVBT_SCALE1_BAA,				// For RTL2832 only
	DVBT_SCALE1_BAB,				// For RTL2832 only
	DVBT_SCALE1_BAC,				// For RTL2832 only
	DVBT_SCALE1_BB0,				// For RTL2832 only
	DVBT_SCALE1_BB1,				// For RTL2832 only
	DVBT_KB_P1,						// For RTL2832 only
	DVBT_KB_P2,						// For RTL2832 only
	DVBT_KB_P3,						// For RTL2832 only
	DVBT_OPT_ADC_IQ,				// For RTL2832 only
	DVBT_AD_AVI,					// For RTL2832 only
	DVBT_AD_AVQ,					// For RTL2832 only
	DVBT_K1_CR_STEP12,				// For RTL2832 only

	// Registers for initializing according to mode
	DVBT_TRK_KS_P2,
	DVBT_TRK_KS_I2,
	DVBT_TR_THD_SET2,
	DVBT_TRK_KC_P2,
	DVBT_TRK_KC_I2,
	DVBT_CR_THD_SET2,

	// Registers for IF setting
	DVBT_PSET_IFFREQ,
	DVBT_SPEC_INV,


	// Registers for bandwidth programming
	DVBT_BW_INDEX,					// For RTL2830 only

	DVBT_RSAMP_RATIO,				// For RTL2832 only
	DVBT_CFREQ_OFF_RATIO,			// For RTL2832 only


	// FSM stage register
	DVBT_FSM_STAGE,

	// TPS content registers
	DVBT_RX_CONSTEL,
	DVBT_RX_HIER,
	DVBT_RX_C_RATE_LP,
	DVBT_RX_C_RATE_HP,
	DVBT_GI_IDX,
	DVBT_FFT_MODE_IDX,
	
	// Performance measurement registers
	DVBT_RSD_BER_EST,
	DVBT_CE_EST_EVM,

	// AGC registers
	DVBT_RF_AGC_VAL,
	DVBT_IF_AGC_VAL,
	DVBT_DAGC_VAL,

	// TR offset and CR offset registers
	DVBT_SFREQ_OFF,
	DVBT_CFREQ_OFF,


	// AGC relative registers
	DVBT_POLAR_RF_AGC,
	DVBT_POLAR_IF_AGC,
	DVBT_AAGC_HOLD,
	DVBT_EN_RF_AGC,
	DVBT_EN_IF_AGC,
	DVBT_IF_AGC_MIN,
	DVBT_IF_AGC_MAX,
	DVBT_RF_AGC_MIN,
	DVBT_RF_AGC_MAX,
	DVBT_IF_AGC_MAN,
	DVBT_IF_AGC_MAN_VAL,
	DVBT_RF_AGC_MAN,
	DVBT_RF_AGC_MAN_VAL,
	DVBT_DAGC_TRG_VAL,

	DVBT_AGC_TARG_VAL,				// For RTL2830 only
	DVBT_LOOP_GAIN_3_0,				// For RTL2830 only
	DVBT_LOOP_GAIN_4,				// For RTL2830 only
	DVBT_VTOP,						// For RTL2830 only
	DVBT_KRF,						// For RTL2830 only

	DVBT_AGC_TARG_VAL_0,			// For RTL2832 only
	DVBT_AGC_TARG_VAL_8_1,			// For RTL2832 only
	DVBT_AAGC_LOOP_GAIN,			// For RTL2832 only
	DVBT_LOOP_GAIN2_3_0,			// For RTL2832 only
	DVBT_LOOP_GAIN2_4,				// For RTL2832 only
	DVBT_LOOP_GAIN3,				// For RTL2832 only
	DVBT_VTOP1,						// For RTL2832 only
	DVBT_VTOP2,						// For RTL2832 only
	DVBT_VTOP3,						// For RTL2832 only
	DVBT_KRF1,						// For RTL2832 only
	DVBT_KRF2,						// For RTL2832 only
	DVBT_KRF3,						// For RTL2832 only
	DVBT_KRF4,						// For RTL2832 only
	DVBT_EN_GI_PGA,					// For RTL2832 only
	DVBT_THD_LOCK_UP,				// For RTL2832 only
	DVBT_THD_LOCK_DW,				// For RTL2832 only
	DVBT_THD_UP1,					// For RTL2832 only
	DVBT_THD_DW1,					// For RTL2832 only
	DVBT_INTER_CNT_LEN,				// For RTL2832 only
	DVBT_GI_PGA_STATE,				// For RTL2832 only
	DVBT_EN_AGC_PGA,				// For RTL2832 only


	// TS interface registers
	DVBT_CKOUTPAR,
	DVBT_CKOUT_PWR,
	DVBT_SYNC_DUR,
	DVBT_ERR_DUR,
	DVBT_SYNC_LVL,
	DVBT_ERR_LVL,
	DVBT_VAL_LVL,
	DVBT_SERIAL,
	DVBT_SER_LSB,
	DVBT_CDIV_PH0,
	DVBT_CDIV_PH1,

	DVBT_CKOUTPAR_PIP,				// For RTL2832 only
	DVBT_CKOUT_PWR_PIP,				// For RTL2832 only
	DVBT_SYNC_LVL_PIP,				// For RTL2832 only
	DVBT_ERR_LVL_PIP,				// For RTL2832 only
	DVBT_VAL_LVL_PIP,				// For RTL2832 only
	DVBT_CKOUTPAR_PID,				// For RTL2832 only
	DVBT_CKOUT_PWR_PID,				// For RTL2832 only
	DVBT_SYNC_LVL_PID,				// For RTL2832 only
	DVBT_ERR_LVL_PID,				// For RTL2832 only
	DVBT_VAL_LVL_PID,				// For RTL2832 only


	// FSM state-holding register
	DVBT_SM_PASS,

	// Registers for function 2 (for RTL2830 only)
	DVBT_UPDATE_REG_2,

	// Registers for function 3 (for RTL2830 only)
	DVBT_BTHD_P3,
	DVBT_BTHD_D3,

	// Registers for function 4 (for RTL2830 only)
	DVBT_FUNC4_REG0,
	DVBT_FUNC4_REG1,
	DVBT_FUNC4_REG2,
	DVBT_FUNC4_REG3,
	DVBT_FUNC4_REG4,
	DVBT_FUNC4_REG5,
	DVBT_FUNC4_REG6,
	DVBT_FUNC4_REG7,
	DVBT_FUNC4_REG8,
	DVBT_FUNC4_REG9,
	DVBT_FUNC4_REG10,

	// Registers for functin 5 (for RTL2830 only)
	DVBT_FUNC5_REG0,
	DVBT_FUNC5_REG1,
	DVBT_FUNC5_REG2,
	DVBT_FUNC5_REG3,
	DVBT_FUNC5_REG4,
	DVBT_FUNC5_REG5,
	DVBT_FUNC5_REG6,
	DVBT_FUNC5_REG7,
	DVBT_FUNC5_REG8,
	DVBT_FUNC5_REG9,
	DVBT_FUNC5_REG10,
	DVBT_FUNC5_REG11,
	DVBT_FUNC5_REG12,
	DVBT_FUNC5_REG13,
	DVBT_FUNC5_REG14,
	DVBT_FUNC5_REG15,
	DVBT_FUNC5_REG16,
	DVBT_FUNC5_REG17,
	DVBT_FUNC5_REG18,


	// AD7 registers (for RTL2832 only)
	DVBT_AD7_SETTING,
	DVBT_RSSI_R,

	// ACI detection registers (for RTL2832 only)
	DVBT_ACI_DET_IND,

	// Clock output registers (for RTL2832 only)
	DVBT_REG_MON,
	DVBT_REG_MONSEL,
	DVBT_REG_GPE,
	DVBT_REG_GPO,
	DVBT_REG_4MSEL,


	// Test registers for test only
	DVBT_TEST_REG_1,
	DVBT_TEST_REG_2,
	DVBT_TEST_REG_3,
	DVBT_TEST_REG_4,

	// Item terminator
	DVBT_REG_BIT_NAME_ITEM_TERMINATOR,
};


struct regdesc {
	u8 reg;
	u8 page:3;
	u8 addr:4;
	u8 pos:4;
	u8 len;
};



static struct regdesc ofsm_init[] = {
	{DVBT_SOFT_RST_1,          1, 0x01, 2, 1},
	{DVBT_IIC_REPEAT_1,        1, 0x01, 3, 1},
};

#endif

static int rtl2830_set_frontend(struct dvb_frontend *fe,
	struct dvb_frontend_parameters *params)
{
	struct rtl2830_state *state = fe->demodulator_priv;
	int ret;
	u8 i, *ptr, bandwidth, len, bw_index;
	u32 bw_mode;
	u64 RsampRatio;
	u32 CfreqOffRatio;

	#define RTL2830_RATIO_ADDR 0x9d
	static u8 RatioTable[3][6] = {
		{0xc3, 0x0c, 0x44, 0x33, 0x33, 0x30,}, /* 6 MHz */
		{0xb8, 0xe3, 0x93, 0x99, 0x99, 0x98,}, /* 7 MHz */
		{0xae, 0xba, 0xf3, 0x26, 0x66, 0x64,}, /* 8 MHz */
	};

	#define RTL2830_H_LPF_X_ADDR 0x1c
	#define RTL2830_H_LPF_X_LEN 34
	#define RTL2832_H_LPF_X_LEN 32
	static u8 rtl3830_HlpfxTable[6][34] = {
		{
		#define RTL2830_6MHz 0
		0x1f, 0xf0, 0x1f, 0xf0, 0x1f, 0xfa, 0x00, 0x17, 0x00, 0x41,
		0x00, 0x64, 0x00, 0x67, 0x00, 0x38, 0x1f, 0xde, 0x1f, 0x7a,
		0x1f, 0x47, 0x1f, 0x7c, 0x00, 0x30, 0x01, 0x4b, 0x02, 0x82,
		0x03, 0x73, 0x03, 0xcf, /* 6 MHz */
		}, {
		#define RTL2830_7MHz 1
		0x1f, 0xfa, 0x1f, 0xda, 0x1f, 0xc1, 0x1f, 0xb3, 0x1f, 0xca,
		0x00, 0x07, 0x00, 0x4d, 0x00, 0x6d, 0x00, 0x40, 0x1f, 0xca,
		0x1f, 0x4d, 0x1f, 0x2a, 0x1f, 0xb2, 0x00, 0xec, 0x02, 0x7e,
		0x03, 0xd0, 0x04, 0x53, /* 7 MHz */
		}, {
		#define RTL2830_8MHz 2
		0x00, 0x10, 0x00, 0x0e, 0x1f, 0xf7, 0x1f, 0xc9, 0x1f, 0xa0,
		0x1f, 0xa6, 0x1f, 0xec, 0x00, 0x4e, 0x00, 0x7d, 0x00, 0x3a,
		0x1f, 0x98, 0x1f, 0x10, 0x1f, 0x40, 0x00, 0x75, 0x02, 0x5f,
		0x04, 0x24, 0x04, 0xdb, /* 8 MHz */
		}, {
		#define RTL2832_6MHz 3
		0xf5, 0xff, 0x15, 0x38, 0x5d, 0x6d, 0x52, 0x07, 0xfa, 0x2f,
		0x53, 0xf5, 0x3f, 0xca, 0x0b, 0x91, 0xea, 0x30, 0x63, 0xb2,
		0x13, 0xda, 0x0b, 0xc4, 0x18, 0x7e, 0x16, 0x66, 0x08, 0x67,
		0x19, 0xe0, /* 6 MHz */
		}, {
		#define RTL2832_7MHz 4
		0xe7, 0xcc, 0xb5, 0xba, 0xe8, 0x2f, 0x67, 0x61, 0x00, 0xaf,
		0x86, 0xf2, 0xbf, 0x59, 0x04, 0x11, 0xb6, 0x33, 0xa4, 0x30,
		0x15, 0x10, 0x0a, 0x42, 0x18, 0xf8, 0x17, 0xd9, 0x07, 0x22,
		0x19, 0x10, /* 7 MHz */
		}, {
		#define RTL2832_8MHz 5
		0x09, 0xf6, 0xd2, 0xa7, 0x9a, 0xc9, 0x27, 0x77, 0x06, 0xbf,
		0xec, 0xf4, 0x4f, 0x0b, 0xfc, 0x01, 0x63, 0x35, 0x54, 0xa7,
		0x16, 0x66, 0x08, 0xb4, 0x19, 0x6e, 0x19, 0x65, 0x05, 0xc8,
		0x19, 0xe0, /* 8 MHz */
		},
	};

	deb_info("%s: freq:%d bw:%d\n", __func__,
		params->frequency, params->u.ofdm.bandwidth);

	/* TODO: check msleeps */

	/* program tuner */
	if (fe->ops.tuner_ops.set_params)
		fe->ops.tuner_ops.set_params(fe, params);

	/* program bandwidth */
	switch (params->u.ofdm.bandwidth) {
	case BANDWIDTH_6_MHZ:
		bandwidth = DVBT_BANDWIDTH_6MHZ;
		if (state->config.rtl2830) {
			ptr = rtl3830_HlpfxTable[RTL2830_6MHz];
			len = RTL2830_H_LPF_X_LEN;
			bw_index = 0;
		} else {
			ptr = rtl3830_HlpfxTable[RTL2832_6MHz];
			len = RTL2832_H_LPF_X_LEN;
			bw_mode = 48000000;
		}
		break;
	case BANDWIDTH_7_MHZ:
		bandwidth = DVBT_BANDWIDTH_7MHZ;
		if (state->config.rtl2830) {
			ptr = rtl3830_HlpfxTable[RTL2830_7MHz];
			len = RTL2830_H_LPF_X_LEN;
			bw_index = 1;
		} else {
			ptr = rtl3830_HlpfxTable[RTL2832_7MHz];
			len = RTL2832_H_LPF_X_LEN;
			bw_mode = 56000000;
		}
		break;
	case BANDWIDTH_8_MHZ:
		bandwidth = DVBT_BANDWIDTH_8MHZ;
		if (state->config.rtl2830) {
			ptr = rtl3830_HlpfxTable[RTL2830_8MHz];
			len = RTL2830_H_LPF_X_LEN;
			bw_index = 2;
		} else {
			ptr = rtl3830_HlpfxTable[RTL2832_8MHz];
			len = RTL2832_H_LPF_X_LEN;
			bw_mode = 64000000;
		}
		break;
	default:
		err("invalid bandwidth");
		return -EINVAL;
	}

	ret = rtl2830_write_regs(state, 1, RTL2830_H_LPF_X_ADDR, ptr, len);

	if (state->config.rtl2830) {
#undef DVBT_BW_INDEX
#define DVBT_BW_INDEX_PAGE 0
#define DVBT_BW_INDEX_POS 1
#define DVBT_BW_INDEX_LEN 2
		ret = rtl2830_write_reg_bits(state, DVBT_BW_INDEX_PAGE, DVBT_BW_INDEX, DVBT_BW_INDEX_POS, DVBT_BW_INDEX_LEN, bw_index);
		ret = rtl2830_write_regs(state, 1, RTL2830_RATIO_ADDR, &RatioTable[bw_index][0], 6);

	} else {
		// Note: RSAMP_RATIO = floor(CrystalFreqHz * 7 * pow(2, 22) / ConstWithBandwidthMode)
		RsampRatio = state->config.crystal_freq*7UL*4194304UL/bw_mode;
		CfreqOffRatio = -(bw_mode*1048576UL/(state->config.crystal_freq*7UL));
		CfreqOffRatio = (CfreqOffRatio & 0x000fffff);
		deb_info("%s: RsampRatio:%lu CfreqOffRatio:%d\n", __func__, RsampRatio, CfreqOffRatio);
		// RsampRatio:13212057 CfreqOffRatio:715695

/*3 26 66 64
static int rtl2830_write_reg_bits(struct rtl2830_state *state, u8 page, u8 reg,
	u8 pos, u8 len, u8 val)


*/
// --> rtl2832_SetBandwidthMode()
	u8 buf2[] = {0xf3, 0x26, 0x66, 0x64};
	u8 buf3[] = {0xae, 0xba, 0xf3};
	ret = rtl2830_write_regs(state, 1, 0x9f, buf2, sizeof(buf2));
	ret = rtl2830_write_regs(state, 1, 0x9d, buf3, sizeof(buf3));
// <-- rtl2832_SetBandwidthMode()

// ---> rtl2832_SetIfFreqHz()
	u8 if_freq1[] = {0x1f};
	u8 if_freq2[] = {0x00, 0x00, 0x00};
	ret = rtl2830_write_regs(state, 1, 0xb1, if_freq1, sizeof(if_freq1));
	ret = rtl2830_write_regs(state, 1, 0x19, if_freq2, sizeof(if_freq2));
//000418:  OUT: 000002 ms 029723 ms 40 00 20 b1 11 00 01 00 >>>  1f // demod page1  > 
//000421:  OUT: 000003 ms 029732 ms 40 00 20 19 11 00 03 00 >>>  00 00 00
// <--- rtl2832_SetIfFreqHz()

// ---> rtl2832_SetSpectrumMode()
	u8 spec[] = {0x06};
	ret = rtl2830_write_regs(state, 1, 0x15, spec, sizeof(spec));
// <--- rtl2832_SetSpectrumMode()

}


#if 1
	/* scan channel */
	/* set initial DVBT_SM_BYPASS */
	ret = state->pDemod->SetRegBits(state->pDemod, DVBT_SM_BYPASS, 0x0fff);
	if (ret)
		goto error;

	/* stage 1 pass 0 */
	ret = state->pDemod->SetRegBits(state->pDemod, DVBT_SM_BYPASS, 0x0ffd);
	if (ret)
		goto error;

	/* stage 7 pass 0 */
	ret = state->pDemod->SetRegBits(state->pDemod, DVBT_SM_BYPASS, 0x0f7d);
	if (ret)
		goto error;

	ret = state->pDemod->SoftwareReset(state->pDemod);
	if (ret)
		goto error;
	msleep(40);

	/* stage 1 pass 1 */
	ret = state->pDemod->SetRegBits(state->pDemod, DVBT_SM_BYPASS, 0x0f7f);
	if (ret)
		goto error;
	msleep(40);

	/* stage 7 pass 1 */
	ret = state->pDemod->SetRegBits(state->pDemod, DVBT_SM_BYPASS, 0x0fff);
	if (ret)
		goto error;

	/* stage 11 pass 0 */
	ret = state->pDemod->SetRegBits(state->pDemod, DVBT_SM_BYPASS, 0x07ff);
	if (ret)
		goto error;

	/* stage 11 pass 1 */
	ret = state->pDemod->SetRegBits(state->pDemod, DVBT_SM_BYPASS, 0x0fff);
	if (ret)
		goto error;
#endif
#if 0
	ret = state->pDemod->ResetFunction4(state->pDemod);
	if (ret)
		goto error;

	ret = state->pDemod->ResetFunction5(state->pDemod);
	if (ret)
		goto error;
#endif
	return 0;
error:
	deb_info("%s: failed:%d\n", __func__, ret);
	return -EIO;
}

static int rtl2830_sleep(struct dvb_frontend *fe)
{
	struct rtl2830_state *state = fe->demodulator_priv;
	deb_info("%s:\n", __func__);
	state->sleep = 1;
	return 0;
}

static int rtl2830_get_frontend(struct dvb_frontend *fe,
	struct dvb_frontend_parameters *params)
{
	struct rtl2830_state *state = fe->demodulator_priv;
	int ret;
	u8 tmp;
	deb_info("%s:\n", __func__);

//	if (state->sleep)
//		return 0;

	ret = state->pDemod->GetGuardInterval(state->pDemod, &tmp);
	if (ret)
		goto error;

	switch (tmp) {
	case DVBT_GUARD_INTERVAL_1_OVER_32:
		params->u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
		break;
	case DVBT_GUARD_INTERVAL_1_OVER_16:
		params->u.ofdm.guard_interval = GUARD_INTERVAL_1_16;
		break;
	case DVBT_GUARD_INTERVAL_1_OVER_8:
		params->u.ofdm.guard_interval = GUARD_INTERVAL_1_8;
		break;
	case DVBT_GUARD_INTERVAL_1_OVER_4:
		params->u.ofdm.guard_interval = GUARD_INTERVAL_1_4;
		break;
	default:
		deb_info("%s: invalid guard_interval\n", __func__);
	}

	ret = state->pDemod->GetFftMode(state->pDemod, &tmp);
	if (ret)
		goto error;

	switch (tmp) {
	case DVBT_FFT_MODE_2K:
		params->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K;
		break;
	case DVBT_FFT_MODE_8K:
		params->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
		break;
	default:
		deb_info("%s: invalid transmission_mode\n", __func__);
	}

	ret = state->pDemod->GetCodeRateHp(state->pDemod, &tmp);
	if (ret)
		goto error;

	switch (tmp) {
	case DVBT_CODE_RATE_1_OVER_2:
		params->u.ofdm.code_rate_HP = FEC_1_2;
		break;
	case DVBT_CODE_RATE_2_OVER_3:
		params->u.ofdm.code_rate_HP = FEC_2_3;
		break;
	case DVBT_CODE_RATE_3_OVER_4:
		params->u.ofdm.code_rate_HP = FEC_3_4;
		break;
	case DVBT_CODE_RATE_5_OVER_6:
		params->u.ofdm.code_rate_HP = FEC_5_6;
		break;
	case DVBT_CODE_RATE_7_OVER_8:
		params->u.ofdm.code_rate_HP = FEC_7_8;
		break;
	default:
		deb_info("%s: invalid code_rate_HP\n", __func__);
	}

	ret = state->pDemod->GetCodeRateLp(state->pDemod, &tmp);
	if (ret)
		goto error;

	switch (tmp) {
	case DVBT_CODE_RATE_1_OVER_2:
		params->u.ofdm.code_rate_LP = FEC_1_2;
		break;
	case DVBT_CODE_RATE_2_OVER_3:
		params->u.ofdm.code_rate_LP = FEC_2_3;
		break;
	case DVBT_CODE_RATE_3_OVER_4:
		params->u.ofdm.code_rate_LP = FEC_3_4;
		break;
	case DVBT_CODE_RATE_5_OVER_6:
		params->u.ofdm.code_rate_LP = FEC_5_6;
		break;
	case DVBT_CODE_RATE_7_OVER_8:
		params->u.ofdm.code_rate_LP = FEC_7_8;
		break;
	default:
		deb_info("%s: invalid code_rate_LP\n", __func__);
	}

	ret = state->pDemod->GetConstellation(state->pDemod, &tmp);
	if (ret)
		goto error;

	switch (tmp) {
	case DVBT_CONSTELLATION_QPSK:
		params->u.ofdm.constellation = QPSK;
		break;
	case DVBT_CONSTELLATION_16QAM:
		params->u.ofdm.constellation = QAM_16;
		break;
	case DVBT_CONSTELLATION_64QAM:
		params->u.ofdm.constellation = QAM_64;
		break;
	default:
		deb_info("%s: invalid constellation\n", __func__);
	}

	ret = state->pDemod->GetHierarchy(state->pDemod, &tmp);
	if (ret)
		goto error;

	switch (tmp) {
	case DVBT_HIERARCHY_NONE:
		params->u.ofdm.hierarchy_information = HIERARCHY_NONE;
		break;
	case DVBT_HIERARCHY_ALPHA_1:
		params->u.ofdm.hierarchy_information = HIERARCHY_1;
		break;
	case DVBT_HIERARCHY_ALPHA_2:
		params->u.ofdm.hierarchy_information = HIERARCHY_2;
		break;
	case DVBT_HIERARCHY_ALPHA_4:
		params->u.ofdm.hierarchy_information = HIERARCHY_4;
		break;
	default:
		deb_info("%s: invalid hierarchy_information\n", __func__);
	}

	return 0;
error:
	deb_info("%s: failed:%d\n", __func__, ret);
	return -EIO;
}


static int rtl2830_update_functions(struct dvb_frontend *fe)
{
	struct rtl2830_state *state = fe->demodulator_priv;
	int ret;

	return 0;

	/* don't update unnecessary often */
	if (time_before(jiffies, state->next_statistics_check))
		return 0;

	/* set minimum update interval */
	state->next_statistics_check =
		jiffies + msecs_to_jiffies(UPDATE_PROCEDURE_PERIOD);

	ret = state->pDemod->UpdateFunction2(state->pDemod);
	if (ret)
		goto error;
	ret = state->pDemod->UpdateFunction3(state->pDemod);
	if (ret)
		goto error;
	ret = state->pDemod->UpdateFunction4(state->pDemod);
	if (ret)
		goto error;
	ret = state->pDemod->UpdateFunction5(state->pDemod);
	if (ret)
		goto error;

	return 0;
error:
	deb_info("%s: failed:%d\n", __func__, ret);
	return -EIO;
}

static int rtl2830_read_status(struct dvb_frontend *fe, fe_status_t * status)
{
	struct rtl2830_state *state = fe->demodulator_priv;
	int ret;
	u8 fsm_stage;

	*status = 0;

	ret = rtl2830_update_functions(fe);
	if (ret)
		return ret;

	ret = state->pDemod->GetFsmStage(state->pDemod, &fsm_stage);
	if (ret)
		goto error;

	deb_info("%s: FSM stage: %d\n", __func__, fsm_stage);

//fsm_stage = 11;

	if (fsm_stage >= 11)
		*status |= FE_HAS_SYNC | FE_HAS_LOCK;
	if (fsm_stage >= 10)
		*status |= FE_HAS_VITERBI | FE_HAS_CARRIER;
	if (fsm_stage >= 5)
		*status |= FE_HAS_SIGNAL;

	return 0;
error:
	deb_info("%s: failed:%d\n", __func__, ret);
	return -EIO;
}

static int rtl2830_read_ber(struct dvb_frontend *fe, u32 *ber)
{
	struct rtl2830_state *state = fe->demodulator_priv;
	int ret;
	unsigned long ber_num, ber_dem;

	ret = rtl2830_update_functions(fe);
	if (ret)
		return ret;

	ret = state->pDemod->GetBer(state->pDemod, &ber_num, &ber_dem);
	if (ret)
		goto error;

	*ber = ber_num;

	return 0;
error:
	deb_info("%s: failed:%d\n", __func__, ret);
	return -EIO;
}

static int rtl2830_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
{
	struct rtl2830_state *state = fe->demodulator_priv;
	int ret;
	u8 _strength;

	ret = rtl2830_update_functions(fe);
	if (ret)
		return ret;

	/* read signal strength from 0-100 scale */
	ret = state->pDemod->GetSignalStrength(state->pDemod, &_strength);
	if (ret)
		goto error;

	/* scale value to 0x0000-0xffff */
	*strength = _strength * 0xffff / 100;

	return 0;
error:
	deb_info("%s: failed:%d\n", __func__, ret);
	return -EIO;
}

static int rtl2830_read_snr(struct dvb_frontend *fe, u16 *snr)
{
	struct rtl2830_state *state = fe->demodulator_priv;
	int ret;
	long _snr, snr_dem;

	ret = rtl2830_update_functions(fe);
	if (ret)
		return ret;

	/* read snr dB x 10 */
	ret = state->pDemod->GetSnrDb(state->pDemod, &_snr, &snr_dem);
	if (ret)
		goto error;

	*snr = _snr;

	return 0;
error:
	deb_info("%s: failed:%d\n", __func__, ret);
	return -EIO;
}

static int rtl2830_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
{
	/* not supported by Realtek sample driver */
	*ucblocks = 0;
	deb_info("%s:\n", __func__);
	return rtl2830_update_functions(fe);
}

static int rtl2830_get_tune_settings(struct dvb_frontend *fe,
	struct dvb_frontend_tune_settings *fe_tune_settings)
{
	/* set tune delay 500ms, no zigzag */
	fe_tune_settings->min_delay_ms = 1000;
	return 0;
}

static int rtl2830_init(struct dvb_frontend *fe)
{
	struct rtl2830_state *state = fe->demodulator_priv;
	int ret;
	deb_info("%s:\n", __func__);

	state->sleep = 0;

	if (state->config.rtl2832) {
#if 0
// ---> rtl2832_Initialize()
000310:  OUT: 000002 ms 029460 ms 40 00 20 08 10 00 01 00 >>>  8d // demod page0 08 > 8d
000313:  OUT: 000002 ms 029467 ms 40 00 20 08 10 00 01 00 >>>  cd // demod page0 08 > cd

000316:  OUT: 000002 ms 029475 ms 40 00 20 8f 11 00 02 00 >>>  28 00 // demod page1 8f > 28 00
000319:  OUT: 000002 ms 029482 ms 40 00 20 95 11 00 01 00 >>>  10 // demod page1  > 

000322:  OUT: 000003 ms 029490 ms 40 00 20 96 11 00 01 00 >>>  20 // demod page1  > 
000325:  OUT: 000003 ms 029497 ms 40 00 20 97 11 00 01 00 >>>  20 // demod page1  > 

000328:  OUT: 000003 ms 029504 ms 40 00 20 98 11 00 01 00 >>>  40 // demod page1  > 
000331:  OUT: 000003 ms 029511 ms 40 00 20 99 11 00 01 00 >>>  22 // demod page1  > 

000334:  OUT: 000003 ms 029518 ms 40 00 20 9a 11 00 01 00 >>>  32 // demod page1  > 
000337:  OUT: 000002 ms 029526 ms 40 00 20 9b 11 00 01 00 >>>  37 // demod page1  > 

000340:  OUT: 000002 ms 029533 ms 40 00 20 9c 11 00 01 00 >>>  39 // demod page1  > 
000343:  OUT: 000002 ms 029540 ms 40 00 20 a6 11 00 01 00 >>>  4d // demod page1  > 

000346:  OUT: 000002 ms 029547 ms 40 00 20 61 11 00 01 00 >>>  24 // demod page1  > 
000349:  OUT: 000003 ms 029554 ms 40 00 20 09 10 00 01 00 >>>  2a // demod page0 09 > 2a

000352:  OUT: 000002 ms 029563 ms 40 00 20 0a 10 00 01 00 >>>  03 // demod page0  > 
000355:  OUT: 000002 ms 029570 ms 40 00 20 21 10 00 01 00 >>>  e0 // demod page0  > 

000358:  OUT: 000003 ms 029577 ms 40 00 20 7d 11 00 01 00 >>>  58 // demod page1  > 
000361:  OUT: 000003 ms 029584 ms 40 00 20 7d 11 00 01 00 >>>  88 // demod page1  > 

000364:  OUT: 000002 ms 029592 ms 40 00 20 92 12 00 01 00 >>>  04 // demod page2  > 
000367:  OUT: 000002 ms 029599 ms 40 00 20 93 12 00 01 00 >>>  b0 // demod page2  > 

000370:  OUT: 000002 ms 029606 ms 40 00 20 a7 12 00 01 00 >>>  78 // demod page2  > 
000373:  OUT: 000002 ms 029613 ms 40 00 20 a9 12 00 01 00 >>>  28 // demod page2  > 

000376:  OUT: 000002 ms 029620 ms 40 00 20 aa 12 00 01 00 >>>  59 // demod page2  > 
000379:  OUT: 000002 ms 029627 ms 40 00 20 ab 12 00 01 00 >>>  83 // demod page2  > 

000382:  OUT: 000002 ms 029634 ms 40 00 20 ac 12 00 01 00 >>>  d4 // demod page2  > 
000385:  OUT: 000002 ms 029642 ms 40 00 20 b0 12 00 01 00 >>>  65 // demod page2  > 

#endif
	u8 b01[] = {0x8d};
	u8 b02[] = {0xcd};
	u8 b03[] = {0x28, 00};
	u8 b04[] = {0x10};
	u8 b05[] = {0x20};
	u8 b06[] = {0x20};
	u8 b07[] = {0x40};
	u8 b08[] = {0x22};
	u8 b09[] = {0x32};
	u8 b10[] = {0x37};
	u8 b11[] = {0x39};
	u8 b12[] = {0x4d};
	u8 b13[] = {0x24};
	u8 b14[] = {0x2a};
	u8 b15[] = {0x03};
	u8 b16[] = {0xe0};
	u8 b17[] = {0x58};
	u8 b18[] = {0x88};
	u8 b19[] = {0x04};
	u8 b20[] = {0xb0};
	u8 b21[] = {0x78};
	u8 b22[] = {0x28};
	u8 b23[] = {0x59};
	u8 b24[] = {0x83};
	u8 b25[] = {0xd4};
	u8 b26[] = {0x65};
//	u8 b07[] = {0x};

	ret = rtl2830_write_regs(state, 0, 0x08, b01, sizeof(b01));
	ret = rtl2830_write_regs(state, 0, 0x08, b02, sizeof(b02));
	ret = rtl2830_write_regs(state, 1, 0x8f, b03, sizeof(b03));
	ret = rtl2830_write_regs(state, 1, 0x95, b04, sizeof(b04));
	ret = rtl2830_write_regs(state, 1, 0x96, b05, sizeof(b05));
	ret = rtl2830_write_regs(state, 1, 0x97, b06, sizeof(b06));
	ret = rtl2830_write_regs(state, 1, 0x98, b07, sizeof(b07));
	ret = rtl2830_write_regs(state, 1, 0x99, b08, sizeof(b08));
	ret = rtl2830_write_regs(state, 1, 0x9a, b09, sizeof(b09));
	ret = rtl2830_write_regs(state, 1, 0x0b, b10, sizeof(b10));
	ret = rtl2830_write_regs(state, 1, 0x9c, b11, sizeof(b11));
	ret = rtl2830_write_regs(state, 1, 0xa6, b12, sizeof(b12));
	ret = rtl2830_write_regs(state, 1, 0x61, b13, sizeof(b13));
	ret = rtl2830_write_regs(state, 0, 0x09, b14, sizeof(b14));
	ret = rtl2830_write_regs(state, 0, 0x0a, b15, sizeof(b15));
	ret = rtl2830_write_regs(state, 0, 0x21, b16, sizeof(b16));
	ret = rtl2830_write_regs(state, 1, 0x7d, b17, sizeof(b17));
	ret = rtl2830_write_regs(state, 1, 0x7d, b18, sizeof(b18));
	ret = rtl2830_write_regs(state, 2, 0x92, b19, sizeof(b19));
	ret = rtl2830_write_regs(state, 2, 0x93, b20, sizeof(b20));
	ret = rtl2830_write_regs(state, 2, 0xa7, b21, sizeof(b21));
	ret = rtl2830_write_regs(state, 2, 0xa9, b22, sizeof(b22));
	ret = rtl2830_write_regs(state, 2, 0xaa, b23, sizeof(b23));
	ret = rtl2830_write_regs(state, 2, 0xab, b24, sizeof(b24));
	ret = rtl2830_write_regs(state, 2, 0xac, b25, sizeof(b25));
	ret = rtl2830_write_regs(state, 2, 0xb0, b26, sizeof(b26));

	u8 b27[] = {0x43};
	u8 b28[] = {0x23};
	u8 b29[] = {0x43};
	u8 b30[] = {0x07};
	u8 b31[] = {0x48, 0xa2};
	u8 b32[] = {0x1c};
	u8 b33[] = {0x3e};
	u8 b34[] = {0x06};
	u8 b35[] = {0x25};
	u8 b36[] = {0x40};

	ret = rtl2830_write_regs(state, 2, 0xb1, b27, sizeof(b27));
	ret = rtl2830_write_regs(state, 1, 0x64, b28, sizeof(b28));
	ret = rtl2830_write_regs(state, 1, 0x64, b29, sizeof(b29));
	ret = rtl2830_write_regs(state, 2, 0x65, b30, sizeof(b30));
	ret = rtl2830_write_regs(state, 1, 0xad, b31, sizeof(b31));
	ret = rtl2830_write_regs(state, 1, 0x6f, b32, sizeof(b32));
	ret = rtl2830_write_regs(state, 1, 0x70, b33, sizeof(b33));
	ret = rtl2830_write_regs(state, 1, 0x72, b34, sizeof(b34));
	ret = rtl2830_write_regs(state, 1, 0x75, b35, sizeof(b35));
	ret = rtl2830_write_regs(state, 1, 0x76, b36, sizeof(b36));

#if 0

000388:  OUT: 000002 ms 029649 ms 40 00 20 b1 12 00 01 00 >>>  43 // demod page2  > 
000391:  OUT: 000002 ms 029657 ms 40 00 20 64 11 00 01 00 >>>  23 // demod page1  > 
000394:  OUT: 000002 ms 029664 ms 40 00 20 64 11 00 01 00 >>>  43 // demod page1  > 
000397:  OUT: 000002 ms 029671 ms 40 00 20 65 11 00 01 00 >>>  07 // demod page1  > 
000400:  OUT: 000003 ms 029678 ms 40 00 20 ad 12 00 02 00 >>>  48 a2
000403:  OUT: 000002 ms 029686 ms 40 00 20 6f 11 00 01 00 >>>  1c // demod page1  > 
000406:  OUT: 000002 ms 029693 ms 40 00 20 70 11 00 01 00 >>>  3e // demod page1  > 
000409:  OUT: 000003 ms 029700 ms 40 00 20 72 11 00 01 00 >>>  06 // demod page1  > 
000412:  OUT: 000003 ms 029707 ms 40 00 20 75 11 00 01 00 >>>  25 // demod page1  > 
000415:  OUT: 000002 ms 029716 ms 40 00 20 76 11 00 01 00 >>>  40 // demod page1  > 
// <--- rtl2832_Initialize()
#endif

	} else {
#if 1
	/* initialize demod */
	ret = state->pDemod->Initialize(state->pDemod,
		RTL2830_APPLICATION_DONGLE,
		state->config.if_freq,
		state->config.rf_spec_inv,
		state->config.vtop,
		state->config.krf);
	if (ret)
		goto error;

	ret = state->pDemod->SetRegBits(state->pDemod, DVBT_AGC_TARG_VAL,
		state->config.agc_targ_val);
	if (ret)
		goto error;
#endif

	}

	if (state->config.rtl2832) {

//	ret = rtl2830_write_regs(state, 1, 0x, "\x44", 1);
#if 1
// 
	deb_info("%s: ---> rtl2832_fc2580_Initialize()\n", __func__);

//000427:  OUT: 000003 ms 029746 ms 40 00 20 12 11 00 01 00 >>>  39 // demod page1  > 
	ret = rtl2830_write_regs(state, 1, 0x12, "\x39", 1);
//000430:  OUT: 000003 ms 029753 ms 40 00 20 02 11 00 01 00 >>>  40 // demod page1  > 
	ret = rtl2830_write_regs(state, 1, 0x02, "\x40", 1);
//000433:  OUT: 000003 ms 029760 ms 40 00 20 03 11 00 01 00 >>>  5a // demod page1  > 
	ret = rtl2830_write_regs(state, 1, 0x03, "\x5a", 1);
//000436:  OUT: 000003 ms 029767 ms 40 00 20 c7 11 00 01 00 >>>  2c // demod page1  > 
	ret = rtl2830_write_regs(state, 1, 0xc7, "\x2c", 1);
//000439:  OUT: 000003 ms 029774 ms 40 00 20 04 11 00 01 00 >>>  cc // demod page1  > 
	ret = rtl2830_write_regs(state, 1, 0x04, "\xcc", 1);
//000442:  OUT: 000003 ms 029781 ms 40 00 20 05 11 00 01 00 >>>  be // demod page1  > 
	ret = rtl2830_write_regs(state, 1, 0x05, "\xbe", 1);
//000445:  OUT: 000002 ms 029790 ms 40 00 20 c8 11 00 01 00 >>>  16 // demod page1  > 
	ret = rtl2830_write_regs(state, 1, 0xc8, "\x16", 1);
//000448:  OUT: 000002 ms 029797 ms 40 00 20 06 11 00 01 00 >>>  35 // demod page1  > 
	ret = rtl2830_write_regs(state, 1, 0x06, "\x35", 1);
//000451:  OUT: 000002 ms 029804 ms 40 00 20 c9 11 00 01 00 >>>  21 // demod page1  > 
	ret = rtl2830_write_regs(state, 1, 0xc9, "\x21", 1);
//000454:  OUT: 000003 ms 029811 ms 40 00 20 ca 11 00 01 00 >>>  21 // demod page1  > 
	ret = rtl2830_write_regs(state, 1, 0xca, "\x21", 1);
//000457:  OUT: 000003 ms 029818 ms 40 00 20 cb 11 00 01 00 >>>  00 // demod page1  > 
	ret = rtl2830_write_regs(state, 1, 0xcb, "\x00", 1);
//000460:  OUT: 000002 ms 029826 ms 40 00 20 07 11 00 01 00 >>>  40 // demod page1  > 
	ret = rtl2830_write_regs(state, 1, 0x07, "\x40", 1);
//000463:  OUT: 000002 ms 029833 ms 40 00 20 cd 11 00 01 00 >>>  10 // demod page1  > 
	ret = rtl2830_write_regs(state, 1, 0xcd, "\x10", 1);
//000466:  OUT: 000003 ms 029840 ms 40 00 20 ce 11 00 01 00 >>>  10 // demod page1  > 
	ret = rtl2830_write_regs(state, 1, 0xce, "\x10", 1);
//000469:  OUT: 000002 ms 029848 ms 40 00 20 08 11 00 01 00 >>>  80 // demod page1  > 
	ret = rtl2830_write_regs(state, 1, 0x08, "\x80", 1);
//000472:  OUT: 000003 ms 029855 ms 40 00 20 09 11 00 01 00 >>>  7f // demod page1  > 
	ret = rtl2830_write_regs(state, 1, 0x09, "\x7f", 1);
//000475:  OUT: 000002 ms 029864 ms 40 00 20 0a 11 00 01 00 >>>  9c // demod page1  > 
	ret = rtl2830_write_regs(state, 1, 0x0a, "\x9c", 1);
//000478:  OUT: 000002 ms 029871 ms 40 00 20 0b 11 00 01 00 >>>  7f // demod page1  > 
	ret = rtl2830_write_regs(state, 1, 0x0b, "\x7f", 1);
//000481:  OUT: 000002 ms 029879 ms 40 00 20 0e 10 00 01 00 >>>  fc // demod page0  > 
	ret = rtl2830_write_regs(state, 0, 0x0e, "\xfc", 1);
//000484:  OUT: 000002 ms 029886 ms 40 00 20 0e 10 00 01 00 >>>  fc // demod page0  > 
	ret = rtl2830_write_regs(state, 0, 0x0e, "\xfc", 1);
//000487:  OUT: 000003 ms 029893 ms 40 00 20 11 10 00 02 00 >>>  e9 f4 // demod page0 
	ret = rtl2830_write_regs(state, 0, 0x11, "\xe9\xf4", 2);
// <-- rtl2832_fc2580_Initialize()
	deb_info("%s: <-- rtl2832_fc2580_Initialize()\n", __func__);

#endif
	}

	ret = state->pDemod->SoftwareReset(state->pDemod);
	if (ret)
		goto error;

	return 0;
error:
	deb_info("%s: failed:%d\n", __func__, ret);
	return -EIO;
}

static int rtl2830_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
{
	/* TODO: demod closes gate automatically after each I2C transfer,
	   thus needed gate open for every I2C transfer... */
	struct rtl2830_state *state = fe->demodulator_priv;
	int ret;
	u8 val = 0x10;

	deb_info("%s: enable:%d\n", __func__, enable);

	if (enable)
		val = 0x18;

	if (!enable && state->config.rtl2832)
		ret = rtl2830_write_regs(state, 1, 1, &val, 1);
	else
		ret = 0;

/*
000576:  OUT: 000002 ms 030131 ms c0 00 20 01 01 00 01 00 <<<  18 // gate
000577:  OUT: 000003 ms 030133 ms 40 00 20 01 11 00 01 00 >>>  10 // gate close
000578:  OUT: 000002 ms 030136 ms c0 00 20 01 01 00 01 00 <<<  10 // gate
000579:  OUT: 000002 ms 030138 ms 40 00 20 01 11 00 01 00 >>>  18 // gate open
Apr 20 20:40:41 localhost kernel: 40 00 20 01 11 00 01 00 >>> 00 

*/

	return ret;
}

static void rtl2830_release(struct dvb_frontend *fe)
{
	struct rtl2830_state *state = fe->demodulator_priv;
	kfree(state);
}

static struct dvb_frontend_ops rtl2830_ops;

struct dvb_frontend *rtl2830_attach(const struct rtl2830_config *config,
				    struct i2c_adapter *i2c)
{
	struct rtl2830_state *state = NULL;
	deb_info("%s:\n", __func__);

	/* allocate memory for the internal state */
	state = kzalloc(sizeof(struct rtl2830_state), GFP_KERNEL);
	if (state == NULL)
		goto error;

	/* setup the state */
	state->i2c = i2c;
	memcpy(&state->config, config, sizeof(struct rtl2830_config));

	/* build base interface module */
	BuildBaseInterface(&state->pBaseInterface,
		&state->BaseInterfaceModuleMemory,
		0, /* max I2C read count */
		0, /* max I2C write count */
		NULL, /* custom I2C read */
		NULL, /* custom I2C write */
		rtl2830_platform_wait);

	/* build RTL2830 DVB-T demod module */
	BuildRtl2830Module(&state->pDemod,
		&state->DvbtDemodModuleMemory,
		&state->BaseInterfaceModuleMemory,
		&state->I2cBridgeModuleMemory,
		0, /* demod I2C address */
		UPDATE_PROCEDURE_PERIOD); /* function 4 update period */

	/* override used I2C transfer functions by own ones */
	state->pDemod->SetRegBytes = rtl2830_demod_write_register_bytes;
	state->pDemod->GetRegBytes = rtl2830_demod_read_register_bytes;

	state->next_statistics_check = jiffies;
	state->sleep = 1;

	/* set user define data state to demod */
	state->pDemod->pBaseInterface->SetUserDefinedDataPointer(
		state->pDemod->pBaseInterface, (void *)state);

	/* create dvb_frontend */
	memcpy(&state->frontend.ops, &rtl2830_ops,
		sizeof(struct dvb_frontend_ops));
	state->frontend.demodulator_priv = state;

	return &state->frontend;
error:
	kfree(state);
	return NULL;
}
EXPORT_SYMBOL(rtl2830_attach);

static struct dvb_frontend_ops rtl2830_ops = {

	.info = {
		.name                   = "Realtek RTL2830 DVB-T",
		.type                   = FE_OFDM,
		.frequency_min          = 174000000,
		.frequency_max          = 862000000,
		.frequency_stepsize     = 166667,
		.frequency_tolerance    = 0,
		.caps = FE_CAN_INVERSION_AUTO |
			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
			FE_CAN_QPSK | FE_CAN_QAM_16 |
			FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
			FE_CAN_TRANSMISSION_MODE_AUTO |
			FE_CAN_GUARD_INTERVAL_AUTO |
			FE_CAN_HIERARCHY_AUTO |
			FE_CAN_RECOVER |
			FE_CAN_MUTE_TS
	},

	.release = rtl2830_release,

	.init = rtl2830_init,
	.sleep = rtl2830_sleep,
	.i2c_gate_ctrl = rtl2830_i2c_gate_ctrl,

	.set_frontend = rtl2830_set_frontend,
//	.get_frontend = rtl2830_get_frontend,
	.get_tune_settings = rtl2830_get_tune_settings,

	.read_status = rtl2830_read_status,
//	.read_ber = rtl2830_read_ber,
//	.read_signal_strength = rtl2830_read_signal_strength,
//	.read_snr = rtl2830_read_snr,
//	.read_ucblocks = rtl2830_read_ucblocks,
};

MODULE_DESCRIPTION("Realtek RTL2830 DVB-T demodulator driver");
MODULE_AUTHOR("ChiaLing"); /* Realtek */
MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
MODULE_LICENSE("GPL");
