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 */
685f939c36SMauro Carvalho Chehab 	u16 ucblocks;
695f939c36SMauro Carvalho Chehab 	unsigned long last_stats_time;
709a0bf528SMauro Carvalho Chehab 
719a0bf528SMauro Carvalho Chehab 	/* Tuner private data */
729a0bf528SMauro Carvalho Chehab 	u32 current_frequency;
739a0bf528SMauro Carvalho Chehab };
749a0bf528SMauro Carvalho Chehab 
759a0bf528SMauro Carvalho Chehab static int i2c_write_demod_bytes(struct lgdt330x_state *state,
7623ba635dSMauro Carvalho Chehab 				 const u8 *buf, /* data bytes to send */
779a0bf528SMauro Carvalho Chehab 				 int len  /* number of bytes to send */)
789a0bf528SMauro Carvalho Chehab {
799a0bf528SMauro Carvalho Chehab 	int i;
809a0bf528SMauro Carvalho Chehab 	int err;
819a0bf528SMauro Carvalho Chehab 
829a0bf528SMauro Carvalho Chehab 	for (i = 0; i < len - 1; i += 2) {
8323ba635dSMauro Carvalho Chehab 		err = i2c_master_send(state->client, buf, 2);
8423ba635dSMauro Carvalho Chehab 		if (err != 2) {
8523ba635dSMauro Carvalho Chehab 			dev_warn(&state->client->dev,
8623ba635dSMauro Carvalho Chehab 				 "%s: error (addr %02x <- %02x, err = %i)\n",
8723ba635dSMauro Carvalho Chehab 				__func__, buf[0], buf[1], err);
889a0bf528SMauro Carvalho Chehab 			if (err < 0)
899a0bf528SMauro Carvalho Chehab 				return err;
909a0bf528SMauro Carvalho Chehab 			else
919a0bf528SMauro Carvalho Chehab 				return -EREMOTEIO;
929a0bf528SMauro Carvalho Chehab 		}
9323ba635dSMauro Carvalho Chehab 		buf += 2;
949a0bf528SMauro Carvalho Chehab 	}
959a0bf528SMauro Carvalho Chehab 	return 0;
969a0bf528SMauro Carvalho Chehab }
979a0bf528SMauro Carvalho Chehab 
989a0bf528SMauro Carvalho Chehab /*
999a0bf528SMauro Carvalho Chehab  * This routine writes the register (reg) to the demod bus
1009a0bf528SMauro Carvalho Chehab  * then reads the data returned for (len) bytes.
1019a0bf528SMauro Carvalho Chehab  */
1029a0bf528SMauro Carvalho Chehab static int i2c_read_demod_bytes(struct lgdt330x_state *state,
1039a0bf528SMauro Carvalho Chehab 				enum I2C_REG reg, u8 *buf, int len)
1049a0bf528SMauro Carvalho Chehab {
1059a0bf528SMauro Carvalho Chehab 	u8 wr[] = { reg };
1069a0bf528SMauro Carvalho Chehab 	struct i2c_msg msg[] = {
107467845a1SMauro Carvalho Chehab 		{
10823ba635dSMauro Carvalho Chehab 			.addr = state->client->addr,
109467845a1SMauro Carvalho Chehab 			.flags = 0,
110467845a1SMauro Carvalho Chehab 			.buf = wr,
111467845a1SMauro Carvalho Chehab 			.len = 1
112467845a1SMauro Carvalho Chehab 		}, {
11323ba635dSMauro Carvalho Chehab 			.addr = state->client->addr,
114467845a1SMauro Carvalho Chehab 			.flags = I2C_M_RD,
115467845a1SMauro Carvalho Chehab 			.buf = buf,
116467845a1SMauro Carvalho Chehab 			.len = len
117467845a1SMauro Carvalho Chehab 		},
1189a0bf528SMauro Carvalho Chehab 	};
1199a0bf528SMauro Carvalho Chehab 	int ret;
120467845a1SMauro Carvalho Chehab 
12123ba635dSMauro Carvalho Chehab 	ret = i2c_transfer(state->client->adapter, msg, 2);
1229a0bf528SMauro Carvalho Chehab 	if (ret != 2) {
12323ba635dSMauro Carvalho Chehab 		dev_warn(&state->client->dev,
12423ba635dSMauro Carvalho Chehab 			 "%s: addr 0x%02x select 0x%02x error (ret == %i)\n",
12523ba635dSMauro Carvalho Chehab 			 __func__, state->client->addr, reg, ret);
1269a0bf528SMauro Carvalho Chehab 		if (ret >= 0)
1279a0bf528SMauro Carvalho Chehab 			ret = -EIO;
1289a0bf528SMauro Carvalho Chehab 	} else {
1299a0bf528SMauro Carvalho Chehab 		ret = 0;
1309a0bf528SMauro Carvalho Chehab 	}
1319a0bf528SMauro Carvalho Chehab 	return ret;
1329a0bf528SMauro Carvalho Chehab }
1339a0bf528SMauro Carvalho Chehab 
1349a0bf528SMauro Carvalho Chehab /* Software reset */
135467845a1SMauro Carvalho Chehab static int lgdt3302_sw_reset(struct lgdt330x_state *state)
1369a0bf528SMauro Carvalho Chehab {
1379a0bf528SMauro Carvalho Chehab 	u8 ret;
1389a0bf528SMauro Carvalho Chehab 	u8 reset[] = {
1399a0bf528SMauro Carvalho Chehab 		IRQ_MASK,
140467845a1SMauro Carvalho Chehab 		/*
141467845a1SMauro Carvalho Chehab 		 * bit 6 is active low software reset
142467845a1SMauro Carvalho Chehab 		 * bits 5-0 are 1 to mask interrupts
143467845a1SMauro Carvalho Chehab 		 */
144467845a1SMauro Carvalho Chehab 		0x00
1459a0bf528SMauro Carvalho Chehab 	};
1469a0bf528SMauro Carvalho Chehab 
1479a0bf528SMauro Carvalho Chehab 	ret = i2c_write_demod_bytes(state,
1489a0bf528SMauro Carvalho Chehab 				    reset, sizeof(reset));
1499a0bf528SMauro Carvalho Chehab 	if (ret == 0) {
1509a0bf528SMauro Carvalho Chehab 		/* force reset high (inactive) and unmask interrupts */
1519a0bf528SMauro Carvalho Chehab 		reset[1] = 0x7f;
1529a0bf528SMauro Carvalho Chehab 		ret = i2c_write_demod_bytes(state,
1539a0bf528SMauro Carvalho Chehab 					    reset, sizeof(reset));
1549a0bf528SMauro Carvalho Chehab 	}
1559a0bf528SMauro Carvalho Chehab 	return ret;
1569a0bf528SMauro Carvalho Chehab }
1579a0bf528SMauro Carvalho Chehab 
158467845a1SMauro Carvalho Chehab static int lgdt3303_sw_reset(struct lgdt330x_state *state)
1599a0bf528SMauro Carvalho Chehab {
1609a0bf528SMauro Carvalho Chehab 	u8 ret;
1619a0bf528SMauro Carvalho Chehab 	u8 reset[] = {
1629a0bf528SMauro Carvalho Chehab 		0x02,
1639a0bf528SMauro Carvalho Chehab 		0x00 /* bit 0 is active low software reset */
1649a0bf528SMauro Carvalho Chehab 	};
1659a0bf528SMauro Carvalho Chehab 
1669a0bf528SMauro Carvalho Chehab 	ret = i2c_write_demod_bytes(state,
1679a0bf528SMauro Carvalho Chehab 				    reset, sizeof(reset));
1689a0bf528SMauro Carvalho Chehab 	if (ret == 0) {
1699a0bf528SMauro Carvalho Chehab 		/* force reset high (inactive) */
1709a0bf528SMauro Carvalho Chehab 		reset[1] = 0x01;
1719a0bf528SMauro Carvalho Chehab 		ret = i2c_write_demod_bytes(state,
1729a0bf528SMauro Carvalho Chehab 					    reset, sizeof(reset));
1739a0bf528SMauro Carvalho Chehab 	}
1749a0bf528SMauro Carvalho Chehab 	return ret;
1759a0bf528SMauro Carvalho Chehab }
1769a0bf528SMauro Carvalho Chehab 
177467845a1SMauro Carvalho Chehab static int lgdt330x_sw_reset(struct lgdt330x_state *state)
1789a0bf528SMauro Carvalho Chehab {
17923ba635dSMauro Carvalho Chehab 	switch (state->config.demod_chip) {
1809a0bf528SMauro Carvalho Chehab 	case LGDT3302:
181467845a1SMauro Carvalho Chehab 		return lgdt3302_sw_reset(state);
1829a0bf528SMauro Carvalho Chehab 	case LGDT3303:
183467845a1SMauro Carvalho Chehab 		return lgdt3303_sw_reset(state);
1849a0bf528SMauro Carvalho Chehab 	default:
1859a0bf528SMauro Carvalho Chehab 		return -ENODEV;
1869a0bf528SMauro Carvalho Chehab 	}
1879a0bf528SMauro Carvalho Chehab }
1889a0bf528SMauro Carvalho Chehab 
1899a0bf528SMauro Carvalho Chehab static int lgdt330x_init(struct dvb_frontend *fe)
1909a0bf528SMauro Carvalho Chehab {
1911334a7dcSMauro Carvalho Chehab 	struct lgdt330x_state *state = fe->demodulator_priv;
19219bdd0d6SMauro Carvalho Chehab 	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
1931334a7dcSMauro Carvalho Chehab 	char  *chip_name;
1941334a7dcSMauro Carvalho Chehab 	int    err;
1959a0bf528SMauro Carvalho Chehab 	/*
1969a0bf528SMauro Carvalho Chehab 	 * Array of byte pairs <address, value>
1979a0bf528SMauro Carvalho Chehab 	 * to initialize each different chip
1989a0bf528SMauro Carvalho Chehab 	 */
1991334a7dcSMauro Carvalho Chehab 	static const u8 lgdt3302_init_data[] = {
200467845a1SMauro Carvalho Chehab 		/* Use 50MHz param values from spec sheet since xtal is 50 */
201467845a1SMauro Carvalho Chehab 		/*
202467845a1SMauro Carvalho Chehab 		 * Change the value of NCOCTFV[25:0] of carrier
203467845a1SMauro Carvalho Chehab 		 * recovery center frequency register
204467845a1SMauro Carvalho Chehab 		 */
2059a0bf528SMauro Carvalho Chehab 		VSB_CARRIER_FREQ0, 0x00,
2069a0bf528SMauro Carvalho Chehab 		VSB_CARRIER_FREQ1, 0x87,
2079a0bf528SMauro Carvalho Chehab 		VSB_CARRIER_FREQ2, 0x8e,
2089a0bf528SMauro Carvalho Chehab 		VSB_CARRIER_FREQ3, 0x01,
209467845a1SMauro Carvalho Chehab 		/*
210467845a1SMauro Carvalho Chehab 		 * Change the TPCLK pin polarity
211467845a1SMauro Carvalho Chehab 		 * data is valid on falling clock
212467845a1SMauro Carvalho Chehab 		 */
2139a0bf528SMauro Carvalho Chehab 		DEMUX_CONTROL, 0xfb,
214467845a1SMauro Carvalho Chehab 		/*
215467845a1SMauro Carvalho Chehab 		 * Change the value of IFBW[11:0] of
216467845a1SMauro Carvalho Chehab 		 * AGC IF/RF loop filter bandwidth register
217467845a1SMauro Carvalho Chehab 		 */
2189a0bf528SMauro Carvalho Chehab 		AGC_RF_BANDWIDTH0, 0x40,
2199a0bf528SMauro Carvalho Chehab 		AGC_RF_BANDWIDTH1, 0x93,
2209a0bf528SMauro Carvalho Chehab 		AGC_RF_BANDWIDTH2, 0x00,
221467845a1SMauro Carvalho Chehab 		/*
222467845a1SMauro Carvalho Chehab 		 * Change the value of bit 6, 'nINAGCBY' and
223467845a1SMauro Carvalho Chehab 		 * 'NSSEL[1:0] of ACG function control register 2
224467845a1SMauro Carvalho Chehab 		 */
2259a0bf528SMauro Carvalho Chehab 		AGC_FUNC_CTRL2, 0xc6,
226467845a1SMauro Carvalho Chehab 		/*
227467845a1SMauro Carvalho Chehab 		 * Change the value of bit 6 'RFFIX'
228467845a1SMauro Carvalho Chehab 		 * of AGC function control register 3
229467845a1SMauro Carvalho Chehab 		 */
2309a0bf528SMauro Carvalho Chehab 		AGC_FUNC_CTRL3, 0x40,
231467845a1SMauro Carvalho Chehab 		/*
232467845a1SMauro Carvalho Chehab 		 * Set the value of 'INLVTHD' register 0x2a/0x2c
233467845a1SMauro Carvalho Chehab 		 * to 0x7fe
234467845a1SMauro Carvalho Chehab 		 */
2359a0bf528SMauro Carvalho Chehab 		AGC_DELAY0, 0x07,
2369a0bf528SMauro Carvalho Chehab 		AGC_DELAY2, 0xfe,
237467845a1SMauro Carvalho Chehab 		/*
238467845a1SMauro Carvalho Chehab 		 * Change the value of IAGCBW[15:8]
239467845a1SMauro Carvalho Chehab 		 * of inner AGC loop filter bandwidth
240467845a1SMauro Carvalho Chehab 		 */
2419a0bf528SMauro Carvalho Chehab 		AGC_LOOP_BANDWIDTH0, 0x08,
2429a0bf528SMauro Carvalho Chehab 		AGC_LOOP_BANDWIDTH1, 0x9a
2439a0bf528SMauro Carvalho Chehab 	};
2441334a7dcSMauro Carvalho Chehab 	static const u8 lgdt3303_init_data[] = {
2459a0bf528SMauro Carvalho Chehab 		0x4c, 0x14
2469a0bf528SMauro Carvalho Chehab 	};
2471334a7dcSMauro Carvalho Chehab 	static const u8 flip_1_lgdt3303_init_data[] = {
2489a0bf528SMauro Carvalho Chehab 		0x4c, 0x14,
2499a0bf528SMauro Carvalho Chehab 		0x87, 0xf3
2509a0bf528SMauro Carvalho Chehab 	};
2511334a7dcSMauro Carvalho Chehab 	static const u8 flip_2_lgdt3303_init_data[] = {
2529a0bf528SMauro Carvalho Chehab 		0x4c, 0x14,
2539a0bf528SMauro Carvalho Chehab 		0x87, 0xda
2549a0bf528SMauro Carvalho Chehab 	};
2559a0bf528SMauro Carvalho Chehab 
2561334a7dcSMauro Carvalho Chehab 	/*
2571334a7dcSMauro Carvalho Chehab 	 * Hardware reset is done using gpio[0] of cx23880x chip.
2581334a7dcSMauro Carvalho Chehab 	 * I'd like to do it here, but don't know how to find chip address.
2591334a7dcSMauro Carvalho Chehab 	 * cx88-cards.c arranges for the reset bit to be inactive (high).
2601334a7dcSMauro Carvalho Chehab 	 * Maybe there needs to be a callable function in cx88-core or
2611334a7dcSMauro Carvalho Chehab 	 * the caller of this function needs to do it.
2621334a7dcSMauro Carvalho Chehab 	 */
2639a0bf528SMauro Carvalho Chehab 
26423ba635dSMauro Carvalho Chehab 	switch (state->config.demod_chip) {
2659a0bf528SMauro Carvalho Chehab 	case LGDT3302:
2669a0bf528SMauro Carvalho Chehab 		chip_name = "LGDT3302";
2679a0bf528SMauro Carvalho Chehab 		err = i2c_write_demod_bytes(state, lgdt3302_init_data,
2689a0bf528SMauro Carvalho Chehab 					    sizeof(lgdt3302_init_data));
2699a0bf528SMauro Carvalho Chehab 		break;
2709a0bf528SMauro Carvalho Chehab 	case LGDT3303:
2719a0bf528SMauro Carvalho Chehab 		chip_name = "LGDT3303";
27223ba635dSMauro Carvalho Chehab 		switch (state->config.clock_polarity_flip) {
2739a0bf528SMauro Carvalho Chehab 		case 2:
2749a0bf528SMauro Carvalho Chehab 			err = i2c_write_demod_bytes(state,
2759a0bf528SMauro Carvalho Chehab 						    flip_2_lgdt3303_init_data,
2769a0bf528SMauro Carvalho Chehab 						    sizeof(flip_2_lgdt3303_init_data));
2779a0bf528SMauro Carvalho Chehab 			break;
2789a0bf528SMauro Carvalho Chehab 		case 1:
2799a0bf528SMauro Carvalho Chehab 			err = i2c_write_demod_bytes(state,
2809a0bf528SMauro Carvalho Chehab 						    flip_1_lgdt3303_init_data,
2819a0bf528SMauro Carvalho Chehab 						    sizeof(flip_1_lgdt3303_init_data));
2829a0bf528SMauro Carvalho Chehab 			break;
2839a0bf528SMauro Carvalho Chehab 		case 0:
2849a0bf528SMauro Carvalho Chehab 		default:
2859a0bf528SMauro Carvalho Chehab 			err = i2c_write_demod_bytes(state, lgdt3303_init_data,
2869a0bf528SMauro Carvalho Chehab 						    sizeof(lgdt3303_init_data));
2879a0bf528SMauro Carvalho Chehab 		}
2889a0bf528SMauro Carvalho Chehab 		break;
2899a0bf528SMauro Carvalho Chehab 	default:
2909a0bf528SMauro Carvalho Chehab 		chip_name = "undefined";
29123ba635dSMauro Carvalho Chehab 		dev_warn(&state->client->dev,
29223ba635dSMauro Carvalho Chehab 			 "Only LGDT3302 and LGDT3303 are supported chips.\n");
2939a0bf528SMauro Carvalho Chehab 		err = -ENODEV;
2949a0bf528SMauro Carvalho Chehab 	}
29523ba635dSMauro Carvalho Chehab 	dprintk(state, "Initialized the %s chip\n", chip_name);
2969a0bf528SMauro Carvalho Chehab 	if (err < 0)
2979a0bf528SMauro Carvalho Chehab 		return err;
29819bdd0d6SMauro Carvalho Chehab 
29919bdd0d6SMauro Carvalho Chehab 	p->cnr.len = 1;
30019bdd0d6SMauro Carvalho Chehab 	p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
3015f939c36SMauro Carvalho Chehab 	p->block_error.len = 1;
3025f939c36SMauro Carvalho Chehab 	p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
3035f939c36SMauro Carvalho Chehab 	p->block_count.len = 1;
3045f939c36SMauro Carvalho Chehab 	p->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
3055f939c36SMauro Carvalho Chehab 	state->last_stats_time = 0;
30619bdd0d6SMauro Carvalho Chehab 
307467845a1SMauro Carvalho Chehab 	return lgdt330x_sw_reset(state);
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 
3145f939c36SMauro Carvalho Chehab 	*ucblocks = state->ucblocks;
3159a0bf528SMauro Carvalho Chehab 
3169a0bf528SMauro Carvalho Chehab 	return 0;
3179a0bf528SMauro Carvalho Chehab }
3189a0bf528SMauro Carvalho Chehab 
3199a0bf528SMauro Carvalho Chehab static int lgdt330x_set_parameters(struct dvb_frontend *fe)
3209a0bf528SMauro Carvalho Chehab {
3219a0bf528SMauro Carvalho Chehab 	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
3221334a7dcSMauro Carvalho Chehab 	struct lgdt330x_state *state = fe->demodulator_priv;
3239a0bf528SMauro Carvalho Chehab 	/*
3249a0bf528SMauro Carvalho Chehab 	 * Array of byte pairs <address, value>
3259a0bf528SMauro Carvalho Chehab 	 * to initialize 8VSB for lgdt3303 chip 50 MHz IF
3269a0bf528SMauro Carvalho Chehab 	 */
3271334a7dcSMauro Carvalho Chehab 	static const u8 lgdt3303_8vsb_44_data[] = {
3289a0bf528SMauro Carvalho Chehab 		0x04, 0x00,
3299a0bf528SMauro Carvalho Chehab 		0x0d, 0x40,
3309a0bf528SMauro Carvalho Chehab 		0x0e, 0x87,
3319a0bf528SMauro Carvalho Chehab 		0x0f, 0x8e,
3329a0bf528SMauro Carvalho Chehab 		0x10, 0x01,
333467845a1SMauro Carvalho Chehab 		0x47, 0x8b
334467845a1SMauro Carvalho Chehab 	};
3359a0bf528SMauro Carvalho Chehab 	/*
3369a0bf528SMauro Carvalho Chehab 	 * Array of byte pairs <address, value>
3379a0bf528SMauro Carvalho Chehab 	 * to initialize QAM for lgdt3303 chip
3389a0bf528SMauro Carvalho Chehab 	 */
3391334a7dcSMauro Carvalho Chehab 	static const u8 lgdt3303_qam_data[] = {
3409a0bf528SMauro Carvalho Chehab 		0x04, 0x00,
3419a0bf528SMauro Carvalho Chehab 		0x0d, 0x00,
3429a0bf528SMauro Carvalho Chehab 		0x0e, 0x00,
3439a0bf528SMauro Carvalho Chehab 		0x0f, 0x00,
3449a0bf528SMauro Carvalho Chehab 		0x10, 0x00,
3459a0bf528SMauro Carvalho Chehab 		0x51, 0x63,
3469a0bf528SMauro Carvalho Chehab 		0x47, 0x66,
3479a0bf528SMauro Carvalho Chehab 		0x48, 0x66,
3489a0bf528SMauro Carvalho Chehab 		0x4d, 0x1a,
3499a0bf528SMauro Carvalho Chehab 		0x49, 0x08,
350467845a1SMauro Carvalho Chehab 		0x4a, 0x9b
351467845a1SMauro Carvalho Chehab 	};
3521334a7dcSMauro Carvalho Chehab 	u8 top_ctrl_cfg[]   = { TOP_CONTROL, 0x03 };
3539a0bf528SMauro Carvalho Chehab 
3549a0bf528SMauro Carvalho Chehab 	int err = 0;
3559a0bf528SMauro Carvalho Chehab 	/* Change only if we are actually changing the modulation */
3569a0bf528SMauro Carvalho Chehab 	if (state->current_modulation != p->modulation) {
3579a0bf528SMauro Carvalho Chehab 		switch (p->modulation) {
3589a0bf528SMauro Carvalho Chehab 		case VSB_8:
35923ba635dSMauro Carvalho Chehab 			dprintk(state, "VSB_8 MODE\n");
3609a0bf528SMauro Carvalho Chehab 
3619a0bf528SMauro Carvalho Chehab 			/* Select VSB mode */
3629a0bf528SMauro Carvalho Chehab 			top_ctrl_cfg[1] = 0x03;
3639a0bf528SMauro Carvalho Chehab 
3649a0bf528SMauro Carvalho Chehab 			/* Select ANT connector if supported by card */
36523ba635dSMauro Carvalho Chehab 			if (state->config.pll_rf_set)
36623ba635dSMauro Carvalho Chehab 				state->config.pll_rf_set(fe, 1);
3679a0bf528SMauro Carvalho Chehab 
36823ba635dSMauro Carvalho Chehab 			if (state->config.demod_chip == LGDT3303) {
369467845a1SMauro Carvalho Chehab 				err = i2c_write_demod_bytes(state,
370467845a1SMauro Carvalho Chehab 							    lgdt3303_8vsb_44_data,
3719a0bf528SMauro Carvalho Chehab 							    sizeof(lgdt3303_8vsb_44_data));
3729a0bf528SMauro Carvalho Chehab 			}
3739a0bf528SMauro Carvalho Chehab 			break;
3749a0bf528SMauro Carvalho Chehab 
3759a0bf528SMauro Carvalho Chehab 		case QAM_64:
37623ba635dSMauro Carvalho Chehab 			dprintk(state, "QAM_64 MODE\n");
3779a0bf528SMauro Carvalho Chehab 
3789a0bf528SMauro Carvalho Chehab 			/* Select QAM_64 mode */
3799a0bf528SMauro Carvalho Chehab 			top_ctrl_cfg[1] = 0x00;
3809a0bf528SMauro Carvalho Chehab 
3819a0bf528SMauro Carvalho Chehab 			/* Select CABLE connector if supported by card */
38223ba635dSMauro Carvalho Chehab 			if (state->config.pll_rf_set)
38323ba635dSMauro Carvalho Chehab 				state->config.pll_rf_set(fe, 0);
3849a0bf528SMauro Carvalho Chehab 
38523ba635dSMauro Carvalho Chehab 			if (state->config.demod_chip == LGDT3303) {
386467845a1SMauro Carvalho Chehab 				err = i2c_write_demod_bytes(state,
387467845a1SMauro Carvalho Chehab 							    lgdt3303_qam_data,
3889a0bf528SMauro Carvalho Chehab 							    sizeof(lgdt3303_qam_data));
3899a0bf528SMauro Carvalho Chehab 			}
3909a0bf528SMauro Carvalho Chehab 			break;
3919a0bf528SMauro Carvalho Chehab 
3929a0bf528SMauro Carvalho Chehab 		case QAM_256:
39323ba635dSMauro Carvalho Chehab 			dprintk(state, "QAM_256 MODE\n");
3949a0bf528SMauro Carvalho Chehab 
3959a0bf528SMauro Carvalho Chehab 			/* Select QAM_256 mode */
3969a0bf528SMauro Carvalho Chehab 			top_ctrl_cfg[1] = 0x01;
3979a0bf528SMauro Carvalho Chehab 
3989a0bf528SMauro Carvalho Chehab 			/* Select CABLE connector if supported by card */
39923ba635dSMauro Carvalho Chehab 			if (state->config.pll_rf_set)
40023ba635dSMauro Carvalho Chehab 				state->config.pll_rf_set(fe, 0);
4019a0bf528SMauro Carvalho Chehab 
40223ba635dSMauro Carvalho Chehab 			if (state->config.demod_chip == LGDT3303) {
403467845a1SMauro Carvalho Chehab 				err = i2c_write_demod_bytes(state,
404467845a1SMauro Carvalho Chehab 							    lgdt3303_qam_data,
4059a0bf528SMauro Carvalho Chehab 							    sizeof(lgdt3303_qam_data));
4069a0bf528SMauro Carvalho Chehab 			}
4079a0bf528SMauro Carvalho Chehab 			break;
4089a0bf528SMauro Carvalho Chehab 		default:
40923ba635dSMauro Carvalho Chehab 			dev_warn(&state->client->dev,
41023ba635dSMauro Carvalho Chehab 				 "%s: Modulation type(%d) UNSUPPORTED\n",
411467845a1SMauro Carvalho Chehab 				 __func__, p->modulation);
4129a0bf528SMauro Carvalho Chehab 			return -1;
4139a0bf528SMauro Carvalho Chehab 		}
4149a0bf528SMauro Carvalho Chehab 		if (err < 0)
41523ba635dSMauro Carvalho Chehab 			dev_warn(&state->client->dev,
41623ba635dSMauro Carvalho Chehab 				 "%s: error blasting bytes to lgdt3303 for modulation type(%d)\n",
4179a0bf528SMauro Carvalho Chehab 				 __func__, p->modulation);
4189a0bf528SMauro Carvalho Chehab 
4199a0bf528SMauro Carvalho Chehab 		/*
420467845a1SMauro Carvalho Chehab 		 * select serial or parallel MPEG hardware interface
4219a0bf528SMauro Carvalho Chehab 		 * Serial:   0x04 for LGDT3302 or 0x40 for LGDT3303
4229a0bf528SMauro Carvalho Chehab 		 * Parallel: 0x00
4239a0bf528SMauro Carvalho Chehab 		 */
42423ba635dSMauro Carvalho Chehab 		top_ctrl_cfg[1] |= state->config.serial_mpeg;
4259a0bf528SMauro Carvalho Chehab 
4269a0bf528SMauro Carvalho Chehab 		/* Select the requested mode */
4279a0bf528SMauro Carvalho Chehab 		i2c_write_demod_bytes(state, top_ctrl_cfg,
4289a0bf528SMauro Carvalho Chehab 				      sizeof(top_ctrl_cfg));
42923ba635dSMauro Carvalho Chehab 		if (state->config.set_ts_params)
43023ba635dSMauro Carvalho Chehab 			state->config.set_ts_params(fe, 0);
4319a0bf528SMauro Carvalho Chehab 		state->current_modulation = p->modulation;
4329a0bf528SMauro Carvalho Chehab 	}
4339a0bf528SMauro Carvalho Chehab 
4349a0bf528SMauro Carvalho Chehab 	/* Tune to the specified frequency */
4359a0bf528SMauro Carvalho Chehab 	if (fe->ops.tuner_ops.set_params) {
4369a0bf528SMauro Carvalho Chehab 		fe->ops.tuner_ops.set_params(fe);
437467845a1SMauro Carvalho Chehab 		if (fe->ops.i2c_gate_ctrl)
438467845a1SMauro Carvalho Chehab 			fe->ops.i2c_gate_ctrl(fe, 0);
4399a0bf528SMauro Carvalho Chehab 	}
4409a0bf528SMauro Carvalho Chehab 
4419a0bf528SMauro Carvalho Chehab 	/* Keep track of the new frequency */
442467845a1SMauro Carvalho Chehab 	/*
443467845a1SMauro Carvalho Chehab 	 * FIXME this is the wrong way to do this...
444467845a1SMauro Carvalho Chehab 	 * The tuner is shared with the video4linux analog API
445467845a1SMauro Carvalho Chehab 	 */
4469a0bf528SMauro Carvalho Chehab 	state->current_frequency = p->frequency;
4479a0bf528SMauro Carvalho Chehab 
448467845a1SMauro Carvalho Chehab 	lgdt330x_sw_reset(state);
4499a0bf528SMauro Carvalho Chehab 	return 0;
4509a0bf528SMauro Carvalho Chehab }
4519a0bf528SMauro Carvalho Chehab 
4527e3e68bcSMauro Carvalho Chehab static int lgdt330x_get_frontend(struct dvb_frontend *fe,
4537e3e68bcSMauro Carvalho Chehab 				 struct dtv_frontend_properties *p)
4549a0bf528SMauro Carvalho Chehab {
4559a0bf528SMauro Carvalho Chehab 	struct lgdt330x_state *state = fe->demodulator_priv;
4567e3e68bcSMauro Carvalho Chehab 
4579a0bf528SMauro Carvalho Chehab 	p->frequency = state->current_frequency;
4589a0bf528SMauro Carvalho Chehab 	return 0;
4599a0bf528SMauro Carvalho Chehab }
4609a0bf528SMauro Carvalho Chehab 
461467845a1SMauro Carvalho Chehab /*
462467845a1SMauro Carvalho Chehab  * Calculate SNR estimation (scaled by 2^24)
463467845a1SMauro Carvalho Chehab  *
464467845a1SMauro Carvalho Chehab  * 8-VSB SNR equations from LGDT3302 and LGDT3303 datasheets, QAM
465467845a1SMauro Carvalho Chehab  * equations from LGDT3303 datasheet.  VSB is the same between the '02
466467845a1SMauro Carvalho Chehab  * and '03, so maybe QAM is too?  Perhaps someone with a newer datasheet
467467845a1SMauro Carvalho Chehab  * that has QAM information could verify?
468467845a1SMauro Carvalho Chehab  *
469467845a1SMauro Carvalho Chehab  * For 8-VSB: (two ways, take your pick)
470467845a1SMauro Carvalho Chehab  * LGDT3302:
471467845a1SMauro Carvalho Chehab  *   SNR_EQ = 10 * log10(25 * 24^2 / EQ_MSE)
472467845a1SMauro Carvalho Chehab  * LGDT3303:
473467845a1SMauro Carvalho Chehab  *   SNR_EQ = 10 * log10(25 * 32^2 / EQ_MSE)
474467845a1SMauro Carvalho Chehab  * LGDT3302 & LGDT3303:
475467845a1SMauro Carvalho Chehab  *   SNR_PT = 10 * log10(25 * 32^2 / PT_MSE)  (we use this one)
476467845a1SMauro Carvalho Chehab  * For 64-QAM:
477467845a1SMauro Carvalho Chehab  *   SNR    = 10 * log10( 688128   / MSEQAM)
478467845a1SMauro Carvalho Chehab  * For 256-QAM:
479467845a1SMauro Carvalho Chehab  *   SNR    = 10 * log10( 696320   / MSEQAM)
480467845a1SMauro Carvalho Chehab  *
481467845a1SMauro Carvalho Chehab  * We re-write the snr equation as:
482467845a1SMauro Carvalho Chehab  *   SNR * 2^24 = 10*(c - intlog10(MSE))
483467845a1SMauro Carvalho Chehab  * Where for 256-QAM, c = log10(696320) * 2^24, and so on.
484467845a1SMauro Carvalho Chehab  */
4859a0bf528SMauro Carvalho Chehab static u32 calculate_snr(u32 mse, u32 c)
4869a0bf528SMauro Carvalho Chehab {
4879a0bf528SMauro Carvalho Chehab 	if (mse == 0) /* No signal */
4889a0bf528SMauro Carvalho Chehab 		return 0;
4899a0bf528SMauro Carvalho Chehab 
4909a0bf528SMauro Carvalho Chehab 	mse = intlog10(mse);
4919a0bf528SMauro Carvalho Chehab 	if (mse > c) {
492467845a1SMauro Carvalho Chehab 		/*
493467845a1SMauro Carvalho Chehab 		 * Negative SNR, which is possible, but realisticly the
494467845a1SMauro Carvalho Chehab 		 * demod will lose lock before the signal gets this bad.
495467845a1SMauro Carvalho Chehab 		 * The API only allows for unsigned values, so just return 0
496467845a1SMauro Carvalho Chehab 		 */
4979a0bf528SMauro Carvalho Chehab 		return 0;
4989a0bf528SMauro Carvalho Chehab 	}
4999a0bf528SMauro Carvalho Chehab 	return 10 * (c - mse);
5009a0bf528SMauro Carvalho Chehab }
5019a0bf528SMauro Carvalho Chehab 
50219bdd0d6SMauro Carvalho Chehab static int lgdt3302_read_snr(struct dvb_frontend *fe)
5039a0bf528SMauro Carvalho Chehab {
504467845a1SMauro Carvalho Chehab 	struct lgdt330x_state *state = fe->demodulator_priv;
5059a0bf528SMauro Carvalho Chehab 	u8 buf[5];	/* read data buffer */
5069a0bf528SMauro Carvalho Chehab 	u32 noise;	/* noise value */
5079a0bf528SMauro Carvalho Chehab 	u32 c;		/* per-modulation SNR calculation constant */
5089a0bf528SMauro Carvalho Chehab 
5099a0bf528SMauro Carvalho Chehab 	switch (state->current_modulation) {
5109a0bf528SMauro Carvalho Chehab 	case VSB_8:
5119a0bf528SMauro Carvalho Chehab 		i2c_read_demod_bytes(state, LGDT3302_EQPH_ERR0, buf, 5);
5129a0bf528SMauro Carvalho Chehab #ifdef USE_EQMSE
5139a0bf528SMauro Carvalho Chehab 		/* Use Equalizer Mean-Square Error Register */
5149a0bf528SMauro Carvalho Chehab 		/* SNR for ranges from -15.61 to +41.58 */
5159a0bf528SMauro Carvalho Chehab 		noise = ((buf[0] & 7) << 16) | (buf[1] << 8) | buf[2];
5169a0bf528SMauro Carvalho Chehab 		c = 69765745; /* log10(25*24^2)*2^24 */
5179a0bf528SMauro Carvalho Chehab #else
5189a0bf528SMauro Carvalho Chehab 		/* Use Phase Tracker Mean-Square Error Register */
5199a0bf528SMauro Carvalho Chehab 		/* SNR for ranges from -13.11 to +44.08 */
5209a0bf528SMauro Carvalho Chehab 		noise = ((buf[0] & 7 << 3) << 13) | (buf[3] << 8) | buf[4];
5219a0bf528SMauro Carvalho Chehab 		c = 73957994; /* log10(25*32^2)*2^24 */
5229a0bf528SMauro Carvalho Chehab #endif
5239a0bf528SMauro Carvalho Chehab 		break;
5249a0bf528SMauro Carvalho Chehab 	case QAM_64:
5259a0bf528SMauro Carvalho Chehab 	case QAM_256:
5269a0bf528SMauro Carvalho Chehab 		i2c_read_demod_bytes(state, CARRIER_MSEQAM1, buf, 2);
5279a0bf528SMauro Carvalho Chehab 		noise = ((buf[0] & 3) << 8) | buf[1];
5289a0bf528SMauro Carvalho Chehab 		c = state->current_modulation == QAM_64 ? 97939837 : 98026066;
5299a0bf528SMauro Carvalho Chehab 		/* log10(688128)*2^24 and log10(696320)*2^24 */
5309a0bf528SMauro Carvalho Chehab 		break;
5319a0bf528SMauro Carvalho Chehab 	default:
53223ba635dSMauro Carvalho Chehab 		dev_err(&state->client->dev,
53323ba635dSMauro Carvalho Chehab 			"%s: Modulation set to unsupported value\n",
5349a0bf528SMauro Carvalho Chehab 			__func__);
53519bdd0d6SMauro Carvalho Chehab 
53619bdd0d6SMauro Carvalho Chehab 		state->snr = 0;
53719bdd0d6SMauro Carvalho Chehab 
5389a0bf528SMauro Carvalho Chehab 		return -EREMOTEIO; /* return -EDRIVER_IS_GIBBERED; */
5399a0bf528SMauro Carvalho Chehab 	}
5409a0bf528SMauro Carvalho Chehab 
5419a0bf528SMauro Carvalho Chehab 	state->snr = calculate_snr(noise, c);
5429a0bf528SMauro Carvalho Chehab 
54323ba635dSMauro Carvalho Chehab 	dprintk(state, "noise = 0x%08x, snr = %d.%02d dB\n", noise,
5449a0bf528SMauro Carvalho Chehab 		state->snr >> 24, (((state->snr >> 8) & 0xffff) * 100) >> 16);
5459a0bf528SMauro Carvalho Chehab 
5469a0bf528SMauro Carvalho Chehab 	return 0;
5479a0bf528SMauro Carvalho Chehab }
5489a0bf528SMauro Carvalho Chehab 
54919bdd0d6SMauro Carvalho Chehab static int lgdt3303_read_snr(struct dvb_frontend *fe)
5509a0bf528SMauro Carvalho Chehab {
551467845a1SMauro Carvalho Chehab 	struct lgdt330x_state *state = fe->demodulator_priv;
5529a0bf528SMauro Carvalho Chehab 	u8 buf[5];	/* read data buffer */
5539a0bf528SMauro Carvalho Chehab 	u32 noise;	/* noise value */
5549a0bf528SMauro Carvalho Chehab 	u32 c;		/* per-modulation SNR calculation constant */
5559a0bf528SMauro Carvalho Chehab 
5569a0bf528SMauro Carvalho Chehab 	switch (state->current_modulation) {
5579a0bf528SMauro Carvalho Chehab 	case VSB_8:
5589a0bf528SMauro Carvalho Chehab 		i2c_read_demod_bytes(state, LGDT3303_EQPH_ERR0, buf, 5);
5599a0bf528SMauro Carvalho Chehab #ifdef USE_EQMSE
5609a0bf528SMauro Carvalho Chehab 		/* Use Equalizer Mean-Square Error Register */
5619a0bf528SMauro Carvalho Chehab 		/* SNR for ranges from -16.12 to +44.08 */
5629a0bf528SMauro Carvalho Chehab 		noise = ((buf[0] & 0x78) << 13) | (buf[1] << 8) | buf[2];
5639a0bf528SMauro Carvalho Chehab 		c = 73957994; /* log10(25*32^2)*2^24 */
5649a0bf528SMauro Carvalho Chehab #else
5659a0bf528SMauro Carvalho Chehab 		/* Use Phase Tracker Mean-Square Error Register */
5669a0bf528SMauro Carvalho Chehab 		/* SNR for ranges from -13.11 to +44.08 */
5679a0bf528SMauro Carvalho Chehab 		noise = ((buf[0] & 7) << 16) | (buf[3] << 8) | buf[4];
5689a0bf528SMauro Carvalho Chehab 		c = 73957994; /* log10(25*32^2)*2^24 */
5699a0bf528SMauro Carvalho Chehab #endif
5709a0bf528SMauro Carvalho Chehab 		break;
5719a0bf528SMauro Carvalho Chehab 	case QAM_64:
5729a0bf528SMauro Carvalho Chehab 	case QAM_256:
5739a0bf528SMauro Carvalho Chehab 		i2c_read_demod_bytes(state, CARRIER_MSEQAM1, buf, 2);
5749a0bf528SMauro Carvalho Chehab 		noise = (buf[0] << 8) | buf[1];
5759a0bf528SMauro Carvalho Chehab 		c = state->current_modulation == QAM_64 ? 97939837 : 98026066;
5769a0bf528SMauro Carvalho Chehab 		/* log10(688128)*2^24 and log10(696320)*2^24 */
5779a0bf528SMauro Carvalho Chehab 		break;
5789a0bf528SMauro Carvalho Chehab 	default:
57923ba635dSMauro Carvalho Chehab 		dev_err(&state->client->dev,
58023ba635dSMauro Carvalho Chehab 			"%s: Modulation set to unsupported value\n",
5819a0bf528SMauro Carvalho Chehab 			__func__);
58219bdd0d6SMauro Carvalho Chehab 		state->snr = 0;
5839a0bf528SMauro Carvalho Chehab 		return -EREMOTEIO; /* return -EDRIVER_IS_GIBBERED; */
5849a0bf528SMauro Carvalho Chehab 	}
5859a0bf528SMauro Carvalho Chehab 
5869a0bf528SMauro Carvalho Chehab 	state->snr = calculate_snr(noise, c);
5879a0bf528SMauro Carvalho Chehab 
58823ba635dSMauro Carvalho Chehab 	dprintk(state, "noise = 0x%08x, snr = %d.%02d dB\n", noise,
5899a0bf528SMauro Carvalho Chehab 		state->snr >> 24, (((state->snr >> 8) & 0xffff) * 100) >> 16);
5909a0bf528SMauro Carvalho Chehab 
5919a0bf528SMauro Carvalho Chehab 	return 0;
5929a0bf528SMauro Carvalho Chehab }
5939a0bf528SMauro Carvalho Chehab 
59419bdd0d6SMauro Carvalho Chehab static int lgdt330x_read_snr(struct dvb_frontend *fe, u16 *snr)
59519bdd0d6SMauro Carvalho Chehab {
59619bdd0d6SMauro Carvalho Chehab 	struct lgdt330x_state *state = fe->demodulator_priv;
59719bdd0d6SMauro Carvalho Chehab 
59819bdd0d6SMauro Carvalho Chehab 	*snr = (state->snr) >> 16; /* Convert from 8.24 fixed-point to 8.8 */
59919bdd0d6SMauro Carvalho Chehab 
60019bdd0d6SMauro Carvalho Chehab 	return 0;
60119bdd0d6SMauro Carvalho Chehab }
60219bdd0d6SMauro Carvalho Chehab 
6039a0bf528SMauro Carvalho Chehab static int lgdt330x_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
6049a0bf528SMauro Carvalho Chehab {
6059a0bf528SMauro Carvalho Chehab 	/* Calculate Strength from SNR up to 35dB */
606467845a1SMauro Carvalho Chehab 	/*
607467845a1SMauro Carvalho Chehab 	 * Even though the SNR can go higher than 35dB, there is some comfort
608467845a1SMauro Carvalho Chehab 	 * factor in having a range of strong signals that can show at 100%
609467845a1SMauro Carvalho Chehab 	 */
610467845a1SMauro Carvalho Chehab 	struct lgdt330x_state *state = fe->demodulator_priv;
6119a0bf528SMauro Carvalho Chehab 	u16 snr;
6129a0bf528SMauro Carvalho Chehab 	int ret;
6139a0bf528SMauro Carvalho Chehab 
6149a0bf528SMauro Carvalho Chehab 	ret = fe->ops.read_snr(fe, &snr);
6159a0bf528SMauro Carvalho Chehab 	if (ret != 0)
6169a0bf528SMauro Carvalho Chehab 		return ret;
6179a0bf528SMauro Carvalho Chehab 	/* Rather than use the 8.8 value snr, use state->snr which is 8.24 */
6189a0bf528SMauro Carvalho Chehab 	/* scale the range 0 - 35*2^24 into 0 - 65535 */
6199a0bf528SMauro Carvalho Chehab 	if (state->snr >= 8960 * 0x10000)
6209a0bf528SMauro Carvalho Chehab 		*strength = 0xffff;
6219a0bf528SMauro Carvalho Chehab 	else
6229a0bf528SMauro Carvalho Chehab 		*strength = state->snr / 8960;
6239a0bf528SMauro Carvalho Chehab 
6249a0bf528SMauro Carvalho Chehab 	return 0;
6259a0bf528SMauro Carvalho Chehab }
6269a0bf528SMauro Carvalho Chehab 
62753d41728SMauro Carvalho Chehab 
62853d41728SMauro Carvalho Chehab static int lgdt3302_read_status(struct dvb_frontend *fe,
62953d41728SMauro Carvalho Chehab 				enum fe_status *status)
63053d41728SMauro Carvalho Chehab {
63153d41728SMauro Carvalho Chehab 	struct lgdt330x_state *state = fe->demodulator_priv;
63219bdd0d6SMauro Carvalho Chehab 	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
63353d41728SMauro Carvalho Chehab 	u8 buf[3];
6345f939c36SMauro Carvalho Chehab 	int err;
63553d41728SMauro Carvalho Chehab 
63653d41728SMauro Carvalho Chehab 	*status = 0; /* Reset status result */
63753d41728SMauro Carvalho Chehab 
63853d41728SMauro Carvalho Chehab 	/* AGC status register */
63953d41728SMauro Carvalho Chehab 	i2c_read_demod_bytes(state, AGC_STATUS, buf, 1);
64053d41728SMauro Carvalho Chehab 	dprintk(state, "AGC_STATUS = 0x%02x\n", buf[0]);
64153d41728SMauro Carvalho Chehab 	if ((buf[0] & 0x0c) == 0x8) {
64253d41728SMauro Carvalho Chehab 		/*
64353d41728SMauro Carvalho Chehab 		 * Test signal does not exist flag
64453d41728SMauro Carvalho Chehab 		 * as well as the AGC lock flag.
64553d41728SMauro Carvalho Chehab 		 */
64653d41728SMauro Carvalho Chehab 		*status |= FE_HAS_SIGNAL;
64753d41728SMauro Carvalho Chehab 	}
64853d41728SMauro Carvalho Chehab 
64953d41728SMauro Carvalho Chehab 	/*
65053d41728SMauro Carvalho Chehab 	 * You must set the Mask bits to 1 in the IRQ_MASK in order
65153d41728SMauro Carvalho Chehab 	 * to see that status bit in the IRQ_STATUS register.
65253d41728SMauro Carvalho Chehab 	 * This is done in SwReset();
65353d41728SMauro Carvalho Chehab 	 */
65453d41728SMauro Carvalho Chehab 
65553d41728SMauro Carvalho Chehab 	/* signal status */
65653d41728SMauro Carvalho Chehab 	i2c_read_demod_bytes(state, TOP_CONTROL, buf, sizeof(buf));
65753d41728SMauro Carvalho Chehab 	dprintk(state,
65853d41728SMauro Carvalho Chehab 		"TOP_CONTROL = 0x%02x, IRO_MASK = 0x%02x, IRQ_STATUS = 0x%02x\n",
65953d41728SMauro Carvalho Chehab 		buf[0], buf[1], buf[2]);
66053d41728SMauro Carvalho Chehab 
66153d41728SMauro Carvalho Chehab 	/* sync status */
66253d41728SMauro Carvalho Chehab 	if ((buf[2] & 0x03) == 0x01)
66353d41728SMauro Carvalho Chehab 		*status |= FE_HAS_SYNC;
66453d41728SMauro Carvalho Chehab 
66553d41728SMauro Carvalho Chehab 	/* FEC error status */
66653d41728SMauro Carvalho Chehab 	if ((buf[2] & 0x0c) == 0x08)
66753d41728SMauro Carvalho Chehab 		*status |= FE_HAS_LOCK | FE_HAS_VITERBI;
66853d41728SMauro Carvalho Chehab 
66953d41728SMauro Carvalho Chehab 	/* Carrier Recovery Lock Status Register */
67053d41728SMauro Carvalho Chehab 	i2c_read_demod_bytes(state, CARRIER_LOCK, buf, 1);
67153d41728SMauro Carvalho Chehab 	dprintk(state, "CARRIER_LOCK = 0x%02x\n", buf[0]);
67253d41728SMauro Carvalho Chehab 	switch (state->current_modulation) {
67353d41728SMauro Carvalho Chehab 	case QAM_256:
67453d41728SMauro Carvalho Chehab 	case QAM_64:
67553d41728SMauro Carvalho Chehab 		/* Need to understand why there are 3 lock levels here */
67653d41728SMauro Carvalho Chehab 		if ((buf[0] & 0x07) == 0x07)
67753d41728SMauro Carvalho Chehab 			*status |= FE_HAS_CARRIER;
67853d41728SMauro Carvalho Chehab 		break;
67953d41728SMauro Carvalho Chehab 	case VSB_8:
68053d41728SMauro Carvalho Chehab 		if ((buf[0] & 0x80) == 0x80)
68153d41728SMauro Carvalho Chehab 			*status |= FE_HAS_CARRIER;
68253d41728SMauro Carvalho Chehab 		break;
68353d41728SMauro Carvalho Chehab 	default:
68453d41728SMauro Carvalho Chehab 		dev_warn(&state->client->dev,
68553d41728SMauro Carvalho Chehab 			 "%s: Modulation set to unsupported value\n",
68653d41728SMauro Carvalho Chehab 			 __func__);
68753d41728SMauro Carvalho Chehab 	}
68853d41728SMauro Carvalho Chehab 
6895f939c36SMauro Carvalho Chehab 	if (!(*status & FE_HAS_LOCK)) {
6905f939c36SMauro Carvalho Chehab 		p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
6915f939c36SMauro Carvalho Chehab 		p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
6925f939c36SMauro Carvalho Chehab 		p->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
6935f939c36SMauro Carvalho Chehab 		return 0;
6945f939c36SMauro Carvalho Chehab 	}
6955f939c36SMauro Carvalho Chehab 
6965f939c36SMauro Carvalho Chehab 	if (state->last_stats_time &&
6975f939c36SMauro Carvalho Chehab 	    time_is_after_jiffies(state->last_stats_time))
6985f939c36SMauro Carvalho Chehab 		return 0;
6995f939c36SMauro Carvalho Chehab 
7005f939c36SMauro Carvalho Chehab 	state->last_stats_time = jiffies + msecs_to_jiffies(1000);
7015f939c36SMauro Carvalho Chehab 
7025f939c36SMauro Carvalho Chehab 	err = lgdt3302_read_snr(fe);
7035f939c36SMauro Carvalho Chehab 	if (!err) {
70419bdd0d6SMauro Carvalho Chehab 		p->cnr.stat[0].scale = FE_SCALE_DECIBEL;
70519bdd0d6SMauro Carvalho Chehab 		p->cnr.stat[0].svalue = (((u64)state->snr) * 1000) >> 24;
70619bdd0d6SMauro Carvalho Chehab 	} else {
70719bdd0d6SMauro Carvalho Chehab 		p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
70819bdd0d6SMauro Carvalho Chehab 	}
70919bdd0d6SMauro Carvalho Chehab 
7105f939c36SMauro Carvalho Chehab 	err = i2c_read_demod_bytes(state, LGDT3302_PACKET_ERR_COUNTER1,
7115f939c36SMauro Carvalho Chehab 					   buf, sizeof(buf));
7125f939c36SMauro Carvalho Chehab 	if (!err) {
7135f939c36SMauro Carvalho Chehab 		state->ucblocks = (buf[0] << 8) | buf[1];
7145f939c36SMauro Carvalho Chehab 
7155f939c36SMauro Carvalho Chehab 		dprintk(state, "UCB = 0x%02x\n", state->ucblocks);
7165f939c36SMauro Carvalho Chehab 
7175f939c36SMauro Carvalho Chehab 		p->block_error.stat[0].uvalue += state->ucblocks;
7185f939c36SMauro Carvalho Chehab 		/* FIXME: what's the basis for block count */
7195f939c36SMauro Carvalho Chehab 		p->block_count.stat[0].uvalue += 10000;
7205f939c36SMauro Carvalho Chehab 
7215f939c36SMauro Carvalho Chehab 		p->block_error.stat[0].scale = FE_SCALE_COUNTER;
7225f939c36SMauro Carvalho Chehab 		p->block_count.stat[0].scale = FE_SCALE_COUNTER;
7235f939c36SMauro Carvalho Chehab 	} else {
7245f939c36SMauro Carvalho Chehab 		p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
7255f939c36SMauro Carvalho Chehab 		p->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
7265f939c36SMauro Carvalho Chehab 	}
7275f939c36SMauro Carvalho Chehab 
72853d41728SMauro Carvalho Chehab 	return 0;
72953d41728SMauro Carvalho Chehab }
73053d41728SMauro Carvalho Chehab 
73153d41728SMauro Carvalho Chehab static int lgdt3303_read_status(struct dvb_frontend *fe,
73253d41728SMauro Carvalho Chehab 				enum fe_status *status)
73353d41728SMauro Carvalho Chehab {
73453d41728SMauro Carvalho Chehab 	struct lgdt330x_state *state = fe->demodulator_priv;
73519bdd0d6SMauro Carvalho Chehab 	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
73653d41728SMauro Carvalho Chehab 	u8 buf[3];
7375f939c36SMauro Carvalho Chehab 	int err;
73853d41728SMauro Carvalho Chehab 
73953d41728SMauro Carvalho Chehab 	*status = 0; /* Reset status result */
74053d41728SMauro Carvalho Chehab 
74153d41728SMauro Carvalho Chehab 	/* lgdt3303 AGC status register */
74253d41728SMauro Carvalho Chehab 	err = i2c_read_demod_bytes(state, 0x58, buf, 1);
74353d41728SMauro Carvalho Chehab 	if (err < 0)
74453d41728SMauro Carvalho Chehab 		return err;
74553d41728SMauro Carvalho Chehab 
74653d41728SMauro Carvalho Chehab 	dprintk(state, "AGC_STATUS = 0x%02x\n", buf[0]);
74753d41728SMauro Carvalho Chehab 	if ((buf[0] & 0x21) == 0x01) {
74853d41728SMauro Carvalho Chehab 		/*
74953d41728SMauro Carvalho Chehab 		 * Test input signal does not exist flag
75053d41728SMauro Carvalho Chehab 		 * as well as the AGC lock flag.
75153d41728SMauro Carvalho Chehab 		 */
75253d41728SMauro Carvalho Chehab 		*status |= FE_HAS_SIGNAL;
75353d41728SMauro Carvalho Chehab 	}
75453d41728SMauro Carvalho Chehab 
75553d41728SMauro Carvalho Chehab 	/* Carrier Recovery Lock Status Register */
75653d41728SMauro Carvalho Chehab 	i2c_read_demod_bytes(state, CARRIER_LOCK, buf, 1);
75753d41728SMauro Carvalho Chehab 	dprintk(state, "CARRIER_LOCK = 0x%02x\n", buf[0]);
75853d41728SMauro Carvalho Chehab 	switch (state->current_modulation) {
75953d41728SMauro Carvalho Chehab 	case QAM_256:
76053d41728SMauro Carvalho Chehab 	case QAM_64:
76153d41728SMauro Carvalho Chehab 		/* Need to understand why there are 3 lock levels here */
76253d41728SMauro Carvalho Chehab 		if ((buf[0] & 0x07) == 0x07)
76353d41728SMauro Carvalho Chehab 			*status |= FE_HAS_CARRIER;
76453d41728SMauro Carvalho Chehab 		else
76553d41728SMauro Carvalho Chehab 			break;
76653d41728SMauro Carvalho Chehab 		i2c_read_demod_bytes(state, 0x8a, buf, 1);
76753d41728SMauro Carvalho Chehab 		dprintk(state, "QAM LOCK = 0x%02x\n", buf[0]);
76853d41728SMauro Carvalho Chehab 
76953d41728SMauro Carvalho Chehab 		if ((buf[0] & 0x04) == 0x04)
77053d41728SMauro Carvalho Chehab 			*status |= FE_HAS_SYNC;
77153d41728SMauro Carvalho Chehab 		if ((buf[0] & 0x01) == 0x01)
77253d41728SMauro Carvalho Chehab 			*status |= FE_HAS_LOCK;
77353d41728SMauro Carvalho Chehab 		if ((buf[0] & 0x08) == 0x08)
77453d41728SMauro Carvalho Chehab 			*status |= FE_HAS_VITERBI;
77553d41728SMauro Carvalho Chehab 		break;
77653d41728SMauro Carvalho Chehab 	case VSB_8:
77753d41728SMauro Carvalho Chehab 		if ((buf[0] & 0x80) == 0x80)
77853d41728SMauro Carvalho Chehab 			*status |= FE_HAS_CARRIER;
77953d41728SMauro Carvalho Chehab 		else
78053d41728SMauro Carvalho Chehab 			break;
78153d41728SMauro Carvalho Chehab 		i2c_read_demod_bytes(state, 0x38, buf, 1);
78253d41728SMauro Carvalho Chehab 		dprintk(state, "8-VSB LOCK = 0x%02x\n", buf[0]);
78353d41728SMauro Carvalho Chehab 
78453d41728SMauro Carvalho Chehab 		if ((buf[0] & 0x02) == 0x00)
78553d41728SMauro Carvalho Chehab 			*status |= FE_HAS_SYNC;
78653d41728SMauro Carvalho Chehab 		if ((buf[0] & 0xfd) == 0x01)
78753d41728SMauro Carvalho Chehab 			*status |= FE_HAS_VITERBI | FE_HAS_LOCK;
78853d41728SMauro Carvalho Chehab 		break;
78953d41728SMauro Carvalho Chehab 	default:
79053d41728SMauro Carvalho Chehab 		dev_warn(&state->client->dev,
79153d41728SMauro Carvalho Chehab 			 "%s: Modulation set to unsupported value\n",
79253d41728SMauro Carvalho Chehab 			 __func__);
79353d41728SMauro Carvalho Chehab 	}
79419bdd0d6SMauro Carvalho Chehab 
7955f939c36SMauro Carvalho Chehab 	if (!(*status & FE_HAS_LOCK)) {
7965f939c36SMauro Carvalho Chehab 		p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
7975f939c36SMauro Carvalho Chehab 		p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
7985f939c36SMauro Carvalho Chehab 		p->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
7995f939c36SMauro Carvalho Chehab 		return 0;
8005f939c36SMauro Carvalho Chehab 	}
8015f939c36SMauro Carvalho Chehab 
8025f939c36SMauro Carvalho Chehab 	if (state->last_stats_time &&
8035f939c36SMauro Carvalho Chehab 	    time_is_after_jiffies(state->last_stats_time))
8045f939c36SMauro Carvalho Chehab 		return 0;
8055f939c36SMauro Carvalho Chehab 
8065f939c36SMauro Carvalho Chehab 	state->last_stats_time = jiffies + msecs_to_jiffies(1000);
8075f939c36SMauro Carvalho Chehab 
8085f939c36SMauro Carvalho Chehab 	err = lgdt3303_read_snr(fe);
8095f939c36SMauro Carvalho Chehab 	if (!err) {
81019bdd0d6SMauro Carvalho Chehab 		p->cnr.stat[0].scale = FE_SCALE_DECIBEL;
81119bdd0d6SMauro Carvalho Chehab 		p->cnr.stat[0].svalue = (((u64)state->snr) * 1000) >> 24;
81219bdd0d6SMauro Carvalho Chehab 	} else {
81319bdd0d6SMauro Carvalho Chehab 		p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
81419bdd0d6SMauro Carvalho Chehab 	}
81519bdd0d6SMauro Carvalho Chehab 
8165f939c36SMauro Carvalho Chehab 	err = i2c_read_demod_bytes(state, LGDT3303_PACKET_ERR_COUNTER1,
8175f939c36SMauro Carvalho Chehab 					   buf, sizeof(buf));
8185f939c36SMauro Carvalho Chehab 	if (!err) {
8195f939c36SMauro Carvalho Chehab 		state->ucblocks = (buf[0] << 8) | buf[1];
8205f939c36SMauro Carvalho Chehab 
8215f939c36SMauro Carvalho Chehab 		dprintk(state, "UCB = 0x%02x\n", state->ucblocks);
8225f939c36SMauro Carvalho Chehab 
8235f939c36SMauro Carvalho Chehab 		p->block_error.stat[0].uvalue += state->ucblocks;
8245f939c36SMauro Carvalho Chehab 		/* FIXME: what's the basis for block count */
8255f939c36SMauro Carvalho Chehab 		p->block_count.stat[0].uvalue += 10000;
8265f939c36SMauro Carvalho Chehab 
8275f939c36SMauro Carvalho Chehab 		p->block_error.stat[0].scale = FE_SCALE_COUNTER;
8285f939c36SMauro Carvalho Chehab 		p->block_count.stat[0].scale = FE_SCALE_COUNTER;
8295f939c36SMauro Carvalho Chehab 	} else {
8305f939c36SMauro Carvalho Chehab 		p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
8315f939c36SMauro Carvalho Chehab 		p->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
8325f939c36SMauro Carvalho Chehab 	}
8335f939c36SMauro Carvalho Chehab 
83453d41728SMauro Carvalho Chehab 	return 0;
83553d41728SMauro Carvalho Chehab }
83653d41728SMauro Carvalho Chehab 
837467845a1SMauro Carvalho Chehab static int
838467845a1SMauro Carvalho Chehab lgdt330x_get_tune_settings(struct dvb_frontend *fe,
839467845a1SMauro Carvalho Chehab 			   struct dvb_frontend_tune_settings *fe_tune_settings)
8409a0bf528SMauro Carvalho Chehab {
8419a0bf528SMauro Carvalho Chehab 	/* I have no idea about this - it may not be needed */
8429a0bf528SMauro Carvalho Chehab 	fe_tune_settings->min_delay_ms = 500;
8439a0bf528SMauro Carvalho Chehab 	fe_tune_settings->step_size = 0;
8449a0bf528SMauro Carvalho Chehab 	fe_tune_settings->max_drift = 0;
8459a0bf528SMauro Carvalho Chehab 	return 0;
8469a0bf528SMauro Carvalho Chehab }
8479a0bf528SMauro Carvalho Chehab 
8489a0bf528SMauro Carvalho Chehab static void lgdt330x_release(struct dvb_frontend *fe)
8499a0bf528SMauro Carvalho Chehab {
850467845a1SMauro Carvalho Chehab 	struct lgdt330x_state *state = fe->demodulator_priv;
85123ba635dSMauro Carvalho Chehab 	struct i2c_client *client = state->client;
852467845a1SMauro Carvalho Chehab 
85323ba635dSMauro Carvalho Chehab 	dev_dbg(&client->dev, "\n");
85423ba635dSMauro Carvalho Chehab 
85523ba635dSMauro Carvalho Chehab 	i2c_unregister_device(client);
85623ba635dSMauro Carvalho Chehab }
85723ba635dSMauro Carvalho Chehab 
85823ba635dSMauro Carvalho Chehab static struct dvb_frontend *lgdt330x_get_dvb_frontend(struct i2c_client *client)
85923ba635dSMauro Carvalho Chehab {
86023ba635dSMauro Carvalho Chehab 	struct lgdt330x_state *state = i2c_get_clientdata(client);
86123ba635dSMauro Carvalho Chehab 
86223ba635dSMauro Carvalho Chehab 	dev_dbg(&client->dev, "\n");
86323ba635dSMauro Carvalho Chehab 
86423ba635dSMauro Carvalho Chehab 	return &state->frontend;
8659a0bf528SMauro Carvalho Chehab }
8669a0bf528SMauro Carvalho Chehab 
867bd336e63SMax Kellermann static const struct dvb_frontend_ops lgdt3302_ops;
868bd336e63SMax Kellermann static const struct dvb_frontend_ops lgdt3303_ops;
8699a0bf528SMauro Carvalho Chehab 
87023ba635dSMauro Carvalho Chehab static int lgdt330x_probe(struct i2c_client *client,
87123ba635dSMauro Carvalho Chehab 			  const struct i2c_device_id *id)
8729a0bf528SMauro Carvalho Chehab {
8739a0bf528SMauro Carvalho Chehab 	struct lgdt330x_state *state = NULL;
8749a0bf528SMauro Carvalho Chehab 	u8 buf[1];
8759a0bf528SMauro Carvalho Chehab 
8769a0bf528SMauro Carvalho Chehab 	/* Allocate memory for the internal state */
877467845a1SMauro Carvalho Chehab 	state = kzalloc(sizeof(*state), GFP_KERNEL);
878467845a1SMauro Carvalho Chehab 	if (!state)
8799a0bf528SMauro Carvalho Chehab 		goto error;
8809a0bf528SMauro Carvalho Chehab 
8819a0bf528SMauro Carvalho Chehab 	/* Setup the state */
88223ba635dSMauro Carvalho Chehab 	memcpy(&state->config, client->dev.platform_data,
88323ba635dSMauro Carvalho Chehab 	       sizeof(state->config));
88423ba635dSMauro Carvalho Chehab 	i2c_set_clientdata(client, state);
88523ba635dSMauro Carvalho Chehab 	state->client = client;
8869a0bf528SMauro Carvalho Chehab 
8879a0bf528SMauro Carvalho Chehab 	/* Create dvb_frontend */
88823ba635dSMauro Carvalho Chehab 	switch (state->config.demod_chip) {
8899a0bf528SMauro Carvalho Chehab 	case LGDT3302:
890467845a1SMauro Carvalho Chehab 		memcpy(&state->frontend.ops, &lgdt3302_ops,
891467845a1SMauro Carvalho Chehab 		       sizeof(struct dvb_frontend_ops));
8929a0bf528SMauro Carvalho Chehab 		break;
8939a0bf528SMauro Carvalho Chehab 	case LGDT3303:
894467845a1SMauro Carvalho Chehab 		memcpy(&state->frontend.ops, &lgdt3303_ops,
895467845a1SMauro Carvalho Chehab 		       sizeof(struct dvb_frontend_ops));
8969a0bf528SMauro Carvalho Chehab 		break;
8979a0bf528SMauro Carvalho Chehab 	default:
8989a0bf528SMauro Carvalho Chehab 		goto error;
8999a0bf528SMauro Carvalho Chehab 	}
9009a0bf528SMauro Carvalho Chehab 	state->frontend.demodulator_priv = state;
9019a0bf528SMauro Carvalho Chehab 
90223ba635dSMauro Carvalho Chehab 	/* Setup get frontend callback */
90323ba635dSMauro Carvalho Chehab 	state->config.get_dvb_frontend = lgdt330x_get_dvb_frontend;
90423ba635dSMauro Carvalho Chehab 
9059a0bf528SMauro Carvalho Chehab 	/* Verify communication with demod chip */
9069a0bf528SMauro Carvalho Chehab 	if (i2c_read_demod_bytes(state, 2, buf, 1))
9079a0bf528SMauro Carvalho Chehab 		goto error;
9089a0bf528SMauro Carvalho Chehab 
9099a0bf528SMauro Carvalho Chehab 	state->current_frequency = -1;
9109a0bf528SMauro Carvalho Chehab 	state->current_modulation = -1;
9119a0bf528SMauro Carvalho Chehab 
91223ba635dSMauro Carvalho Chehab 	dev_info(&state->client->dev,
91323ba635dSMauro Carvalho Chehab 		"Demod loaded for LGDT330%s chip\n",
91423ba635dSMauro Carvalho Chehab 		state->config.demod_chip == LGDT3302 ? "2" : "3");
915ff093612SMauro Carvalho Chehab 
91623ba635dSMauro Carvalho Chehab 	return 0;
9179a0bf528SMauro Carvalho Chehab 
9189a0bf528SMauro Carvalho Chehab error:
9199a0bf528SMauro Carvalho Chehab 	kfree(state);
92089eaaf2dSMauro Carvalho Chehab 	if (debug)
92189eaaf2dSMauro Carvalho Chehab 		dev_printk(KERN_DEBUG, &client->dev, "Error loading lgdt330x driver\n");
92223ba635dSMauro Carvalho Chehab 	return -ENODEV;
92323ba635dSMauro Carvalho Chehab }
92423ba635dSMauro Carvalho Chehab struct dvb_frontend *lgdt330x_attach(const struct lgdt330x_config *_config,
92523ba635dSMauro Carvalho Chehab 				     u8 demod_address,
92623ba635dSMauro Carvalho Chehab 				     struct i2c_adapter *i2c)
92723ba635dSMauro Carvalho Chehab {
92823ba635dSMauro Carvalho Chehab 	struct i2c_client *client;
92923ba635dSMauro Carvalho Chehab 	struct i2c_board_info board_info = {};
93023ba635dSMauro Carvalho Chehab 	struct lgdt330x_config config = *_config;
93123ba635dSMauro Carvalho Chehab 
93223ba635dSMauro Carvalho Chehab 	strlcpy(board_info.type, "lgdt330x", sizeof(board_info.type));
93323ba635dSMauro Carvalho Chehab 	board_info.addr = demod_address;
93423ba635dSMauro Carvalho Chehab 	board_info.platform_data = &config;
93523ba635dSMauro Carvalho Chehab 	client = i2c_new_device(i2c, &board_info);
93623ba635dSMauro Carvalho Chehab 	if (!client || !client->dev.driver)
9379a0bf528SMauro Carvalho Chehab 		return NULL;
93823ba635dSMauro Carvalho Chehab 
93923ba635dSMauro Carvalho Chehab 	return lgdt330x_get_dvb_frontend(client);
9409a0bf528SMauro Carvalho Chehab }
941467845a1SMauro Carvalho Chehab EXPORT_SYMBOL(lgdt330x_attach);
9429a0bf528SMauro Carvalho Chehab 
943bd336e63SMax Kellermann static const struct dvb_frontend_ops lgdt3302_ops = {
9449a0bf528SMauro Carvalho Chehab 	.delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
9459a0bf528SMauro Carvalho Chehab 	.info = {
9469a0bf528SMauro Carvalho Chehab 		.name = "LG Electronics LGDT3302 VSB/QAM Frontend",
9479a0bf528SMauro Carvalho Chehab 		.frequency_min = 54000000,
9489a0bf528SMauro Carvalho Chehab 		.frequency_max = 858000000,
9499a0bf528SMauro Carvalho Chehab 		.frequency_stepsize = 62500,
9509a0bf528SMauro Carvalho Chehab 		.symbol_rate_min    = 5056941,	/* QAM 64 */
9519a0bf528SMauro Carvalho Chehab 		.symbol_rate_max    = 10762000,	/* VSB 8  */
9529a0bf528SMauro Carvalho Chehab 		.caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
9539a0bf528SMauro Carvalho Chehab 	},
9549a0bf528SMauro Carvalho Chehab 	.init                 = lgdt330x_init,
9559a0bf528SMauro Carvalho Chehab 	.set_frontend         = lgdt330x_set_parameters,
9569a0bf528SMauro Carvalho Chehab 	.get_frontend         = lgdt330x_get_frontend,
9579a0bf528SMauro Carvalho Chehab 	.get_tune_settings    = lgdt330x_get_tune_settings,
9589a0bf528SMauro Carvalho Chehab 	.read_status          = lgdt3302_read_status,
9599a0bf528SMauro Carvalho Chehab 	.read_signal_strength = lgdt330x_read_signal_strength,
96019bdd0d6SMauro Carvalho Chehab 	.read_snr             = lgdt330x_read_snr,
9619a0bf528SMauro Carvalho Chehab 	.read_ucblocks        = lgdt330x_read_ucblocks,
9629a0bf528SMauro Carvalho Chehab 	.release              = lgdt330x_release,
9639a0bf528SMauro Carvalho Chehab };
9649a0bf528SMauro Carvalho Chehab 
965bd336e63SMax Kellermann static const struct dvb_frontend_ops lgdt3303_ops = {
9669a0bf528SMauro Carvalho Chehab 	.delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
9679a0bf528SMauro Carvalho Chehab 	.info = {
9689a0bf528SMauro Carvalho Chehab 		.name = "LG Electronics LGDT3303 VSB/QAM Frontend",
9699a0bf528SMauro Carvalho Chehab 		.frequency_min = 54000000,
9709a0bf528SMauro Carvalho Chehab 		.frequency_max = 858000000,
9719a0bf528SMauro Carvalho Chehab 		.frequency_stepsize = 62500,
9729a0bf528SMauro Carvalho Chehab 		.symbol_rate_min    = 5056941,	/* QAM 64 */
9739a0bf528SMauro Carvalho Chehab 		.symbol_rate_max    = 10762000,	/* VSB 8  */
9749a0bf528SMauro Carvalho Chehab 		.caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
9759a0bf528SMauro Carvalho Chehab 	},
9769a0bf528SMauro Carvalho Chehab 	.init                 = lgdt330x_init,
9779a0bf528SMauro Carvalho Chehab 	.set_frontend         = lgdt330x_set_parameters,
9789a0bf528SMauro Carvalho Chehab 	.get_frontend         = lgdt330x_get_frontend,
9799a0bf528SMauro Carvalho Chehab 	.get_tune_settings    = lgdt330x_get_tune_settings,
9809a0bf528SMauro Carvalho Chehab 	.read_status          = lgdt3303_read_status,
9819a0bf528SMauro Carvalho Chehab 	.read_signal_strength = lgdt330x_read_signal_strength,
98219bdd0d6SMauro Carvalho Chehab 	.read_snr             = lgdt330x_read_snr,
9839a0bf528SMauro Carvalho Chehab 	.read_ucblocks        = lgdt330x_read_ucblocks,
9849a0bf528SMauro Carvalho Chehab 	.release              = lgdt330x_release,
9859a0bf528SMauro Carvalho Chehab };
9869a0bf528SMauro Carvalho Chehab 
98723ba635dSMauro Carvalho Chehab static int lgdt330x_remove(struct i2c_client *client)
98823ba635dSMauro Carvalho Chehab {
98923ba635dSMauro Carvalho Chehab 	struct lgdt330x_state *state = i2c_get_clientdata(client);
99023ba635dSMauro Carvalho Chehab 
99123ba635dSMauro Carvalho Chehab 	dev_dbg(&client->dev, "\n");
99223ba635dSMauro Carvalho Chehab 
99323ba635dSMauro Carvalho Chehab 	kfree(state);
99423ba635dSMauro Carvalho Chehab 
99523ba635dSMauro Carvalho Chehab 	return 0;
99623ba635dSMauro Carvalho Chehab }
99723ba635dSMauro Carvalho Chehab 
99823ba635dSMauro Carvalho Chehab static const struct i2c_device_id lgdt330x_id_table[] = {
99923ba635dSMauro Carvalho Chehab 	{"lgdt330x", 0},
100023ba635dSMauro Carvalho Chehab 	{}
100123ba635dSMauro Carvalho Chehab };
100223ba635dSMauro Carvalho Chehab MODULE_DEVICE_TABLE(i2c, lgdt330x_id_table);
100323ba635dSMauro Carvalho Chehab 
100423ba635dSMauro Carvalho Chehab static struct i2c_driver lgdt330x_driver = {
100523ba635dSMauro Carvalho Chehab 	.driver = {
100623ba635dSMauro Carvalho Chehab 		.name	= "lgdt330x",
100723ba635dSMauro Carvalho Chehab 		.suppress_bind_attrs = true,
100823ba635dSMauro Carvalho Chehab 	},
100923ba635dSMauro Carvalho Chehab 	.probe		= lgdt330x_probe,
101023ba635dSMauro Carvalho Chehab 	.remove		= lgdt330x_remove,
101123ba635dSMauro Carvalho Chehab 	.id_table	= lgdt330x_id_table,
101223ba635dSMauro Carvalho Chehab };
101323ba635dSMauro Carvalho Chehab 
101423ba635dSMauro Carvalho Chehab module_i2c_driver(lgdt330x_driver);
101523ba635dSMauro Carvalho Chehab 
101623ba635dSMauro Carvalho Chehab 
10179a0bf528SMauro Carvalho Chehab MODULE_DESCRIPTION("LGDT330X (ATSC 8VSB & ITU-T J.83 AnnexB 64/256 QAM) Demodulator Driver");
10189a0bf528SMauro Carvalho Chehab MODULE_AUTHOR("Wilson Michaels");
10199a0bf528SMauro Carvalho Chehab MODULE_LICENSE("GPL");
1020