19a0bf528SMauro Carvalho Chehab /*
29a0bf528SMauro Carvalho Chehab  *    Support for LGDT3302 and LGDT3303 - VSB/QAM
39a0bf528SMauro Carvalho Chehab  *
49a0bf528SMauro Carvalho Chehab  *    Copyright (C) 2005 Wilson Michaels <wilsonmichaels@earthlink.net>
59a0bf528SMauro Carvalho Chehab  *
69a0bf528SMauro Carvalho Chehab  *    This program is free software; you can redistribute it and/or modify
79a0bf528SMauro Carvalho Chehab  *    it under the terms of the GNU General Public License as published by
89a0bf528SMauro Carvalho Chehab  *    the Free Software Foundation; either version 2 of the License, or
99a0bf528SMauro Carvalho Chehab  *    (at your option) any later version.
109a0bf528SMauro Carvalho Chehab  *
119a0bf528SMauro Carvalho Chehab  *    This program is distributed in the hope that it will be useful,
129a0bf528SMauro Carvalho Chehab  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
139a0bf528SMauro Carvalho Chehab  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
149a0bf528SMauro Carvalho Chehab  *    GNU General Public License for more details.
159a0bf528SMauro Carvalho Chehab  *
169a0bf528SMauro Carvalho Chehab  */
179a0bf528SMauro Carvalho Chehab 
189a0bf528SMauro Carvalho Chehab /*
199a0bf528SMauro Carvalho Chehab  *                      NOTES ABOUT THIS DRIVER
209a0bf528SMauro Carvalho Chehab  *
219a0bf528SMauro Carvalho Chehab  * This Linux driver supports:
229a0bf528SMauro Carvalho Chehab  *   DViCO FusionHDTV 3 Gold-Q
239a0bf528SMauro Carvalho Chehab  *   DViCO FusionHDTV 3 Gold-T
249a0bf528SMauro Carvalho Chehab  *   DViCO FusionHDTV 5 Gold
259a0bf528SMauro Carvalho Chehab  *   DViCO FusionHDTV 5 Lite
269a0bf528SMauro Carvalho Chehab  *   DViCO FusionHDTV 5 USB Gold
279a0bf528SMauro Carvalho Chehab  *   Air2PC/AirStar 2 ATSC 3rd generation (HD5000)
289a0bf528SMauro Carvalho Chehab  *   pcHDTV HD5500
299a0bf528SMauro Carvalho Chehab  *
309a0bf528SMauro Carvalho Chehab  */
319a0bf528SMauro Carvalho Chehab 
329a0bf528SMauro Carvalho Chehab #include <linux/kernel.h>
339a0bf528SMauro Carvalho Chehab #include <linux/module.h>
349a0bf528SMauro Carvalho Chehab #include <linux/init.h>
359a0bf528SMauro Carvalho Chehab #include <linux/delay.h>
369a0bf528SMauro Carvalho Chehab #include <linux/string.h>
379a0bf528SMauro Carvalho Chehab #include <linux/slab.h>
389a0bf528SMauro Carvalho Chehab #include <asm/byteorder.h>
399a0bf528SMauro Carvalho Chehab 
40fada1935SMauro Carvalho Chehab #include <media/dvb_frontend.h>
41fada1935SMauro Carvalho Chehab #include <media/dvb_math.h>
429a0bf528SMauro Carvalho Chehab #include "lgdt330x_priv.h"
439a0bf528SMauro Carvalho Chehab #include "lgdt330x.h"
449a0bf528SMauro Carvalho Chehab 
459a0bf528SMauro Carvalho Chehab /* Use Equalizer Mean Squared Error instead of Phaser Tracker MSE */
469a0bf528SMauro Carvalho Chehab /* #define USE_EQMSE */
479a0bf528SMauro Carvalho Chehab 
489a0bf528SMauro Carvalho Chehab static int debug;
499a0bf528SMauro Carvalho Chehab module_param(debug, int, 0644);
509a0bf528SMauro Carvalho Chehab MODULE_PARM_DESC(debug, "Turn on/off lgdt330x frontend debugging (default:off).");
51467845a1SMauro Carvalho Chehab #define dprintk(args...) do {				\
52467845a1SMauro Carvalho Chehab 	if (debug)					\
53467845a1SMauro Carvalho Chehab 		printk(KERN_DEBUG "lgdt330x: " args);	\
549a0bf528SMauro Carvalho Chehab } while (0)
559a0bf528SMauro Carvalho Chehab 
56467845a1SMauro Carvalho Chehab struct lgdt330x_state {
579a0bf528SMauro Carvalho Chehab 	struct i2c_adapter *i2c;
589a0bf528SMauro Carvalho Chehab 
599a0bf528SMauro Carvalho Chehab 	/* Configuration settings */
609a0bf528SMauro Carvalho Chehab 	const struct lgdt330x_config *config;
619a0bf528SMauro Carvalho Chehab 
629a0bf528SMauro Carvalho Chehab 	struct dvb_frontend frontend;
639a0bf528SMauro Carvalho Chehab 
649a0bf528SMauro Carvalho Chehab 	/* Demodulator private data */
650df289a2SMauro Carvalho Chehab 	enum fe_modulation current_modulation;
669a0bf528SMauro Carvalho Chehab 	u32 snr; /* Result of last SNR calculation */
679a0bf528SMauro Carvalho Chehab 
689a0bf528SMauro Carvalho Chehab 	/* Tuner private data */
699a0bf528SMauro Carvalho Chehab 	u32 current_frequency;
709a0bf528SMauro Carvalho Chehab };
719a0bf528SMauro Carvalho Chehab 
729a0bf528SMauro Carvalho Chehab static int i2c_write_demod_bytes(struct lgdt330x_state *state,
739a0bf528SMauro Carvalho Chehab 				 u8 *buf, /* data bytes to send */
749a0bf528SMauro Carvalho Chehab 				 int len  /* number of bytes to send */)
759a0bf528SMauro Carvalho Chehab {
76467845a1SMauro Carvalho Chehab 	struct i2c_msg msg = {
77467845a1SMauro Carvalho Chehab 		.addr = state->config->demod_address,
789a0bf528SMauro Carvalho Chehab 		.flags = 0,
799a0bf528SMauro Carvalho Chehab 		.buf = buf,
80467845a1SMauro Carvalho Chehab 		.len = 2
81467845a1SMauro Carvalho Chehab 	};
829a0bf528SMauro Carvalho Chehab 	int i;
839a0bf528SMauro Carvalho Chehab 	int err;
849a0bf528SMauro Carvalho Chehab 
859a0bf528SMauro Carvalho Chehab 	for (i = 0; i < len - 1; i += 2) {
86467845a1SMauro Carvalho Chehab 		err = i2c_transfer(state->i2c, &msg, 1);
87467845a1SMauro Carvalho Chehab 		if (err != 1) {
88467845a1SMauro Carvalho Chehab 			printk(KERN_WARNING "lgdt330x: %s error (addr %02x <- %02x, err = %i)\n",
89467845a1SMauro Carvalho Chehab 			       __func__, msg.buf[0], msg.buf[1], err);
909a0bf528SMauro Carvalho Chehab 			if (err < 0)
919a0bf528SMauro Carvalho Chehab 				return err;
929a0bf528SMauro Carvalho Chehab 			else
939a0bf528SMauro Carvalho Chehab 				return -EREMOTEIO;
949a0bf528SMauro Carvalho Chehab 		}
959a0bf528SMauro Carvalho Chehab 		msg.buf += 2;
969a0bf528SMauro Carvalho Chehab 	}
979a0bf528SMauro Carvalho Chehab 	return 0;
989a0bf528SMauro Carvalho Chehab }
999a0bf528SMauro Carvalho Chehab 
1009a0bf528SMauro Carvalho Chehab /*
1019a0bf528SMauro Carvalho Chehab  * This routine writes the register (reg) to the demod bus
1029a0bf528SMauro Carvalho Chehab  * then reads the data returned for (len) bytes.
1039a0bf528SMauro Carvalho Chehab  */
1049a0bf528SMauro Carvalho Chehab static int i2c_read_demod_bytes(struct lgdt330x_state *state,
1059a0bf528SMauro Carvalho Chehab 				enum I2C_REG reg, u8 *buf, int len)
1069a0bf528SMauro Carvalho Chehab {
1079a0bf528SMauro Carvalho Chehab 	u8 wr[] = { reg };
1089a0bf528SMauro Carvalho Chehab 	struct i2c_msg msg[] = {
109467845a1SMauro Carvalho Chehab 		{
110467845a1SMauro Carvalho Chehab 			.addr = state->config->demod_address,
111467845a1SMauro Carvalho Chehab 			.flags = 0,
112467845a1SMauro Carvalho Chehab 			.buf = wr,
113467845a1SMauro Carvalho Chehab 			.len = 1
114467845a1SMauro Carvalho Chehab 		}, {
115467845a1SMauro Carvalho Chehab 			.addr = state->config->demod_address,
116467845a1SMauro Carvalho Chehab 			.flags = I2C_M_RD,
117467845a1SMauro Carvalho Chehab 			.buf = buf,
118467845a1SMauro Carvalho Chehab 			.len = len
119467845a1SMauro Carvalho Chehab 		},
1209a0bf528SMauro Carvalho Chehab 	};
1219a0bf528SMauro Carvalho Chehab 	int ret;
122467845a1SMauro Carvalho Chehab 
1239a0bf528SMauro Carvalho Chehab 	ret = i2c_transfer(state->i2c, msg, 2);
1249a0bf528SMauro Carvalho Chehab 	if (ret != 2) {
125467845a1SMauro Carvalho Chehab 		printk(KERN_WARNING "lgdt330x: %s: addr 0x%02x select 0x%02x error (ret == %i)\n",
126467845a1SMauro Carvalho Chehab 		       __func__, state->config->demod_address, reg, ret);
1279a0bf528SMauro Carvalho Chehab 		if (ret >= 0)
1289a0bf528SMauro Carvalho Chehab 			ret = -EIO;
1299a0bf528SMauro Carvalho Chehab 	} else {
1309a0bf528SMauro Carvalho Chehab 		ret = 0;
1319a0bf528SMauro Carvalho Chehab 	}
1329a0bf528SMauro Carvalho Chehab 	return ret;
1339a0bf528SMauro Carvalho Chehab }
1349a0bf528SMauro Carvalho Chehab 
1359a0bf528SMauro Carvalho Chehab /* Software reset */
136467845a1SMauro Carvalho Chehab static int lgdt3302_sw_reset(struct lgdt330x_state *state)
1379a0bf528SMauro Carvalho Chehab {
1389a0bf528SMauro Carvalho Chehab 	u8 ret;
1399a0bf528SMauro Carvalho Chehab 	u8 reset[] = {
1409a0bf528SMauro Carvalho Chehab 		IRQ_MASK,
141467845a1SMauro Carvalho Chehab 		/*
142467845a1SMauro Carvalho Chehab 		 * bit 6 is active low software reset
143467845a1SMauro Carvalho Chehab 		 * bits 5-0 are 1 to mask interrupts
144467845a1SMauro Carvalho Chehab 		 */
145467845a1SMauro Carvalho Chehab 		0x00
1469a0bf528SMauro Carvalho Chehab 	};
1479a0bf528SMauro Carvalho Chehab 
1489a0bf528SMauro Carvalho Chehab 	ret = i2c_write_demod_bytes(state,
1499a0bf528SMauro Carvalho Chehab 				    reset, sizeof(reset));
1509a0bf528SMauro Carvalho Chehab 	if (ret == 0) {
1519a0bf528SMauro Carvalho Chehab 		/* force reset high (inactive) and unmask interrupts */
1529a0bf528SMauro Carvalho Chehab 		reset[1] = 0x7f;
1539a0bf528SMauro Carvalho Chehab 		ret = i2c_write_demod_bytes(state,
1549a0bf528SMauro Carvalho Chehab 					    reset, sizeof(reset));
1559a0bf528SMauro Carvalho Chehab 	}
1569a0bf528SMauro Carvalho Chehab 	return ret;
1579a0bf528SMauro Carvalho Chehab }
1589a0bf528SMauro Carvalho Chehab 
159467845a1SMauro Carvalho Chehab static int lgdt3303_sw_reset(struct lgdt330x_state *state)
1609a0bf528SMauro Carvalho Chehab {
1619a0bf528SMauro Carvalho Chehab 	u8 ret;
1629a0bf528SMauro Carvalho Chehab 	u8 reset[] = {
1639a0bf528SMauro Carvalho Chehab 		0x02,
1649a0bf528SMauro Carvalho Chehab 		0x00 /* bit 0 is active low software reset */
1659a0bf528SMauro Carvalho Chehab 	};
1669a0bf528SMauro Carvalho Chehab 
1679a0bf528SMauro Carvalho Chehab 	ret = i2c_write_demod_bytes(state,
1689a0bf528SMauro Carvalho Chehab 				    reset, sizeof(reset));
1699a0bf528SMauro Carvalho Chehab 	if (ret == 0) {
1709a0bf528SMauro Carvalho Chehab 		/* force reset high (inactive) */
1719a0bf528SMauro Carvalho Chehab 		reset[1] = 0x01;
1729a0bf528SMauro Carvalho Chehab 		ret = i2c_write_demod_bytes(state,
1739a0bf528SMauro Carvalho Chehab 					    reset, sizeof(reset));
1749a0bf528SMauro Carvalho Chehab 	}
1759a0bf528SMauro Carvalho Chehab 	return ret;
1769a0bf528SMauro Carvalho Chehab }
1779a0bf528SMauro Carvalho Chehab 
178467845a1SMauro Carvalho Chehab static int lgdt330x_sw_reset(struct lgdt330x_state *state)
1799a0bf528SMauro Carvalho Chehab {
1809a0bf528SMauro Carvalho Chehab 	switch (state->config->demod_chip) {
1819a0bf528SMauro Carvalho Chehab 	case LGDT3302:
182467845a1SMauro Carvalho Chehab 		return lgdt3302_sw_reset(state);
1839a0bf528SMauro Carvalho Chehab 	case LGDT3303:
184467845a1SMauro Carvalho Chehab 		return lgdt3303_sw_reset(state);
1859a0bf528SMauro Carvalho Chehab 	default:
1869a0bf528SMauro Carvalho Chehab 		return -ENODEV;
1879a0bf528SMauro Carvalho Chehab 	}
1889a0bf528SMauro Carvalho Chehab }
1899a0bf528SMauro Carvalho Chehab 
1909a0bf528SMauro Carvalho Chehab static int lgdt330x_init(struct dvb_frontend *fe)
1919a0bf528SMauro Carvalho Chehab {
192467845a1SMauro Carvalho Chehab 	/*
193467845a1SMauro Carvalho Chehab 	 * Hardware reset is done using gpio[0] of cx23880x chip.
1949a0bf528SMauro Carvalho Chehab 	 * I'd like to do it here, but don't know how to find chip address.
1959a0bf528SMauro Carvalho Chehab 	 * cx88-cards.c arranges for the reset bit to be inactive (high).
1969a0bf528SMauro Carvalho Chehab 	 * Maybe there needs to be a callable function in cx88-core or
197467845a1SMauro Carvalho Chehab 	 * the caller of this function needs to do it.
198467845a1SMauro Carvalho Chehab 	 */
1999a0bf528SMauro Carvalho Chehab 
2009a0bf528SMauro Carvalho Chehab 	/*
2019a0bf528SMauro Carvalho Chehab 	 * Array of byte pairs <address, value>
2029a0bf528SMauro Carvalho Chehab 	 * to initialize each different chip
2039a0bf528SMauro Carvalho Chehab 	 */
2049a0bf528SMauro Carvalho Chehab 	static u8 lgdt3302_init_data[] = {
205467845a1SMauro Carvalho Chehab 		/* Use 50MHz param values from spec sheet since xtal is 50 */
206467845a1SMauro Carvalho Chehab 		/*
207467845a1SMauro Carvalho Chehab 		 * Change the value of NCOCTFV[25:0] of carrier
208467845a1SMauro Carvalho Chehab 		 * recovery center frequency register
209467845a1SMauro Carvalho Chehab 		 */
2109a0bf528SMauro Carvalho Chehab 		VSB_CARRIER_FREQ0, 0x00,
2119a0bf528SMauro Carvalho Chehab 		VSB_CARRIER_FREQ1, 0x87,
2129a0bf528SMauro Carvalho Chehab 		VSB_CARRIER_FREQ2, 0x8e,
2139a0bf528SMauro Carvalho Chehab 		VSB_CARRIER_FREQ3, 0x01,
214467845a1SMauro Carvalho Chehab 		/*
215467845a1SMauro Carvalho Chehab 		 * Change the TPCLK pin polarity
216467845a1SMauro Carvalho Chehab 		 * data is valid on falling clock
217467845a1SMauro Carvalho Chehab 		 */
2189a0bf528SMauro Carvalho Chehab 		DEMUX_CONTROL, 0xfb,
219467845a1SMauro Carvalho Chehab 		/*
220467845a1SMauro Carvalho Chehab 		 * Change the value of IFBW[11:0] of
221467845a1SMauro Carvalho Chehab 		 * AGC IF/RF loop filter bandwidth register
222467845a1SMauro Carvalho Chehab 		 */
2239a0bf528SMauro Carvalho Chehab 		AGC_RF_BANDWIDTH0, 0x40,
2249a0bf528SMauro Carvalho Chehab 		AGC_RF_BANDWIDTH1, 0x93,
2259a0bf528SMauro Carvalho Chehab 		AGC_RF_BANDWIDTH2, 0x00,
226467845a1SMauro Carvalho Chehab 		/*
227467845a1SMauro Carvalho Chehab 		 * Change the value of bit 6, 'nINAGCBY' and
228467845a1SMauro Carvalho Chehab 		 * 'NSSEL[1:0] of ACG function control register 2
229467845a1SMauro Carvalho Chehab 		 */
2309a0bf528SMauro Carvalho Chehab 		AGC_FUNC_CTRL2, 0xc6,
231467845a1SMauro Carvalho Chehab 		/*
232467845a1SMauro Carvalho Chehab 		 * Change the value of bit 6 'RFFIX'
233467845a1SMauro Carvalho Chehab 		 * of AGC function control register 3
234467845a1SMauro Carvalho Chehab 		 */
2359a0bf528SMauro Carvalho Chehab 		AGC_FUNC_CTRL3, 0x40,
236467845a1SMauro Carvalho Chehab 		/*
237467845a1SMauro Carvalho Chehab 		 * Set the value of 'INLVTHD' register 0x2a/0x2c
238467845a1SMauro Carvalho Chehab 		 * to 0x7fe
239467845a1SMauro Carvalho Chehab 		 */
2409a0bf528SMauro Carvalho Chehab 		AGC_DELAY0, 0x07,
2419a0bf528SMauro Carvalho Chehab 		AGC_DELAY2, 0xfe,
242467845a1SMauro Carvalho Chehab 		/*
243467845a1SMauro Carvalho Chehab 		 * Change the value of IAGCBW[15:8]
244467845a1SMauro Carvalho Chehab 		 * of inner AGC loop filter bandwidth
245467845a1SMauro Carvalho Chehab 		 */
2469a0bf528SMauro Carvalho Chehab 		AGC_LOOP_BANDWIDTH0, 0x08,
2479a0bf528SMauro Carvalho Chehab 		AGC_LOOP_BANDWIDTH1, 0x9a
2489a0bf528SMauro Carvalho Chehab 	};
2499a0bf528SMauro Carvalho Chehab 
2509a0bf528SMauro Carvalho Chehab 	static u8 lgdt3303_init_data[] = {
2519a0bf528SMauro Carvalho Chehab 		0x4c, 0x14
2529a0bf528SMauro Carvalho Chehab 	};
2539a0bf528SMauro Carvalho Chehab 
2549a0bf528SMauro Carvalho Chehab 	static u8 flip_1_lgdt3303_init_data[] = {
2559a0bf528SMauro Carvalho Chehab 		0x4c, 0x14,
2569a0bf528SMauro Carvalho Chehab 		0x87, 0xf3
2579a0bf528SMauro Carvalho Chehab 	};
2589a0bf528SMauro Carvalho Chehab 
2599a0bf528SMauro Carvalho Chehab 	static u8 flip_2_lgdt3303_init_data[] = {
2609a0bf528SMauro Carvalho Chehab 		0x4c, 0x14,
2619a0bf528SMauro Carvalho Chehab 		0x87, 0xda
2629a0bf528SMauro Carvalho Chehab 	};
2639a0bf528SMauro Carvalho Chehab 
2649a0bf528SMauro Carvalho Chehab 	struct lgdt330x_state *state = fe->demodulator_priv;
2659a0bf528SMauro Carvalho Chehab 	char  *chip_name;
2669a0bf528SMauro Carvalho Chehab 	int    err;
2679a0bf528SMauro Carvalho Chehab 
2689a0bf528SMauro Carvalho Chehab 	switch (state->config->demod_chip) {
2699a0bf528SMauro Carvalho Chehab 	case LGDT3302:
2709a0bf528SMauro Carvalho Chehab 		chip_name = "LGDT3302";
2719a0bf528SMauro Carvalho Chehab 		err = i2c_write_demod_bytes(state, lgdt3302_init_data,
2729a0bf528SMauro Carvalho Chehab 					    sizeof(lgdt3302_init_data));
2739a0bf528SMauro Carvalho Chehab 		break;
2749a0bf528SMauro Carvalho Chehab 	case LGDT3303:
2759a0bf528SMauro Carvalho Chehab 		chip_name = "LGDT3303";
2769a0bf528SMauro Carvalho Chehab 		switch (state->config->clock_polarity_flip) {
2779a0bf528SMauro Carvalho Chehab 		case 2:
2789a0bf528SMauro Carvalho Chehab 			err = i2c_write_demod_bytes(state,
2799a0bf528SMauro Carvalho Chehab 						    flip_2_lgdt3303_init_data,
2809a0bf528SMauro Carvalho Chehab 						    sizeof(flip_2_lgdt3303_init_data));
2819a0bf528SMauro Carvalho Chehab 			break;
2829a0bf528SMauro Carvalho Chehab 		case 1:
2839a0bf528SMauro Carvalho Chehab 			err = i2c_write_demod_bytes(state,
2849a0bf528SMauro Carvalho Chehab 						    flip_1_lgdt3303_init_data,
2859a0bf528SMauro Carvalho Chehab 						    sizeof(flip_1_lgdt3303_init_data));
2869a0bf528SMauro Carvalho Chehab 			break;
2879a0bf528SMauro Carvalho Chehab 		case 0:
2889a0bf528SMauro Carvalho Chehab 		default:
2899a0bf528SMauro Carvalho Chehab 			err = i2c_write_demod_bytes(state, lgdt3303_init_data,
2909a0bf528SMauro Carvalho Chehab 						    sizeof(lgdt3303_init_data));
2919a0bf528SMauro Carvalho Chehab 		}
2929a0bf528SMauro Carvalho Chehab 		break;
2939a0bf528SMauro Carvalho Chehab 	default:
2949a0bf528SMauro Carvalho Chehab 		chip_name = "undefined";
2959a0bf528SMauro Carvalho Chehab 		printk(KERN_WARNING "Only LGDT3302 and LGDT3303 are supported chips.\n");
2969a0bf528SMauro Carvalho Chehab 		err = -ENODEV;
2979a0bf528SMauro Carvalho Chehab 	}
2989a0bf528SMauro Carvalho Chehab 	dprintk("%s entered as %s\n", __func__, chip_name);
2999a0bf528SMauro Carvalho Chehab 	if (err < 0)
3009a0bf528SMauro Carvalho Chehab 		return err;
301467845a1SMauro Carvalho Chehab 	return lgdt330x_sw_reset(state);
3029a0bf528SMauro Carvalho Chehab }
3039a0bf528SMauro Carvalho Chehab 
3049a0bf528SMauro Carvalho Chehab static int lgdt330x_read_ber(struct dvb_frontend *fe, u32 *ber)
3059a0bf528SMauro Carvalho Chehab {
3069a0bf528SMauro Carvalho Chehab 	*ber = 0; /* Not supplied by the demod chips */
3079a0bf528SMauro Carvalho Chehab 	return 0;
3089a0bf528SMauro Carvalho Chehab }
3099a0bf528SMauro Carvalho Chehab 
3109a0bf528SMauro Carvalho Chehab static int lgdt330x_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
3119a0bf528SMauro Carvalho Chehab {
3129a0bf528SMauro Carvalho Chehab 	struct lgdt330x_state *state = fe->demodulator_priv;
3139a0bf528SMauro Carvalho Chehab 	int err;
3149a0bf528SMauro Carvalho Chehab 	u8 buf[2];
3159a0bf528SMauro Carvalho Chehab 
3169a0bf528SMauro Carvalho Chehab 	*ucblocks = 0;
3179a0bf528SMauro Carvalho Chehab 
3189a0bf528SMauro Carvalho Chehab 	switch (state->config->demod_chip) {
3199a0bf528SMauro Carvalho Chehab 	case LGDT3302:
3209a0bf528SMauro Carvalho Chehab 		err = i2c_read_demod_bytes(state, LGDT3302_PACKET_ERR_COUNTER1,
3219a0bf528SMauro Carvalho Chehab 					   buf, sizeof(buf));
3229a0bf528SMauro Carvalho Chehab 		break;
3239a0bf528SMauro Carvalho Chehab 	case LGDT3303:
3249a0bf528SMauro Carvalho Chehab 		err = i2c_read_demod_bytes(state, LGDT3303_PACKET_ERR_COUNTER1,
3259a0bf528SMauro Carvalho Chehab 					   buf, sizeof(buf));
3269a0bf528SMauro Carvalho Chehab 		break;
3279a0bf528SMauro Carvalho Chehab 	default:
328467845a1SMauro Carvalho Chehab 		printk(KERN_WARNING "Only LGDT3302 and LGDT3303 are supported chips.\n");
3299a0bf528SMauro Carvalho Chehab 		err = -ENODEV;
3309a0bf528SMauro Carvalho Chehab 	}
3319a0bf528SMauro Carvalho Chehab 	if (err < 0)
3329a0bf528SMauro Carvalho Chehab 		return err;
3339a0bf528SMauro Carvalho Chehab 
3349a0bf528SMauro Carvalho Chehab 	*ucblocks = (buf[0] << 8) | buf[1];
3359a0bf528SMauro Carvalho Chehab 	return 0;
3369a0bf528SMauro Carvalho Chehab }
3379a0bf528SMauro Carvalho Chehab 
3389a0bf528SMauro Carvalho Chehab static int lgdt330x_set_parameters(struct dvb_frontend *fe)
3399a0bf528SMauro Carvalho Chehab {
3409a0bf528SMauro Carvalho Chehab 	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
3419a0bf528SMauro Carvalho Chehab 	/*
3429a0bf528SMauro Carvalho Chehab 	 * Array of byte pairs <address, value>
3439a0bf528SMauro Carvalho Chehab 	 * to initialize 8VSB for lgdt3303 chip 50 MHz IF
3449a0bf528SMauro Carvalho Chehab 	 */
3459a0bf528SMauro Carvalho Chehab 	static u8 lgdt3303_8vsb_44_data[] = {
3469a0bf528SMauro Carvalho Chehab 		0x04, 0x00,
3479a0bf528SMauro Carvalho Chehab 		0x0d, 0x40,
3489a0bf528SMauro Carvalho Chehab 		0x0e, 0x87,
3499a0bf528SMauro Carvalho Chehab 		0x0f, 0x8e,
3509a0bf528SMauro Carvalho Chehab 		0x10, 0x01,
351467845a1SMauro Carvalho Chehab 		0x47, 0x8b
352467845a1SMauro Carvalho Chehab 	};
3539a0bf528SMauro Carvalho Chehab 
3549a0bf528SMauro Carvalho Chehab 	/*
3559a0bf528SMauro Carvalho Chehab 	 * Array of byte pairs <address, value>
3569a0bf528SMauro Carvalho Chehab 	 * to initialize QAM for lgdt3303 chip
3579a0bf528SMauro Carvalho Chehab 	 */
3589a0bf528SMauro Carvalho Chehab 	static u8 lgdt3303_qam_data[] = {
3599a0bf528SMauro Carvalho Chehab 		0x04, 0x00,
3609a0bf528SMauro Carvalho Chehab 		0x0d, 0x00,
3619a0bf528SMauro Carvalho Chehab 		0x0e, 0x00,
3629a0bf528SMauro Carvalho Chehab 		0x0f, 0x00,
3639a0bf528SMauro Carvalho Chehab 		0x10, 0x00,
3649a0bf528SMauro Carvalho Chehab 		0x51, 0x63,
3659a0bf528SMauro Carvalho Chehab 		0x47, 0x66,
3669a0bf528SMauro Carvalho Chehab 		0x48, 0x66,
3679a0bf528SMauro Carvalho Chehab 		0x4d, 0x1a,
3689a0bf528SMauro Carvalho Chehab 		0x49, 0x08,
369467845a1SMauro Carvalho Chehab 		0x4a, 0x9b
370467845a1SMauro Carvalho Chehab 	};
3719a0bf528SMauro Carvalho Chehab 
3729a0bf528SMauro Carvalho Chehab 	struct lgdt330x_state *state = fe->demodulator_priv;
3739a0bf528SMauro Carvalho Chehab 
3749a0bf528SMauro Carvalho Chehab 	static u8 top_ctrl_cfg[]   = { TOP_CONTROL, 0x03 };
3759a0bf528SMauro Carvalho Chehab 
3769a0bf528SMauro Carvalho Chehab 	int err = 0;
3779a0bf528SMauro Carvalho Chehab 	/* Change only if we are actually changing the modulation */
3789a0bf528SMauro Carvalho Chehab 	if (state->current_modulation != p->modulation) {
3799a0bf528SMauro Carvalho Chehab 		switch (p->modulation) {
3809a0bf528SMauro Carvalho Chehab 		case VSB_8:
3819a0bf528SMauro Carvalho Chehab 			dprintk("%s: VSB_8 MODE\n", __func__);
3829a0bf528SMauro Carvalho Chehab 
3839a0bf528SMauro Carvalho Chehab 			/* Select VSB mode */
3849a0bf528SMauro Carvalho Chehab 			top_ctrl_cfg[1] = 0x03;
3859a0bf528SMauro Carvalho Chehab 
3869a0bf528SMauro Carvalho Chehab 			/* Select ANT connector if supported by card */
3879a0bf528SMauro Carvalho Chehab 			if (state->config->pll_rf_set)
3889a0bf528SMauro Carvalho Chehab 				state->config->pll_rf_set(fe, 1);
3899a0bf528SMauro Carvalho Chehab 
3909a0bf528SMauro Carvalho Chehab 			if (state->config->demod_chip == LGDT3303) {
391467845a1SMauro Carvalho Chehab 				err = i2c_write_demod_bytes(state,
392467845a1SMauro Carvalho Chehab 							    lgdt3303_8vsb_44_data,
3939a0bf528SMauro Carvalho Chehab 							    sizeof(lgdt3303_8vsb_44_data));
3949a0bf528SMauro Carvalho Chehab 			}
3959a0bf528SMauro Carvalho Chehab 			break;
3969a0bf528SMauro Carvalho Chehab 
3979a0bf528SMauro Carvalho Chehab 		case QAM_64:
3989a0bf528SMauro Carvalho Chehab 			dprintk("%s: QAM_64 MODE\n", __func__);
3999a0bf528SMauro Carvalho Chehab 
4009a0bf528SMauro Carvalho Chehab 			/* Select QAM_64 mode */
4019a0bf528SMauro Carvalho Chehab 			top_ctrl_cfg[1] = 0x00;
4029a0bf528SMauro Carvalho Chehab 
4039a0bf528SMauro Carvalho Chehab 			/* Select CABLE connector if supported by card */
4049a0bf528SMauro Carvalho Chehab 			if (state->config->pll_rf_set)
4059a0bf528SMauro Carvalho Chehab 				state->config->pll_rf_set(fe, 0);
4069a0bf528SMauro Carvalho Chehab 
4079a0bf528SMauro Carvalho Chehab 			if (state->config->demod_chip == LGDT3303) {
408467845a1SMauro Carvalho Chehab 				err = i2c_write_demod_bytes(state,
409467845a1SMauro Carvalho Chehab 							    lgdt3303_qam_data,
4109a0bf528SMauro Carvalho Chehab 							    sizeof(lgdt3303_qam_data));
4119a0bf528SMauro Carvalho Chehab 			}
4129a0bf528SMauro Carvalho Chehab 			break;
4139a0bf528SMauro Carvalho Chehab 
4149a0bf528SMauro Carvalho Chehab 		case QAM_256:
4159a0bf528SMauro Carvalho Chehab 			dprintk("%s: QAM_256 MODE\n", __func__);
4169a0bf528SMauro Carvalho Chehab 
4179a0bf528SMauro Carvalho Chehab 			/* Select QAM_256 mode */
4189a0bf528SMauro Carvalho Chehab 			top_ctrl_cfg[1] = 0x01;
4199a0bf528SMauro Carvalho Chehab 
4209a0bf528SMauro Carvalho Chehab 			/* Select CABLE connector if supported by card */
4219a0bf528SMauro Carvalho Chehab 			if (state->config->pll_rf_set)
4229a0bf528SMauro Carvalho Chehab 				state->config->pll_rf_set(fe, 0);
4239a0bf528SMauro Carvalho Chehab 
4249a0bf528SMauro Carvalho Chehab 			if (state->config->demod_chip == LGDT3303) {
425467845a1SMauro Carvalho Chehab 				err = i2c_write_demod_bytes(state,
426467845a1SMauro Carvalho Chehab 							    lgdt3303_qam_data,
4279a0bf528SMauro Carvalho Chehab 							    sizeof(lgdt3303_qam_data));
4289a0bf528SMauro Carvalho Chehab 			}
4299a0bf528SMauro Carvalho Chehab 			break;
4309a0bf528SMauro Carvalho Chehab 		default:
431467845a1SMauro Carvalho Chehab 			printk(KERN_WARNING "lgdt330x: %s: Modulation type(%d) UNSUPPORTED\n",
432467845a1SMauro Carvalho Chehab 			       __func__, p->modulation);
4339a0bf528SMauro Carvalho Chehab 			return -1;
4349a0bf528SMauro Carvalho Chehab 		}
4359a0bf528SMauro Carvalho Chehab 		if (err < 0)
4364bd69e7bSMauro Carvalho Chehab 			printk(KERN_WARNING "lgdt330x: %s: error blasting bytes to lgdt3303 for modulation type(%d)\n",
4379a0bf528SMauro Carvalho Chehab 			       __func__, p->modulation);
4389a0bf528SMauro Carvalho Chehab 
4399a0bf528SMauro Carvalho Chehab 		/*
440467845a1SMauro Carvalho Chehab 		 * select serial or parallel MPEG hardware interface
4419a0bf528SMauro Carvalho Chehab 		 * Serial:   0x04 for LGDT3302 or 0x40 for LGDT3303
4429a0bf528SMauro Carvalho Chehab 		 * Parallel: 0x00
4439a0bf528SMauro Carvalho Chehab 		 */
4449a0bf528SMauro Carvalho Chehab 		top_ctrl_cfg[1] |= state->config->serial_mpeg;
4459a0bf528SMauro Carvalho Chehab 
4469a0bf528SMauro Carvalho Chehab 		/* Select the requested mode */
4479a0bf528SMauro Carvalho Chehab 		i2c_write_demod_bytes(state, top_ctrl_cfg,
4489a0bf528SMauro Carvalho Chehab 				      sizeof(top_ctrl_cfg));
4499a0bf528SMauro Carvalho Chehab 		if (state->config->set_ts_params)
4509a0bf528SMauro Carvalho Chehab 			state->config->set_ts_params(fe, 0);
4519a0bf528SMauro Carvalho Chehab 		state->current_modulation = p->modulation;
4529a0bf528SMauro Carvalho Chehab 	}
4539a0bf528SMauro Carvalho Chehab 
4549a0bf528SMauro Carvalho Chehab 	/* Tune to the specified frequency */
4559a0bf528SMauro Carvalho Chehab 	if (fe->ops.tuner_ops.set_params) {
4569a0bf528SMauro Carvalho Chehab 		fe->ops.tuner_ops.set_params(fe);
457467845a1SMauro Carvalho Chehab 		if (fe->ops.i2c_gate_ctrl)
458467845a1SMauro Carvalho Chehab 			fe->ops.i2c_gate_ctrl(fe, 0);
4599a0bf528SMauro Carvalho Chehab 	}
4609a0bf528SMauro Carvalho Chehab 
4619a0bf528SMauro Carvalho Chehab 	/* Keep track of the new frequency */
462467845a1SMauro Carvalho Chehab 	/*
463467845a1SMauro Carvalho Chehab 	 * FIXME this is the wrong way to do this...
464467845a1SMauro Carvalho Chehab 	 * The tuner is shared with the video4linux analog API
465467845a1SMauro Carvalho Chehab 	 */
4669a0bf528SMauro Carvalho Chehab 	state->current_frequency = p->frequency;
4679a0bf528SMauro Carvalho Chehab 
468467845a1SMauro Carvalho Chehab 	lgdt330x_sw_reset(state);
4699a0bf528SMauro Carvalho Chehab 	return 0;
4709a0bf528SMauro Carvalho Chehab }
4719a0bf528SMauro Carvalho Chehab 
4727e3e68bcSMauro Carvalho Chehab static int lgdt330x_get_frontend(struct dvb_frontend *fe,
4737e3e68bcSMauro Carvalho Chehab 				 struct dtv_frontend_properties *p)
4749a0bf528SMauro Carvalho Chehab {
4759a0bf528SMauro Carvalho Chehab 	struct lgdt330x_state *state = fe->demodulator_priv;
4767e3e68bcSMauro Carvalho Chehab 
4779a0bf528SMauro Carvalho Chehab 	p->frequency = state->current_frequency;
4789a0bf528SMauro Carvalho Chehab 	return 0;
4799a0bf528SMauro Carvalho Chehab }
4809a0bf528SMauro Carvalho Chehab 
4810df289a2SMauro Carvalho Chehab static int lgdt3302_read_status(struct dvb_frontend *fe,
4820df289a2SMauro Carvalho Chehab 				enum fe_status *status)
4839a0bf528SMauro Carvalho Chehab {
4849a0bf528SMauro Carvalho Chehab 	struct lgdt330x_state *state = fe->demodulator_priv;
4859a0bf528SMauro Carvalho Chehab 	u8 buf[3];
4869a0bf528SMauro Carvalho Chehab 
4879a0bf528SMauro Carvalho Chehab 	*status = 0; /* Reset status result */
4889a0bf528SMauro Carvalho Chehab 
4899a0bf528SMauro Carvalho Chehab 	/* AGC status register */
4909a0bf528SMauro Carvalho Chehab 	i2c_read_demod_bytes(state, AGC_STATUS, buf, 1);
4919a0bf528SMauro Carvalho Chehab 	dprintk("%s: AGC_STATUS = 0x%02x\n", __func__, buf[0]);
4929a0bf528SMauro Carvalho Chehab 	if ((buf[0] & 0x0c) == 0x8) {
493467845a1SMauro Carvalho Chehab 		/*
494467845a1SMauro Carvalho Chehab 		 * Test signal does not exist flag
495467845a1SMauro Carvalho Chehab 		 * as well as the AGC lock flag.
496467845a1SMauro Carvalho Chehab 		 */
4979a0bf528SMauro Carvalho Chehab 		*status |= FE_HAS_SIGNAL;
4989a0bf528SMauro Carvalho Chehab 	}
4999a0bf528SMauro Carvalho Chehab 
5009a0bf528SMauro Carvalho Chehab 	/*
5019a0bf528SMauro Carvalho Chehab 	 * You must set the Mask bits to 1 in the IRQ_MASK in order
5029a0bf528SMauro Carvalho Chehab 	 * to see that status bit in the IRQ_STATUS register.
5039a0bf528SMauro Carvalho Chehab 	 * This is done in SwReset();
5049a0bf528SMauro Carvalho Chehab 	 */
505467845a1SMauro Carvalho Chehab 
5069a0bf528SMauro Carvalho Chehab 	/* signal status */
5079a0bf528SMauro Carvalho Chehab 	i2c_read_demod_bytes(state, TOP_CONTROL, buf, sizeof(buf));
508467845a1SMauro Carvalho Chehab 	dprintk("%s: TOP_CONTROL = 0x%02x, IRO_MASK = 0x%02x, IRQ_STATUS = 0x%02x\n",
509467845a1SMauro Carvalho Chehab 		__func__, buf[0], buf[1], buf[2]);
5109a0bf528SMauro Carvalho Chehab 
5119a0bf528SMauro Carvalho Chehab 	/* sync status */
512467845a1SMauro Carvalho Chehab 	if ((buf[2] & 0x03) == 0x01)
5139a0bf528SMauro Carvalho Chehab 		*status |= FE_HAS_SYNC;
5149a0bf528SMauro Carvalho Chehab 
5159a0bf528SMauro Carvalho Chehab 	/* FEC error status */
5169a0bf528SMauro Carvalho Chehab 	if ((buf[2] & 0x0c) == 0x08) {
5179a0bf528SMauro Carvalho Chehab 		*status |= FE_HAS_LOCK;
5189a0bf528SMauro Carvalho Chehab 		*status |= FE_HAS_VITERBI;
5199a0bf528SMauro Carvalho Chehab 	}
5209a0bf528SMauro Carvalho Chehab 
5219a0bf528SMauro Carvalho Chehab 	/* Carrier Recovery Lock Status Register */
5229a0bf528SMauro Carvalho Chehab 	i2c_read_demod_bytes(state, CARRIER_LOCK, buf, 1);
5239a0bf528SMauro Carvalho Chehab 	dprintk("%s: CARRIER_LOCK = 0x%02x\n", __func__, buf[0]);
5249a0bf528SMauro Carvalho Chehab 	switch (state->current_modulation) {
5259a0bf528SMauro Carvalho Chehab 	case QAM_256:
5269a0bf528SMauro Carvalho Chehab 	case QAM_64:
5279a0bf528SMauro Carvalho Chehab 		/* Need to understand why there are 3 lock levels here */
5289a0bf528SMauro Carvalho Chehab 		if ((buf[0] & 0x07) == 0x07)
5299a0bf528SMauro Carvalho Chehab 			*status |= FE_HAS_CARRIER;
5309a0bf528SMauro Carvalho Chehab 		break;
5319a0bf528SMauro Carvalho Chehab 	case VSB_8:
5329a0bf528SMauro Carvalho Chehab 		if ((buf[0] & 0x80) == 0x80)
5339a0bf528SMauro Carvalho Chehab 			*status |= FE_HAS_CARRIER;
5349a0bf528SMauro Carvalho Chehab 		break;
5359a0bf528SMauro Carvalho Chehab 	default:
536467845a1SMauro Carvalho Chehab 		printk(KERN_WARNING "lgdt330x: %s: Modulation set to unsupported value\n",
537467845a1SMauro Carvalho Chehab 		       __func__);
5389a0bf528SMauro Carvalho Chehab 	}
5399a0bf528SMauro Carvalho Chehab 
5409a0bf528SMauro Carvalho Chehab 	return 0;
5419a0bf528SMauro Carvalho Chehab }
5429a0bf528SMauro Carvalho Chehab 
5430df289a2SMauro Carvalho Chehab static int lgdt3303_read_status(struct dvb_frontend *fe,
5440df289a2SMauro Carvalho Chehab 				enum fe_status *status)
5459a0bf528SMauro Carvalho Chehab {
5469a0bf528SMauro Carvalho Chehab 	struct lgdt330x_state *state = fe->demodulator_priv;
5479a0bf528SMauro Carvalho Chehab 	int err;
5489a0bf528SMauro Carvalho Chehab 	u8 buf[3];
5499a0bf528SMauro Carvalho Chehab 
5509a0bf528SMauro Carvalho Chehab 	*status = 0; /* Reset status result */
5519a0bf528SMauro Carvalho Chehab 
5529a0bf528SMauro Carvalho Chehab 	/* lgdt3303 AGC status register */
5539a0bf528SMauro Carvalho Chehab 	err = i2c_read_demod_bytes(state, 0x58, buf, 1);
5549a0bf528SMauro Carvalho Chehab 	if (err < 0)
5559a0bf528SMauro Carvalho Chehab 		return err;
5569a0bf528SMauro Carvalho Chehab 
5579a0bf528SMauro Carvalho Chehab 	dprintk("%s: AGC_STATUS = 0x%02x\n", __func__, buf[0]);
5589a0bf528SMauro Carvalho Chehab 	if ((buf[0] & 0x21) == 0x01) {
559467845a1SMauro Carvalho Chehab 		/*
560467845a1SMauro Carvalho Chehab 		 * Test input signal does not exist flag
561467845a1SMauro Carvalho Chehab 		 * as well as the AGC lock flag.
562467845a1SMauro Carvalho Chehab 		 */
5639a0bf528SMauro Carvalho Chehab 		*status |= FE_HAS_SIGNAL;
5649a0bf528SMauro Carvalho Chehab 	}
5659a0bf528SMauro Carvalho Chehab 
5669a0bf528SMauro Carvalho Chehab 	/* Carrier Recovery Lock Status Register */
5679a0bf528SMauro Carvalho Chehab 	i2c_read_demod_bytes(state, CARRIER_LOCK, buf, 1);
5689a0bf528SMauro Carvalho Chehab 	dprintk("%s: CARRIER_LOCK = 0x%02x\n", __func__, buf[0]);
5699a0bf528SMauro Carvalho Chehab 	switch (state->current_modulation) {
5709a0bf528SMauro Carvalho Chehab 	case QAM_256:
5719a0bf528SMauro Carvalho Chehab 	case QAM_64:
5729a0bf528SMauro Carvalho Chehab 		/* Need to understand why there are 3 lock levels here */
5739a0bf528SMauro Carvalho Chehab 		if ((buf[0] & 0x07) == 0x07)
5749a0bf528SMauro Carvalho Chehab 			*status |= FE_HAS_CARRIER;
5759a0bf528SMauro Carvalho Chehab 		else
5769a0bf528SMauro Carvalho Chehab 			break;
5779a0bf528SMauro Carvalho Chehab 		i2c_read_demod_bytes(state, 0x8a, buf, 1);
5789a0bf528SMauro Carvalho Chehab 		if ((buf[0] & 0x04) == 0x04)
5799a0bf528SMauro Carvalho Chehab 			*status |= FE_HAS_SYNC;
5809a0bf528SMauro Carvalho Chehab 		if ((buf[0] & 0x01) == 0x01)
5819a0bf528SMauro Carvalho Chehab 			*status |= FE_HAS_LOCK;
5829a0bf528SMauro Carvalho Chehab 		if ((buf[0] & 0x08) == 0x08)
5839a0bf528SMauro Carvalho Chehab 			*status |= FE_HAS_VITERBI;
5849a0bf528SMauro Carvalho Chehab 		break;
5859a0bf528SMauro Carvalho Chehab 	case VSB_8:
5869a0bf528SMauro Carvalho Chehab 		if ((buf[0] & 0x80) == 0x80)
5879a0bf528SMauro Carvalho Chehab 			*status |= FE_HAS_CARRIER;
5889a0bf528SMauro Carvalho Chehab 		else
5899a0bf528SMauro Carvalho Chehab 			break;
5909a0bf528SMauro Carvalho Chehab 		i2c_read_demod_bytes(state, 0x38, buf, 1);
5919a0bf528SMauro Carvalho Chehab 		if ((buf[0] & 0x02) == 0x00)
5929a0bf528SMauro Carvalho Chehab 			*status |= FE_HAS_SYNC;
5939a0bf528SMauro Carvalho Chehab 		if ((buf[0] & 0x01) == 0x01) {
5949a0bf528SMauro Carvalho Chehab 			*status |= FE_HAS_LOCK;
5959a0bf528SMauro Carvalho Chehab 			*status |= FE_HAS_VITERBI;
5969a0bf528SMauro Carvalho Chehab 		}
5979a0bf528SMauro Carvalho Chehab 		break;
5989a0bf528SMauro Carvalho Chehab 	default:
599467845a1SMauro Carvalho Chehab 		printk(KERN_WARNING "lgdt330x: %s: Modulation set to unsupported value\n",
600467845a1SMauro Carvalho Chehab 		       __func__);
6019a0bf528SMauro Carvalho Chehab 	}
6029a0bf528SMauro Carvalho Chehab 	return 0;
6039a0bf528SMauro Carvalho Chehab }
6049a0bf528SMauro Carvalho Chehab 
605467845a1SMauro Carvalho Chehab /*
606467845a1SMauro Carvalho Chehab  * Calculate SNR estimation (scaled by 2^24)
607467845a1SMauro Carvalho Chehab  *
608467845a1SMauro Carvalho Chehab  * 8-VSB SNR equations from LGDT3302 and LGDT3303 datasheets, QAM
609467845a1SMauro Carvalho Chehab  * equations from LGDT3303 datasheet.  VSB is the same between the '02
610467845a1SMauro Carvalho Chehab  * and '03, so maybe QAM is too?  Perhaps someone with a newer datasheet
611467845a1SMauro Carvalho Chehab  * that has QAM information could verify?
612467845a1SMauro Carvalho Chehab  *
613467845a1SMauro Carvalho Chehab  * For 8-VSB: (two ways, take your pick)
614467845a1SMauro Carvalho Chehab  * LGDT3302:
615467845a1SMauro Carvalho Chehab  *   SNR_EQ = 10 * log10(25 * 24^2 / EQ_MSE)
616467845a1SMauro Carvalho Chehab  * LGDT3303:
617467845a1SMauro Carvalho Chehab  *   SNR_EQ = 10 * log10(25 * 32^2 / EQ_MSE)
618467845a1SMauro Carvalho Chehab  * LGDT3302 & LGDT3303:
619467845a1SMauro Carvalho Chehab  *   SNR_PT = 10 * log10(25 * 32^2 / PT_MSE)  (we use this one)
620467845a1SMauro Carvalho Chehab  * For 64-QAM:
621467845a1SMauro Carvalho Chehab  *   SNR    = 10 * log10( 688128   / MSEQAM)
622467845a1SMauro Carvalho Chehab  * For 256-QAM:
623467845a1SMauro Carvalho Chehab  *   SNR    = 10 * log10( 696320   / MSEQAM)
624467845a1SMauro Carvalho Chehab  *
625467845a1SMauro Carvalho Chehab  * We re-write the snr equation as:
626467845a1SMauro Carvalho Chehab  *   SNR * 2^24 = 10*(c - intlog10(MSE))
627467845a1SMauro Carvalho Chehab  * Where for 256-QAM, c = log10(696320) * 2^24, and so on.
628467845a1SMauro Carvalho Chehab  */
6299a0bf528SMauro Carvalho Chehab static u32 calculate_snr(u32 mse, u32 c)
6309a0bf528SMauro Carvalho Chehab {
6319a0bf528SMauro Carvalho Chehab 	if (mse == 0) /* No signal */
6329a0bf528SMauro Carvalho Chehab 		return 0;
6339a0bf528SMauro Carvalho Chehab 
6349a0bf528SMauro Carvalho Chehab 	mse = intlog10(mse);
6359a0bf528SMauro Carvalho Chehab 	if (mse > c) {
636467845a1SMauro Carvalho Chehab 		/*
637467845a1SMauro Carvalho Chehab 		 * Negative SNR, which is possible, but realisticly the
638467845a1SMauro Carvalho Chehab 		 * demod will lose lock before the signal gets this bad.
639467845a1SMauro Carvalho Chehab 		 * The API only allows for unsigned values, so just return 0
640467845a1SMauro Carvalho Chehab 		 */
6419a0bf528SMauro Carvalho Chehab 		return 0;
6429a0bf528SMauro Carvalho Chehab 	}
6439a0bf528SMauro Carvalho Chehab 	return 10 * (c - mse);
6449a0bf528SMauro Carvalho Chehab }
6459a0bf528SMauro Carvalho Chehab 
6469a0bf528SMauro Carvalho Chehab static int lgdt3302_read_snr(struct dvb_frontend *fe, u16 *snr)
6479a0bf528SMauro Carvalho Chehab {
648467845a1SMauro Carvalho Chehab 	struct lgdt330x_state *state = fe->demodulator_priv;
6499a0bf528SMauro Carvalho Chehab 	u8 buf[5];	/* read data buffer */
6509a0bf528SMauro Carvalho Chehab 	u32 noise;	/* noise value */
6519a0bf528SMauro Carvalho Chehab 	u32 c;		/* per-modulation SNR calculation constant */
6529a0bf528SMauro Carvalho Chehab 
6539a0bf528SMauro Carvalho Chehab 	switch (state->current_modulation) {
6549a0bf528SMauro Carvalho Chehab 	case VSB_8:
6559a0bf528SMauro Carvalho Chehab 		i2c_read_demod_bytes(state, LGDT3302_EQPH_ERR0, buf, 5);
6569a0bf528SMauro Carvalho Chehab #ifdef USE_EQMSE
6579a0bf528SMauro Carvalho Chehab 		/* Use Equalizer Mean-Square Error Register */
6589a0bf528SMauro Carvalho Chehab 		/* SNR for ranges from -15.61 to +41.58 */
6599a0bf528SMauro Carvalho Chehab 		noise = ((buf[0] & 7) << 16) | (buf[1] << 8) | buf[2];
6609a0bf528SMauro Carvalho Chehab 		c = 69765745; /* log10(25*24^2)*2^24 */
6619a0bf528SMauro Carvalho Chehab #else
6629a0bf528SMauro Carvalho Chehab 		/* Use Phase Tracker Mean-Square Error Register */
6639a0bf528SMauro Carvalho Chehab 		/* SNR for ranges from -13.11 to +44.08 */
6649a0bf528SMauro Carvalho Chehab 		noise = ((buf[0] & 7 << 3) << 13) | (buf[3] << 8) | buf[4];
6659a0bf528SMauro Carvalho Chehab 		c = 73957994; /* log10(25*32^2)*2^24 */
6669a0bf528SMauro Carvalho Chehab #endif
6679a0bf528SMauro Carvalho Chehab 		break;
6689a0bf528SMauro Carvalho Chehab 	case QAM_64:
6699a0bf528SMauro Carvalho Chehab 	case QAM_256:
6709a0bf528SMauro Carvalho Chehab 		i2c_read_demod_bytes(state, CARRIER_MSEQAM1, buf, 2);
6719a0bf528SMauro Carvalho Chehab 		noise = ((buf[0] & 3) << 8) | buf[1];
6729a0bf528SMauro Carvalho Chehab 		c = state->current_modulation == QAM_64 ? 97939837 : 98026066;
6739a0bf528SMauro Carvalho Chehab 		/* log10(688128)*2^24 and log10(696320)*2^24 */
6749a0bf528SMauro Carvalho Chehab 		break;
6759a0bf528SMauro Carvalho Chehab 	default:
6769a0bf528SMauro Carvalho Chehab 		printk(KERN_ERR "lgdt330x: %s: Modulation set to unsupported value\n",
6779a0bf528SMauro Carvalho Chehab 		       __func__);
6789a0bf528SMauro Carvalho Chehab 		return -EREMOTEIO; /* return -EDRIVER_IS_GIBBERED; */
6799a0bf528SMauro Carvalho Chehab 	}
6809a0bf528SMauro Carvalho Chehab 
6819a0bf528SMauro Carvalho Chehab 	state->snr = calculate_snr(noise, c);
6829a0bf528SMauro Carvalho Chehab 	*snr = (state->snr) >> 16; /* Convert from 8.24 fixed-point to 8.8 */
6839a0bf528SMauro Carvalho Chehab 
6849a0bf528SMauro Carvalho Chehab 	dprintk("%s: noise = 0x%08x, snr = %d.%02d dB\n", __func__, noise,
6859a0bf528SMauro Carvalho Chehab 		state->snr >> 24, (((state->snr >> 8) & 0xffff) * 100) >> 16);
6869a0bf528SMauro Carvalho Chehab 
6879a0bf528SMauro Carvalho Chehab 	return 0;
6889a0bf528SMauro Carvalho Chehab }
6899a0bf528SMauro Carvalho Chehab 
6909a0bf528SMauro Carvalho Chehab static int lgdt3303_read_snr(struct dvb_frontend *fe, u16 *snr)
6919a0bf528SMauro Carvalho Chehab {
692467845a1SMauro Carvalho Chehab 	struct lgdt330x_state *state = fe->demodulator_priv;
6939a0bf528SMauro Carvalho Chehab 	u8 buf[5];	/* read data buffer */
6949a0bf528SMauro Carvalho Chehab 	u32 noise;	/* noise value */
6959a0bf528SMauro Carvalho Chehab 	u32 c;		/* per-modulation SNR calculation constant */
6969a0bf528SMauro Carvalho Chehab 
6979a0bf528SMauro Carvalho Chehab 	switch (state->current_modulation) {
6989a0bf528SMauro Carvalho Chehab 	case VSB_8:
6999a0bf528SMauro Carvalho Chehab 		i2c_read_demod_bytes(state, LGDT3303_EQPH_ERR0, buf, 5);
7009a0bf528SMauro Carvalho Chehab #ifdef USE_EQMSE
7019a0bf528SMauro Carvalho Chehab 		/* Use Equalizer Mean-Square Error Register */
7029a0bf528SMauro Carvalho Chehab 		/* SNR for ranges from -16.12 to +44.08 */
7039a0bf528SMauro Carvalho Chehab 		noise = ((buf[0] & 0x78) << 13) | (buf[1] << 8) | buf[2];
7049a0bf528SMauro Carvalho Chehab 		c = 73957994; /* log10(25*32^2)*2^24 */
7059a0bf528SMauro Carvalho Chehab #else
7069a0bf528SMauro Carvalho Chehab 		/* Use Phase Tracker Mean-Square Error Register */
7079a0bf528SMauro Carvalho Chehab 		/* SNR for ranges from -13.11 to +44.08 */
7089a0bf528SMauro Carvalho Chehab 		noise = ((buf[0] & 7) << 16) | (buf[3] << 8) | buf[4];
7099a0bf528SMauro Carvalho Chehab 		c = 73957994; /* log10(25*32^2)*2^24 */
7109a0bf528SMauro Carvalho Chehab #endif
7119a0bf528SMauro Carvalho Chehab 		break;
7129a0bf528SMauro Carvalho Chehab 	case QAM_64:
7139a0bf528SMauro Carvalho Chehab 	case QAM_256:
7149a0bf528SMauro Carvalho Chehab 		i2c_read_demod_bytes(state, CARRIER_MSEQAM1, buf, 2);
7159a0bf528SMauro Carvalho Chehab 		noise = (buf[0] << 8) | buf[1];
7169a0bf528SMauro Carvalho Chehab 		c = state->current_modulation == QAM_64 ? 97939837 : 98026066;
7179a0bf528SMauro Carvalho Chehab 		/* log10(688128)*2^24 and log10(696320)*2^24 */
7189a0bf528SMauro Carvalho Chehab 		break;
7199a0bf528SMauro Carvalho Chehab 	default:
7209a0bf528SMauro Carvalho Chehab 		printk(KERN_ERR "lgdt330x: %s: Modulation set to unsupported value\n",
7219a0bf528SMauro Carvalho Chehab 		       __func__);
7229a0bf528SMauro Carvalho Chehab 		return -EREMOTEIO; /* return -EDRIVER_IS_GIBBERED; */
7239a0bf528SMauro Carvalho Chehab 	}
7249a0bf528SMauro Carvalho Chehab 
7259a0bf528SMauro Carvalho Chehab 	state->snr = calculate_snr(noise, c);
7269a0bf528SMauro Carvalho Chehab 	*snr = (state->snr) >> 16; /* Convert from 8.24 fixed-point to 8.8 */
7279a0bf528SMauro Carvalho Chehab 
7289a0bf528SMauro Carvalho Chehab 	dprintk("%s: noise = 0x%08x, snr = %d.%02d dB\n", __func__, noise,
7299a0bf528SMauro Carvalho Chehab 		state->snr >> 24, (((state->snr >> 8) & 0xffff) * 100) >> 16);
7309a0bf528SMauro Carvalho Chehab 
7319a0bf528SMauro Carvalho Chehab 	return 0;
7329a0bf528SMauro Carvalho Chehab }
7339a0bf528SMauro Carvalho Chehab 
7349a0bf528SMauro Carvalho Chehab static int lgdt330x_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
7359a0bf528SMauro Carvalho Chehab {
7369a0bf528SMauro Carvalho Chehab 	/* Calculate Strength from SNR up to 35dB */
737467845a1SMauro Carvalho Chehab 	/*
738467845a1SMauro Carvalho Chehab 	 * Even though the SNR can go higher than 35dB, there is some comfort
739467845a1SMauro Carvalho Chehab 	 * factor in having a range of strong signals that can show at 100%
740467845a1SMauro Carvalho Chehab 	 */
741467845a1SMauro Carvalho Chehab 	struct lgdt330x_state *state = fe->demodulator_priv;
7429a0bf528SMauro Carvalho Chehab 	u16 snr;
7439a0bf528SMauro Carvalho Chehab 	int ret;
7449a0bf528SMauro Carvalho Chehab 
7459a0bf528SMauro Carvalho Chehab 	ret = fe->ops.read_snr(fe, &snr);
7469a0bf528SMauro Carvalho Chehab 	if (ret != 0)
7479a0bf528SMauro Carvalho Chehab 		return ret;
7489a0bf528SMauro Carvalho Chehab 	/* Rather than use the 8.8 value snr, use state->snr which is 8.24 */
7499a0bf528SMauro Carvalho Chehab 	/* scale the range 0 - 35*2^24 into 0 - 65535 */
7509a0bf528SMauro Carvalho Chehab 	if (state->snr >= 8960 * 0x10000)
7519a0bf528SMauro Carvalho Chehab 		*strength = 0xffff;
7529a0bf528SMauro Carvalho Chehab 	else
7539a0bf528SMauro Carvalho Chehab 		*strength = state->snr / 8960;
7549a0bf528SMauro Carvalho Chehab 
7559a0bf528SMauro Carvalho Chehab 	return 0;
7569a0bf528SMauro Carvalho Chehab }
7579a0bf528SMauro Carvalho Chehab 
758467845a1SMauro Carvalho Chehab static int
759467845a1SMauro Carvalho Chehab lgdt330x_get_tune_settings(struct dvb_frontend *fe,
760467845a1SMauro Carvalho Chehab 			   struct dvb_frontend_tune_settings *fe_tune_settings)
7619a0bf528SMauro Carvalho Chehab {
7629a0bf528SMauro Carvalho Chehab 	/* I have no idea about this - it may not be needed */
7639a0bf528SMauro Carvalho Chehab 	fe_tune_settings->min_delay_ms = 500;
7649a0bf528SMauro Carvalho Chehab 	fe_tune_settings->step_size = 0;
7659a0bf528SMauro Carvalho Chehab 	fe_tune_settings->max_drift = 0;
7669a0bf528SMauro Carvalho Chehab 	return 0;
7679a0bf528SMauro Carvalho Chehab }
7689a0bf528SMauro Carvalho Chehab 
7699a0bf528SMauro Carvalho Chehab static void lgdt330x_release(struct dvb_frontend *fe)
7709a0bf528SMauro Carvalho Chehab {
771467845a1SMauro Carvalho Chehab 	struct lgdt330x_state *state = fe->demodulator_priv;
772467845a1SMauro Carvalho Chehab 
7739a0bf528SMauro Carvalho Chehab 	kfree(state);
7749a0bf528SMauro Carvalho Chehab }
7759a0bf528SMauro Carvalho Chehab 
776bd336e63SMax Kellermann static const struct dvb_frontend_ops lgdt3302_ops;
777bd336e63SMax Kellermann static const struct dvb_frontend_ops lgdt3303_ops;
7789a0bf528SMauro Carvalho Chehab 
7799a0bf528SMauro Carvalho Chehab struct dvb_frontend *lgdt330x_attach(const struct lgdt330x_config *config,
7809a0bf528SMauro Carvalho Chehab 				     struct i2c_adapter *i2c)
7819a0bf528SMauro Carvalho Chehab {
7829a0bf528SMauro Carvalho Chehab 	struct lgdt330x_state *state = NULL;
7839a0bf528SMauro Carvalho Chehab 	u8 buf[1];
7849a0bf528SMauro Carvalho Chehab 
7859a0bf528SMauro Carvalho Chehab 	/* Allocate memory for the internal state */
786467845a1SMauro Carvalho Chehab 	state = kzalloc(sizeof(*state), GFP_KERNEL);
787467845a1SMauro Carvalho Chehab 	if (!state)
7889a0bf528SMauro Carvalho Chehab 		goto error;
7899a0bf528SMauro Carvalho Chehab 
7909a0bf528SMauro Carvalho Chehab 	/* Setup the state */
7919a0bf528SMauro Carvalho Chehab 	state->config = config;
7929a0bf528SMauro Carvalho Chehab 	state->i2c = i2c;
7939a0bf528SMauro Carvalho Chehab 
7949a0bf528SMauro Carvalho Chehab 	/* Create dvb_frontend */
7959a0bf528SMauro Carvalho Chehab 	switch (config->demod_chip) {
7969a0bf528SMauro Carvalho Chehab 	case LGDT3302:
797467845a1SMauro Carvalho Chehab 		memcpy(&state->frontend.ops, &lgdt3302_ops,
798467845a1SMauro Carvalho Chehab 		       sizeof(struct dvb_frontend_ops));
7999a0bf528SMauro Carvalho Chehab 		break;
8009a0bf528SMauro Carvalho Chehab 	case LGDT3303:
801467845a1SMauro Carvalho Chehab 		memcpy(&state->frontend.ops, &lgdt3303_ops,
802467845a1SMauro Carvalho Chehab 		       sizeof(struct dvb_frontend_ops));
8039a0bf528SMauro Carvalho Chehab 		break;
8049a0bf528SMauro Carvalho Chehab 	default:
8059a0bf528SMauro Carvalho Chehab 		goto error;
8069a0bf528SMauro Carvalho Chehab 	}
8079a0bf528SMauro Carvalho Chehab 	state->frontend.demodulator_priv = state;
8089a0bf528SMauro Carvalho Chehab 
8099a0bf528SMauro Carvalho Chehab 	/* Verify communication with demod chip */
8109a0bf528SMauro Carvalho Chehab 	if (i2c_read_demod_bytes(state, 2, buf, 1))
8119a0bf528SMauro Carvalho Chehab 		goto error;
8129a0bf528SMauro Carvalho Chehab 
8139a0bf528SMauro Carvalho Chehab 	state->current_frequency = -1;
8149a0bf528SMauro Carvalho Chehab 	state->current_modulation = -1;
8159a0bf528SMauro Carvalho Chehab 
8169a0bf528SMauro Carvalho Chehab 	return &state->frontend;
8179a0bf528SMauro Carvalho Chehab 
8189a0bf528SMauro Carvalho Chehab error:
8199a0bf528SMauro Carvalho Chehab 	kfree(state);
8209a0bf528SMauro Carvalho Chehab 	dprintk("%s: ERROR\n", __func__);
8219a0bf528SMauro Carvalho Chehab 	return NULL;
8229a0bf528SMauro Carvalho Chehab }
823467845a1SMauro Carvalho Chehab EXPORT_SYMBOL(lgdt330x_attach);
8249a0bf528SMauro Carvalho Chehab 
825bd336e63SMax Kellermann static const struct dvb_frontend_ops lgdt3302_ops = {
8269a0bf528SMauro Carvalho Chehab 	.delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
8279a0bf528SMauro Carvalho Chehab 	.info = {
8289a0bf528SMauro Carvalho Chehab 		.name = "LG Electronics LGDT3302 VSB/QAM Frontend",
8299a0bf528SMauro Carvalho Chehab 		.frequency_min = 54000000,
8309a0bf528SMauro Carvalho Chehab 		.frequency_max = 858000000,
8319a0bf528SMauro Carvalho Chehab 		.frequency_stepsize = 62500,
8329a0bf528SMauro Carvalho Chehab 		.symbol_rate_min    = 5056941,	/* QAM 64 */
8339a0bf528SMauro Carvalho Chehab 		.symbol_rate_max    = 10762000,	/* VSB 8  */
8349a0bf528SMauro Carvalho Chehab 		.caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
8359a0bf528SMauro Carvalho Chehab 	},
8369a0bf528SMauro Carvalho Chehab 	.init                 = lgdt330x_init,
8379a0bf528SMauro Carvalho Chehab 	.set_frontend         = lgdt330x_set_parameters,
8389a0bf528SMauro Carvalho Chehab 	.get_frontend         = lgdt330x_get_frontend,
8399a0bf528SMauro Carvalho Chehab 	.get_tune_settings    = lgdt330x_get_tune_settings,
8409a0bf528SMauro Carvalho Chehab 	.read_status          = lgdt3302_read_status,
8419a0bf528SMauro Carvalho Chehab 	.read_ber             = lgdt330x_read_ber,
8429a0bf528SMauro Carvalho Chehab 	.read_signal_strength = lgdt330x_read_signal_strength,
8439a0bf528SMauro Carvalho Chehab 	.read_snr             = lgdt3302_read_snr,
8449a0bf528SMauro Carvalho Chehab 	.read_ucblocks        = lgdt330x_read_ucblocks,
8459a0bf528SMauro Carvalho Chehab 	.release              = lgdt330x_release,
8469a0bf528SMauro Carvalho Chehab };
8479a0bf528SMauro Carvalho Chehab 
848bd336e63SMax Kellermann static const struct dvb_frontend_ops lgdt3303_ops = {
8499a0bf528SMauro Carvalho Chehab 	.delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
8509a0bf528SMauro Carvalho Chehab 	.info = {
8519a0bf528SMauro Carvalho Chehab 		.name = "LG Electronics LGDT3303 VSB/QAM Frontend",
8529a0bf528SMauro Carvalho Chehab 		.frequency_min = 54000000,
8539a0bf528SMauro Carvalho Chehab 		.frequency_max = 858000000,
8549a0bf528SMauro Carvalho Chehab 		.frequency_stepsize = 62500,
8559a0bf528SMauro Carvalho Chehab 		.symbol_rate_min    = 5056941,	/* QAM 64 */
8569a0bf528SMauro Carvalho Chehab 		.symbol_rate_max    = 10762000,	/* VSB 8  */
8579a0bf528SMauro Carvalho Chehab 		.caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
8589a0bf528SMauro Carvalho Chehab 	},
8599a0bf528SMauro Carvalho Chehab 	.init                 = lgdt330x_init,
8609a0bf528SMauro Carvalho Chehab 	.set_frontend         = lgdt330x_set_parameters,
8619a0bf528SMauro Carvalho Chehab 	.get_frontend         = lgdt330x_get_frontend,
8629a0bf528SMauro Carvalho Chehab 	.get_tune_settings    = lgdt330x_get_tune_settings,
8639a0bf528SMauro Carvalho Chehab 	.read_status          = lgdt3303_read_status,
8649a0bf528SMauro Carvalho Chehab 	.read_ber             = lgdt330x_read_ber,
8659a0bf528SMauro Carvalho Chehab 	.read_signal_strength = lgdt330x_read_signal_strength,
8669a0bf528SMauro Carvalho Chehab 	.read_snr             = lgdt3303_read_snr,
8679a0bf528SMauro Carvalho Chehab 	.read_ucblocks        = lgdt330x_read_ucblocks,
8689a0bf528SMauro Carvalho Chehab 	.release              = lgdt330x_release,
8699a0bf528SMauro Carvalho Chehab };
8709a0bf528SMauro Carvalho Chehab 
8719a0bf528SMauro Carvalho Chehab MODULE_DESCRIPTION("LGDT330X (ATSC 8VSB & ITU-T J.83 AnnexB 64/256 QAM) Demodulator Driver");
8729a0bf528SMauro Carvalho Chehab MODULE_AUTHOR("Wilson Michaels");
8739a0bf528SMauro Carvalho Chehab MODULE_LICENSE("GPL");
874