18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *    Support for LGDT3302 and LGDT3303 - VSB/QAM
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *    Copyright (C) 2005 Wilson Michaels <wilsonmichaels@earthlink.net>
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci/*
98c2ecf20Sopenharmony_ci *                      NOTES ABOUT THIS DRIVER
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci * This Linux driver supports:
128c2ecf20Sopenharmony_ci *   DViCO FusionHDTV 3 Gold-Q
138c2ecf20Sopenharmony_ci *   DViCO FusionHDTV 3 Gold-T
148c2ecf20Sopenharmony_ci *   DViCO FusionHDTV 5 Gold
158c2ecf20Sopenharmony_ci *   DViCO FusionHDTV 5 Lite
168c2ecf20Sopenharmony_ci *   DViCO FusionHDTV 5 USB Gold
178c2ecf20Sopenharmony_ci *   Air2PC/AirStar 2 ATSC 3rd generation (HD5000)
188c2ecf20Sopenharmony_ci *   pcHDTV HD5500
198c2ecf20Sopenharmony_ci *
208c2ecf20Sopenharmony_ci */
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#include <linux/kernel.h>
238c2ecf20Sopenharmony_ci#include <linux/module.h>
248c2ecf20Sopenharmony_ci#include <linux/init.h>
258c2ecf20Sopenharmony_ci#include <linux/delay.h>
268c2ecf20Sopenharmony_ci#include <linux/string.h>
278c2ecf20Sopenharmony_ci#include <linux/slab.h>
288c2ecf20Sopenharmony_ci#include <asm/byteorder.h>
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci#include <media/dvb_frontend.h>
318c2ecf20Sopenharmony_ci#include <media/dvb_math.h>
328c2ecf20Sopenharmony_ci#include "lgdt330x_priv.h"
338c2ecf20Sopenharmony_ci#include "lgdt330x.h"
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci/* Use Equalizer Mean Squared Error instead of Phaser Tracker MSE */
368c2ecf20Sopenharmony_ci/* #define USE_EQMSE */
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_cistatic int debug;
398c2ecf20Sopenharmony_cimodule_param(debug, int, 0644);
408c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "Turn on/off lgdt330x frontend debugging (default:off).");
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci#define dprintk(state, fmt, arg...) do {				\
438c2ecf20Sopenharmony_ci	if (debug)							\
448c2ecf20Sopenharmony_ci		dev_printk(KERN_DEBUG, &state->client->dev, fmt, ##arg);\
458c2ecf20Sopenharmony_ci} while (0)
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_cistruct lgdt330x_state {
488c2ecf20Sopenharmony_ci	struct i2c_client *client;
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci	/* Configuration settings */
518c2ecf20Sopenharmony_ci	struct lgdt330x_config config;
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	struct dvb_frontend frontend;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	/* Demodulator private data */
568c2ecf20Sopenharmony_ci	enum fe_modulation current_modulation;
578c2ecf20Sopenharmony_ci	u32 snr;	/* Result of last SNR calculation */
588c2ecf20Sopenharmony_ci	u16 ucblocks;
598c2ecf20Sopenharmony_ci	unsigned long last_stats_time;
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	/* Tuner private data */
628c2ecf20Sopenharmony_ci	u32 current_frequency;
638c2ecf20Sopenharmony_ci};
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_cistatic int i2c_write_demod_bytes(struct lgdt330x_state *state,
668c2ecf20Sopenharmony_ci				 const u8 *buf, /* data bytes to send */
678c2ecf20Sopenharmony_ci				 int len  /* number of bytes to send */)
688c2ecf20Sopenharmony_ci{
698c2ecf20Sopenharmony_ci	int i;
708c2ecf20Sopenharmony_ci	int err;
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	for (i = 0; i < len - 1; i += 2) {
738c2ecf20Sopenharmony_ci		err = i2c_master_send(state->client, buf, 2);
748c2ecf20Sopenharmony_ci		if (err != 2) {
758c2ecf20Sopenharmony_ci			dev_warn(&state->client->dev,
768c2ecf20Sopenharmony_ci				 "%s: error (addr %02x <- %02x, err = %i)\n",
778c2ecf20Sopenharmony_ci				__func__, buf[0], buf[1], err);
788c2ecf20Sopenharmony_ci			if (err < 0)
798c2ecf20Sopenharmony_ci				return err;
808c2ecf20Sopenharmony_ci			else
818c2ecf20Sopenharmony_ci				return -EREMOTEIO;
828c2ecf20Sopenharmony_ci		}
838c2ecf20Sopenharmony_ci		buf += 2;
848c2ecf20Sopenharmony_ci	}
858c2ecf20Sopenharmony_ci	return 0;
868c2ecf20Sopenharmony_ci}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci/*
898c2ecf20Sopenharmony_ci * This routine writes the register (reg) to the demod bus
908c2ecf20Sopenharmony_ci * then reads the data returned for (len) bytes.
918c2ecf20Sopenharmony_ci */
928c2ecf20Sopenharmony_cistatic int i2c_read_demod_bytes(struct lgdt330x_state *state,
938c2ecf20Sopenharmony_ci				enum I2C_REG reg, u8 *buf, int len)
948c2ecf20Sopenharmony_ci{
958c2ecf20Sopenharmony_ci	u8 wr[] = { reg };
968c2ecf20Sopenharmony_ci	struct i2c_msg msg[] = {
978c2ecf20Sopenharmony_ci		{
988c2ecf20Sopenharmony_ci			.addr = state->client->addr,
998c2ecf20Sopenharmony_ci			.flags = 0,
1008c2ecf20Sopenharmony_ci			.buf = wr,
1018c2ecf20Sopenharmony_ci			.len = 1
1028c2ecf20Sopenharmony_ci		}, {
1038c2ecf20Sopenharmony_ci			.addr = state->client->addr,
1048c2ecf20Sopenharmony_ci			.flags = I2C_M_RD,
1058c2ecf20Sopenharmony_ci			.buf = buf,
1068c2ecf20Sopenharmony_ci			.len = len
1078c2ecf20Sopenharmony_ci		},
1088c2ecf20Sopenharmony_ci	};
1098c2ecf20Sopenharmony_ci	int ret;
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	ret = i2c_transfer(state->client->adapter, msg, 2);
1128c2ecf20Sopenharmony_ci	if (ret != 2) {
1138c2ecf20Sopenharmony_ci		dev_warn(&state->client->dev,
1148c2ecf20Sopenharmony_ci			 "%s: addr 0x%02x select 0x%02x error (ret == %i)\n",
1158c2ecf20Sopenharmony_ci			 __func__, state->client->addr, reg, ret);
1168c2ecf20Sopenharmony_ci		if (ret >= 0)
1178c2ecf20Sopenharmony_ci			ret = -EIO;
1188c2ecf20Sopenharmony_ci	} else {
1198c2ecf20Sopenharmony_ci		ret = 0;
1208c2ecf20Sopenharmony_ci	}
1218c2ecf20Sopenharmony_ci	return ret;
1228c2ecf20Sopenharmony_ci}
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci/* Software reset */
1258c2ecf20Sopenharmony_cistatic int lgdt3302_sw_reset(struct lgdt330x_state *state)
1268c2ecf20Sopenharmony_ci{
1278c2ecf20Sopenharmony_ci	u8 ret;
1288c2ecf20Sopenharmony_ci	u8 reset[] = {
1298c2ecf20Sopenharmony_ci		IRQ_MASK,
1308c2ecf20Sopenharmony_ci		/*
1318c2ecf20Sopenharmony_ci		 * bit 6 is active low software reset
1328c2ecf20Sopenharmony_ci		 * bits 5-0 are 1 to mask interrupts
1338c2ecf20Sopenharmony_ci		 */
1348c2ecf20Sopenharmony_ci		0x00
1358c2ecf20Sopenharmony_ci	};
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	ret = i2c_write_demod_bytes(state,
1388c2ecf20Sopenharmony_ci				    reset, sizeof(reset));
1398c2ecf20Sopenharmony_ci	if (ret == 0) {
1408c2ecf20Sopenharmony_ci		/* force reset high (inactive) and unmask interrupts */
1418c2ecf20Sopenharmony_ci		reset[1] = 0x7f;
1428c2ecf20Sopenharmony_ci		ret = i2c_write_demod_bytes(state,
1438c2ecf20Sopenharmony_ci					    reset, sizeof(reset));
1448c2ecf20Sopenharmony_ci	}
1458c2ecf20Sopenharmony_ci	return ret;
1468c2ecf20Sopenharmony_ci}
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_cistatic int lgdt3303_sw_reset(struct lgdt330x_state *state)
1498c2ecf20Sopenharmony_ci{
1508c2ecf20Sopenharmony_ci	u8 ret;
1518c2ecf20Sopenharmony_ci	u8 reset[] = {
1528c2ecf20Sopenharmony_ci		0x02,
1538c2ecf20Sopenharmony_ci		0x00 /* bit 0 is active low software reset */
1548c2ecf20Sopenharmony_ci	};
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	ret = i2c_write_demod_bytes(state,
1578c2ecf20Sopenharmony_ci				    reset, sizeof(reset));
1588c2ecf20Sopenharmony_ci	if (ret == 0) {
1598c2ecf20Sopenharmony_ci		/* force reset high (inactive) */
1608c2ecf20Sopenharmony_ci		reset[1] = 0x01;
1618c2ecf20Sopenharmony_ci		ret = i2c_write_demod_bytes(state,
1628c2ecf20Sopenharmony_ci					    reset, sizeof(reset));
1638c2ecf20Sopenharmony_ci	}
1648c2ecf20Sopenharmony_ci	return ret;
1658c2ecf20Sopenharmony_ci}
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_cistatic int lgdt330x_sw_reset(struct lgdt330x_state *state)
1688c2ecf20Sopenharmony_ci{
1698c2ecf20Sopenharmony_ci	switch (state->config.demod_chip) {
1708c2ecf20Sopenharmony_ci	case LGDT3302:
1718c2ecf20Sopenharmony_ci		return lgdt3302_sw_reset(state);
1728c2ecf20Sopenharmony_ci	case LGDT3303:
1738c2ecf20Sopenharmony_ci		return lgdt3303_sw_reset(state);
1748c2ecf20Sopenharmony_ci	default:
1758c2ecf20Sopenharmony_ci		return -ENODEV;
1768c2ecf20Sopenharmony_ci	}
1778c2ecf20Sopenharmony_ci}
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_cistatic int lgdt330x_init(struct dvb_frontend *fe)
1808c2ecf20Sopenharmony_ci{
1818c2ecf20Sopenharmony_ci	struct lgdt330x_state *state = fe->demodulator_priv;
1828c2ecf20Sopenharmony_ci	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
1838c2ecf20Sopenharmony_ci	char  *chip_name;
1848c2ecf20Sopenharmony_ci	int    err;
1858c2ecf20Sopenharmony_ci	/*
1868c2ecf20Sopenharmony_ci	 * Array of byte pairs <address, value>
1878c2ecf20Sopenharmony_ci	 * to initialize each different chip
1888c2ecf20Sopenharmony_ci	 */
1898c2ecf20Sopenharmony_ci	static const u8 lgdt3302_init_data[] = {
1908c2ecf20Sopenharmony_ci		/* Use 50MHz param values from spec sheet since xtal is 50 */
1918c2ecf20Sopenharmony_ci		/*
1928c2ecf20Sopenharmony_ci		 * Change the value of NCOCTFV[25:0] of carrier
1938c2ecf20Sopenharmony_ci		 * recovery center frequency register
1948c2ecf20Sopenharmony_ci		 */
1958c2ecf20Sopenharmony_ci		VSB_CARRIER_FREQ0, 0x00,
1968c2ecf20Sopenharmony_ci		VSB_CARRIER_FREQ1, 0x87,
1978c2ecf20Sopenharmony_ci		VSB_CARRIER_FREQ2, 0x8e,
1988c2ecf20Sopenharmony_ci		VSB_CARRIER_FREQ3, 0x01,
1998c2ecf20Sopenharmony_ci		/*
2008c2ecf20Sopenharmony_ci		 * Change the TPCLK pin polarity
2018c2ecf20Sopenharmony_ci		 * data is valid on falling clock
2028c2ecf20Sopenharmony_ci		 */
2038c2ecf20Sopenharmony_ci		DEMUX_CONTROL, 0xfb,
2048c2ecf20Sopenharmony_ci		/*
2058c2ecf20Sopenharmony_ci		 * Change the value of IFBW[11:0] of
2068c2ecf20Sopenharmony_ci		 * AGC IF/RF loop filter bandwidth register
2078c2ecf20Sopenharmony_ci		 */
2088c2ecf20Sopenharmony_ci		AGC_RF_BANDWIDTH0, 0x40,
2098c2ecf20Sopenharmony_ci		AGC_RF_BANDWIDTH1, 0x93,
2108c2ecf20Sopenharmony_ci		AGC_RF_BANDWIDTH2, 0x00,
2118c2ecf20Sopenharmony_ci		/*
2128c2ecf20Sopenharmony_ci		 * Change the value of bit 6, 'nINAGCBY' and
2138c2ecf20Sopenharmony_ci		 * 'NSSEL[1:0] of ACG function control register 2
2148c2ecf20Sopenharmony_ci		 */
2158c2ecf20Sopenharmony_ci		AGC_FUNC_CTRL2, 0xc6,
2168c2ecf20Sopenharmony_ci		/*
2178c2ecf20Sopenharmony_ci		 * Change the value of bit 6 'RFFIX'
2188c2ecf20Sopenharmony_ci		 * of AGC function control register 3
2198c2ecf20Sopenharmony_ci		 */
2208c2ecf20Sopenharmony_ci		AGC_FUNC_CTRL3, 0x40,
2218c2ecf20Sopenharmony_ci		/*
2228c2ecf20Sopenharmony_ci		 * Set the value of 'INLVTHD' register 0x2a/0x2c
2238c2ecf20Sopenharmony_ci		 * to 0x7fe
2248c2ecf20Sopenharmony_ci		 */
2258c2ecf20Sopenharmony_ci		AGC_DELAY0, 0x07,
2268c2ecf20Sopenharmony_ci		AGC_DELAY2, 0xfe,
2278c2ecf20Sopenharmony_ci		/*
2288c2ecf20Sopenharmony_ci		 * Change the value of IAGCBW[15:8]
2298c2ecf20Sopenharmony_ci		 * of inner AGC loop filter bandwidth
2308c2ecf20Sopenharmony_ci		 */
2318c2ecf20Sopenharmony_ci		AGC_LOOP_BANDWIDTH0, 0x08,
2328c2ecf20Sopenharmony_ci		AGC_LOOP_BANDWIDTH1, 0x9a
2338c2ecf20Sopenharmony_ci	};
2348c2ecf20Sopenharmony_ci	static const u8 lgdt3303_init_data[] = {
2358c2ecf20Sopenharmony_ci		0x4c, 0x14
2368c2ecf20Sopenharmony_ci	};
2378c2ecf20Sopenharmony_ci	static const u8 flip_1_lgdt3303_init_data[] = {
2388c2ecf20Sopenharmony_ci		0x4c, 0x14,
2398c2ecf20Sopenharmony_ci		0x87, 0xf3
2408c2ecf20Sopenharmony_ci	};
2418c2ecf20Sopenharmony_ci	static const u8 flip_2_lgdt3303_init_data[] = {
2428c2ecf20Sopenharmony_ci		0x4c, 0x14,
2438c2ecf20Sopenharmony_ci		0x87, 0xda
2448c2ecf20Sopenharmony_ci	};
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	/*
2478c2ecf20Sopenharmony_ci	 * Hardware reset is done using gpio[0] of cx23880x chip.
2488c2ecf20Sopenharmony_ci	 * I'd like to do it here, but don't know how to find chip address.
2498c2ecf20Sopenharmony_ci	 * cx88-cards.c arranges for the reset bit to be inactive (high).
2508c2ecf20Sopenharmony_ci	 * Maybe there needs to be a callable function in cx88-core or
2518c2ecf20Sopenharmony_ci	 * the caller of this function needs to do it.
2528c2ecf20Sopenharmony_ci	 */
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	switch (state->config.demod_chip) {
2558c2ecf20Sopenharmony_ci	case LGDT3302:
2568c2ecf20Sopenharmony_ci		chip_name = "LGDT3302";
2578c2ecf20Sopenharmony_ci		err = i2c_write_demod_bytes(state, lgdt3302_init_data,
2588c2ecf20Sopenharmony_ci					    sizeof(lgdt3302_init_data));
2598c2ecf20Sopenharmony_ci		break;
2608c2ecf20Sopenharmony_ci	case LGDT3303:
2618c2ecf20Sopenharmony_ci		chip_name = "LGDT3303";
2628c2ecf20Sopenharmony_ci		switch (state->config.clock_polarity_flip) {
2638c2ecf20Sopenharmony_ci		case 2:
2648c2ecf20Sopenharmony_ci			err = i2c_write_demod_bytes(state,
2658c2ecf20Sopenharmony_ci						    flip_2_lgdt3303_init_data,
2668c2ecf20Sopenharmony_ci						    sizeof(flip_2_lgdt3303_init_data));
2678c2ecf20Sopenharmony_ci			break;
2688c2ecf20Sopenharmony_ci		case 1:
2698c2ecf20Sopenharmony_ci			err = i2c_write_demod_bytes(state,
2708c2ecf20Sopenharmony_ci						    flip_1_lgdt3303_init_data,
2718c2ecf20Sopenharmony_ci						    sizeof(flip_1_lgdt3303_init_data));
2728c2ecf20Sopenharmony_ci			break;
2738c2ecf20Sopenharmony_ci		case 0:
2748c2ecf20Sopenharmony_ci		default:
2758c2ecf20Sopenharmony_ci			err = i2c_write_demod_bytes(state, lgdt3303_init_data,
2768c2ecf20Sopenharmony_ci						    sizeof(lgdt3303_init_data));
2778c2ecf20Sopenharmony_ci		}
2788c2ecf20Sopenharmony_ci		break;
2798c2ecf20Sopenharmony_ci	default:
2808c2ecf20Sopenharmony_ci		chip_name = "undefined";
2818c2ecf20Sopenharmony_ci		dev_warn(&state->client->dev,
2828c2ecf20Sopenharmony_ci			 "Only LGDT3302 and LGDT3303 are supported chips.\n");
2838c2ecf20Sopenharmony_ci		err = -ENODEV;
2848c2ecf20Sopenharmony_ci	}
2858c2ecf20Sopenharmony_ci	dprintk(state, "Initialized the %s chip\n", chip_name);
2868c2ecf20Sopenharmony_ci	if (err < 0)
2878c2ecf20Sopenharmony_ci		return err;
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	p->cnr.len = 1;
2908c2ecf20Sopenharmony_ci	p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
2918c2ecf20Sopenharmony_ci	p->block_error.len = 1;
2928c2ecf20Sopenharmony_ci	p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
2938c2ecf20Sopenharmony_ci	p->block_count.len = 1;
2948c2ecf20Sopenharmony_ci	p->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
2958c2ecf20Sopenharmony_ci	state->last_stats_time = 0;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	return lgdt330x_sw_reset(state);
2988c2ecf20Sopenharmony_ci}
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_cistatic int lgdt330x_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
3018c2ecf20Sopenharmony_ci{
3028c2ecf20Sopenharmony_ci	struct lgdt330x_state *state = fe->demodulator_priv;
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	*ucblocks = state->ucblocks;
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	return 0;
3078c2ecf20Sopenharmony_ci}
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_cistatic int lgdt330x_set_parameters(struct dvb_frontend *fe)
3108c2ecf20Sopenharmony_ci{
3118c2ecf20Sopenharmony_ci	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
3128c2ecf20Sopenharmony_ci	struct lgdt330x_state *state = fe->demodulator_priv;
3138c2ecf20Sopenharmony_ci	/*
3148c2ecf20Sopenharmony_ci	 * Array of byte pairs <address, value>
3158c2ecf20Sopenharmony_ci	 * to initialize 8VSB for lgdt3303 chip 50 MHz IF
3168c2ecf20Sopenharmony_ci	 */
3178c2ecf20Sopenharmony_ci	static const u8 lgdt3303_8vsb_44_data[] = {
3188c2ecf20Sopenharmony_ci		0x04, 0x00,
3198c2ecf20Sopenharmony_ci		0x0d, 0x40,
3208c2ecf20Sopenharmony_ci		0x0e, 0x87,
3218c2ecf20Sopenharmony_ci		0x0f, 0x8e,
3228c2ecf20Sopenharmony_ci		0x10, 0x01,
3238c2ecf20Sopenharmony_ci		0x47, 0x8b
3248c2ecf20Sopenharmony_ci	};
3258c2ecf20Sopenharmony_ci	/*
3268c2ecf20Sopenharmony_ci	 * Array of byte pairs <address, value>
3278c2ecf20Sopenharmony_ci	 * to initialize QAM for lgdt3303 chip
3288c2ecf20Sopenharmony_ci	 */
3298c2ecf20Sopenharmony_ci	static const u8 lgdt3303_qam_data[] = {
3308c2ecf20Sopenharmony_ci		0x04, 0x00,
3318c2ecf20Sopenharmony_ci		0x0d, 0x00,
3328c2ecf20Sopenharmony_ci		0x0e, 0x00,
3338c2ecf20Sopenharmony_ci		0x0f, 0x00,
3348c2ecf20Sopenharmony_ci		0x10, 0x00,
3358c2ecf20Sopenharmony_ci		0x51, 0x63,
3368c2ecf20Sopenharmony_ci		0x47, 0x66,
3378c2ecf20Sopenharmony_ci		0x48, 0x66,
3388c2ecf20Sopenharmony_ci		0x4d, 0x1a,
3398c2ecf20Sopenharmony_ci		0x49, 0x08,
3408c2ecf20Sopenharmony_ci		0x4a, 0x9b
3418c2ecf20Sopenharmony_ci	};
3428c2ecf20Sopenharmony_ci	u8 top_ctrl_cfg[]   = { TOP_CONTROL, 0x03 };
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	int err = 0;
3458c2ecf20Sopenharmony_ci	/* Change only if we are actually changing the modulation */
3468c2ecf20Sopenharmony_ci	if (state->current_modulation != p->modulation) {
3478c2ecf20Sopenharmony_ci		switch (p->modulation) {
3488c2ecf20Sopenharmony_ci		case VSB_8:
3498c2ecf20Sopenharmony_ci			dprintk(state, "VSB_8 MODE\n");
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci			/* Select VSB mode */
3528c2ecf20Sopenharmony_ci			top_ctrl_cfg[1] = 0x03;
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci			/* Select ANT connector if supported by card */
3558c2ecf20Sopenharmony_ci			if (state->config.pll_rf_set)
3568c2ecf20Sopenharmony_ci				state->config.pll_rf_set(fe, 1);
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci			if (state->config.demod_chip == LGDT3303) {
3598c2ecf20Sopenharmony_ci				err = i2c_write_demod_bytes(state,
3608c2ecf20Sopenharmony_ci							    lgdt3303_8vsb_44_data,
3618c2ecf20Sopenharmony_ci							    sizeof(lgdt3303_8vsb_44_data));
3628c2ecf20Sopenharmony_ci			}
3638c2ecf20Sopenharmony_ci			break;
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci		case QAM_64:
3668c2ecf20Sopenharmony_ci			dprintk(state, "QAM_64 MODE\n");
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci			/* Select QAM_64 mode */
3698c2ecf20Sopenharmony_ci			top_ctrl_cfg[1] = 0x00;
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci			/* Select CABLE connector if supported by card */
3728c2ecf20Sopenharmony_ci			if (state->config.pll_rf_set)
3738c2ecf20Sopenharmony_ci				state->config.pll_rf_set(fe, 0);
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci			if (state->config.demod_chip == LGDT3303) {
3768c2ecf20Sopenharmony_ci				err = i2c_write_demod_bytes(state,
3778c2ecf20Sopenharmony_ci							    lgdt3303_qam_data,
3788c2ecf20Sopenharmony_ci							    sizeof(lgdt3303_qam_data));
3798c2ecf20Sopenharmony_ci			}
3808c2ecf20Sopenharmony_ci			break;
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci		case QAM_256:
3838c2ecf20Sopenharmony_ci			dprintk(state, "QAM_256 MODE\n");
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci			/* Select QAM_256 mode */
3868c2ecf20Sopenharmony_ci			top_ctrl_cfg[1] = 0x01;
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci			/* Select CABLE connector if supported by card */
3898c2ecf20Sopenharmony_ci			if (state->config.pll_rf_set)
3908c2ecf20Sopenharmony_ci				state->config.pll_rf_set(fe, 0);
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci			if (state->config.demod_chip == LGDT3303) {
3938c2ecf20Sopenharmony_ci				err = i2c_write_demod_bytes(state,
3948c2ecf20Sopenharmony_ci							    lgdt3303_qam_data,
3958c2ecf20Sopenharmony_ci							    sizeof(lgdt3303_qam_data));
3968c2ecf20Sopenharmony_ci			}
3978c2ecf20Sopenharmony_ci			break;
3988c2ecf20Sopenharmony_ci		default:
3998c2ecf20Sopenharmony_ci			dev_warn(&state->client->dev,
4008c2ecf20Sopenharmony_ci				 "%s: Modulation type(%d) UNSUPPORTED\n",
4018c2ecf20Sopenharmony_ci				 __func__, p->modulation);
4028c2ecf20Sopenharmony_ci			return -1;
4038c2ecf20Sopenharmony_ci		}
4048c2ecf20Sopenharmony_ci		if (err < 0)
4058c2ecf20Sopenharmony_ci			dev_warn(&state->client->dev,
4068c2ecf20Sopenharmony_ci				 "%s: error blasting bytes to lgdt3303 for modulation type(%d)\n",
4078c2ecf20Sopenharmony_ci				 __func__, p->modulation);
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci		/*
4108c2ecf20Sopenharmony_ci		 * select serial or parallel MPEG hardware interface
4118c2ecf20Sopenharmony_ci		 * Serial:   0x04 for LGDT3302 or 0x40 for LGDT3303
4128c2ecf20Sopenharmony_ci		 * Parallel: 0x00
4138c2ecf20Sopenharmony_ci		 */
4148c2ecf20Sopenharmony_ci		top_ctrl_cfg[1] |= state->config.serial_mpeg;
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci		/* Select the requested mode */
4178c2ecf20Sopenharmony_ci		i2c_write_demod_bytes(state, top_ctrl_cfg,
4188c2ecf20Sopenharmony_ci				      sizeof(top_ctrl_cfg));
4198c2ecf20Sopenharmony_ci		if (state->config.set_ts_params)
4208c2ecf20Sopenharmony_ci			state->config.set_ts_params(fe, 0);
4218c2ecf20Sopenharmony_ci		state->current_modulation = p->modulation;
4228c2ecf20Sopenharmony_ci	}
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	/* Tune to the specified frequency */
4258c2ecf20Sopenharmony_ci	if (fe->ops.tuner_ops.set_params) {
4268c2ecf20Sopenharmony_ci		fe->ops.tuner_ops.set_params(fe);
4278c2ecf20Sopenharmony_ci		if (fe->ops.i2c_gate_ctrl)
4288c2ecf20Sopenharmony_ci			fe->ops.i2c_gate_ctrl(fe, 0);
4298c2ecf20Sopenharmony_ci	}
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	/* Keep track of the new frequency */
4328c2ecf20Sopenharmony_ci	/*
4338c2ecf20Sopenharmony_ci	 * FIXME this is the wrong way to do this...
4348c2ecf20Sopenharmony_ci	 * The tuner is shared with the video4linux analog API
4358c2ecf20Sopenharmony_ci	 */
4368c2ecf20Sopenharmony_ci	state->current_frequency = p->frequency;
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	lgdt330x_sw_reset(state);
4398c2ecf20Sopenharmony_ci	return 0;
4408c2ecf20Sopenharmony_ci}
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_cistatic int lgdt330x_get_frontend(struct dvb_frontend *fe,
4438c2ecf20Sopenharmony_ci				 struct dtv_frontend_properties *p)
4448c2ecf20Sopenharmony_ci{
4458c2ecf20Sopenharmony_ci	struct lgdt330x_state *state = fe->demodulator_priv;
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	p->frequency = state->current_frequency;
4488c2ecf20Sopenharmony_ci	return 0;
4498c2ecf20Sopenharmony_ci}
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci/*
4528c2ecf20Sopenharmony_ci * Calculate SNR estimation (scaled by 2^24)
4538c2ecf20Sopenharmony_ci *
4548c2ecf20Sopenharmony_ci * 8-VSB SNR equations from LGDT3302 and LGDT3303 datasheets, QAM
4558c2ecf20Sopenharmony_ci * equations from LGDT3303 datasheet.  VSB is the same between the '02
4568c2ecf20Sopenharmony_ci * and '03, so maybe QAM is too?  Perhaps someone with a newer datasheet
4578c2ecf20Sopenharmony_ci * that has QAM information could verify?
4588c2ecf20Sopenharmony_ci *
4598c2ecf20Sopenharmony_ci * For 8-VSB: (two ways, take your pick)
4608c2ecf20Sopenharmony_ci * LGDT3302:
4618c2ecf20Sopenharmony_ci *   SNR_EQ = 10 * log10(25 * 24^2 / EQ_MSE)
4628c2ecf20Sopenharmony_ci * LGDT3303:
4638c2ecf20Sopenharmony_ci *   SNR_EQ = 10 * log10(25 * 32^2 / EQ_MSE)
4648c2ecf20Sopenharmony_ci * LGDT3302 & LGDT3303:
4658c2ecf20Sopenharmony_ci *   SNR_PT = 10 * log10(25 * 32^2 / PT_MSE)  (we use this one)
4668c2ecf20Sopenharmony_ci * For 64-QAM:
4678c2ecf20Sopenharmony_ci *   SNR    = 10 * log10( 688128   / MSEQAM)
4688c2ecf20Sopenharmony_ci * For 256-QAM:
4698c2ecf20Sopenharmony_ci *   SNR    = 10 * log10( 696320   / MSEQAM)
4708c2ecf20Sopenharmony_ci *
4718c2ecf20Sopenharmony_ci * We re-write the snr equation as:
4728c2ecf20Sopenharmony_ci *   SNR * 2^24 = 10*(c - intlog10(MSE))
4738c2ecf20Sopenharmony_ci * Where for 256-QAM, c = log10(696320) * 2^24, and so on.
4748c2ecf20Sopenharmony_ci */
4758c2ecf20Sopenharmony_cistatic u32 calculate_snr(u32 mse, u32 c)
4768c2ecf20Sopenharmony_ci{
4778c2ecf20Sopenharmony_ci	if (mse == 0) /* No signal */
4788c2ecf20Sopenharmony_ci		return 0;
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	mse = intlog10(mse);
4818c2ecf20Sopenharmony_ci	if (mse > c) {
4828c2ecf20Sopenharmony_ci		/*
4838c2ecf20Sopenharmony_ci		 * Negative SNR, which is possible, but realisticly the
4848c2ecf20Sopenharmony_ci		 * demod will lose lock before the signal gets this bad.
4858c2ecf20Sopenharmony_ci		 * The API only allows for unsigned values, so just return 0
4868c2ecf20Sopenharmony_ci		 */
4878c2ecf20Sopenharmony_ci		return 0;
4888c2ecf20Sopenharmony_ci	}
4898c2ecf20Sopenharmony_ci	return 10 * (c - mse);
4908c2ecf20Sopenharmony_ci}
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_cistatic int lgdt3302_read_snr(struct dvb_frontend *fe)
4938c2ecf20Sopenharmony_ci{
4948c2ecf20Sopenharmony_ci	struct lgdt330x_state *state = fe->demodulator_priv;
4958c2ecf20Sopenharmony_ci	u8 buf[5];	/* read data buffer */
4968c2ecf20Sopenharmony_ci	u32 noise;	/* noise value */
4978c2ecf20Sopenharmony_ci	u32 c;		/* per-modulation SNR calculation constant */
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	switch (state->current_modulation) {
5008c2ecf20Sopenharmony_ci	case VSB_8:
5018c2ecf20Sopenharmony_ci		i2c_read_demod_bytes(state, LGDT3302_EQPH_ERR0, buf, 5);
5028c2ecf20Sopenharmony_ci#ifdef USE_EQMSE
5038c2ecf20Sopenharmony_ci		/* Use Equalizer Mean-Square Error Register */
5048c2ecf20Sopenharmony_ci		/* SNR for ranges from -15.61 to +41.58 */
5058c2ecf20Sopenharmony_ci		noise = ((buf[0] & 7) << 16) | (buf[1] << 8) | buf[2];
5068c2ecf20Sopenharmony_ci		c = 69765745; /* log10(25*24^2)*2^24 */
5078c2ecf20Sopenharmony_ci#else
5088c2ecf20Sopenharmony_ci		/* Use Phase Tracker Mean-Square Error Register */
5098c2ecf20Sopenharmony_ci		/* SNR for ranges from -13.11 to +44.08 */
5108c2ecf20Sopenharmony_ci		noise = ((buf[0] & 7 << 3) << 13) | (buf[3] << 8) | buf[4];
5118c2ecf20Sopenharmony_ci		c = 73957994; /* log10(25*32^2)*2^24 */
5128c2ecf20Sopenharmony_ci#endif
5138c2ecf20Sopenharmony_ci		break;
5148c2ecf20Sopenharmony_ci	case QAM_64:
5158c2ecf20Sopenharmony_ci	case QAM_256:
5168c2ecf20Sopenharmony_ci		i2c_read_demod_bytes(state, CARRIER_MSEQAM1, buf, 2);
5178c2ecf20Sopenharmony_ci		noise = ((buf[0] & 3) << 8) | buf[1];
5188c2ecf20Sopenharmony_ci		c = state->current_modulation == QAM_64 ? 97939837 : 98026066;
5198c2ecf20Sopenharmony_ci		/* log10(688128)*2^24 and log10(696320)*2^24 */
5208c2ecf20Sopenharmony_ci		break;
5218c2ecf20Sopenharmony_ci	default:
5228c2ecf20Sopenharmony_ci		dev_err(&state->client->dev,
5238c2ecf20Sopenharmony_ci			"%s: Modulation set to unsupported value\n",
5248c2ecf20Sopenharmony_ci			__func__);
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci		state->snr = 0;
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci		return -EREMOTEIO; /* return -EDRIVER_IS_GIBBERED; */
5298c2ecf20Sopenharmony_ci	}
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci	state->snr = calculate_snr(noise, c);
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	dprintk(state, "noise = 0x%08x, snr = %d.%02d dB\n", noise,
5348c2ecf20Sopenharmony_ci		state->snr >> 24, (((state->snr >> 8) & 0xffff) * 100) >> 16);
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci	return 0;
5378c2ecf20Sopenharmony_ci}
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_cistatic int lgdt3303_read_snr(struct dvb_frontend *fe)
5408c2ecf20Sopenharmony_ci{
5418c2ecf20Sopenharmony_ci	struct lgdt330x_state *state = fe->demodulator_priv;
5428c2ecf20Sopenharmony_ci	u8 buf[5];	/* read data buffer */
5438c2ecf20Sopenharmony_ci	u32 noise;	/* noise value */
5448c2ecf20Sopenharmony_ci	u32 c;		/* per-modulation SNR calculation constant */
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci	switch (state->current_modulation) {
5478c2ecf20Sopenharmony_ci	case VSB_8:
5488c2ecf20Sopenharmony_ci		i2c_read_demod_bytes(state, LGDT3303_EQPH_ERR0, buf, 5);
5498c2ecf20Sopenharmony_ci#ifdef USE_EQMSE
5508c2ecf20Sopenharmony_ci		/* Use Equalizer Mean-Square Error Register */
5518c2ecf20Sopenharmony_ci		/* SNR for ranges from -16.12 to +44.08 */
5528c2ecf20Sopenharmony_ci		noise = ((buf[0] & 0x78) << 13) | (buf[1] << 8) | buf[2];
5538c2ecf20Sopenharmony_ci		c = 73957994; /* log10(25*32^2)*2^24 */
5548c2ecf20Sopenharmony_ci#else
5558c2ecf20Sopenharmony_ci		/* Use Phase Tracker Mean-Square Error Register */
5568c2ecf20Sopenharmony_ci		/* SNR for ranges from -13.11 to +44.08 */
5578c2ecf20Sopenharmony_ci		noise = ((buf[0] & 7) << 16) | (buf[3] << 8) | buf[4];
5588c2ecf20Sopenharmony_ci		c = 73957994; /* log10(25*32^2)*2^24 */
5598c2ecf20Sopenharmony_ci#endif
5608c2ecf20Sopenharmony_ci		break;
5618c2ecf20Sopenharmony_ci	case QAM_64:
5628c2ecf20Sopenharmony_ci	case QAM_256:
5638c2ecf20Sopenharmony_ci		i2c_read_demod_bytes(state, CARRIER_MSEQAM1, buf, 2);
5648c2ecf20Sopenharmony_ci		noise = (buf[0] << 8) | buf[1];
5658c2ecf20Sopenharmony_ci		c = state->current_modulation == QAM_64 ? 97939837 : 98026066;
5668c2ecf20Sopenharmony_ci		/* log10(688128)*2^24 and log10(696320)*2^24 */
5678c2ecf20Sopenharmony_ci		break;
5688c2ecf20Sopenharmony_ci	default:
5698c2ecf20Sopenharmony_ci		dev_err(&state->client->dev,
5708c2ecf20Sopenharmony_ci			"%s: Modulation set to unsupported value\n",
5718c2ecf20Sopenharmony_ci			__func__);
5728c2ecf20Sopenharmony_ci		state->snr = 0;
5738c2ecf20Sopenharmony_ci		return -EREMOTEIO; /* return -EDRIVER_IS_GIBBERED; */
5748c2ecf20Sopenharmony_ci	}
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci	state->snr = calculate_snr(noise, c);
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	dprintk(state, "noise = 0x%08x, snr = %d.%02d dB\n", noise,
5798c2ecf20Sopenharmony_ci		state->snr >> 24, (((state->snr >> 8) & 0xffff) * 100) >> 16);
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci	return 0;
5828c2ecf20Sopenharmony_ci}
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_cistatic int lgdt330x_read_snr(struct dvb_frontend *fe, u16 *snr)
5858c2ecf20Sopenharmony_ci{
5868c2ecf20Sopenharmony_ci	struct lgdt330x_state *state = fe->demodulator_priv;
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci	*snr = (state->snr) >> 16; /* Convert from 8.24 fixed-point to 8.8 */
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci	return 0;
5918c2ecf20Sopenharmony_ci}
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_cistatic int lgdt330x_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
5948c2ecf20Sopenharmony_ci{
5958c2ecf20Sopenharmony_ci	/* Calculate Strength from SNR up to 35dB */
5968c2ecf20Sopenharmony_ci	/*
5978c2ecf20Sopenharmony_ci	 * Even though the SNR can go higher than 35dB, there is some comfort
5988c2ecf20Sopenharmony_ci	 * factor in having a range of strong signals that can show at 100%
5998c2ecf20Sopenharmony_ci	 */
6008c2ecf20Sopenharmony_ci	struct lgdt330x_state *state = fe->demodulator_priv;
6018c2ecf20Sopenharmony_ci	u16 snr;
6028c2ecf20Sopenharmony_ci	int ret;
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_ci	ret = fe->ops.read_snr(fe, &snr);
6058c2ecf20Sopenharmony_ci	if (ret != 0)
6068c2ecf20Sopenharmony_ci		return ret;
6078c2ecf20Sopenharmony_ci	/* Rather than use the 8.8 value snr, use state->snr which is 8.24 */
6088c2ecf20Sopenharmony_ci	/* scale the range 0 - 35*2^24 into 0 - 65535 */
6098c2ecf20Sopenharmony_ci	if (state->snr >= 8960 * 0x10000)
6108c2ecf20Sopenharmony_ci		*strength = 0xffff;
6118c2ecf20Sopenharmony_ci	else
6128c2ecf20Sopenharmony_ci		*strength = state->snr / 8960;
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci	return 0;
6158c2ecf20Sopenharmony_ci}
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_cistatic int lgdt3302_read_status(struct dvb_frontend *fe,
6198c2ecf20Sopenharmony_ci				enum fe_status *status)
6208c2ecf20Sopenharmony_ci{
6218c2ecf20Sopenharmony_ci	struct lgdt330x_state *state = fe->demodulator_priv;
6228c2ecf20Sopenharmony_ci	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
6238c2ecf20Sopenharmony_ci	u8 buf[3];
6248c2ecf20Sopenharmony_ci	int err;
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci	*status = 0; /* Reset status result */
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci	/* AGC status register */
6298c2ecf20Sopenharmony_ci	i2c_read_demod_bytes(state, AGC_STATUS, buf, 1);
6308c2ecf20Sopenharmony_ci	dprintk(state, "AGC_STATUS = 0x%02x\n", buf[0]);
6318c2ecf20Sopenharmony_ci	if ((buf[0] & 0x0c) == 0x8) {
6328c2ecf20Sopenharmony_ci		/*
6338c2ecf20Sopenharmony_ci		 * Test signal does not exist flag
6348c2ecf20Sopenharmony_ci		 * as well as the AGC lock flag.
6358c2ecf20Sopenharmony_ci		 */
6368c2ecf20Sopenharmony_ci		*status |= FE_HAS_SIGNAL;
6378c2ecf20Sopenharmony_ci	}
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_ci	/*
6408c2ecf20Sopenharmony_ci	 * You must set the Mask bits to 1 in the IRQ_MASK in order
6418c2ecf20Sopenharmony_ci	 * to see that status bit in the IRQ_STATUS register.
6428c2ecf20Sopenharmony_ci	 * This is done in SwReset();
6438c2ecf20Sopenharmony_ci	 */
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci	/* signal status */
6468c2ecf20Sopenharmony_ci	i2c_read_demod_bytes(state, TOP_CONTROL, buf, sizeof(buf));
6478c2ecf20Sopenharmony_ci	dprintk(state,
6488c2ecf20Sopenharmony_ci		"TOP_CONTROL = 0x%02x, IRO_MASK = 0x%02x, IRQ_STATUS = 0x%02x\n",
6498c2ecf20Sopenharmony_ci		buf[0], buf[1], buf[2]);
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci	/* sync status */
6528c2ecf20Sopenharmony_ci	if ((buf[2] & 0x03) == 0x01)
6538c2ecf20Sopenharmony_ci		*status |= FE_HAS_SYNC;
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci	/* FEC error status */
6568c2ecf20Sopenharmony_ci	if ((buf[2] & 0x0c) == 0x08)
6578c2ecf20Sopenharmony_ci		*status |= FE_HAS_LOCK | FE_HAS_VITERBI;
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci	/* Carrier Recovery Lock Status Register */
6608c2ecf20Sopenharmony_ci	i2c_read_demod_bytes(state, CARRIER_LOCK, buf, 1);
6618c2ecf20Sopenharmony_ci	dprintk(state, "CARRIER_LOCK = 0x%02x\n", buf[0]);
6628c2ecf20Sopenharmony_ci	switch (state->current_modulation) {
6638c2ecf20Sopenharmony_ci	case QAM_256:
6648c2ecf20Sopenharmony_ci	case QAM_64:
6658c2ecf20Sopenharmony_ci		/* Need to understand why there are 3 lock levels here */
6668c2ecf20Sopenharmony_ci		if ((buf[0] & 0x07) == 0x07)
6678c2ecf20Sopenharmony_ci			*status |= FE_HAS_CARRIER;
6688c2ecf20Sopenharmony_ci		break;
6698c2ecf20Sopenharmony_ci	case VSB_8:
6708c2ecf20Sopenharmony_ci		if ((buf[0] & 0x80) == 0x80)
6718c2ecf20Sopenharmony_ci			*status |= FE_HAS_CARRIER;
6728c2ecf20Sopenharmony_ci		break;
6738c2ecf20Sopenharmony_ci	default:
6748c2ecf20Sopenharmony_ci		dev_warn(&state->client->dev,
6758c2ecf20Sopenharmony_ci			 "%s: Modulation set to unsupported value\n",
6768c2ecf20Sopenharmony_ci			 __func__);
6778c2ecf20Sopenharmony_ci	}
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_ci	if (!(*status & FE_HAS_LOCK)) {
6808c2ecf20Sopenharmony_ci		p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
6818c2ecf20Sopenharmony_ci		p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
6828c2ecf20Sopenharmony_ci		p->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
6838c2ecf20Sopenharmony_ci		return 0;
6848c2ecf20Sopenharmony_ci	}
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci	if (state->last_stats_time &&
6878c2ecf20Sopenharmony_ci	    time_is_after_jiffies(state->last_stats_time))
6888c2ecf20Sopenharmony_ci		return 0;
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_ci	state->last_stats_time = jiffies + msecs_to_jiffies(1000);
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_ci	err = lgdt3302_read_snr(fe);
6938c2ecf20Sopenharmony_ci	if (!err) {
6948c2ecf20Sopenharmony_ci		p->cnr.stat[0].scale = FE_SCALE_DECIBEL;
6958c2ecf20Sopenharmony_ci		p->cnr.stat[0].svalue = (((u64)state->snr) * 1000) >> 24;
6968c2ecf20Sopenharmony_ci	} else {
6978c2ecf20Sopenharmony_ci		p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
6988c2ecf20Sopenharmony_ci	}
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci	err = i2c_read_demod_bytes(state, LGDT3302_PACKET_ERR_COUNTER1,
7018c2ecf20Sopenharmony_ci					   buf, sizeof(buf));
7028c2ecf20Sopenharmony_ci	if (!err) {
7038c2ecf20Sopenharmony_ci		state->ucblocks = (buf[0] << 8) | buf[1];
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_ci		dprintk(state, "UCB = 0x%02x\n", state->ucblocks);
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci		p->block_error.stat[0].uvalue += state->ucblocks;
7088c2ecf20Sopenharmony_ci		/* FIXME: what's the basis for block count */
7098c2ecf20Sopenharmony_ci		p->block_count.stat[0].uvalue += 10000;
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_ci		p->block_error.stat[0].scale = FE_SCALE_COUNTER;
7128c2ecf20Sopenharmony_ci		p->block_count.stat[0].scale = FE_SCALE_COUNTER;
7138c2ecf20Sopenharmony_ci	} else {
7148c2ecf20Sopenharmony_ci		p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
7158c2ecf20Sopenharmony_ci		p->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
7168c2ecf20Sopenharmony_ci	}
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci	return 0;
7198c2ecf20Sopenharmony_ci}
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_cistatic int lgdt3303_read_status(struct dvb_frontend *fe,
7228c2ecf20Sopenharmony_ci				enum fe_status *status)
7238c2ecf20Sopenharmony_ci{
7248c2ecf20Sopenharmony_ci	struct lgdt330x_state *state = fe->demodulator_priv;
7258c2ecf20Sopenharmony_ci	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
7268c2ecf20Sopenharmony_ci	u8 buf[3];
7278c2ecf20Sopenharmony_ci	int err;
7288c2ecf20Sopenharmony_ci
7298c2ecf20Sopenharmony_ci	*status = 0; /* Reset status result */
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci	/* lgdt3303 AGC status register */
7328c2ecf20Sopenharmony_ci	err = i2c_read_demod_bytes(state, 0x58, buf, 1);
7338c2ecf20Sopenharmony_ci	if (err < 0)
7348c2ecf20Sopenharmony_ci		return err;
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ci	dprintk(state, "AGC_STATUS = 0x%02x\n", buf[0]);
7378c2ecf20Sopenharmony_ci	if ((buf[0] & 0x21) == 0x01) {
7388c2ecf20Sopenharmony_ci		/*
7398c2ecf20Sopenharmony_ci		 * Test input signal does not exist flag
7408c2ecf20Sopenharmony_ci		 * as well as the AGC lock flag.
7418c2ecf20Sopenharmony_ci		 */
7428c2ecf20Sopenharmony_ci		*status |= FE_HAS_SIGNAL;
7438c2ecf20Sopenharmony_ci	}
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_ci	/* Carrier Recovery Lock Status Register */
7468c2ecf20Sopenharmony_ci	i2c_read_demod_bytes(state, CARRIER_LOCK, buf, 1);
7478c2ecf20Sopenharmony_ci	dprintk(state, "CARRIER_LOCK = 0x%02x\n", buf[0]);
7488c2ecf20Sopenharmony_ci	switch (state->current_modulation) {
7498c2ecf20Sopenharmony_ci	case QAM_256:
7508c2ecf20Sopenharmony_ci	case QAM_64:
7518c2ecf20Sopenharmony_ci		/* Need to understand why there are 3 lock levels here */
7528c2ecf20Sopenharmony_ci		if ((buf[0] & 0x07) == 0x07)
7538c2ecf20Sopenharmony_ci			*status |= FE_HAS_CARRIER;
7548c2ecf20Sopenharmony_ci		else
7558c2ecf20Sopenharmony_ci			break;
7568c2ecf20Sopenharmony_ci		i2c_read_demod_bytes(state, 0x8a, buf, 1);
7578c2ecf20Sopenharmony_ci		dprintk(state, "QAM LOCK = 0x%02x\n", buf[0]);
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci		if ((buf[0] & 0x04) == 0x04)
7608c2ecf20Sopenharmony_ci			*status |= FE_HAS_SYNC;
7618c2ecf20Sopenharmony_ci		if ((buf[0] & 0x01) == 0x01)
7628c2ecf20Sopenharmony_ci			*status |= FE_HAS_LOCK;
7638c2ecf20Sopenharmony_ci		if ((buf[0] & 0x08) == 0x08)
7648c2ecf20Sopenharmony_ci			*status |= FE_HAS_VITERBI;
7658c2ecf20Sopenharmony_ci		break;
7668c2ecf20Sopenharmony_ci	case VSB_8:
7678c2ecf20Sopenharmony_ci		if ((buf[0] & 0x80) == 0x80)
7688c2ecf20Sopenharmony_ci			*status |= FE_HAS_CARRIER;
7698c2ecf20Sopenharmony_ci		else
7708c2ecf20Sopenharmony_ci			break;
7718c2ecf20Sopenharmony_ci		i2c_read_demod_bytes(state, 0x38, buf, 1);
7728c2ecf20Sopenharmony_ci		dprintk(state, "8-VSB LOCK = 0x%02x\n", buf[0]);
7738c2ecf20Sopenharmony_ci
7748c2ecf20Sopenharmony_ci		if ((buf[0] & 0x02) == 0x00)
7758c2ecf20Sopenharmony_ci			*status |= FE_HAS_SYNC;
7768c2ecf20Sopenharmony_ci		if ((buf[0] & 0x01) == 0x01)
7778c2ecf20Sopenharmony_ci			*status |= FE_HAS_VITERBI | FE_HAS_LOCK;
7788c2ecf20Sopenharmony_ci		break;
7798c2ecf20Sopenharmony_ci	default:
7808c2ecf20Sopenharmony_ci		dev_warn(&state->client->dev,
7818c2ecf20Sopenharmony_ci			 "%s: Modulation set to unsupported value\n",
7828c2ecf20Sopenharmony_ci			 __func__);
7838c2ecf20Sopenharmony_ci	}
7848c2ecf20Sopenharmony_ci
7858c2ecf20Sopenharmony_ci	if (!(*status & FE_HAS_LOCK)) {
7868c2ecf20Sopenharmony_ci		p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
7878c2ecf20Sopenharmony_ci		p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
7888c2ecf20Sopenharmony_ci		p->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
7898c2ecf20Sopenharmony_ci		return 0;
7908c2ecf20Sopenharmony_ci	}
7918c2ecf20Sopenharmony_ci
7928c2ecf20Sopenharmony_ci	if (state->last_stats_time &&
7938c2ecf20Sopenharmony_ci	    time_is_after_jiffies(state->last_stats_time))
7948c2ecf20Sopenharmony_ci		return 0;
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_ci	state->last_stats_time = jiffies + msecs_to_jiffies(1000);
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci	err = lgdt3303_read_snr(fe);
7998c2ecf20Sopenharmony_ci	if (!err) {
8008c2ecf20Sopenharmony_ci		p->cnr.stat[0].scale = FE_SCALE_DECIBEL;
8018c2ecf20Sopenharmony_ci		p->cnr.stat[0].svalue = (((u64)state->snr) * 1000) >> 24;
8028c2ecf20Sopenharmony_ci	} else {
8038c2ecf20Sopenharmony_ci		p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
8048c2ecf20Sopenharmony_ci	}
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_ci	err = i2c_read_demod_bytes(state, LGDT3303_PACKET_ERR_COUNTER1,
8078c2ecf20Sopenharmony_ci					   buf, sizeof(buf));
8088c2ecf20Sopenharmony_ci	if (!err) {
8098c2ecf20Sopenharmony_ci		state->ucblocks = (buf[0] << 8) | buf[1];
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci		dprintk(state, "UCB = 0x%02x\n", state->ucblocks);
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_ci		p->block_error.stat[0].uvalue += state->ucblocks;
8148c2ecf20Sopenharmony_ci		/* FIXME: what's the basis for block count */
8158c2ecf20Sopenharmony_ci		p->block_count.stat[0].uvalue += 10000;
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_ci		p->block_error.stat[0].scale = FE_SCALE_COUNTER;
8188c2ecf20Sopenharmony_ci		p->block_count.stat[0].scale = FE_SCALE_COUNTER;
8198c2ecf20Sopenharmony_ci	} else {
8208c2ecf20Sopenharmony_ci		p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
8218c2ecf20Sopenharmony_ci		p->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
8228c2ecf20Sopenharmony_ci	}
8238c2ecf20Sopenharmony_ci
8248c2ecf20Sopenharmony_ci	return 0;
8258c2ecf20Sopenharmony_ci}
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_cistatic int
8288c2ecf20Sopenharmony_cilgdt330x_get_tune_settings(struct dvb_frontend *fe,
8298c2ecf20Sopenharmony_ci			   struct dvb_frontend_tune_settings *fe_tune_settings)
8308c2ecf20Sopenharmony_ci{
8318c2ecf20Sopenharmony_ci	/* I have no idea about this - it may not be needed */
8328c2ecf20Sopenharmony_ci	fe_tune_settings->min_delay_ms = 500;
8338c2ecf20Sopenharmony_ci	fe_tune_settings->step_size = 0;
8348c2ecf20Sopenharmony_ci	fe_tune_settings->max_drift = 0;
8358c2ecf20Sopenharmony_ci	return 0;
8368c2ecf20Sopenharmony_ci}
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_cistatic void lgdt330x_release(struct dvb_frontend *fe)
8398c2ecf20Sopenharmony_ci{
8408c2ecf20Sopenharmony_ci	struct lgdt330x_state *state = fe->demodulator_priv;
8418c2ecf20Sopenharmony_ci	struct i2c_client *client = state->client;
8428c2ecf20Sopenharmony_ci
8438c2ecf20Sopenharmony_ci	dev_dbg(&client->dev, "\n");
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci	i2c_unregister_device(client);
8468c2ecf20Sopenharmony_ci}
8478c2ecf20Sopenharmony_ci
8488c2ecf20Sopenharmony_cistatic struct dvb_frontend *lgdt330x_get_dvb_frontend(struct i2c_client *client)
8498c2ecf20Sopenharmony_ci{
8508c2ecf20Sopenharmony_ci	struct lgdt330x_state *state = i2c_get_clientdata(client);
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_ci	dev_dbg(&client->dev, "\n");
8538c2ecf20Sopenharmony_ci
8548c2ecf20Sopenharmony_ci	return &state->frontend;
8558c2ecf20Sopenharmony_ci}
8568c2ecf20Sopenharmony_ci
8578c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops lgdt3302_ops;
8588c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops lgdt3303_ops;
8598c2ecf20Sopenharmony_ci
8608c2ecf20Sopenharmony_cistatic int lgdt330x_probe(struct i2c_client *client,
8618c2ecf20Sopenharmony_ci			  const struct i2c_device_id *id)
8628c2ecf20Sopenharmony_ci{
8638c2ecf20Sopenharmony_ci	struct lgdt330x_state *state = NULL;
8648c2ecf20Sopenharmony_ci	u8 buf[1];
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_ci	/* Allocate memory for the internal state */
8678c2ecf20Sopenharmony_ci	state = kzalloc(sizeof(*state), GFP_KERNEL);
8688c2ecf20Sopenharmony_ci	if (!state)
8698c2ecf20Sopenharmony_ci		goto error;
8708c2ecf20Sopenharmony_ci
8718c2ecf20Sopenharmony_ci	/* Setup the state */
8728c2ecf20Sopenharmony_ci	memcpy(&state->config, client->dev.platform_data,
8738c2ecf20Sopenharmony_ci	       sizeof(state->config));
8748c2ecf20Sopenharmony_ci	i2c_set_clientdata(client, state);
8758c2ecf20Sopenharmony_ci	state->client = client;
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_ci	/* Create dvb_frontend */
8788c2ecf20Sopenharmony_ci	switch (state->config.demod_chip) {
8798c2ecf20Sopenharmony_ci	case LGDT3302:
8808c2ecf20Sopenharmony_ci		memcpy(&state->frontend.ops, &lgdt3302_ops,
8818c2ecf20Sopenharmony_ci		       sizeof(struct dvb_frontend_ops));
8828c2ecf20Sopenharmony_ci		break;
8838c2ecf20Sopenharmony_ci	case LGDT3303:
8848c2ecf20Sopenharmony_ci		memcpy(&state->frontend.ops, &lgdt3303_ops,
8858c2ecf20Sopenharmony_ci		       sizeof(struct dvb_frontend_ops));
8868c2ecf20Sopenharmony_ci		break;
8878c2ecf20Sopenharmony_ci	default:
8888c2ecf20Sopenharmony_ci		goto error;
8898c2ecf20Sopenharmony_ci	}
8908c2ecf20Sopenharmony_ci	state->frontend.demodulator_priv = state;
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_ci	/* Setup get frontend callback */
8938c2ecf20Sopenharmony_ci	state->config.get_dvb_frontend = lgdt330x_get_dvb_frontend;
8948c2ecf20Sopenharmony_ci
8958c2ecf20Sopenharmony_ci	/* Verify communication with demod chip */
8968c2ecf20Sopenharmony_ci	if (i2c_read_demod_bytes(state, 2, buf, 1))
8978c2ecf20Sopenharmony_ci		goto error;
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_ci	state->current_frequency = -1;
9008c2ecf20Sopenharmony_ci	state->current_modulation = -1;
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_ci	dev_info(&state->client->dev,
9038c2ecf20Sopenharmony_ci		"Demod loaded for LGDT330%s chip\n",
9048c2ecf20Sopenharmony_ci		state->config.demod_chip == LGDT3302 ? "2" : "3");
9058c2ecf20Sopenharmony_ci
9068c2ecf20Sopenharmony_ci	return 0;
9078c2ecf20Sopenharmony_ci
9088c2ecf20Sopenharmony_cierror:
9098c2ecf20Sopenharmony_ci	kfree(state);
9108c2ecf20Sopenharmony_ci	if (debug)
9118c2ecf20Sopenharmony_ci		dev_printk(KERN_DEBUG, &client->dev, "Error loading lgdt330x driver\n");
9128c2ecf20Sopenharmony_ci	return -ENODEV;
9138c2ecf20Sopenharmony_ci}
9148c2ecf20Sopenharmony_cistruct dvb_frontend *lgdt330x_attach(const struct lgdt330x_config *_config,
9158c2ecf20Sopenharmony_ci				     u8 demod_address,
9168c2ecf20Sopenharmony_ci				     struct i2c_adapter *i2c)
9178c2ecf20Sopenharmony_ci{
9188c2ecf20Sopenharmony_ci	struct i2c_client *client;
9198c2ecf20Sopenharmony_ci	struct i2c_board_info board_info = {};
9208c2ecf20Sopenharmony_ci	struct lgdt330x_config config = *_config;
9218c2ecf20Sopenharmony_ci
9228c2ecf20Sopenharmony_ci	strscpy(board_info.type, "lgdt330x", sizeof(board_info.type));
9238c2ecf20Sopenharmony_ci	board_info.addr = demod_address;
9248c2ecf20Sopenharmony_ci	board_info.platform_data = &config;
9258c2ecf20Sopenharmony_ci	client = i2c_new_client_device(i2c, &board_info);
9268c2ecf20Sopenharmony_ci	if (!i2c_client_has_driver(client))
9278c2ecf20Sopenharmony_ci		return NULL;
9288c2ecf20Sopenharmony_ci
9298c2ecf20Sopenharmony_ci	return lgdt330x_get_dvb_frontend(client);
9308c2ecf20Sopenharmony_ci}
9318c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(lgdt330x_attach);
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops lgdt3302_ops = {
9348c2ecf20Sopenharmony_ci	.delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
9358c2ecf20Sopenharmony_ci	.info = {
9368c2ecf20Sopenharmony_ci		.name = "LG Electronics LGDT3302 VSB/QAM Frontend",
9378c2ecf20Sopenharmony_ci		.frequency_min_hz =  54 * MHz,
9388c2ecf20Sopenharmony_ci		.frequency_max_hz = 858 * MHz,
9398c2ecf20Sopenharmony_ci		.frequency_stepsize_hz = 62500,
9408c2ecf20Sopenharmony_ci		.symbol_rate_min    = 5056941,	/* QAM 64 */
9418c2ecf20Sopenharmony_ci		.symbol_rate_max    = 10762000,	/* VSB 8  */
9428c2ecf20Sopenharmony_ci		.caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
9438c2ecf20Sopenharmony_ci	},
9448c2ecf20Sopenharmony_ci	.init                 = lgdt330x_init,
9458c2ecf20Sopenharmony_ci	.set_frontend         = lgdt330x_set_parameters,
9468c2ecf20Sopenharmony_ci	.get_frontend         = lgdt330x_get_frontend,
9478c2ecf20Sopenharmony_ci	.get_tune_settings    = lgdt330x_get_tune_settings,
9488c2ecf20Sopenharmony_ci	.read_status          = lgdt3302_read_status,
9498c2ecf20Sopenharmony_ci	.read_signal_strength = lgdt330x_read_signal_strength,
9508c2ecf20Sopenharmony_ci	.read_snr             = lgdt330x_read_snr,
9518c2ecf20Sopenharmony_ci	.read_ucblocks        = lgdt330x_read_ucblocks,
9528c2ecf20Sopenharmony_ci	.release              = lgdt330x_release,
9538c2ecf20Sopenharmony_ci};
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops lgdt3303_ops = {
9568c2ecf20Sopenharmony_ci	.delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
9578c2ecf20Sopenharmony_ci	.info = {
9588c2ecf20Sopenharmony_ci		.name = "LG Electronics LGDT3303 VSB/QAM Frontend",
9598c2ecf20Sopenharmony_ci		.frequency_min_hz =  54 * MHz,
9608c2ecf20Sopenharmony_ci		.frequency_max_hz = 858 * MHz,
9618c2ecf20Sopenharmony_ci		.frequency_stepsize_hz = 62500,
9628c2ecf20Sopenharmony_ci		.symbol_rate_min    = 5056941,	/* QAM 64 */
9638c2ecf20Sopenharmony_ci		.symbol_rate_max    = 10762000,	/* VSB 8  */
9648c2ecf20Sopenharmony_ci		.caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
9658c2ecf20Sopenharmony_ci	},
9668c2ecf20Sopenharmony_ci	.init                 = lgdt330x_init,
9678c2ecf20Sopenharmony_ci	.set_frontend         = lgdt330x_set_parameters,
9688c2ecf20Sopenharmony_ci	.get_frontend         = lgdt330x_get_frontend,
9698c2ecf20Sopenharmony_ci	.get_tune_settings    = lgdt330x_get_tune_settings,
9708c2ecf20Sopenharmony_ci	.read_status          = lgdt3303_read_status,
9718c2ecf20Sopenharmony_ci	.read_signal_strength = lgdt330x_read_signal_strength,
9728c2ecf20Sopenharmony_ci	.read_snr             = lgdt330x_read_snr,
9738c2ecf20Sopenharmony_ci	.read_ucblocks        = lgdt330x_read_ucblocks,
9748c2ecf20Sopenharmony_ci	.release              = lgdt330x_release,
9758c2ecf20Sopenharmony_ci};
9768c2ecf20Sopenharmony_ci
9778c2ecf20Sopenharmony_cistatic int lgdt330x_remove(struct i2c_client *client)
9788c2ecf20Sopenharmony_ci{
9798c2ecf20Sopenharmony_ci	struct lgdt330x_state *state = i2c_get_clientdata(client);
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ci	dev_dbg(&client->dev, "\n");
9828c2ecf20Sopenharmony_ci
9838c2ecf20Sopenharmony_ci	kfree(state);
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_ci	return 0;
9868c2ecf20Sopenharmony_ci}
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_cistatic const struct i2c_device_id lgdt330x_id_table[] = {
9898c2ecf20Sopenharmony_ci	{"lgdt330x", 0},
9908c2ecf20Sopenharmony_ci	{}
9918c2ecf20Sopenharmony_ci};
9928c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, lgdt330x_id_table);
9938c2ecf20Sopenharmony_ci
9948c2ecf20Sopenharmony_cistatic struct i2c_driver lgdt330x_driver = {
9958c2ecf20Sopenharmony_ci	.driver = {
9968c2ecf20Sopenharmony_ci		.name	= "lgdt330x",
9978c2ecf20Sopenharmony_ci		.suppress_bind_attrs = true,
9988c2ecf20Sopenharmony_ci	},
9998c2ecf20Sopenharmony_ci	.probe		= lgdt330x_probe,
10008c2ecf20Sopenharmony_ci	.remove		= lgdt330x_remove,
10018c2ecf20Sopenharmony_ci	.id_table	= lgdt330x_id_table,
10028c2ecf20Sopenharmony_ci};
10038c2ecf20Sopenharmony_ci
10048c2ecf20Sopenharmony_cimodule_i2c_driver(lgdt330x_driver);
10058c2ecf20Sopenharmony_ci
10068c2ecf20Sopenharmony_ci
10078c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("LGDT330X (ATSC 8VSB & ITU-T J.83 AnnexB 64/256 QAM) Demodulator Driver");
10088c2ecf20Sopenharmony_ciMODULE_AUTHOR("Wilson Michaels");
10098c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
1010