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).");
516752c797SMauro Carvalho Chehab 
5223ba635dSMauro Carvalho Chehab #define dprintk(state, fmt, arg...) do {				\
53467845a1SMauro Carvalho Chehab 	if (debug)							\
5423ba635dSMauro Carvalho Chehab 		dev_printk(KERN_DEBUG, &state->client->dev, fmt, ##arg);\
559a0bf528SMauro Carvalho Chehab } while (0)
569a0bf528SMauro Carvalho Chehab 
57467845a1SMauro Carvalho Chehab struct lgdt330x_state {
5823ba635dSMauro Carvalho Chehab 	struct i2c_client *client;
599a0bf528SMauro Carvalho Chehab 
609a0bf528SMauro Carvalho Chehab 	/* Configuration settings */
6123ba635dSMauro Carvalho Chehab 	struct lgdt330x_config config;
629a0bf528SMauro Carvalho Chehab 
639a0bf528SMauro Carvalho Chehab 	struct dvb_frontend frontend;
649a0bf528SMauro Carvalho Chehab 
659a0bf528SMauro Carvalho Chehab 	/* Demodulator private data */
660df289a2SMauro Carvalho Chehab 	enum fe_modulation current_modulation;
679a0bf528SMauro Carvalho Chehab 	u32 snr; /* Result of last SNR calculation */
689a0bf528SMauro Carvalho Chehab 
699a0bf528SMauro Carvalho Chehab 	/* Tuner private data */
709a0bf528SMauro Carvalho Chehab 	u32 current_frequency;
719a0bf528SMauro Carvalho Chehab };
729a0bf528SMauro Carvalho Chehab 
739a0bf528SMauro Carvalho Chehab static int i2c_write_demod_bytes(struct lgdt330x_state *state,
7423ba635dSMauro Carvalho Chehab 				 const u8 *buf, /* data bytes to send */
759a0bf528SMauro Carvalho Chehab 				 int len  /* number of bytes to send */)
769a0bf528SMauro Carvalho Chehab {
779a0bf528SMauro Carvalho Chehab 	int i;
789a0bf528SMauro Carvalho Chehab 	int err;
799a0bf528SMauro Carvalho Chehab 
809a0bf528SMauro Carvalho Chehab 	for (i = 0; i < len - 1; i += 2) {
8123ba635dSMauro Carvalho Chehab 		err = i2c_master_send(state->client, buf, 2);
8223ba635dSMauro Carvalho Chehab 		if (err != 2) {
8323ba635dSMauro Carvalho Chehab 			dev_warn(&state->client->dev,
8423ba635dSMauro Carvalho Chehab 				 "%s: error (addr %02x <- %02x, err = %i)\n",
8523ba635dSMauro Carvalho Chehab 				__func__, buf[0], buf[1], err);
869a0bf528SMauro Carvalho Chehab 			if (err < 0)
879a0bf528SMauro Carvalho Chehab 				return err;
889a0bf528SMauro Carvalho Chehab 			else
899a0bf528SMauro Carvalho Chehab 				return -EREMOTEIO;
909a0bf528SMauro Carvalho Chehab 		}
9123ba635dSMauro Carvalho Chehab 		buf += 2;
929a0bf528SMauro Carvalho Chehab 	}
939a0bf528SMauro Carvalho Chehab 	return 0;
949a0bf528SMauro Carvalho Chehab }
959a0bf528SMauro Carvalho Chehab 
969a0bf528SMauro Carvalho Chehab /*
979a0bf528SMauro Carvalho Chehab  * This routine writes the register (reg) to the demod bus
989a0bf528SMauro Carvalho Chehab  * then reads the data returned for (len) bytes.
999a0bf528SMauro Carvalho Chehab  */
1009a0bf528SMauro Carvalho Chehab static int i2c_read_demod_bytes(struct lgdt330x_state *state,
1019a0bf528SMauro Carvalho Chehab 				enum I2C_REG reg, u8 *buf, int len)
1029a0bf528SMauro Carvalho Chehab {
1039a0bf528SMauro Carvalho Chehab 	u8 wr[] = { reg };
1049a0bf528SMauro Carvalho Chehab 	struct i2c_msg msg[] = {
105467845a1SMauro Carvalho Chehab 		{
10623ba635dSMauro Carvalho Chehab 			.addr = state->client->addr,
107467845a1SMauro Carvalho Chehab 			.flags = 0,
108467845a1SMauro Carvalho Chehab 			.buf = wr,
109467845a1SMauro Carvalho Chehab 			.len = 1
110467845a1SMauro Carvalho Chehab 		}, {
11123ba635dSMauro Carvalho Chehab 			.addr = state->client->addr,
112467845a1SMauro Carvalho Chehab 			.flags = I2C_M_RD,
113467845a1SMauro Carvalho Chehab 			.buf = buf,
114467845a1SMauro Carvalho Chehab 			.len = len
115467845a1SMauro Carvalho Chehab 		},
1169a0bf528SMauro Carvalho Chehab 	};
1179a0bf528SMauro Carvalho Chehab 	int ret;
118467845a1SMauro Carvalho Chehab 
11923ba635dSMauro Carvalho Chehab 	ret = i2c_transfer(state->client->adapter, msg, 2);
1209a0bf528SMauro Carvalho Chehab 	if (ret != 2) {
12123ba635dSMauro Carvalho Chehab 		dev_warn(&state->client->dev,
12223ba635dSMauro Carvalho Chehab 			 "%s: addr 0x%02x select 0x%02x error (ret == %i)\n",
12323ba635dSMauro Carvalho Chehab 			 __func__, state->client->addr, reg, ret);
1249a0bf528SMauro Carvalho Chehab 		if (ret >= 0)
1259a0bf528SMauro Carvalho Chehab 			ret = -EIO;
1269a0bf528SMauro Carvalho Chehab 	} else {
1279a0bf528SMauro Carvalho Chehab 		ret = 0;
1289a0bf528SMauro Carvalho Chehab 	}
1299a0bf528SMauro Carvalho Chehab 	return ret;
1309a0bf528SMauro Carvalho Chehab }
1319a0bf528SMauro Carvalho Chehab 
1329a0bf528SMauro Carvalho Chehab /* Software reset */
133467845a1SMauro Carvalho Chehab static int lgdt3302_sw_reset(struct lgdt330x_state *state)
1349a0bf528SMauro Carvalho Chehab {
1359a0bf528SMauro Carvalho Chehab 	u8 ret;
1369a0bf528SMauro Carvalho Chehab 	u8 reset[] = {
1379a0bf528SMauro Carvalho Chehab 		IRQ_MASK,
138467845a1SMauro Carvalho Chehab 		/*
139467845a1SMauro Carvalho Chehab 		 * bit 6 is active low software reset
140467845a1SMauro Carvalho Chehab 		 * bits 5-0 are 1 to mask interrupts
141467845a1SMauro Carvalho Chehab 		 */
142467845a1SMauro Carvalho Chehab 		0x00
1439a0bf528SMauro Carvalho Chehab 	};
1449a0bf528SMauro Carvalho Chehab 
1459a0bf528SMauro Carvalho Chehab 	ret = i2c_write_demod_bytes(state,
1469a0bf528SMauro Carvalho Chehab 				    reset, sizeof(reset));
1479a0bf528SMauro Carvalho Chehab 	if (ret == 0) {
1489a0bf528SMauro Carvalho Chehab 		/* force reset high (inactive) and unmask interrupts */
1499a0bf528SMauro Carvalho Chehab 		reset[1] = 0x7f;
1509a0bf528SMauro Carvalho Chehab 		ret = i2c_write_demod_bytes(state,
1519a0bf528SMauro Carvalho Chehab 					    reset, sizeof(reset));
1529a0bf528SMauro Carvalho Chehab 	}
1539a0bf528SMauro Carvalho Chehab 	return ret;
1549a0bf528SMauro Carvalho Chehab }
1559a0bf528SMauro Carvalho Chehab 
156467845a1SMauro Carvalho Chehab static int lgdt3303_sw_reset(struct lgdt330x_state *state)
1579a0bf528SMauro Carvalho Chehab {
1589a0bf528SMauro Carvalho Chehab 	u8 ret;
1599a0bf528SMauro Carvalho Chehab 	u8 reset[] = {
1609a0bf528SMauro Carvalho Chehab 		0x02,
1619a0bf528SMauro Carvalho Chehab 		0x00 /* bit 0 is active low software reset */
1629a0bf528SMauro Carvalho Chehab 	};
1639a0bf528SMauro Carvalho Chehab 
1649a0bf528SMauro Carvalho Chehab 	ret = i2c_write_demod_bytes(state,
1659a0bf528SMauro Carvalho Chehab 				    reset, sizeof(reset));
1669a0bf528SMauro Carvalho Chehab 	if (ret == 0) {
1679a0bf528SMauro Carvalho Chehab 		/* force reset high (inactive) */
1689a0bf528SMauro Carvalho Chehab 		reset[1] = 0x01;
1699a0bf528SMauro Carvalho Chehab 		ret = i2c_write_demod_bytes(state,
1709a0bf528SMauro Carvalho Chehab 					    reset, sizeof(reset));
1719a0bf528SMauro Carvalho Chehab 	}
1729a0bf528SMauro Carvalho Chehab 	return ret;
1739a0bf528SMauro Carvalho Chehab }
1749a0bf528SMauro Carvalho Chehab 
175467845a1SMauro Carvalho Chehab static int lgdt330x_sw_reset(struct lgdt330x_state *state)
1769a0bf528SMauro Carvalho Chehab {
17723ba635dSMauro Carvalho Chehab 	switch (state->config.demod_chip) {
1789a0bf528SMauro Carvalho Chehab 	case LGDT3302:
179467845a1SMauro Carvalho Chehab 		return lgdt3302_sw_reset(state);
1809a0bf528SMauro Carvalho Chehab 	case LGDT3303:
181467845a1SMauro Carvalho Chehab 		return lgdt3303_sw_reset(state);
1829a0bf528SMauro Carvalho Chehab 	default:
1839a0bf528SMauro Carvalho Chehab 		return -ENODEV;
1849a0bf528SMauro Carvalho Chehab 	}
1859a0bf528SMauro Carvalho Chehab }
1869a0bf528SMauro Carvalho Chehab 
1879a0bf528SMauro Carvalho Chehab static int lgdt330x_init(struct dvb_frontend *fe)
1889a0bf528SMauro Carvalho Chehab {
189467845a1SMauro Carvalho Chehab 	/*
190467845a1SMauro Carvalho Chehab 	 * Hardware reset is done using gpio[0] of cx23880x chip.
1919a0bf528SMauro Carvalho Chehab 	 * I'd like to do it here, but don't know how to find chip address.
1929a0bf528SMauro Carvalho Chehab 	 * cx88-cards.c arranges for the reset bit to be inactive (high).
1939a0bf528SMauro Carvalho Chehab 	 * Maybe there needs to be a callable function in cx88-core or
194467845a1SMauro Carvalho Chehab 	 * the caller of this function needs to do it.
195467845a1SMauro Carvalho Chehab 	 */
1969a0bf528SMauro Carvalho Chehab 
1979a0bf528SMauro Carvalho Chehab 	/*
1989a0bf528SMauro Carvalho Chehab 	 * Array of byte pairs <address, value>
1999a0bf528SMauro Carvalho Chehab 	 * to initialize each different chip
2009a0bf528SMauro Carvalho Chehab 	 */
2019a0bf528SMauro Carvalho Chehab 	static u8 lgdt3302_init_data[] = {
202467845a1SMauro Carvalho Chehab 		/* Use 50MHz param values from spec sheet since xtal is 50 */
203467845a1SMauro Carvalho Chehab 		/*
204467845a1SMauro Carvalho Chehab 		 * Change the value of NCOCTFV[25:0] of carrier
205467845a1SMauro Carvalho Chehab 		 * recovery center frequency register
206467845a1SMauro Carvalho Chehab 		 */
2079a0bf528SMauro Carvalho Chehab 		VSB_CARRIER_FREQ0, 0x00,
2089a0bf528SMauro Carvalho Chehab 		VSB_CARRIER_FREQ1, 0x87,
2099a0bf528SMauro Carvalho Chehab 		VSB_CARRIER_FREQ2, 0x8e,
2109a0bf528SMauro Carvalho Chehab 		VSB_CARRIER_FREQ3, 0x01,
211467845a1SMauro Carvalho Chehab 		/*
212467845a1SMauro Carvalho Chehab 		 * Change the TPCLK pin polarity
213467845a1SMauro Carvalho Chehab 		 * data is valid on falling clock
214467845a1SMauro Carvalho Chehab 		 */
2159a0bf528SMauro Carvalho Chehab 		DEMUX_CONTROL, 0xfb,
216467845a1SMauro Carvalho Chehab 		/*
217467845a1SMauro Carvalho Chehab 		 * Change the value of IFBW[11:0] of
218467845a1SMauro Carvalho Chehab 		 * AGC IF/RF loop filter bandwidth register
219467845a1SMauro Carvalho Chehab 		 */
2209a0bf528SMauro Carvalho Chehab 		AGC_RF_BANDWIDTH0, 0x40,
2219a0bf528SMauro Carvalho Chehab 		AGC_RF_BANDWIDTH1, 0x93,
2229a0bf528SMauro Carvalho Chehab 		AGC_RF_BANDWIDTH2, 0x00,
223467845a1SMauro Carvalho Chehab 		/*
224467845a1SMauro Carvalho Chehab 		 * Change the value of bit 6, 'nINAGCBY' and
225467845a1SMauro Carvalho Chehab 		 * 'NSSEL[1:0] of ACG function control register 2
226467845a1SMauro Carvalho Chehab 		 */
2279a0bf528SMauro Carvalho Chehab 		AGC_FUNC_CTRL2, 0xc6,
228467845a1SMauro Carvalho Chehab 		/*
229467845a1SMauro Carvalho Chehab 		 * Change the value of bit 6 'RFFIX'
230467845a1SMauro Carvalho Chehab 		 * of AGC function control register 3
231467845a1SMauro Carvalho Chehab 		 */
2329a0bf528SMauro Carvalho Chehab 		AGC_FUNC_CTRL3, 0x40,
233467845a1SMauro Carvalho Chehab 		/*
234467845a1SMauro Carvalho Chehab 		 * Set the value of 'INLVTHD' register 0x2a/0x2c
235467845a1SMauro Carvalho Chehab 		 * to 0x7fe
236467845a1SMauro Carvalho Chehab 		 */
2379a0bf528SMauro Carvalho Chehab 		AGC_DELAY0, 0x07,
2389a0bf528SMauro Carvalho Chehab 		AGC_DELAY2, 0xfe,
239467845a1SMauro Carvalho Chehab 		/*
240467845a1SMauro Carvalho Chehab 		 * Change the value of IAGCBW[15:8]
241467845a1SMauro Carvalho Chehab 		 * of inner AGC loop filter bandwidth
242467845a1SMauro Carvalho Chehab 		 */
2439a0bf528SMauro Carvalho Chehab 		AGC_LOOP_BANDWIDTH0, 0x08,
2449a0bf528SMauro Carvalho Chehab 		AGC_LOOP_BANDWIDTH1, 0x9a
2459a0bf528SMauro Carvalho Chehab 	};
2469a0bf528SMauro Carvalho Chehab 
2479a0bf528SMauro Carvalho Chehab 	static u8 lgdt3303_init_data[] = {
2489a0bf528SMauro Carvalho Chehab 		0x4c, 0x14
2499a0bf528SMauro Carvalho Chehab 	};
2509a0bf528SMauro Carvalho Chehab 
2519a0bf528SMauro Carvalho Chehab 	static u8 flip_1_lgdt3303_init_data[] = {
2529a0bf528SMauro Carvalho Chehab 		0x4c, 0x14,
2539a0bf528SMauro Carvalho Chehab 		0x87, 0xf3
2549a0bf528SMauro Carvalho Chehab 	};
2559a0bf528SMauro Carvalho Chehab 
2569a0bf528SMauro Carvalho Chehab 	static u8 flip_2_lgdt3303_init_data[] = {
2579a0bf528SMauro Carvalho Chehab 		0x4c, 0x14,
2589a0bf528SMauro Carvalho Chehab 		0x87, 0xda
2599a0bf528SMauro Carvalho Chehab 	};
2609a0bf528SMauro Carvalho Chehab 
2619a0bf528SMauro Carvalho Chehab 	struct lgdt330x_state *state = fe->demodulator_priv;
2629a0bf528SMauro Carvalho Chehab 	char  *chip_name;
2639a0bf528SMauro Carvalho Chehab 	int    err;
2649a0bf528SMauro Carvalho Chehab 
26523ba635dSMauro Carvalho Chehab 	switch (state->config.demod_chip) {
2669a0bf528SMauro Carvalho Chehab 	case LGDT3302:
2679a0bf528SMauro Carvalho Chehab 		chip_name = "LGDT3302";
2689a0bf528SMauro Carvalho Chehab 		err = i2c_write_demod_bytes(state, lgdt3302_init_data,
2699a0bf528SMauro Carvalho Chehab 					    sizeof(lgdt3302_init_data));
2709a0bf528SMauro Carvalho Chehab 		break;
2719a0bf528SMauro Carvalho Chehab 	case LGDT3303:
2729a0bf528SMauro Carvalho Chehab 		chip_name = "LGDT3303";
27323ba635dSMauro Carvalho Chehab 		switch (state->config.clock_polarity_flip) {
2749a0bf528SMauro Carvalho Chehab 		case 2:
2759a0bf528SMauro Carvalho Chehab 			err = i2c_write_demod_bytes(state,
2769a0bf528SMauro Carvalho Chehab 						    flip_2_lgdt3303_init_data,
2779a0bf528SMauro Carvalho Chehab 						    sizeof(flip_2_lgdt3303_init_data));
2789a0bf528SMauro Carvalho Chehab 			break;
2799a0bf528SMauro Carvalho Chehab 		case 1:
2809a0bf528SMauro Carvalho Chehab 			err = i2c_write_demod_bytes(state,
2819a0bf528SMauro Carvalho Chehab 						    flip_1_lgdt3303_init_data,
2829a0bf528SMauro Carvalho Chehab 						    sizeof(flip_1_lgdt3303_init_data));
2839a0bf528SMauro Carvalho Chehab 			break;
2849a0bf528SMauro Carvalho Chehab 		case 0:
2859a0bf528SMauro Carvalho Chehab 		default:
2869a0bf528SMauro Carvalho Chehab 			err = i2c_write_demod_bytes(state, lgdt3303_init_data,
2879a0bf528SMauro Carvalho Chehab 						    sizeof(lgdt3303_init_data));
2889a0bf528SMauro Carvalho Chehab 		}
2899a0bf528SMauro Carvalho Chehab 		break;
2909a0bf528SMauro Carvalho Chehab 	default:
2919a0bf528SMauro Carvalho Chehab 		chip_name = "undefined";
29223ba635dSMauro Carvalho Chehab 		dev_warn(&state->client->dev,
29323ba635dSMauro Carvalho Chehab 			 "Only LGDT3302 and LGDT3303 are supported chips.\n");
2949a0bf528SMauro Carvalho Chehab 		err = -ENODEV;
2959a0bf528SMauro Carvalho Chehab 	}
29623ba635dSMauro Carvalho Chehab 	dprintk(state, "Initialized the %s chip\n", chip_name);
2979a0bf528SMauro Carvalho Chehab 	if (err < 0)
2989a0bf528SMauro Carvalho Chehab 		return err;
299467845a1SMauro Carvalho Chehab 	return lgdt330x_sw_reset(state);
3009a0bf528SMauro Carvalho Chehab }
3019a0bf528SMauro Carvalho Chehab 
3029a0bf528SMauro Carvalho Chehab static int lgdt330x_read_ber(struct dvb_frontend *fe, u32 *ber)
3039a0bf528SMauro Carvalho Chehab {
3049a0bf528SMauro Carvalho Chehab 	*ber = 0; /* Not supplied by the demod chips */
3059a0bf528SMauro Carvalho Chehab 	return 0;
3069a0bf528SMauro Carvalho Chehab }
3079a0bf528SMauro Carvalho Chehab 
3089a0bf528SMauro Carvalho Chehab static int lgdt330x_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
3099a0bf528SMauro Carvalho Chehab {
3109a0bf528SMauro Carvalho Chehab 	struct lgdt330x_state *state = fe->demodulator_priv;
3119a0bf528SMauro Carvalho Chehab 	int err;
3129a0bf528SMauro Carvalho Chehab 	u8 buf[2];
3139a0bf528SMauro Carvalho Chehab 
3149a0bf528SMauro Carvalho Chehab 	*ucblocks = 0;
3159a0bf528SMauro Carvalho Chehab 
31623ba635dSMauro Carvalho Chehab 	switch (state->config.demod_chip) {
3179a0bf528SMauro Carvalho Chehab 	case LGDT3302:
3189a0bf528SMauro Carvalho Chehab 		err = i2c_read_demod_bytes(state, LGDT3302_PACKET_ERR_COUNTER1,
3199a0bf528SMauro Carvalho Chehab 					   buf, sizeof(buf));
3209a0bf528SMauro Carvalho Chehab 		break;
3219a0bf528SMauro Carvalho Chehab 	case LGDT3303:
3229a0bf528SMauro Carvalho Chehab 		err = i2c_read_demod_bytes(state, LGDT3303_PACKET_ERR_COUNTER1,
3239a0bf528SMauro Carvalho Chehab 					   buf, sizeof(buf));
3249a0bf528SMauro Carvalho Chehab 		break;
3259a0bf528SMauro Carvalho Chehab 	default:
32623ba635dSMauro Carvalho Chehab 		dev_warn(&state->client->dev,
32723ba635dSMauro Carvalho Chehab 			 "Only LGDT3302 and LGDT3303 are supported chips.\n");
3289a0bf528SMauro Carvalho Chehab 		err = -ENODEV;
3299a0bf528SMauro Carvalho Chehab 	}
3309a0bf528SMauro Carvalho Chehab 	if (err < 0)
3319a0bf528SMauro Carvalho Chehab 		return err;
3329a0bf528SMauro Carvalho Chehab 
3339a0bf528SMauro Carvalho Chehab 	*ucblocks = (buf[0] << 8) | buf[1];
3349a0bf528SMauro Carvalho Chehab 	return 0;
3359a0bf528SMauro Carvalho Chehab }
3369a0bf528SMauro Carvalho Chehab 
3379a0bf528SMauro Carvalho Chehab static int lgdt330x_set_parameters(struct dvb_frontend *fe)
3389a0bf528SMauro Carvalho Chehab {
3399a0bf528SMauro Carvalho Chehab 	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
3409a0bf528SMauro Carvalho Chehab 	/*
3419a0bf528SMauro Carvalho Chehab 	 * Array of byte pairs <address, value>
3429a0bf528SMauro Carvalho Chehab 	 * to initialize 8VSB for lgdt3303 chip 50 MHz IF
3439a0bf528SMauro Carvalho Chehab 	 */
3449a0bf528SMauro Carvalho Chehab 	static u8 lgdt3303_8vsb_44_data[] = {
3459a0bf528SMauro Carvalho Chehab 		0x04, 0x00,
3469a0bf528SMauro Carvalho Chehab 		0x0d, 0x40,
3479a0bf528SMauro Carvalho Chehab 		0x0e, 0x87,
3489a0bf528SMauro Carvalho Chehab 		0x0f, 0x8e,
3499a0bf528SMauro Carvalho Chehab 		0x10, 0x01,
350467845a1SMauro Carvalho Chehab 		0x47, 0x8b
351467845a1SMauro Carvalho Chehab 	};
3529a0bf528SMauro Carvalho Chehab 
3539a0bf528SMauro Carvalho Chehab 	/*
3549a0bf528SMauro Carvalho Chehab 	 * Array of byte pairs <address, value>
3559a0bf528SMauro Carvalho Chehab 	 * to initialize QAM for lgdt3303 chip
3569a0bf528SMauro Carvalho Chehab 	 */
3579a0bf528SMauro Carvalho Chehab 	static u8 lgdt3303_qam_data[] = {
3589a0bf528SMauro Carvalho Chehab 		0x04, 0x00,
3599a0bf528SMauro Carvalho Chehab 		0x0d, 0x00,
3609a0bf528SMauro Carvalho Chehab 		0x0e, 0x00,
3619a0bf528SMauro Carvalho Chehab 		0x0f, 0x00,
3629a0bf528SMauro Carvalho Chehab 		0x10, 0x00,
3639a0bf528SMauro Carvalho Chehab 		0x51, 0x63,
3649a0bf528SMauro Carvalho Chehab 		0x47, 0x66,
3659a0bf528SMauro Carvalho Chehab 		0x48, 0x66,
3669a0bf528SMauro Carvalho Chehab 		0x4d, 0x1a,
3679a0bf528SMauro Carvalho Chehab 		0x49, 0x08,
368467845a1SMauro Carvalho Chehab 		0x4a, 0x9b
369467845a1SMauro Carvalho Chehab 	};
3709a0bf528SMauro Carvalho Chehab 
3719a0bf528SMauro Carvalho Chehab 	struct lgdt330x_state *state = fe->demodulator_priv;
3729a0bf528SMauro Carvalho Chehab 
3739a0bf528SMauro Carvalho Chehab 	static u8 top_ctrl_cfg[]   = { TOP_CONTROL, 0x03 };
3749a0bf528SMauro Carvalho Chehab 
3759a0bf528SMauro Carvalho Chehab 	int err = 0;
3769a0bf528SMauro Carvalho Chehab 	/* Change only if we are actually changing the modulation */
3779a0bf528SMauro Carvalho Chehab 	if (state->current_modulation != p->modulation) {
3789a0bf528SMauro Carvalho Chehab 		switch (p->modulation) {
3799a0bf528SMauro Carvalho Chehab 		case VSB_8:
38023ba635dSMauro Carvalho Chehab 			dprintk(state, "VSB_8 MODE\n");
3819a0bf528SMauro Carvalho Chehab 
3829a0bf528SMauro Carvalho Chehab 			/* Select VSB mode */
3839a0bf528SMauro Carvalho Chehab 			top_ctrl_cfg[1] = 0x03;
3849a0bf528SMauro Carvalho Chehab 
3859a0bf528SMauro Carvalho Chehab 			/* Select ANT connector if supported by card */
38623ba635dSMauro Carvalho Chehab 			if (state->config.pll_rf_set)
38723ba635dSMauro Carvalho Chehab 				state->config.pll_rf_set(fe, 1);
3889a0bf528SMauro Carvalho Chehab 
38923ba635dSMauro Carvalho Chehab 			if (state->config.demod_chip == LGDT3303) {
390467845a1SMauro Carvalho Chehab 				err = i2c_write_demod_bytes(state,
391467845a1SMauro Carvalho Chehab 							    lgdt3303_8vsb_44_data,
3929a0bf528SMauro Carvalho Chehab 							    sizeof(lgdt3303_8vsb_44_data));
3939a0bf528SMauro Carvalho Chehab 			}
3949a0bf528SMauro Carvalho Chehab 			break;
3959a0bf528SMauro Carvalho Chehab 
3969a0bf528SMauro Carvalho Chehab 		case QAM_64:
39723ba635dSMauro Carvalho Chehab 			dprintk(state, "QAM_64 MODE\n");
3989a0bf528SMauro Carvalho Chehab 
3999a0bf528SMauro Carvalho Chehab 			/* Select QAM_64 mode */
4009a0bf528SMauro Carvalho Chehab 			top_ctrl_cfg[1] = 0x00;
4019a0bf528SMauro Carvalho Chehab 
4029a0bf528SMauro Carvalho Chehab 			/* Select CABLE connector if supported by card */
40323ba635dSMauro Carvalho Chehab 			if (state->config.pll_rf_set)
40423ba635dSMauro Carvalho Chehab 				state->config.pll_rf_set(fe, 0);
4059a0bf528SMauro Carvalho Chehab 
40623ba635dSMauro Carvalho Chehab 			if (state->config.demod_chip == LGDT3303) {
407467845a1SMauro Carvalho Chehab 				err = i2c_write_demod_bytes(state,
408467845a1SMauro Carvalho Chehab 							    lgdt3303_qam_data,
4099a0bf528SMauro Carvalho Chehab 							    sizeof(lgdt3303_qam_data));
4109a0bf528SMauro Carvalho Chehab 			}
4119a0bf528SMauro Carvalho Chehab 			break;
4129a0bf528SMauro Carvalho Chehab 
4139a0bf528SMauro Carvalho Chehab 		case QAM_256:
41423ba635dSMauro Carvalho Chehab 			dprintk(state, "QAM_256 MODE\n");
4159a0bf528SMauro Carvalho Chehab 
4169a0bf528SMauro Carvalho Chehab 			/* Select QAM_256 mode */
4179a0bf528SMauro Carvalho Chehab 			top_ctrl_cfg[1] = 0x01;
4189a0bf528SMauro Carvalho Chehab 
4199a0bf528SMauro Carvalho Chehab 			/* Select CABLE connector if supported by card */
42023ba635dSMauro Carvalho Chehab 			if (state->config.pll_rf_set)
42123ba635dSMauro Carvalho Chehab 				state->config.pll_rf_set(fe, 0);
4229a0bf528SMauro Carvalho Chehab 
42323ba635dSMauro Carvalho Chehab 			if (state->config.demod_chip == LGDT3303) {
424467845a1SMauro Carvalho Chehab 				err = i2c_write_demod_bytes(state,
425467845a1SMauro Carvalho Chehab 							    lgdt3303_qam_data,
4269a0bf528SMauro Carvalho Chehab 							    sizeof(lgdt3303_qam_data));
4279a0bf528SMauro Carvalho Chehab 			}
4289a0bf528SMauro Carvalho Chehab 			break;
4299a0bf528SMauro Carvalho Chehab 		default:
43023ba635dSMauro Carvalho Chehab 			dev_warn(&state->client->dev,
43123ba635dSMauro Carvalho Chehab 				 "%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)
43623ba635dSMauro Carvalho Chehab 			dev_warn(&state->client->dev,
43723ba635dSMauro Carvalho Chehab 				 "%s: error blasting bytes to lgdt3303 for modulation type(%d)\n",
4389a0bf528SMauro Carvalho Chehab 				 __func__, p->modulation);
4399a0bf528SMauro Carvalho Chehab 
4409a0bf528SMauro Carvalho Chehab 		/*
441467845a1SMauro Carvalho Chehab 		 * select serial or parallel MPEG hardware interface
4429a0bf528SMauro Carvalho Chehab 		 * Serial:   0x04 for LGDT3302 or 0x40 for LGDT3303
4439a0bf528SMauro Carvalho Chehab 		 * Parallel: 0x00
4449a0bf528SMauro Carvalho Chehab 		 */
44523ba635dSMauro Carvalho Chehab 		top_ctrl_cfg[1] |= state->config.serial_mpeg;
4469a0bf528SMauro Carvalho Chehab 
4479a0bf528SMauro Carvalho Chehab 		/* Select the requested mode */
4489a0bf528SMauro Carvalho Chehab 		i2c_write_demod_bytes(state, top_ctrl_cfg,
4499a0bf528SMauro Carvalho Chehab 				      sizeof(top_ctrl_cfg));
45023ba635dSMauro Carvalho Chehab 		if (state->config.set_ts_params)
45123ba635dSMauro Carvalho Chehab 			state->config.set_ts_params(fe, 0);
4529a0bf528SMauro Carvalho Chehab 		state->current_modulation = p->modulation;
4539a0bf528SMauro Carvalho Chehab 	}
4549a0bf528SMauro Carvalho Chehab 
4559a0bf528SMauro Carvalho Chehab 	/* Tune to the specified frequency */
4569a0bf528SMauro Carvalho Chehab 	if (fe->ops.tuner_ops.set_params) {
4579a0bf528SMauro Carvalho Chehab 		fe->ops.tuner_ops.set_params(fe);
458467845a1SMauro Carvalho Chehab 		if (fe->ops.i2c_gate_ctrl)
459467845a1SMauro Carvalho Chehab 			fe->ops.i2c_gate_ctrl(fe, 0);
4609a0bf528SMauro Carvalho Chehab 	}
4619a0bf528SMauro Carvalho Chehab 
4629a0bf528SMauro Carvalho Chehab 	/* Keep track of the new frequency */
463467845a1SMauro Carvalho Chehab 	/*
464467845a1SMauro Carvalho Chehab 	 * FIXME this is the wrong way to do this...
465467845a1SMauro Carvalho Chehab 	 * The tuner is shared with the video4linux analog API
466467845a1SMauro Carvalho Chehab 	 */
4679a0bf528SMauro Carvalho Chehab 	state->current_frequency = p->frequency;
4689a0bf528SMauro Carvalho Chehab 
469467845a1SMauro Carvalho Chehab 	lgdt330x_sw_reset(state);
4709a0bf528SMauro Carvalho Chehab 	return 0;
4719a0bf528SMauro Carvalho Chehab }
4729a0bf528SMauro Carvalho Chehab 
4737e3e68bcSMauro Carvalho Chehab static int lgdt330x_get_frontend(struct dvb_frontend *fe,
4747e3e68bcSMauro Carvalho Chehab 				 struct dtv_frontend_properties *p)
4759a0bf528SMauro Carvalho Chehab {
4769a0bf528SMauro Carvalho Chehab 	struct lgdt330x_state *state = fe->demodulator_priv;
4777e3e68bcSMauro Carvalho Chehab 
4789a0bf528SMauro Carvalho Chehab 	p->frequency = state->current_frequency;
4799a0bf528SMauro Carvalho Chehab 	return 0;
4809a0bf528SMauro Carvalho Chehab }
4819a0bf528SMauro Carvalho Chehab 
4820df289a2SMauro Carvalho Chehab static int lgdt3302_read_status(struct dvb_frontend *fe,
4830df289a2SMauro Carvalho Chehab 				enum fe_status *status)
4849a0bf528SMauro Carvalho Chehab {
4859a0bf528SMauro Carvalho Chehab 	struct lgdt330x_state *state = fe->demodulator_priv;
4869a0bf528SMauro Carvalho Chehab 	u8 buf[3];
4879a0bf528SMauro Carvalho Chehab 
4889a0bf528SMauro Carvalho Chehab 	*status = 0; /* Reset status result */
4899a0bf528SMauro Carvalho Chehab 
4909a0bf528SMauro Carvalho Chehab 	/* AGC status register */
4919a0bf528SMauro Carvalho Chehab 	i2c_read_demod_bytes(state, AGC_STATUS, buf, 1);
49223ba635dSMauro Carvalho Chehab 	dprintk(state, "AGC_STATUS = 0x%02x\n", buf[0]);
4939a0bf528SMauro Carvalho Chehab 	if ((buf[0] & 0x0c) == 0x8) {
494467845a1SMauro Carvalho Chehab 		/*
495467845a1SMauro Carvalho Chehab 		 * Test signal does not exist flag
496467845a1SMauro Carvalho Chehab 		 * as well as the AGC lock flag.
497467845a1SMauro Carvalho Chehab 		 */
4989a0bf528SMauro Carvalho Chehab 		*status |= FE_HAS_SIGNAL;
4999a0bf528SMauro Carvalho Chehab 	}
5009a0bf528SMauro Carvalho Chehab 
5019a0bf528SMauro Carvalho Chehab 	/*
5029a0bf528SMauro Carvalho Chehab 	 * You must set the Mask bits to 1 in the IRQ_MASK in order
5039a0bf528SMauro Carvalho Chehab 	 * to see that status bit in the IRQ_STATUS register.
5049a0bf528SMauro Carvalho Chehab 	 * This is done in SwReset();
5059a0bf528SMauro Carvalho Chehab 	 */
506467845a1SMauro Carvalho Chehab 
5079a0bf528SMauro Carvalho Chehab 	/* signal status */
5089a0bf528SMauro Carvalho Chehab 	i2c_read_demod_bytes(state, TOP_CONTROL, buf, sizeof(buf));
50923ba635dSMauro Carvalho Chehab 	dprintk(state,
51023ba635dSMauro Carvalho Chehab 		"TOP_CONTROL = 0x%02x, IRO_MASK = 0x%02x, IRQ_STATUS = 0x%02x\n",
5116752c797SMauro Carvalho Chehab 		buf[0], buf[1], buf[2]);
5129a0bf528SMauro Carvalho Chehab 
5139a0bf528SMauro Carvalho Chehab 	/* sync status */
514467845a1SMauro Carvalho Chehab 	if ((buf[2] & 0x03) == 0x01)
5159a0bf528SMauro Carvalho Chehab 		*status |= FE_HAS_SYNC;
5169a0bf528SMauro Carvalho Chehab 
5179a0bf528SMauro Carvalho Chehab 	/* FEC error status */
5189a0bf528SMauro Carvalho Chehab 	if ((buf[2] & 0x0c) == 0x08) {
5199a0bf528SMauro Carvalho Chehab 		*status |= FE_HAS_LOCK;
5209a0bf528SMauro Carvalho Chehab 		*status |= FE_HAS_VITERBI;
5219a0bf528SMauro Carvalho Chehab 	}
5229a0bf528SMauro Carvalho Chehab 
5239a0bf528SMauro Carvalho Chehab 	/* Carrier Recovery Lock Status Register */
5249a0bf528SMauro Carvalho Chehab 	i2c_read_demod_bytes(state, CARRIER_LOCK, buf, 1);
52523ba635dSMauro Carvalho Chehab 	dprintk(state, "CARRIER_LOCK = 0x%02x\n", buf[0]);
5269a0bf528SMauro Carvalho Chehab 	switch (state->current_modulation) {
5279a0bf528SMauro Carvalho Chehab 	case QAM_256:
5289a0bf528SMauro Carvalho Chehab 	case QAM_64:
5299a0bf528SMauro Carvalho Chehab 		/* Need to understand why there are 3 lock levels here */
5309a0bf528SMauro Carvalho Chehab 		if ((buf[0] & 0x07) == 0x07)
5319a0bf528SMauro Carvalho Chehab 			*status |= FE_HAS_CARRIER;
5329a0bf528SMauro Carvalho Chehab 		break;
5339a0bf528SMauro Carvalho Chehab 	case VSB_8:
5349a0bf528SMauro Carvalho Chehab 		if ((buf[0] & 0x80) == 0x80)
5359a0bf528SMauro Carvalho Chehab 			*status |= FE_HAS_CARRIER;
5369a0bf528SMauro Carvalho Chehab 		break;
5379a0bf528SMauro Carvalho Chehab 	default:
53823ba635dSMauro Carvalho Chehab 		dev_warn(&state->client->dev,
53923ba635dSMauro Carvalho Chehab 			 "%s: Modulation set to unsupported value\n",
540467845a1SMauro Carvalho Chehab 			 __func__);
5419a0bf528SMauro Carvalho Chehab 	}
5429a0bf528SMauro Carvalho Chehab 
5439a0bf528SMauro Carvalho Chehab 	return 0;
5449a0bf528SMauro Carvalho Chehab }
5459a0bf528SMauro Carvalho Chehab 
5460df289a2SMauro Carvalho Chehab static int lgdt3303_read_status(struct dvb_frontend *fe,
5470df289a2SMauro Carvalho Chehab 				enum fe_status *status)
5489a0bf528SMauro Carvalho Chehab {
5499a0bf528SMauro Carvalho Chehab 	struct lgdt330x_state *state = fe->demodulator_priv;
5509a0bf528SMauro Carvalho Chehab 	int err;
5519a0bf528SMauro Carvalho Chehab 	u8 buf[3];
5529a0bf528SMauro Carvalho Chehab 
5539a0bf528SMauro Carvalho Chehab 	*status = 0; /* Reset status result */
5549a0bf528SMauro Carvalho Chehab 
5559a0bf528SMauro Carvalho Chehab 	/* lgdt3303 AGC status register */
5569a0bf528SMauro Carvalho Chehab 	err = i2c_read_demod_bytes(state, 0x58, buf, 1);
5579a0bf528SMauro Carvalho Chehab 	if (err < 0)
5589a0bf528SMauro Carvalho Chehab 		return err;
5599a0bf528SMauro Carvalho Chehab 
56023ba635dSMauro Carvalho Chehab 	dprintk(state, "AGC_STATUS = 0x%02x\n", buf[0]);
5619a0bf528SMauro Carvalho Chehab 	if ((buf[0] & 0x21) == 0x01) {
562467845a1SMauro Carvalho Chehab 		/*
563467845a1SMauro Carvalho Chehab 		 * Test input signal does not exist flag
564467845a1SMauro Carvalho Chehab 		 * as well as the AGC lock flag.
565467845a1SMauro Carvalho Chehab 		 */
5669a0bf528SMauro Carvalho Chehab 		*status |= FE_HAS_SIGNAL;
5679a0bf528SMauro Carvalho Chehab 	}
5689a0bf528SMauro Carvalho Chehab 
5699a0bf528SMauro Carvalho Chehab 	/* Carrier Recovery Lock Status Register */
5709a0bf528SMauro Carvalho Chehab 	i2c_read_demod_bytes(state, CARRIER_LOCK, buf, 1);
57123ba635dSMauro Carvalho Chehab 	dprintk(state, "CARRIER_LOCK = 0x%02x\n", buf[0]);
5729a0bf528SMauro Carvalho Chehab 	switch (state->current_modulation) {
5739a0bf528SMauro Carvalho Chehab 	case QAM_256:
5749a0bf528SMauro Carvalho Chehab 	case QAM_64:
5759a0bf528SMauro Carvalho Chehab 		/* Need to understand why there are 3 lock levels here */
5769a0bf528SMauro Carvalho Chehab 		if ((buf[0] & 0x07) == 0x07)
5779a0bf528SMauro Carvalho Chehab 			*status |= FE_HAS_CARRIER;
5789a0bf528SMauro Carvalho Chehab 		else
5799a0bf528SMauro Carvalho Chehab 			break;
5809a0bf528SMauro Carvalho Chehab 		i2c_read_demod_bytes(state, 0x8a, buf, 1);
5819a0bf528SMauro Carvalho Chehab 		if ((buf[0] & 0x04) == 0x04)
5829a0bf528SMauro Carvalho Chehab 			*status |= FE_HAS_SYNC;
5839a0bf528SMauro Carvalho Chehab 		if ((buf[0] & 0x01) == 0x01)
5849a0bf528SMauro Carvalho Chehab 			*status |= FE_HAS_LOCK;
5859a0bf528SMauro Carvalho Chehab 		if ((buf[0] & 0x08) == 0x08)
5869a0bf528SMauro Carvalho Chehab 			*status |= FE_HAS_VITERBI;
5879a0bf528SMauro Carvalho Chehab 		break;
5889a0bf528SMauro Carvalho Chehab 	case VSB_8:
5899a0bf528SMauro Carvalho Chehab 		if ((buf[0] & 0x80) == 0x80)
5909a0bf528SMauro Carvalho Chehab 			*status |= FE_HAS_CARRIER;
5919a0bf528SMauro Carvalho Chehab 		else
5929a0bf528SMauro Carvalho Chehab 			break;
5939a0bf528SMauro Carvalho Chehab 		i2c_read_demod_bytes(state, 0x38, buf, 1);
5949a0bf528SMauro Carvalho Chehab 		if ((buf[0] & 0x02) == 0x00)
5959a0bf528SMauro Carvalho Chehab 			*status |= FE_HAS_SYNC;
5969a0bf528SMauro Carvalho Chehab 		if ((buf[0] & 0x01) == 0x01) {
5979a0bf528SMauro Carvalho Chehab 			*status |= FE_HAS_LOCK;
5989a0bf528SMauro Carvalho Chehab 			*status |= FE_HAS_VITERBI;
5999a0bf528SMauro Carvalho Chehab 		}
6009a0bf528SMauro Carvalho Chehab 		break;
6019a0bf528SMauro Carvalho Chehab 	default:
60223ba635dSMauro Carvalho Chehab 		dev_warn(&state->client->dev,
60323ba635dSMauro Carvalho Chehab 			 "%s: Modulation set to unsupported value\n",
604467845a1SMauro Carvalho Chehab 			 __func__);
6059a0bf528SMauro Carvalho Chehab 	}
6069a0bf528SMauro Carvalho Chehab 	return 0;
6079a0bf528SMauro Carvalho Chehab }
6089a0bf528SMauro Carvalho Chehab 
609467845a1SMauro Carvalho Chehab /*
610467845a1SMauro Carvalho Chehab  * Calculate SNR estimation (scaled by 2^24)
611467845a1SMauro Carvalho Chehab  *
612467845a1SMauro Carvalho Chehab  * 8-VSB SNR equations from LGDT3302 and LGDT3303 datasheets, QAM
613467845a1SMauro Carvalho Chehab  * equations from LGDT3303 datasheet.  VSB is the same between the '02
614467845a1SMauro Carvalho Chehab  * and '03, so maybe QAM is too?  Perhaps someone with a newer datasheet
615467845a1SMauro Carvalho Chehab  * that has QAM information could verify?
616467845a1SMauro Carvalho Chehab  *
617467845a1SMauro Carvalho Chehab  * For 8-VSB: (two ways, take your pick)
618467845a1SMauro Carvalho Chehab  * LGDT3302:
619467845a1SMauro Carvalho Chehab  *   SNR_EQ = 10 * log10(25 * 24^2 / EQ_MSE)
620467845a1SMauro Carvalho Chehab  * LGDT3303:
621467845a1SMauro Carvalho Chehab  *   SNR_EQ = 10 * log10(25 * 32^2 / EQ_MSE)
622467845a1SMauro Carvalho Chehab  * LGDT3302 & LGDT3303:
623467845a1SMauro Carvalho Chehab  *   SNR_PT = 10 * log10(25 * 32^2 / PT_MSE)  (we use this one)
624467845a1SMauro Carvalho Chehab  * For 64-QAM:
625467845a1SMauro Carvalho Chehab  *   SNR    = 10 * log10( 688128   / MSEQAM)
626467845a1SMauro Carvalho Chehab  * For 256-QAM:
627467845a1SMauro Carvalho Chehab  *   SNR    = 10 * log10( 696320   / MSEQAM)
628467845a1SMauro Carvalho Chehab  *
629467845a1SMauro Carvalho Chehab  * We re-write the snr equation as:
630467845a1SMauro Carvalho Chehab  *   SNR * 2^24 = 10*(c - intlog10(MSE))
631467845a1SMauro Carvalho Chehab  * Where for 256-QAM, c = log10(696320) * 2^24, and so on.
632467845a1SMauro Carvalho Chehab  */
6339a0bf528SMauro Carvalho Chehab static u32 calculate_snr(u32 mse, u32 c)
6349a0bf528SMauro Carvalho Chehab {
6359a0bf528SMauro Carvalho Chehab 	if (mse == 0) /* No signal */
6369a0bf528SMauro Carvalho Chehab 		return 0;
6379a0bf528SMauro Carvalho Chehab 
6389a0bf528SMauro Carvalho Chehab 	mse = intlog10(mse);
6399a0bf528SMauro Carvalho Chehab 	if (mse > c) {
640467845a1SMauro Carvalho Chehab 		/*
641467845a1SMauro Carvalho Chehab 		 * Negative SNR, which is possible, but realisticly the
642467845a1SMauro Carvalho Chehab 		 * demod will lose lock before the signal gets this bad.
643467845a1SMauro Carvalho Chehab 		 * The API only allows for unsigned values, so just return 0
644467845a1SMauro Carvalho Chehab 		 */
6459a0bf528SMauro Carvalho Chehab 		return 0;
6469a0bf528SMauro Carvalho Chehab 	}
6479a0bf528SMauro Carvalho Chehab 	return 10 * (c - mse);
6489a0bf528SMauro Carvalho Chehab }
6499a0bf528SMauro Carvalho Chehab 
6509a0bf528SMauro Carvalho Chehab static int lgdt3302_read_snr(struct dvb_frontend *fe, u16 *snr)
6519a0bf528SMauro Carvalho Chehab {
652467845a1SMauro Carvalho Chehab 	struct lgdt330x_state *state = fe->demodulator_priv;
6539a0bf528SMauro Carvalho Chehab 	u8 buf[5];	/* read data buffer */
6549a0bf528SMauro Carvalho Chehab 	u32 noise;	/* noise value */
6559a0bf528SMauro Carvalho Chehab 	u32 c;		/* per-modulation SNR calculation constant */
6569a0bf528SMauro Carvalho Chehab 
6579a0bf528SMauro Carvalho Chehab 	switch (state->current_modulation) {
6589a0bf528SMauro Carvalho Chehab 	case VSB_8:
6599a0bf528SMauro Carvalho Chehab 		i2c_read_demod_bytes(state, LGDT3302_EQPH_ERR0, buf, 5);
6609a0bf528SMauro Carvalho Chehab #ifdef USE_EQMSE
6619a0bf528SMauro Carvalho Chehab 		/* Use Equalizer Mean-Square Error Register */
6629a0bf528SMauro Carvalho Chehab 		/* SNR for ranges from -15.61 to +41.58 */
6639a0bf528SMauro Carvalho Chehab 		noise = ((buf[0] & 7) << 16) | (buf[1] << 8) | buf[2];
6649a0bf528SMauro Carvalho Chehab 		c = 69765745; /* log10(25*24^2)*2^24 */
6659a0bf528SMauro Carvalho Chehab #else
6669a0bf528SMauro Carvalho Chehab 		/* Use Phase Tracker Mean-Square Error Register */
6679a0bf528SMauro Carvalho Chehab 		/* SNR for ranges from -13.11 to +44.08 */
6689a0bf528SMauro Carvalho Chehab 		noise = ((buf[0] & 7 << 3) << 13) | (buf[3] << 8) | buf[4];
6699a0bf528SMauro Carvalho Chehab 		c = 73957994; /* log10(25*32^2)*2^24 */
6709a0bf528SMauro Carvalho Chehab #endif
6719a0bf528SMauro Carvalho Chehab 		break;
6729a0bf528SMauro Carvalho Chehab 	case QAM_64:
6739a0bf528SMauro Carvalho Chehab 	case QAM_256:
6749a0bf528SMauro Carvalho Chehab 		i2c_read_demod_bytes(state, CARRIER_MSEQAM1, buf, 2);
6759a0bf528SMauro Carvalho Chehab 		noise = ((buf[0] & 3) << 8) | buf[1];
6769a0bf528SMauro Carvalho Chehab 		c = state->current_modulation == QAM_64 ? 97939837 : 98026066;
6779a0bf528SMauro Carvalho Chehab 		/* log10(688128)*2^24 and log10(696320)*2^24 */
6789a0bf528SMauro Carvalho Chehab 		break;
6799a0bf528SMauro Carvalho Chehab 	default:
68023ba635dSMauro Carvalho Chehab 		dev_err(&state->client->dev,
68123ba635dSMauro Carvalho Chehab 			"%s: Modulation set to unsupported value\n",
6829a0bf528SMauro Carvalho Chehab 			__func__);
6839a0bf528SMauro Carvalho Chehab 		return -EREMOTEIO; /* return -EDRIVER_IS_GIBBERED; */
6849a0bf528SMauro Carvalho Chehab 	}
6859a0bf528SMauro Carvalho Chehab 
6869a0bf528SMauro Carvalho Chehab 	state->snr = calculate_snr(noise, c);
6879a0bf528SMauro Carvalho Chehab 	*snr = (state->snr) >> 16; /* Convert from 8.24 fixed-point to 8.8 */
6889a0bf528SMauro Carvalho Chehab 
68923ba635dSMauro Carvalho Chehab 	dprintk(state, "noise = 0x%08x, snr = %d.%02d dB\n", noise,
6909a0bf528SMauro Carvalho Chehab 		state->snr >> 24, (((state->snr >> 8) & 0xffff) * 100) >> 16);
6919a0bf528SMauro Carvalho Chehab 
6929a0bf528SMauro Carvalho Chehab 	return 0;
6939a0bf528SMauro Carvalho Chehab }
6949a0bf528SMauro Carvalho Chehab 
6959a0bf528SMauro Carvalho Chehab static int lgdt3303_read_snr(struct dvb_frontend *fe, u16 *snr)
6969a0bf528SMauro Carvalho Chehab {
697467845a1SMauro Carvalho Chehab 	struct lgdt330x_state *state = fe->demodulator_priv;
6989a0bf528SMauro Carvalho Chehab 	u8 buf[5];	/* read data buffer */
6999a0bf528SMauro Carvalho Chehab 	u32 noise;	/* noise value */
7009a0bf528SMauro Carvalho Chehab 	u32 c;		/* per-modulation SNR calculation constant */
7019a0bf528SMauro Carvalho Chehab 
7029a0bf528SMauro Carvalho Chehab 	switch (state->current_modulation) {
7039a0bf528SMauro Carvalho Chehab 	case VSB_8:
7049a0bf528SMauro Carvalho Chehab 		i2c_read_demod_bytes(state, LGDT3303_EQPH_ERR0, buf, 5);
7059a0bf528SMauro Carvalho Chehab #ifdef USE_EQMSE
7069a0bf528SMauro Carvalho Chehab 		/* Use Equalizer Mean-Square Error Register */
7079a0bf528SMauro Carvalho Chehab 		/* SNR for ranges from -16.12 to +44.08 */
7089a0bf528SMauro Carvalho Chehab 		noise = ((buf[0] & 0x78) << 13) | (buf[1] << 8) | buf[2];
7099a0bf528SMauro Carvalho Chehab 		c = 73957994; /* log10(25*32^2)*2^24 */
7109a0bf528SMauro Carvalho Chehab #else
7119a0bf528SMauro Carvalho Chehab 		/* Use Phase Tracker Mean-Square Error Register */
7129a0bf528SMauro Carvalho Chehab 		/* SNR for ranges from -13.11 to +44.08 */
7139a0bf528SMauro Carvalho Chehab 		noise = ((buf[0] & 7) << 16) | (buf[3] << 8) | buf[4];
7149a0bf528SMauro Carvalho Chehab 		c = 73957994; /* log10(25*32^2)*2^24 */
7159a0bf528SMauro Carvalho Chehab #endif
7169a0bf528SMauro Carvalho Chehab 		break;
7179a0bf528SMauro Carvalho Chehab 	case QAM_64:
7189a0bf528SMauro Carvalho Chehab 	case QAM_256:
7199a0bf528SMauro Carvalho Chehab 		i2c_read_demod_bytes(state, CARRIER_MSEQAM1, buf, 2);
7209a0bf528SMauro Carvalho Chehab 		noise = (buf[0] << 8) | buf[1];
7219a0bf528SMauro Carvalho Chehab 		c = state->current_modulation == QAM_64 ? 97939837 : 98026066;
7229a0bf528SMauro Carvalho Chehab 		/* log10(688128)*2^24 and log10(696320)*2^24 */
7239a0bf528SMauro Carvalho Chehab 		break;
7249a0bf528SMauro Carvalho Chehab 	default:
72523ba635dSMauro Carvalho Chehab 		dev_err(&state->client->dev,
72623ba635dSMauro Carvalho Chehab 			"%s: Modulation set to unsupported value\n",
7279a0bf528SMauro Carvalho Chehab 			__func__);
7289a0bf528SMauro Carvalho Chehab 		return -EREMOTEIO; /* return -EDRIVER_IS_GIBBERED; */
7299a0bf528SMauro Carvalho Chehab 	}
7309a0bf528SMauro Carvalho Chehab 
7319a0bf528SMauro Carvalho Chehab 	state->snr = calculate_snr(noise, c);
7329a0bf528SMauro Carvalho Chehab 	*snr = (state->snr) >> 16; /* Convert from 8.24 fixed-point to 8.8 */
7339a0bf528SMauro Carvalho Chehab 
73423ba635dSMauro Carvalho Chehab 	dprintk(state, "noise = 0x%08x, snr = %d.%02d dB\n", noise,
7359a0bf528SMauro Carvalho Chehab 		state->snr >> 24, (((state->snr >> 8) & 0xffff) * 100) >> 16);
7369a0bf528SMauro Carvalho Chehab 
7379a0bf528SMauro Carvalho Chehab 	return 0;
7389a0bf528SMauro Carvalho Chehab }
7399a0bf528SMauro Carvalho Chehab 
7409a0bf528SMauro Carvalho Chehab static int lgdt330x_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
7419a0bf528SMauro Carvalho Chehab {
7429a0bf528SMauro Carvalho Chehab 	/* Calculate Strength from SNR up to 35dB */
743467845a1SMauro Carvalho Chehab 	/*
744467845a1SMauro Carvalho Chehab 	 * Even though the SNR can go higher than 35dB, there is some comfort
745467845a1SMauro Carvalho Chehab 	 * factor in having a range of strong signals that can show at 100%
746467845a1SMauro Carvalho Chehab 	 */
747467845a1SMauro Carvalho Chehab 	struct lgdt330x_state *state = fe->demodulator_priv;
7489a0bf528SMauro Carvalho Chehab 	u16 snr;
7499a0bf528SMauro Carvalho Chehab 	int ret;
7509a0bf528SMauro Carvalho Chehab 
7519a0bf528SMauro Carvalho Chehab 	ret = fe->ops.read_snr(fe, &snr);
7529a0bf528SMauro Carvalho Chehab 	if (ret != 0)
7539a0bf528SMauro Carvalho Chehab 		return ret;
7549a0bf528SMauro Carvalho Chehab 	/* Rather than use the 8.8 value snr, use state->snr which is 8.24 */
7559a0bf528SMauro Carvalho Chehab 	/* scale the range 0 - 35*2^24 into 0 - 65535 */
7569a0bf528SMauro Carvalho Chehab 	if (state->snr >= 8960 * 0x10000)
7579a0bf528SMauro Carvalho Chehab 		*strength = 0xffff;
7589a0bf528SMauro Carvalho Chehab 	else
7599a0bf528SMauro Carvalho Chehab 		*strength = state->snr / 8960;
7609a0bf528SMauro Carvalho Chehab 
7619a0bf528SMauro Carvalho Chehab 	return 0;
7629a0bf528SMauro Carvalho Chehab }
7639a0bf528SMauro Carvalho Chehab 
764467845a1SMauro Carvalho Chehab static int
765467845a1SMauro Carvalho Chehab lgdt330x_get_tune_settings(struct dvb_frontend *fe,
766467845a1SMauro Carvalho Chehab 			   struct dvb_frontend_tune_settings *fe_tune_settings)
7679a0bf528SMauro Carvalho Chehab {
7689a0bf528SMauro Carvalho Chehab 	/* I have no idea about this - it may not be needed */
7699a0bf528SMauro Carvalho Chehab 	fe_tune_settings->min_delay_ms = 500;
7709a0bf528SMauro Carvalho Chehab 	fe_tune_settings->step_size = 0;
7719a0bf528SMauro Carvalho Chehab 	fe_tune_settings->max_drift = 0;
7729a0bf528SMauro Carvalho Chehab 	return 0;
7739a0bf528SMauro Carvalho Chehab }
7749a0bf528SMauro Carvalho Chehab 
7759a0bf528SMauro Carvalho Chehab static void lgdt330x_release(struct dvb_frontend *fe)
7769a0bf528SMauro Carvalho Chehab {
777467845a1SMauro Carvalho Chehab 	struct lgdt330x_state *state = fe->demodulator_priv;
77823ba635dSMauro Carvalho Chehab 	struct i2c_client *client = state->client;
779467845a1SMauro Carvalho Chehab 
78023ba635dSMauro Carvalho Chehab 	dev_dbg(&client->dev, "\n");
78123ba635dSMauro Carvalho Chehab 
78223ba635dSMauro Carvalho Chehab 	i2c_unregister_device(client);
78323ba635dSMauro Carvalho Chehab }
78423ba635dSMauro Carvalho Chehab 
78523ba635dSMauro Carvalho Chehab static struct dvb_frontend *lgdt330x_get_dvb_frontend(struct i2c_client *client)
78623ba635dSMauro Carvalho Chehab {
78723ba635dSMauro Carvalho Chehab 	struct lgdt330x_state *state = i2c_get_clientdata(client);
78823ba635dSMauro Carvalho Chehab 
78923ba635dSMauro Carvalho Chehab 	dev_dbg(&client->dev, "\n");
79023ba635dSMauro Carvalho Chehab 
79123ba635dSMauro Carvalho Chehab 	return &state->frontend;
7929a0bf528SMauro Carvalho Chehab }
7939a0bf528SMauro Carvalho Chehab 
794bd336e63SMax Kellermann static const struct dvb_frontend_ops lgdt3302_ops;
795bd336e63SMax Kellermann static const struct dvb_frontend_ops lgdt3303_ops;
7969a0bf528SMauro Carvalho Chehab 
79723ba635dSMauro Carvalho Chehab static int lgdt330x_probe(struct i2c_client *client,
79823ba635dSMauro Carvalho Chehab 			  const struct i2c_device_id *id)
7999a0bf528SMauro Carvalho Chehab {
8009a0bf528SMauro Carvalho Chehab 	struct lgdt330x_state *state = NULL;
8019a0bf528SMauro Carvalho Chehab 	u8 buf[1];
8029a0bf528SMauro Carvalho Chehab 
8039a0bf528SMauro Carvalho Chehab 	/* Allocate memory for the internal state */
804467845a1SMauro Carvalho Chehab 	state = kzalloc(sizeof(*state), GFP_KERNEL);
805467845a1SMauro Carvalho Chehab 	if (!state)
8069a0bf528SMauro Carvalho Chehab 		goto error;
8079a0bf528SMauro Carvalho Chehab 
8089a0bf528SMauro Carvalho Chehab 	/* Setup the state */
80923ba635dSMauro Carvalho Chehab 	memcpy(&state->config, client->dev.platform_data,
81023ba635dSMauro Carvalho Chehab 	       sizeof(state->config));
81123ba635dSMauro Carvalho Chehab 	i2c_set_clientdata(client, state);
81223ba635dSMauro Carvalho Chehab 	state->client = client;
8139a0bf528SMauro Carvalho Chehab 
8149a0bf528SMauro Carvalho Chehab 	/* Create dvb_frontend */
81523ba635dSMauro Carvalho Chehab 	switch (state->config.demod_chip) {
8169a0bf528SMauro Carvalho Chehab 	case LGDT3302:
817467845a1SMauro Carvalho Chehab 		memcpy(&state->frontend.ops, &lgdt3302_ops,
818467845a1SMauro Carvalho Chehab 		       sizeof(struct dvb_frontend_ops));
8199a0bf528SMauro Carvalho Chehab 		break;
8209a0bf528SMauro Carvalho Chehab 	case LGDT3303:
821467845a1SMauro Carvalho Chehab 		memcpy(&state->frontend.ops, &lgdt3303_ops,
822467845a1SMauro Carvalho Chehab 		       sizeof(struct dvb_frontend_ops));
8239a0bf528SMauro Carvalho Chehab 		break;
8249a0bf528SMauro Carvalho Chehab 	default:
8259a0bf528SMauro Carvalho Chehab 		goto error;
8269a0bf528SMauro Carvalho Chehab 	}
8279a0bf528SMauro Carvalho Chehab 	state->frontend.demodulator_priv = state;
8289a0bf528SMauro Carvalho Chehab 
82923ba635dSMauro Carvalho Chehab 	/* Setup get frontend callback */
83023ba635dSMauro Carvalho Chehab 	state->config.get_dvb_frontend = lgdt330x_get_dvb_frontend;
83123ba635dSMauro Carvalho Chehab 
8329a0bf528SMauro Carvalho Chehab 	/* Verify communication with demod chip */
8339a0bf528SMauro Carvalho Chehab 	if (i2c_read_demod_bytes(state, 2, buf, 1))
8349a0bf528SMauro Carvalho Chehab 		goto error;
8359a0bf528SMauro Carvalho Chehab 
8369a0bf528SMauro Carvalho Chehab 	state->current_frequency = -1;
8379a0bf528SMauro Carvalho Chehab 	state->current_modulation = -1;
8389a0bf528SMauro Carvalho Chehab 
83923ba635dSMauro Carvalho Chehab 	dev_info(&state->client->dev,
84023ba635dSMauro Carvalho Chehab 		"Demod loaded for LGDT330%s chip\n",
84123ba635dSMauro Carvalho Chehab 		state->config.demod_chip == LGDT3302 ? "2" : "3");
842ff093612SMauro Carvalho Chehab 
84323ba635dSMauro Carvalho Chehab 	return 0;
8449a0bf528SMauro Carvalho Chehab 
8459a0bf528SMauro Carvalho Chehab error:
8469a0bf528SMauro Carvalho Chehab 	kfree(state);
84723ba635dSMauro Carvalho Chehab 	dprintk(state, "ERROR\n");
84823ba635dSMauro Carvalho Chehab 	return -ENODEV;
84923ba635dSMauro Carvalho Chehab }
85023ba635dSMauro Carvalho Chehab struct dvb_frontend *lgdt330x_attach(const struct lgdt330x_config *_config,
85123ba635dSMauro Carvalho Chehab 				     u8 demod_address,
85223ba635dSMauro Carvalho Chehab 				     struct i2c_adapter *i2c)
85323ba635dSMauro Carvalho Chehab {
85423ba635dSMauro Carvalho Chehab 	struct i2c_client *client;
85523ba635dSMauro Carvalho Chehab 	struct i2c_board_info board_info = {};
85623ba635dSMauro Carvalho Chehab 	struct lgdt330x_config config = *_config;
85723ba635dSMauro Carvalho Chehab 
85823ba635dSMauro Carvalho Chehab 	strlcpy(board_info.type, "lgdt330x", sizeof(board_info.type));
85923ba635dSMauro Carvalho Chehab 	board_info.addr = demod_address;
86023ba635dSMauro Carvalho Chehab 	board_info.platform_data = &config;
86123ba635dSMauro Carvalho Chehab 	client = i2c_new_device(i2c, &board_info);
86223ba635dSMauro Carvalho Chehab 	if (!client || !client->dev.driver)
8639a0bf528SMauro Carvalho Chehab 		return NULL;
86423ba635dSMauro Carvalho Chehab 
86523ba635dSMauro Carvalho Chehab 	return lgdt330x_get_dvb_frontend(client);
8669a0bf528SMauro Carvalho Chehab }
867467845a1SMauro Carvalho Chehab EXPORT_SYMBOL(lgdt330x_attach);
8689a0bf528SMauro Carvalho Chehab 
869bd336e63SMax Kellermann static const struct dvb_frontend_ops lgdt3302_ops = {
8709a0bf528SMauro Carvalho Chehab 	.delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
8719a0bf528SMauro Carvalho Chehab 	.info = {
8729a0bf528SMauro Carvalho Chehab 		.name = "LG Electronics LGDT3302 VSB/QAM Frontend",
8739a0bf528SMauro Carvalho Chehab 		.frequency_min = 54000000,
8749a0bf528SMauro Carvalho Chehab 		.frequency_max = 858000000,
8759a0bf528SMauro Carvalho Chehab 		.frequency_stepsize = 62500,
8769a0bf528SMauro Carvalho Chehab 		.symbol_rate_min    = 5056941,	/* QAM 64 */
8779a0bf528SMauro Carvalho Chehab 		.symbol_rate_max    = 10762000,	/* VSB 8  */
8789a0bf528SMauro Carvalho Chehab 		.caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
8799a0bf528SMauro Carvalho Chehab 	},
8809a0bf528SMauro Carvalho Chehab 	.init                 = lgdt330x_init,
8819a0bf528SMauro Carvalho Chehab 	.set_frontend         = lgdt330x_set_parameters,
8829a0bf528SMauro Carvalho Chehab 	.get_frontend         = lgdt330x_get_frontend,
8839a0bf528SMauro Carvalho Chehab 	.get_tune_settings    = lgdt330x_get_tune_settings,
8849a0bf528SMauro Carvalho Chehab 	.read_status          = lgdt3302_read_status,
8859a0bf528SMauro Carvalho Chehab 	.read_ber             = lgdt330x_read_ber,
8869a0bf528SMauro Carvalho Chehab 	.read_signal_strength = lgdt330x_read_signal_strength,
8879a0bf528SMauro Carvalho Chehab 	.read_snr             = lgdt3302_read_snr,
8889a0bf528SMauro Carvalho Chehab 	.read_ucblocks        = lgdt330x_read_ucblocks,
8899a0bf528SMauro Carvalho Chehab 	.release              = lgdt330x_release,
8909a0bf528SMauro Carvalho Chehab };
8919a0bf528SMauro Carvalho Chehab 
892bd336e63SMax Kellermann static const struct dvb_frontend_ops lgdt3303_ops = {
8939a0bf528SMauro Carvalho Chehab 	.delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
8949a0bf528SMauro Carvalho Chehab 	.info = {
8959a0bf528SMauro Carvalho Chehab 		.name = "LG Electronics LGDT3303 VSB/QAM Frontend",
8969a0bf528SMauro Carvalho Chehab 		.frequency_min = 54000000,
8979a0bf528SMauro Carvalho Chehab 		.frequency_max = 858000000,
8989a0bf528SMauro Carvalho Chehab 		.frequency_stepsize = 62500,
8999a0bf528SMauro Carvalho Chehab 		.symbol_rate_min    = 5056941,	/* QAM 64 */
9009a0bf528SMauro Carvalho Chehab 		.symbol_rate_max    = 10762000,	/* VSB 8  */
9019a0bf528SMauro Carvalho Chehab 		.caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
9029a0bf528SMauro Carvalho Chehab 	},
9039a0bf528SMauro Carvalho Chehab 	.init                 = lgdt330x_init,
9049a0bf528SMauro Carvalho Chehab 	.set_frontend         = lgdt330x_set_parameters,
9059a0bf528SMauro Carvalho Chehab 	.get_frontend         = lgdt330x_get_frontend,
9069a0bf528SMauro Carvalho Chehab 	.get_tune_settings    = lgdt330x_get_tune_settings,
9079a0bf528SMauro Carvalho Chehab 	.read_status          = lgdt3303_read_status,
9089a0bf528SMauro Carvalho Chehab 	.read_ber             = lgdt330x_read_ber,
9099a0bf528SMauro Carvalho Chehab 	.read_signal_strength = lgdt330x_read_signal_strength,
9109a0bf528SMauro Carvalho Chehab 	.read_snr             = lgdt3303_read_snr,
9119a0bf528SMauro Carvalho Chehab 	.read_ucblocks        = lgdt330x_read_ucblocks,
9129a0bf528SMauro Carvalho Chehab 	.release              = lgdt330x_release,
9139a0bf528SMauro Carvalho Chehab };
9149a0bf528SMauro Carvalho Chehab 
91523ba635dSMauro Carvalho Chehab static int lgdt330x_remove(struct i2c_client *client)
91623ba635dSMauro Carvalho Chehab {
91723ba635dSMauro Carvalho Chehab 	struct lgdt330x_state *state = i2c_get_clientdata(client);
91823ba635dSMauro Carvalho Chehab 
91923ba635dSMauro Carvalho Chehab 	dev_dbg(&client->dev, "\n");
92023ba635dSMauro Carvalho Chehab 
92123ba635dSMauro Carvalho Chehab 	kfree(state);
92223ba635dSMauro Carvalho Chehab 
92323ba635dSMauro Carvalho Chehab 	return 0;
92423ba635dSMauro Carvalho Chehab }
92523ba635dSMauro Carvalho Chehab 
92623ba635dSMauro Carvalho Chehab static const struct i2c_device_id lgdt330x_id_table[] = {
92723ba635dSMauro Carvalho Chehab 	{"lgdt330x", 0},
92823ba635dSMauro Carvalho Chehab 	{}
92923ba635dSMauro Carvalho Chehab };
93023ba635dSMauro Carvalho Chehab MODULE_DEVICE_TABLE(i2c, lgdt330x_id_table);
93123ba635dSMauro Carvalho Chehab 
93223ba635dSMauro Carvalho Chehab static struct i2c_driver lgdt330x_driver = {
93323ba635dSMauro Carvalho Chehab 	.driver = {
93423ba635dSMauro Carvalho Chehab 		.name	= "lgdt330x",
93523ba635dSMauro Carvalho Chehab 		.suppress_bind_attrs = true,
93623ba635dSMauro Carvalho Chehab 	},
93723ba635dSMauro Carvalho Chehab 	.probe		= lgdt330x_probe,
93823ba635dSMauro Carvalho Chehab 	.remove		= lgdt330x_remove,
93923ba635dSMauro Carvalho Chehab 	.id_table	= lgdt330x_id_table,
94023ba635dSMauro Carvalho Chehab };
94123ba635dSMauro Carvalho Chehab 
94223ba635dSMauro Carvalho Chehab module_i2c_driver(lgdt330x_driver);
94323ba635dSMauro Carvalho Chehab 
94423ba635dSMauro Carvalho Chehab 
9459a0bf528SMauro Carvalho Chehab MODULE_DESCRIPTION("LGDT330X (ATSC 8VSB & ITU-T J.83 AnnexB 64/256 QAM) Demodulator Driver");
9469a0bf528SMauro Carvalho Chehab MODULE_AUTHOR("Wilson Michaels");
9479a0bf528SMauro Carvalho Chehab MODULE_LICENSE("GPL");
948