1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
29a0bf528SMauro Carvalho Chehab /*
39a0bf528SMauro Carvalho Chehab  *    Support for LGDT3302 and LGDT3303 - VSB/QAM
49a0bf528SMauro Carvalho Chehab  *
59a0bf528SMauro Carvalho Chehab  *    Copyright (C) 2005 Wilson Michaels <wilsonmichaels@earthlink.net>
69a0bf528SMauro Carvalho Chehab  */
79a0bf528SMauro Carvalho Chehab 
89a0bf528SMauro Carvalho Chehab /*
99a0bf528SMauro Carvalho Chehab  *                      NOTES ABOUT THIS DRIVER
109a0bf528SMauro Carvalho Chehab  *
119a0bf528SMauro Carvalho Chehab  * This Linux driver supports:
129a0bf528SMauro Carvalho Chehab  *   DViCO FusionHDTV 3 Gold-Q
139a0bf528SMauro Carvalho Chehab  *   DViCO FusionHDTV 3 Gold-T
149a0bf528SMauro Carvalho Chehab  *   DViCO FusionHDTV 5 Gold
159a0bf528SMauro Carvalho Chehab  *   DViCO FusionHDTV 5 Lite
169a0bf528SMauro Carvalho Chehab  *   DViCO FusionHDTV 5 USB Gold
179a0bf528SMauro Carvalho Chehab  *   Air2PC/AirStar 2 ATSC 3rd generation (HD5000)
189a0bf528SMauro Carvalho Chehab  *   pcHDTV HD5500
199a0bf528SMauro Carvalho Chehab  *
209a0bf528SMauro Carvalho Chehab  */
219a0bf528SMauro Carvalho Chehab 
229a0bf528SMauro Carvalho Chehab #include <linux/kernel.h>
239a0bf528SMauro Carvalho Chehab #include <linux/module.h>
249a0bf528SMauro Carvalho Chehab #include <linux/init.h>
259a0bf528SMauro Carvalho Chehab #include <linux/delay.h>
269a0bf528SMauro Carvalho Chehab #include <linux/string.h>
279a0bf528SMauro Carvalho Chehab #include <linux/slab.h>
289a0bf528SMauro Carvalho Chehab #include <asm/byteorder.h>
299a0bf528SMauro Carvalho Chehab 
30fada1935SMauro Carvalho Chehab #include <media/dvb_frontend.h>
31f97fa3dcSAndy Shevchenko #include <linux/int_log.h>
329a0bf528SMauro Carvalho Chehab #include "lgdt330x_priv.h"
339a0bf528SMauro Carvalho Chehab #include "lgdt330x.h"
349a0bf528SMauro Carvalho Chehab 
359a0bf528SMauro Carvalho Chehab /* Use Equalizer Mean Squared Error instead of Phaser Tracker MSE */
369a0bf528SMauro Carvalho Chehab /* #define USE_EQMSE */
379a0bf528SMauro Carvalho Chehab 
389a0bf528SMauro Carvalho Chehab static int debug;
399a0bf528SMauro Carvalho Chehab module_param(debug, int, 0644);
409a0bf528SMauro Carvalho Chehab MODULE_PARM_DESC(debug, "Turn on/off lgdt330x frontend debugging (default:off).");
416752c797SMauro Carvalho Chehab 
4223ba635dSMauro Carvalho Chehab #define dprintk(state, fmt, arg...) do {				\
43467845a1SMauro Carvalho Chehab 	if (debug)							\
4423ba635dSMauro Carvalho Chehab 		dev_printk(KERN_DEBUG, &state->client->dev, fmt, ##arg);\
459a0bf528SMauro Carvalho Chehab } while (0)
469a0bf528SMauro Carvalho Chehab 
47467845a1SMauro Carvalho Chehab struct lgdt330x_state {
4823ba635dSMauro Carvalho Chehab 	struct i2c_client *client;
499a0bf528SMauro Carvalho Chehab 
509a0bf528SMauro Carvalho Chehab 	/* Configuration settings */
5123ba635dSMauro Carvalho Chehab 	struct lgdt330x_config config;
529a0bf528SMauro Carvalho Chehab 
539a0bf528SMauro Carvalho Chehab 	struct dvb_frontend frontend;
549a0bf528SMauro Carvalho Chehab 
559a0bf528SMauro Carvalho Chehab 	/* Demodulator private data */
560df289a2SMauro Carvalho Chehab 	enum fe_modulation current_modulation;
579a0bf528SMauro Carvalho Chehab 	u32 snr;	/* Result of last SNR calculation */
585f939c36SMauro Carvalho Chehab 	u16 ucblocks;
595f939c36SMauro Carvalho Chehab 	unsigned long last_stats_time;
609a0bf528SMauro Carvalho Chehab 
619a0bf528SMauro Carvalho Chehab 	/* Tuner private data */
629a0bf528SMauro Carvalho Chehab 	u32 current_frequency;
639a0bf528SMauro Carvalho Chehab };
649a0bf528SMauro Carvalho Chehab 
i2c_write_demod_bytes(struct lgdt330x_state * state,const u8 * buf,int len)659a0bf528SMauro Carvalho Chehab static int i2c_write_demod_bytes(struct lgdt330x_state *state,
6623ba635dSMauro Carvalho Chehab 				 const u8 *buf, /* data bytes to send */
679a0bf528SMauro Carvalho Chehab 				 int len  /* number of bytes to send */)
689a0bf528SMauro Carvalho Chehab {
699a0bf528SMauro Carvalho Chehab 	int i;
709a0bf528SMauro Carvalho Chehab 	int err;
719a0bf528SMauro Carvalho Chehab 
729a0bf528SMauro Carvalho Chehab 	for (i = 0; i < len - 1; i += 2) {
7323ba635dSMauro Carvalho Chehab 		err = i2c_master_send(state->client, buf, 2);
7423ba635dSMauro Carvalho Chehab 		if (err != 2) {
7523ba635dSMauro Carvalho Chehab 			dev_warn(&state->client->dev,
7623ba635dSMauro Carvalho Chehab 				 "%s: error (addr %02x <- %02x, err = %i)\n",
7723ba635dSMauro Carvalho Chehab 				__func__, buf[0], buf[1], err);
789a0bf528SMauro Carvalho Chehab 			if (err < 0)
799a0bf528SMauro Carvalho Chehab 				return err;
809a0bf528SMauro Carvalho Chehab 			else
819a0bf528SMauro Carvalho Chehab 				return -EREMOTEIO;
829a0bf528SMauro Carvalho Chehab 		}
8323ba635dSMauro Carvalho Chehab 		buf += 2;
849a0bf528SMauro Carvalho Chehab 	}
859a0bf528SMauro Carvalho Chehab 	return 0;
869a0bf528SMauro Carvalho Chehab }
879a0bf528SMauro Carvalho Chehab 
889a0bf528SMauro Carvalho Chehab /*
899a0bf528SMauro Carvalho Chehab  * This routine writes the register (reg) to the demod bus
909a0bf528SMauro Carvalho Chehab  * then reads the data returned for (len) bytes.
919a0bf528SMauro Carvalho Chehab  */
i2c_read_demod_bytes(struct lgdt330x_state * state,enum I2C_REG reg,u8 * buf,int len)929a0bf528SMauro Carvalho Chehab static int i2c_read_demod_bytes(struct lgdt330x_state *state,
939a0bf528SMauro Carvalho Chehab 				enum I2C_REG reg, u8 *buf, int len)
949a0bf528SMauro Carvalho Chehab {
959a0bf528SMauro Carvalho Chehab 	u8 wr[] = { reg };
969a0bf528SMauro Carvalho Chehab 	struct i2c_msg msg[] = {
97467845a1SMauro Carvalho Chehab 		{
9823ba635dSMauro Carvalho Chehab 			.addr = state->client->addr,
99467845a1SMauro Carvalho Chehab 			.flags = 0,
100467845a1SMauro Carvalho Chehab 			.buf = wr,
101467845a1SMauro Carvalho Chehab 			.len = 1
102467845a1SMauro Carvalho Chehab 		}, {
10323ba635dSMauro Carvalho Chehab 			.addr = state->client->addr,
104467845a1SMauro Carvalho Chehab 			.flags = I2C_M_RD,
105467845a1SMauro Carvalho Chehab 			.buf = buf,
106467845a1SMauro Carvalho Chehab 			.len = len
107467845a1SMauro Carvalho Chehab 		},
1089a0bf528SMauro Carvalho Chehab 	};
1099a0bf528SMauro Carvalho Chehab 	int ret;
110467845a1SMauro Carvalho Chehab 
11123ba635dSMauro Carvalho Chehab 	ret = i2c_transfer(state->client->adapter, msg, 2);
1129a0bf528SMauro Carvalho Chehab 	if (ret != 2) {
11323ba635dSMauro Carvalho Chehab 		dev_warn(&state->client->dev,
11423ba635dSMauro Carvalho Chehab 			 "%s: addr 0x%02x select 0x%02x error (ret == %i)\n",
11523ba635dSMauro Carvalho Chehab 			 __func__, state->client->addr, reg, ret);
1169a0bf528SMauro Carvalho Chehab 		if (ret >= 0)
1179a0bf528SMauro Carvalho Chehab 			ret = -EIO;
1189a0bf528SMauro Carvalho Chehab 	} else {
1199a0bf528SMauro Carvalho Chehab 		ret = 0;
1209a0bf528SMauro Carvalho Chehab 	}
1219a0bf528SMauro Carvalho Chehab 	return ret;
1229a0bf528SMauro Carvalho Chehab }
1239a0bf528SMauro Carvalho Chehab 
1249a0bf528SMauro Carvalho Chehab /* Software reset */
lgdt3302_sw_reset(struct lgdt330x_state * state)125467845a1SMauro Carvalho Chehab static int lgdt3302_sw_reset(struct lgdt330x_state *state)
1269a0bf528SMauro Carvalho Chehab {
1279a0bf528SMauro Carvalho Chehab 	u8 ret;
1289a0bf528SMauro Carvalho Chehab 	u8 reset[] = {
1299a0bf528SMauro Carvalho Chehab 		IRQ_MASK,
130467845a1SMauro Carvalho Chehab 		/*
131467845a1SMauro Carvalho Chehab 		 * bit 6 is active low software reset
132467845a1SMauro Carvalho Chehab 		 * bits 5-0 are 1 to mask interrupts
133467845a1SMauro Carvalho Chehab 		 */
134467845a1SMauro Carvalho Chehab 		0x00
1359a0bf528SMauro Carvalho Chehab 	};
1369a0bf528SMauro Carvalho Chehab 
1379a0bf528SMauro Carvalho Chehab 	ret = i2c_write_demod_bytes(state,
1389a0bf528SMauro Carvalho Chehab 				    reset, sizeof(reset));
1399a0bf528SMauro Carvalho Chehab 	if (ret == 0) {
1409a0bf528SMauro Carvalho Chehab 		/* force reset high (inactive) and unmask interrupts */
1419a0bf528SMauro Carvalho Chehab 		reset[1] = 0x7f;
1429a0bf528SMauro Carvalho Chehab 		ret = i2c_write_demod_bytes(state,
1439a0bf528SMauro Carvalho Chehab 					    reset, sizeof(reset));
1449a0bf528SMauro Carvalho Chehab 	}
1459a0bf528SMauro Carvalho Chehab 	return ret;
1469a0bf528SMauro Carvalho Chehab }
1479a0bf528SMauro Carvalho Chehab 
lgdt3303_sw_reset(struct lgdt330x_state * state)148467845a1SMauro Carvalho Chehab static int lgdt3303_sw_reset(struct lgdt330x_state *state)
1499a0bf528SMauro Carvalho Chehab {
1509a0bf528SMauro Carvalho Chehab 	u8 ret;
1519a0bf528SMauro Carvalho Chehab 	u8 reset[] = {
1529a0bf528SMauro Carvalho Chehab 		0x02,
1539a0bf528SMauro Carvalho Chehab 		0x00 /* bit 0 is active low software reset */
1549a0bf528SMauro Carvalho Chehab 	};
1559a0bf528SMauro Carvalho Chehab 
1569a0bf528SMauro Carvalho Chehab 	ret = i2c_write_demod_bytes(state,
1579a0bf528SMauro Carvalho Chehab 				    reset, sizeof(reset));
1589a0bf528SMauro Carvalho Chehab 	if (ret == 0) {
1599a0bf528SMauro Carvalho Chehab 		/* force reset high (inactive) */
1609a0bf528SMauro Carvalho Chehab 		reset[1] = 0x01;
1619a0bf528SMauro Carvalho Chehab 		ret = i2c_write_demod_bytes(state,
1629a0bf528SMauro Carvalho Chehab 					    reset, sizeof(reset));
1639a0bf528SMauro Carvalho Chehab 	}
1649a0bf528SMauro Carvalho Chehab 	return ret;
1659a0bf528SMauro Carvalho Chehab }
1669a0bf528SMauro Carvalho Chehab 
lgdt330x_sw_reset(struct lgdt330x_state * state)167467845a1SMauro Carvalho Chehab static int lgdt330x_sw_reset(struct lgdt330x_state *state)
1689a0bf528SMauro Carvalho Chehab {
16923ba635dSMauro Carvalho Chehab 	switch (state->config.demod_chip) {
1709a0bf528SMauro Carvalho Chehab 	case LGDT3302:
171467845a1SMauro Carvalho Chehab 		return lgdt3302_sw_reset(state);
1729a0bf528SMauro Carvalho Chehab 	case LGDT3303:
173467845a1SMauro Carvalho Chehab 		return lgdt3303_sw_reset(state);
1749a0bf528SMauro Carvalho Chehab 	default:
1759a0bf528SMauro Carvalho Chehab 		return -ENODEV;
1769a0bf528SMauro Carvalho Chehab 	}
1779a0bf528SMauro Carvalho Chehab }
1789a0bf528SMauro Carvalho Chehab 
lgdt330x_init(struct dvb_frontend * fe)1799a0bf528SMauro Carvalho Chehab static int lgdt330x_init(struct dvb_frontend *fe)
1809a0bf528SMauro Carvalho Chehab {
1811334a7dcSMauro Carvalho Chehab 	struct lgdt330x_state *state = fe->demodulator_priv;
18219bdd0d6SMauro Carvalho Chehab 	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
1831334a7dcSMauro Carvalho Chehab 	char  *chip_name;
1841334a7dcSMauro Carvalho Chehab 	int    err;
1859a0bf528SMauro Carvalho Chehab 	/*
1869a0bf528SMauro Carvalho Chehab 	 * Array of byte pairs <address, value>
1879a0bf528SMauro Carvalho Chehab 	 * to initialize each different chip
1889a0bf528SMauro Carvalho Chehab 	 */
1891334a7dcSMauro Carvalho Chehab 	static const u8 lgdt3302_init_data[] = {
190467845a1SMauro Carvalho Chehab 		/* Use 50MHz param values from spec sheet since xtal is 50 */
191467845a1SMauro Carvalho Chehab 		/*
192467845a1SMauro Carvalho Chehab 		 * Change the value of NCOCTFV[25:0] of carrier
193467845a1SMauro Carvalho Chehab 		 * recovery center frequency register
194467845a1SMauro Carvalho Chehab 		 */
1959a0bf528SMauro Carvalho Chehab 		VSB_CARRIER_FREQ0, 0x00,
1969a0bf528SMauro Carvalho Chehab 		VSB_CARRIER_FREQ1, 0x87,
1979a0bf528SMauro Carvalho Chehab 		VSB_CARRIER_FREQ2, 0x8e,
1989a0bf528SMauro Carvalho Chehab 		VSB_CARRIER_FREQ3, 0x01,
199467845a1SMauro Carvalho Chehab 		/*
200467845a1SMauro Carvalho Chehab 		 * Change the TPCLK pin polarity
201467845a1SMauro Carvalho Chehab 		 * data is valid on falling clock
202467845a1SMauro Carvalho Chehab 		 */
2039a0bf528SMauro Carvalho Chehab 		DEMUX_CONTROL, 0xfb,
204467845a1SMauro Carvalho Chehab 		/*
205467845a1SMauro Carvalho Chehab 		 * Change the value of IFBW[11:0] of
206467845a1SMauro Carvalho Chehab 		 * AGC IF/RF loop filter bandwidth register
207467845a1SMauro Carvalho Chehab 		 */
2089a0bf528SMauro Carvalho Chehab 		AGC_RF_BANDWIDTH0, 0x40,
2099a0bf528SMauro Carvalho Chehab 		AGC_RF_BANDWIDTH1, 0x93,
2109a0bf528SMauro Carvalho Chehab 		AGC_RF_BANDWIDTH2, 0x00,
211467845a1SMauro Carvalho Chehab 		/*
212467845a1SMauro Carvalho Chehab 		 * Change the value of bit 6, 'nINAGCBY' and
213467845a1SMauro Carvalho Chehab 		 * 'NSSEL[1:0] of ACG function control register 2
214467845a1SMauro Carvalho Chehab 		 */
2159a0bf528SMauro Carvalho Chehab 		AGC_FUNC_CTRL2, 0xc6,
216467845a1SMauro Carvalho Chehab 		/*
217467845a1SMauro Carvalho Chehab 		 * Change the value of bit 6 'RFFIX'
218467845a1SMauro Carvalho Chehab 		 * of AGC function control register 3
219467845a1SMauro Carvalho Chehab 		 */
2209a0bf528SMauro Carvalho Chehab 		AGC_FUNC_CTRL3, 0x40,
221467845a1SMauro Carvalho Chehab 		/*
222467845a1SMauro Carvalho Chehab 		 * Set the value of 'INLVTHD' register 0x2a/0x2c
223467845a1SMauro Carvalho Chehab 		 * to 0x7fe
224467845a1SMauro Carvalho Chehab 		 */
2259a0bf528SMauro Carvalho Chehab 		AGC_DELAY0, 0x07,
2269a0bf528SMauro Carvalho Chehab 		AGC_DELAY2, 0xfe,
227467845a1SMauro Carvalho Chehab 		/*
228467845a1SMauro Carvalho Chehab 		 * Change the value of IAGCBW[15:8]
229467845a1SMauro Carvalho Chehab 		 * of inner AGC loop filter bandwidth
230467845a1SMauro Carvalho Chehab 		 */
2319a0bf528SMauro Carvalho Chehab 		AGC_LOOP_BANDWIDTH0, 0x08,
2329a0bf528SMauro Carvalho Chehab 		AGC_LOOP_BANDWIDTH1, 0x9a
2339a0bf528SMauro Carvalho Chehab 	};
2341334a7dcSMauro Carvalho Chehab 	static const u8 lgdt3303_init_data[] = {
2359a0bf528SMauro Carvalho Chehab 		0x4c, 0x14
2369a0bf528SMauro Carvalho Chehab 	};
2371334a7dcSMauro Carvalho Chehab 	static const u8 flip_1_lgdt3303_init_data[] = {
2389a0bf528SMauro Carvalho Chehab 		0x4c, 0x14,
2399a0bf528SMauro Carvalho Chehab 		0x87, 0xf3
2409a0bf528SMauro Carvalho Chehab 	};
2411334a7dcSMauro Carvalho Chehab 	static const u8 flip_2_lgdt3303_init_data[] = {
2429a0bf528SMauro Carvalho Chehab 		0x4c, 0x14,
2439a0bf528SMauro Carvalho Chehab 		0x87, 0xda
2449a0bf528SMauro Carvalho Chehab 	};
2459a0bf528SMauro Carvalho Chehab 
2461334a7dcSMauro Carvalho Chehab 	/*
2471334a7dcSMauro Carvalho Chehab 	 * Hardware reset is done using gpio[0] of cx23880x chip.
2481334a7dcSMauro Carvalho Chehab 	 * I'd like to do it here, but don't know how to find chip address.
2491334a7dcSMauro Carvalho Chehab 	 * cx88-cards.c arranges for the reset bit to be inactive (high).
2501334a7dcSMauro Carvalho Chehab 	 * Maybe there needs to be a callable function in cx88-core or
2511334a7dcSMauro Carvalho Chehab 	 * the caller of this function needs to do it.
2521334a7dcSMauro Carvalho Chehab 	 */
2539a0bf528SMauro Carvalho Chehab 
25423ba635dSMauro Carvalho Chehab 	switch (state->config.demod_chip) {
2559a0bf528SMauro Carvalho Chehab 	case LGDT3302:
2569a0bf528SMauro Carvalho Chehab 		chip_name = "LGDT3302";
2579a0bf528SMauro Carvalho Chehab 		err = i2c_write_demod_bytes(state, lgdt3302_init_data,
2589a0bf528SMauro Carvalho Chehab 					    sizeof(lgdt3302_init_data));
2599a0bf528SMauro Carvalho Chehab 		break;
2609a0bf528SMauro Carvalho Chehab 	case LGDT3303:
2619a0bf528SMauro Carvalho Chehab 		chip_name = "LGDT3303";
26223ba635dSMauro Carvalho Chehab 		switch (state->config.clock_polarity_flip) {
2639a0bf528SMauro Carvalho Chehab 		case 2:
2649a0bf528SMauro Carvalho Chehab 			err = i2c_write_demod_bytes(state,
2659a0bf528SMauro Carvalho Chehab 						    flip_2_lgdt3303_init_data,
2669a0bf528SMauro Carvalho Chehab 						    sizeof(flip_2_lgdt3303_init_data));
2679a0bf528SMauro Carvalho Chehab 			break;
2689a0bf528SMauro Carvalho Chehab 		case 1:
2699a0bf528SMauro Carvalho Chehab 			err = i2c_write_demod_bytes(state,
2709a0bf528SMauro Carvalho Chehab 						    flip_1_lgdt3303_init_data,
2719a0bf528SMauro Carvalho Chehab 						    sizeof(flip_1_lgdt3303_init_data));
2729a0bf528SMauro Carvalho Chehab 			break;
2739a0bf528SMauro Carvalho Chehab 		case 0:
2749a0bf528SMauro Carvalho Chehab 		default:
2759a0bf528SMauro Carvalho Chehab 			err = i2c_write_demod_bytes(state, lgdt3303_init_data,
2769a0bf528SMauro Carvalho Chehab 						    sizeof(lgdt3303_init_data));
2779a0bf528SMauro Carvalho Chehab 		}
2789a0bf528SMauro Carvalho Chehab 		break;
2799a0bf528SMauro Carvalho Chehab 	default:
2809a0bf528SMauro Carvalho Chehab 		chip_name = "undefined";
28123ba635dSMauro Carvalho Chehab 		dev_warn(&state->client->dev,
28223ba635dSMauro Carvalho Chehab 			 "Only LGDT3302 and LGDT3303 are supported chips.\n");
2839a0bf528SMauro Carvalho Chehab 		err = -ENODEV;
2849a0bf528SMauro Carvalho Chehab 	}
28523ba635dSMauro Carvalho Chehab 	dprintk(state, "Initialized the %s chip\n", chip_name);
2869a0bf528SMauro Carvalho Chehab 	if (err < 0)
2879a0bf528SMauro Carvalho Chehab 		return err;
28819bdd0d6SMauro Carvalho Chehab 
28919bdd0d6SMauro Carvalho Chehab 	p->cnr.len = 1;
29019bdd0d6SMauro Carvalho Chehab 	p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
2915f939c36SMauro Carvalho Chehab 	p->block_error.len = 1;
2925f939c36SMauro Carvalho Chehab 	p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
2935f939c36SMauro Carvalho Chehab 	p->block_count.len = 1;
2945f939c36SMauro Carvalho Chehab 	p->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
2955f939c36SMauro Carvalho Chehab 	state->last_stats_time = 0;
29619bdd0d6SMauro Carvalho Chehab 
297467845a1SMauro Carvalho Chehab 	return lgdt330x_sw_reset(state);
2989a0bf528SMauro Carvalho Chehab }
2999a0bf528SMauro Carvalho Chehab 
lgdt330x_read_ucblocks(struct dvb_frontend * fe,u32 * ucblocks)3009a0bf528SMauro Carvalho Chehab static int lgdt330x_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
3019a0bf528SMauro Carvalho Chehab {
3029a0bf528SMauro Carvalho Chehab 	struct lgdt330x_state *state = fe->demodulator_priv;
3039a0bf528SMauro Carvalho Chehab 
3045f939c36SMauro Carvalho Chehab 	*ucblocks = state->ucblocks;
3059a0bf528SMauro Carvalho Chehab 
3069a0bf528SMauro Carvalho Chehab 	return 0;
3079a0bf528SMauro Carvalho Chehab }
3089a0bf528SMauro Carvalho Chehab 
lgdt330x_set_parameters(struct dvb_frontend * fe)3099a0bf528SMauro Carvalho Chehab static int lgdt330x_set_parameters(struct dvb_frontend *fe)
3109a0bf528SMauro Carvalho Chehab {
3119a0bf528SMauro Carvalho Chehab 	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
3121334a7dcSMauro Carvalho Chehab 	struct lgdt330x_state *state = fe->demodulator_priv;
3139a0bf528SMauro Carvalho Chehab 	/*
3149a0bf528SMauro Carvalho Chehab 	 * Array of byte pairs <address, value>
3159a0bf528SMauro Carvalho Chehab 	 * to initialize 8VSB for lgdt3303 chip 50 MHz IF
3169a0bf528SMauro Carvalho Chehab 	 */
3171334a7dcSMauro Carvalho Chehab 	static const u8 lgdt3303_8vsb_44_data[] = {
3189a0bf528SMauro Carvalho Chehab 		0x04, 0x00,
3199a0bf528SMauro Carvalho Chehab 		0x0d, 0x40,
3209a0bf528SMauro Carvalho Chehab 		0x0e, 0x87,
3219a0bf528SMauro Carvalho Chehab 		0x0f, 0x8e,
3229a0bf528SMauro Carvalho Chehab 		0x10, 0x01,
323467845a1SMauro Carvalho Chehab 		0x47, 0x8b
324467845a1SMauro Carvalho Chehab 	};
3259a0bf528SMauro Carvalho Chehab 	/*
3269a0bf528SMauro Carvalho Chehab 	 * Array of byte pairs <address, value>
3279a0bf528SMauro Carvalho Chehab 	 * to initialize QAM for lgdt3303 chip
3289a0bf528SMauro Carvalho Chehab 	 */
3291334a7dcSMauro Carvalho Chehab 	static const u8 lgdt3303_qam_data[] = {
3309a0bf528SMauro Carvalho Chehab 		0x04, 0x00,
3319a0bf528SMauro Carvalho Chehab 		0x0d, 0x00,
3329a0bf528SMauro Carvalho Chehab 		0x0e, 0x00,
3339a0bf528SMauro Carvalho Chehab 		0x0f, 0x00,
3349a0bf528SMauro Carvalho Chehab 		0x10, 0x00,
3359a0bf528SMauro Carvalho Chehab 		0x51, 0x63,
3369a0bf528SMauro Carvalho Chehab 		0x47, 0x66,
3379a0bf528SMauro Carvalho Chehab 		0x48, 0x66,
3389a0bf528SMauro Carvalho Chehab 		0x4d, 0x1a,
3399a0bf528SMauro Carvalho Chehab 		0x49, 0x08,
340467845a1SMauro Carvalho Chehab 		0x4a, 0x9b
341467845a1SMauro Carvalho Chehab 	};
3421334a7dcSMauro Carvalho Chehab 	u8 top_ctrl_cfg[]   = { TOP_CONTROL, 0x03 };
3439a0bf528SMauro Carvalho Chehab 
3449a0bf528SMauro Carvalho Chehab 	int err = 0;
3459a0bf528SMauro Carvalho Chehab 	/* Change only if we are actually changing the modulation */
3469a0bf528SMauro Carvalho Chehab 	if (state->current_modulation != p->modulation) {
3479a0bf528SMauro Carvalho Chehab 		switch (p->modulation) {
3489a0bf528SMauro Carvalho Chehab 		case VSB_8:
34923ba635dSMauro Carvalho Chehab 			dprintk(state, "VSB_8 MODE\n");
3509a0bf528SMauro Carvalho Chehab 
3519a0bf528SMauro Carvalho Chehab 			/* Select VSB mode */
3529a0bf528SMauro Carvalho Chehab 			top_ctrl_cfg[1] = 0x03;
3539a0bf528SMauro Carvalho Chehab 
3549a0bf528SMauro Carvalho Chehab 			/* Select ANT connector if supported by card */
35523ba635dSMauro Carvalho Chehab 			if (state->config.pll_rf_set)
35623ba635dSMauro Carvalho Chehab 				state->config.pll_rf_set(fe, 1);
3579a0bf528SMauro Carvalho Chehab 
35823ba635dSMauro Carvalho Chehab 			if (state->config.demod_chip == LGDT3303) {
359467845a1SMauro Carvalho Chehab 				err = i2c_write_demod_bytes(state,
360467845a1SMauro Carvalho Chehab 							    lgdt3303_8vsb_44_data,
3619a0bf528SMauro Carvalho Chehab 							    sizeof(lgdt3303_8vsb_44_data));
3629a0bf528SMauro Carvalho Chehab 			}
3639a0bf528SMauro Carvalho Chehab 			break;
3649a0bf528SMauro Carvalho Chehab 
3659a0bf528SMauro Carvalho Chehab 		case QAM_64:
36623ba635dSMauro Carvalho Chehab 			dprintk(state, "QAM_64 MODE\n");
3679a0bf528SMauro Carvalho Chehab 
3689a0bf528SMauro Carvalho Chehab 			/* Select QAM_64 mode */
3699a0bf528SMauro Carvalho Chehab 			top_ctrl_cfg[1] = 0x00;
3709a0bf528SMauro Carvalho Chehab 
3719a0bf528SMauro Carvalho Chehab 			/* Select CABLE connector if supported by card */
37223ba635dSMauro Carvalho Chehab 			if (state->config.pll_rf_set)
37323ba635dSMauro Carvalho Chehab 				state->config.pll_rf_set(fe, 0);
3749a0bf528SMauro Carvalho Chehab 
37523ba635dSMauro Carvalho Chehab 			if (state->config.demod_chip == LGDT3303) {
376467845a1SMauro Carvalho Chehab 				err = i2c_write_demod_bytes(state,
377467845a1SMauro Carvalho Chehab 							    lgdt3303_qam_data,
3789a0bf528SMauro Carvalho Chehab 							    sizeof(lgdt3303_qam_data));
3799a0bf528SMauro Carvalho Chehab 			}
3809a0bf528SMauro Carvalho Chehab 			break;
3819a0bf528SMauro Carvalho Chehab 
3829a0bf528SMauro Carvalho Chehab 		case QAM_256:
38323ba635dSMauro Carvalho Chehab 			dprintk(state, "QAM_256 MODE\n");
3849a0bf528SMauro Carvalho Chehab 
3859a0bf528SMauro Carvalho Chehab 			/* Select QAM_256 mode */
3869a0bf528SMauro Carvalho Chehab 			top_ctrl_cfg[1] = 0x01;
3879a0bf528SMauro Carvalho Chehab 
3889a0bf528SMauro Carvalho Chehab 			/* Select CABLE connector if supported by card */
38923ba635dSMauro Carvalho Chehab 			if (state->config.pll_rf_set)
39023ba635dSMauro Carvalho Chehab 				state->config.pll_rf_set(fe, 0);
3919a0bf528SMauro Carvalho Chehab 
39223ba635dSMauro Carvalho Chehab 			if (state->config.demod_chip == LGDT3303) {
393467845a1SMauro Carvalho Chehab 				err = i2c_write_demod_bytes(state,
394467845a1SMauro Carvalho Chehab 							    lgdt3303_qam_data,
3959a0bf528SMauro Carvalho Chehab 							    sizeof(lgdt3303_qam_data));
3969a0bf528SMauro Carvalho Chehab 			}
3979a0bf528SMauro Carvalho Chehab 			break;
3989a0bf528SMauro Carvalho Chehab 		default:
39923ba635dSMauro Carvalho Chehab 			dev_warn(&state->client->dev,
40023ba635dSMauro Carvalho Chehab 				 "%s: Modulation type(%d) UNSUPPORTED\n",
401467845a1SMauro Carvalho Chehab 				 __func__, p->modulation);
4029a0bf528SMauro Carvalho Chehab 			return -1;
4039a0bf528SMauro Carvalho Chehab 		}
4049a0bf528SMauro Carvalho Chehab 		if (err < 0)
40523ba635dSMauro Carvalho Chehab 			dev_warn(&state->client->dev,
40623ba635dSMauro Carvalho Chehab 				 "%s: error blasting bytes to lgdt3303 for modulation type(%d)\n",
4079a0bf528SMauro Carvalho Chehab 				 __func__, p->modulation);
4089a0bf528SMauro Carvalho Chehab 
4099a0bf528SMauro Carvalho Chehab 		/*
410467845a1SMauro Carvalho Chehab 		 * select serial or parallel MPEG hardware interface
4119a0bf528SMauro Carvalho Chehab 		 * Serial:   0x04 for LGDT3302 or 0x40 for LGDT3303
4129a0bf528SMauro Carvalho Chehab 		 * Parallel: 0x00
4139a0bf528SMauro Carvalho Chehab 		 */
41423ba635dSMauro Carvalho Chehab 		top_ctrl_cfg[1] |= state->config.serial_mpeg;
4159a0bf528SMauro Carvalho Chehab 
4169a0bf528SMauro Carvalho Chehab 		/* Select the requested mode */
4179a0bf528SMauro Carvalho Chehab 		i2c_write_demod_bytes(state, top_ctrl_cfg,
4189a0bf528SMauro Carvalho Chehab 				      sizeof(top_ctrl_cfg));
41923ba635dSMauro Carvalho Chehab 		if (state->config.set_ts_params)
42023ba635dSMauro Carvalho Chehab 			state->config.set_ts_params(fe, 0);
4219a0bf528SMauro Carvalho Chehab 		state->current_modulation = p->modulation;
4229a0bf528SMauro Carvalho Chehab 	}
4239a0bf528SMauro Carvalho Chehab 
4249a0bf528SMauro Carvalho Chehab 	/* Tune to the specified frequency */
4259a0bf528SMauro Carvalho Chehab 	if (fe->ops.tuner_ops.set_params) {
4269a0bf528SMauro Carvalho Chehab 		fe->ops.tuner_ops.set_params(fe);
427467845a1SMauro Carvalho Chehab 		if (fe->ops.i2c_gate_ctrl)
428467845a1SMauro Carvalho Chehab 			fe->ops.i2c_gate_ctrl(fe, 0);
4299a0bf528SMauro Carvalho Chehab 	}
4309a0bf528SMauro Carvalho Chehab 
4319a0bf528SMauro Carvalho Chehab 	/* Keep track of the new frequency */
432467845a1SMauro Carvalho Chehab 	/*
433467845a1SMauro Carvalho Chehab 	 * FIXME this is the wrong way to do this...
434467845a1SMauro Carvalho Chehab 	 * The tuner is shared with the video4linux analog API
435467845a1SMauro Carvalho Chehab 	 */
4369a0bf528SMauro Carvalho Chehab 	state->current_frequency = p->frequency;
4379a0bf528SMauro Carvalho Chehab 
438467845a1SMauro Carvalho Chehab 	lgdt330x_sw_reset(state);
4399a0bf528SMauro Carvalho Chehab 	return 0;
4409a0bf528SMauro Carvalho Chehab }
4419a0bf528SMauro Carvalho Chehab 
lgdt330x_get_frontend(struct dvb_frontend * fe,struct dtv_frontend_properties * p)4427e3e68bcSMauro Carvalho Chehab static int lgdt330x_get_frontend(struct dvb_frontend *fe,
4437e3e68bcSMauro Carvalho Chehab 				 struct dtv_frontend_properties *p)
4449a0bf528SMauro Carvalho Chehab {
4459a0bf528SMauro Carvalho Chehab 	struct lgdt330x_state *state = fe->demodulator_priv;
4467e3e68bcSMauro Carvalho Chehab 
4479a0bf528SMauro Carvalho Chehab 	p->frequency = state->current_frequency;
4489a0bf528SMauro Carvalho Chehab 	return 0;
4499a0bf528SMauro Carvalho Chehab }
4509a0bf528SMauro Carvalho Chehab 
451467845a1SMauro Carvalho Chehab /*
452467845a1SMauro Carvalho Chehab  * Calculate SNR estimation (scaled by 2^24)
453467845a1SMauro Carvalho Chehab  *
454467845a1SMauro Carvalho Chehab  * 8-VSB SNR equations from LGDT3302 and LGDT3303 datasheets, QAM
455467845a1SMauro Carvalho Chehab  * equations from LGDT3303 datasheet.  VSB is the same between the '02
456467845a1SMauro Carvalho Chehab  * and '03, so maybe QAM is too?  Perhaps someone with a newer datasheet
457467845a1SMauro Carvalho Chehab  * that has QAM information could verify?
458467845a1SMauro Carvalho Chehab  *
459467845a1SMauro Carvalho Chehab  * For 8-VSB: (two ways, take your pick)
460467845a1SMauro Carvalho Chehab  * LGDT3302:
461467845a1SMauro Carvalho Chehab  *   SNR_EQ = 10 * log10(25 * 24^2 / EQ_MSE)
462467845a1SMauro Carvalho Chehab  * LGDT3303:
463467845a1SMauro Carvalho Chehab  *   SNR_EQ = 10 * log10(25 * 32^2 / EQ_MSE)
464467845a1SMauro Carvalho Chehab  * LGDT3302 & LGDT3303:
465467845a1SMauro Carvalho Chehab  *   SNR_PT = 10 * log10(25 * 32^2 / PT_MSE)  (we use this one)
466467845a1SMauro Carvalho Chehab  * For 64-QAM:
467467845a1SMauro Carvalho Chehab  *   SNR    = 10 * log10( 688128   / MSEQAM)
468467845a1SMauro Carvalho Chehab  * For 256-QAM:
469467845a1SMauro Carvalho Chehab  *   SNR    = 10 * log10( 696320   / MSEQAM)
470467845a1SMauro Carvalho Chehab  *
471467845a1SMauro Carvalho Chehab  * We re-write the snr equation as:
472467845a1SMauro Carvalho Chehab  *   SNR * 2^24 = 10*(c - intlog10(MSE))
473467845a1SMauro Carvalho Chehab  * Where for 256-QAM, c = log10(696320) * 2^24, and so on.
474467845a1SMauro Carvalho Chehab  */
calculate_snr(u32 mse,u32 c)4759a0bf528SMauro Carvalho Chehab static u32 calculate_snr(u32 mse, u32 c)
4769a0bf528SMauro Carvalho Chehab {
4779a0bf528SMauro Carvalho Chehab 	if (mse == 0) /* No signal */
4789a0bf528SMauro Carvalho Chehab 		return 0;
4799a0bf528SMauro Carvalho Chehab 
4809a0bf528SMauro Carvalho Chehab 	mse = intlog10(mse);
4819a0bf528SMauro Carvalho Chehab 	if (mse > c) {
482467845a1SMauro Carvalho Chehab 		/*
483467845a1SMauro Carvalho Chehab 		 * Negative SNR, which is possible, but realisticly the
484467845a1SMauro Carvalho Chehab 		 * demod will lose lock before the signal gets this bad.
485467845a1SMauro Carvalho Chehab 		 * The API only allows for unsigned values, so just return 0
486467845a1SMauro Carvalho Chehab 		 */
4879a0bf528SMauro Carvalho Chehab 		return 0;
4889a0bf528SMauro Carvalho Chehab 	}
4899a0bf528SMauro Carvalho Chehab 	return 10 * (c - mse);
4909a0bf528SMauro Carvalho Chehab }
4919a0bf528SMauro Carvalho Chehab 
lgdt3302_read_snr(struct dvb_frontend * fe)49219bdd0d6SMauro Carvalho Chehab static int lgdt3302_read_snr(struct dvb_frontend *fe)
4939a0bf528SMauro Carvalho Chehab {
494467845a1SMauro Carvalho Chehab 	struct lgdt330x_state *state = fe->demodulator_priv;
4959a0bf528SMauro Carvalho Chehab 	u8 buf[5];	/* read data buffer */
4969a0bf528SMauro Carvalho Chehab 	u32 noise;	/* noise value */
4979a0bf528SMauro Carvalho Chehab 	u32 c;		/* per-modulation SNR calculation constant */
4989a0bf528SMauro Carvalho Chehab 
4999a0bf528SMauro Carvalho Chehab 	switch (state->current_modulation) {
5009a0bf528SMauro Carvalho Chehab 	case VSB_8:
5019a0bf528SMauro Carvalho Chehab 		i2c_read_demod_bytes(state, LGDT3302_EQPH_ERR0, buf, 5);
5029a0bf528SMauro Carvalho Chehab #ifdef USE_EQMSE
5039a0bf528SMauro Carvalho Chehab 		/* Use Equalizer Mean-Square Error Register */
5049a0bf528SMauro Carvalho Chehab 		/* SNR for ranges from -15.61 to +41.58 */
5059a0bf528SMauro Carvalho Chehab 		noise = ((buf[0] & 7) << 16) | (buf[1] << 8) | buf[2];
5069a0bf528SMauro Carvalho Chehab 		c = 69765745; /* log10(25*24^2)*2^24 */
5079a0bf528SMauro Carvalho Chehab #else
5089a0bf528SMauro Carvalho Chehab 		/* Use Phase Tracker Mean-Square Error Register */
5099a0bf528SMauro Carvalho Chehab 		/* SNR for ranges from -13.11 to +44.08 */
5109a0bf528SMauro Carvalho Chehab 		noise = ((buf[0] & 7 << 3) << 13) | (buf[3] << 8) | buf[4];
5119a0bf528SMauro Carvalho Chehab 		c = 73957994; /* log10(25*32^2)*2^24 */
5129a0bf528SMauro Carvalho Chehab #endif
5139a0bf528SMauro Carvalho Chehab 		break;
5149a0bf528SMauro Carvalho Chehab 	case QAM_64:
5159a0bf528SMauro Carvalho Chehab 	case QAM_256:
5169a0bf528SMauro Carvalho Chehab 		i2c_read_demod_bytes(state, CARRIER_MSEQAM1, buf, 2);
5179a0bf528SMauro Carvalho Chehab 		noise = ((buf[0] & 3) << 8) | buf[1];
5189a0bf528SMauro Carvalho Chehab 		c = state->current_modulation == QAM_64 ? 97939837 : 98026066;
5199a0bf528SMauro Carvalho Chehab 		/* log10(688128)*2^24 and log10(696320)*2^24 */
5209a0bf528SMauro Carvalho Chehab 		break;
5219a0bf528SMauro Carvalho Chehab 	default:
52223ba635dSMauro Carvalho Chehab 		dev_err(&state->client->dev,
52323ba635dSMauro Carvalho Chehab 			"%s: Modulation set to unsupported value\n",
5249a0bf528SMauro Carvalho Chehab 			__func__);
52519bdd0d6SMauro Carvalho Chehab 
52619bdd0d6SMauro Carvalho Chehab 		state->snr = 0;
52719bdd0d6SMauro Carvalho Chehab 
5289a0bf528SMauro Carvalho Chehab 		return -EREMOTEIO; /* return -EDRIVER_IS_GIBBERED; */
5299a0bf528SMauro Carvalho Chehab 	}
5309a0bf528SMauro Carvalho Chehab 
5319a0bf528SMauro Carvalho Chehab 	state->snr = calculate_snr(noise, c);
5329a0bf528SMauro Carvalho Chehab 
53323ba635dSMauro Carvalho Chehab 	dprintk(state, "noise = 0x%08x, snr = %d.%02d dB\n", noise,
5349a0bf528SMauro Carvalho Chehab 		state->snr >> 24, (((state->snr >> 8) & 0xffff) * 100) >> 16);
5359a0bf528SMauro Carvalho Chehab 
5369a0bf528SMauro Carvalho Chehab 	return 0;
5379a0bf528SMauro Carvalho Chehab }
5389a0bf528SMauro Carvalho Chehab 
lgdt3303_read_snr(struct dvb_frontend * fe)53919bdd0d6SMauro Carvalho Chehab static int lgdt3303_read_snr(struct dvb_frontend *fe)
5409a0bf528SMauro Carvalho Chehab {
541467845a1SMauro Carvalho Chehab 	struct lgdt330x_state *state = fe->demodulator_priv;
5429a0bf528SMauro Carvalho Chehab 	u8 buf[5];	/* read data buffer */
5439a0bf528SMauro Carvalho Chehab 	u32 noise;	/* noise value */
5449a0bf528SMauro Carvalho Chehab 	u32 c;		/* per-modulation SNR calculation constant */
5459a0bf528SMauro Carvalho Chehab 
5469a0bf528SMauro Carvalho Chehab 	switch (state->current_modulation) {
5479a0bf528SMauro Carvalho Chehab 	case VSB_8:
5489a0bf528SMauro Carvalho Chehab 		i2c_read_demod_bytes(state, LGDT3303_EQPH_ERR0, buf, 5);
5499a0bf528SMauro Carvalho Chehab #ifdef USE_EQMSE
5509a0bf528SMauro Carvalho Chehab 		/* Use Equalizer Mean-Square Error Register */
5519a0bf528SMauro Carvalho Chehab 		/* SNR for ranges from -16.12 to +44.08 */
5529a0bf528SMauro Carvalho Chehab 		noise = ((buf[0] & 0x78) << 13) | (buf[1] << 8) | buf[2];
5539a0bf528SMauro Carvalho Chehab 		c = 73957994; /* log10(25*32^2)*2^24 */
5549a0bf528SMauro Carvalho Chehab #else
5559a0bf528SMauro Carvalho Chehab 		/* Use Phase Tracker Mean-Square Error Register */
5569a0bf528SMauro Carvalho Chehab 		/* SNR for ranges from -13.11 to +44.08 */
5579a0bf528SMauro Carvalho Chehab 		noise = ((buf[0] & 7) << 16) | (buf[3] << 8) | buf[4];
5589a0bf528SMauro Carvalho Chehab 		c = 73957994; /* log10(25*32^2)*2^24 */
5599a0bf528SMauro Carvalho Chehab #endif
5609a0bf528SMauro Carvalho Chehab 		break;
5619a0bf528SMauro Carvalho Chehab 	case QAM_64:
5629a0bf528SMauro Carvalho Chehab 	case QAM_256:
5639a0bf528SMauro Carvalho Chehab 		i2c_read_demod_bytes(state, CARRIER_MSEQAM1, buf, 2);
5649a0bf528SMauro Carvalho Chehab 		noise = (buf[0] << 8) | buf[1];
5659a0bf528SMauro Carvalho Chehab 		c = state->current_modulation == QAM_64 ? 97939837 : 98026066;
5669a0bf528SMauro Carvalho Chehab 		/* log10(688128)*2^24 and log10(696320)*2^24 */
5679a0bf528SMauro Carvalho Chehab 		break;
5689a0bf528SMauro Carvalho Chehab 	default:
56923ba635dSMauro Carvalho Chehab 		dev_err(&state->client->dev,
57023ba635dSMauro Carvalho Chehab 			"%s: Modulation set to unsupported value\n",
5719a0bf528SMauro Carvalho Chehab 			__func__);
57219bdd0d6SMauro Carvalho Chehab 		state->snr = 0;
5739a0bf528SMauro Carvalho Chehab 		return -EREMOTEIO; /* return -EDRIVER_IS_GIBBERED; */
5749a0bf528SMauro Carvalho Chehab 	}
5759a0bf528SMauro Carvalho Chehab 
5769a0bf528SMauro Carvalho Chehab 	state->snr = calculate_snr(noise, c);
5779a0bf528SMauro Carvalho Chehab 
57823ba635dSMauro Carvalho Chehab 	dprintk(state, "noise = 0x%08x, snr = %d.%02d dB\n", noise,
5799a0bf528SMauro Carvalho Chehab 		state->snr >> 24, (((state->snr >> 8) & 0xffff) * 100) >> 16);
5809a0bf528SMauro Carvalho Chehab 
5819a0bf528SMauro Carvalho Chehab 	return 0;
5829a0bf528SMauro Carvalho Chehab }
5839a0bf528SMauro Carvalho Chehab 
lgdt330x_read_snr(struct dvb_frontend * fe,u16 * snr)58419bdd0d6SMauro Carvalho Chehab static int lgdt330x_read_snr(struct dvb_frontend *fe, u16 *snr)
58519bdd0d6SMauro Carvalho Chehab {
58619bdd0d6SMauro Carvalho Chehab 	struct lgdt330x_state *state = fe->demodulator_priv;
58719bdd0d6SMauro Carvalho Chehab 
58819bdd0d6SMauro Carvalho Chehab 	*snr = (state->snr) >> 16; /* Convert from 8.24 fixed-point to 8.8 */
58919bdd0d6SMauro Carvalho Chehab 
59019bdd0d6SMauro Carvalho Chehab 	return 0;
59119bdd0d6SMauro Carvalho Chehab }
59219bdd0d6SMauro Carvalho Chehab 
lgdt330x_read_signal_strength(struct dvb_frontend * fe,u16 * strength)5939a0bf528SMauro Carvalho Chehab static int lgdt330x_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
5949a0bf528SMauro Carvalho Chehab {
5959a0bf528SMauro Carvalho Chehab 	/* Calculate Strength from SNR up to 35dB */
596467845a1SMauro Carvalho Chehab 	/*
597467845a1SMauro Carvalho Chehab 	 * Even though the SNR can go higher than 35dB, there is some comfort
598467845a1SMauro Carvalho Chehab 	 * factor in having a range of strong signals that can show at 100%
599467845a1SMauro Carvalho Chehab 	 */
600467845a1SMauro Carvalho Chehab 	struct lgdt330x_state *state = fe->demodulator_priv;
6019a0bf528SMauro Carvalho Chehab 	u16 snr;
6029a0bf528SMauro Carvalho Chehab 	int ret;
6039a0bf528SMauro Carvalho Chehab 
6049a0bf528SMauro Carvalho Chehab 	ret = fe->ops.read_snr(fe, &snr);
6059a0bf528SMauro Carvalho Chehab 	if (ret != 0)
6069a0bf528SMauro Carvalho Chehab 		return ret;
6079a0bf528SMauro Carvalho Chehab 	/* Rather than use the 8.8 value snr, use state->snr which is 8.24 */
6089a0bf528SMauro Carvalho Chehab 	/* scale the range 0 - 35*2^24 into 0 - 65535 */
6099a0bf528SMauro Carvalho Chehab 	if (state->snr >= 8960 * 0x10000)
6109a0bf528SMauro Carvalho Chehab 		*strength = 0xffff;
6119a0bf528SMauro Carvalho Chehab 	else
6129a0bf528SMauro Carvalho Chehab 		*strength = state->snr / 8960;
6139a0bf528SMauro Carvalho Chehab 
6149a0bf528SMauro Carvalho Chehab 	return 0;
6159a0bf528SMauro Carvalho Chehab }
6169a0bf528SMauro Carvalho Chehab 
61753d41728SMauro Carvalho Chehab 
lgdt3302_read_status(struct dvb_frontend * fe,enum fe_status * status)61853d41728SMauro Carvalho Chehab static int lgdt3302_read_status(struct dvb_frontend *fe,
61953d41728SMauro Carvalho Chehab 				enum fe_status *status)
62053d41728SMauro Carvalho Chehab {
62153d41728SMauro Carvalho Chehab 	struct lgdt330x_state *state = fe->demodulator_priv;
62219bdd0d6SMauro Carvalho Chehab 	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
62353d41728SMauro Carvalho Chehab 	u8 buf[3];
6245f939c36SMauro Carvalho Chehab 	int err;
62553d41728SMauro Carvalho Chehab 
62653d41728SMauro Carvalho Chehab 	*status = 0; /* Reset status result */
62753d41728SMauro Carvalho Chehab 
62853d41728SMauro Carvalho Chehab 	/* AGC status register */
62953d41728SMauro Carvalho Chehab 	i2c_read_demod_bytes(state, AGC_STATUS, buf, 1);
63053d41728SMauro Carvalho Chehab 	dprintk(state, "AGC_STATUS = 0x%02x\n", buf[0]);
63153d41728SMauro Carvalho Chehab 	if ((buf[0] & 0x0c) == 0x8) {
63253d41728SMauro Carvalho Chehab 		/*
63353d41728SMauro Carvalho Chehab 		 * Test signal does not exist flag
63453d41728SMauro Carvalho Chehab 		 * as well as the AGC lock flag.
63553d41728SMauro Carvalho Chehab 		 */
63653d41728SMauro Carvalho Chehab 		*status |= FE_HAS_SIGNAL;
63753d41728SMauro Carvalho Chehab 	}
63853d41728SMauro Carvalho Chehab 
63953d41728SMauro Carvalho Chehab 	/*
64053d41728SMauro Carvalho Chehab 	 * You must set the Mask bits to 1 in the IRQ_MASK in order
64153d41728SMauro Carvalho Chehab 	 * to see that status bit in the IRQ_STATUS register.
64253d41728SMauro Carvalho Chehab 	 * This is done in SwReset();
64353d41728SMauro Carvalho Chehab 	 */
64453d41728SMauro Carvalho Chehab 
64553d41728SMauro Carvalho Chehab 	/* signal status */
64653d41728SMauro Carvalho Chehab 	i2c_read_demod_bytes(state, TOP_CONTROL, buf, sizeof(buf));
64753d41728SMauro Carvalho Chehab 	dprintk(state,
64853d41728SMauro Carvalho Chehab 		"TOP_CONTROL = 0x%02x, IRO_MASK = 0x%02x, IRQ_STATUS = 0x%02x\n",
64953d41728SMauro Carvalho Chehab 		buf[0], buf[1], buf[2]);
65053d41728SMauro Carvalho Chehab 
65153d41728SMauro Carvalho Chehab 	/* sync status */
65253d41728SMauro Carvalho Chehab 	if ((buf[2] & 0x03) == 0x01)
65353d41728SMauro Carvalho Chehab 		*status |= FE_HAS_SYNC;
65453d41728SMauro Carvalho Chehab 
65553d41728SMauro Carvalho Chehab 	/* FEC error status */
65653d41728SMauro Carvalho Chehab 	if ((buf[2] & 0x0c) == 0x08)
65753d41728SMauro Carvalho Chehab 		*status |= FE_HAS_LOCK | FE_HAS_VITERBI;
65853d41728SMauro Carvalho Chehab 
65953d41728SMauro Carvalho Chehab 	/* Carrier Recovery Lock Status Register */
66053d41728SMauro Carvalho Chehab 	i2c_read_demod_bytes(state, CARRIER_LOCK, buf, 1);
66153d41728SMauro Carvalho Chehab 	dprintk(state, "CARRIER_LOCK = 0x%02x\n", buf[0]);
66253d41728SMauro Carvalho Chehab 	switch (state->current_modulation) {
66353d41728SMauro Carvalho Chehab 	case QAM_256:
66453d41728SMauro Carvalho Chehab 	case QAM_64:
66553d41728SMauro Carvalho Chehab 		/* Need to understand why there are 3 lock levels here */
66653d41728SMauro Carvalho Chehab 		if ((buf[0] & 0x07) == 0x07)
66753d41728SMauro Carvalho Chehab 			*status |= FE_HAS_CARRIER;
66853d41728SMauro Carvalho Chehab 		break;
66953d41728SMauro Carvalho Chehab 	case VSB_8:
67053d41728SMauro Carvalho Chehab 		if ((buf[0] & 0x80) == 0x80)
67153d41728SMauro Carvalho Chehab 			*status |= FE_HAS_CARRIER;
67253d41728SMauro Carvalho Chehab 		break;
67353d41728SMauro Carvalho Chehab 	default:
67453d41728SMauro Carvalho Chehab 		dev_warn(&state->client->dev,
67553d41728SMauro Carvalho Chehab 			 "%s: Modulation set to unsupported value\n",
67653d41728SMauro Carvalho Chehab 			 __func__);
67753d41728SMauro Carvalho Chehab 	}
67853d41728SMauro Carvalho Chehab 
6795f939c36SMauro Carvalho Chehab 	if (!(*status & FE_HAS_LOCK)) {
6805f939c36SMauro Carvalho Chehab 		p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
6815f939c36SMauro Carvalho Chehab 		p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
6825f939c36SMauro Carvalho Chehab 		p->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
6835f939c36SMauro Carvalho Chehab 		return 0;
6845f939c36SMauro Carvalho Chehab 	}
6855f939c36SMauro Carvalho Chehab 
6865f939c36SMauro Carvalho Chehab 	if (state->last_stats_time &&
6875f939c36SMauro Carvalho Chehab 	    time_is_after_jiffies(state->last_stats_time))
6885f939c36SMauro Carvalho Chehab 		return 0;
6895f939c36SMauro Carvalho Chehab 
6905f939c36SMauro Carvalho Chehab 	state->last_stats_time = jiffies + msecs_to_jiffies(1000);
6915f939c36SMauro Carvalho Chehab 
6925f939c36SMauro Carvalho Chehab 	err = lgdt3302_read_snr(fe);
6935f939c36SMauro Carvalho Chehab 	if (!err) {
69419bdd0d6SMauro Carvalho Chehab 		p->cnr.stat[0].scale = FE_SCALE_DECIBEL;
69519bdd0d6SMauro Carvalho Chehab 		p->cnr.stat[0].svalue = (((u64)state->snr) * 1000) >> 24;
69619bdd0d6SMauro Carvalho Chehab 	} else {
69719bdd0d6SMauro Carvalho Chehab 		p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
69819bdd0d6SMauro Carvalho Chehab 	}
69919bdd0d6SMauro Carvalho Chehab 
7005f939c36SMauro Carvalho Chehab 	err = i2c_read_demod_bytes(state, LGDT3302_PACKET_ERR_COUNTER1,
7015f939c36SMauro Carvalho Chehab 					   buf, sizeof(buf));
7025f939c36SMauro Carvalho Chehab 	if (!err) {
7035f939c36SMauro Carvalho Chehab 		state->ucblocks = (buf[0] << 8) | buf[1];
7045f939c36SMauro Carvalho Chehab 
7055f939c36SMauro Carvalho Chehab 		dprintk(state, "UCB = 0x%02x\n", state->ucblocks);
7065f939c36SMauro Carvalho Chehab 
7075f939c36SMauro Carvalho Chehab 		p->block_error.stat[0].uvalue += state->ucblocks;
7085f939c36SMauro Carvalho Chehab 		/* FIXME: what's the basis for block count */
7095f939c36SMauro Carvalho Chehab 		p->block_count.stat[0].uvalue += 10000;
7105f939c36SMauro Carvalho Chehab 
7115f939c36SMauro Carvalho Chehab 		p->block_error.stat[0].scale = FE_SCALE_COUNTER;
7125f939c36SMauro Carvalho Chehab 		p->block_count.stat[0].scale = FE_SCALE_COUNTER;
7135f939c36SMauro Carvalho Chehab 	} else {
7145f939c36SMauro Carvalho Chehab 		p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
7155f939c36SMauro Carvalho Chehab 		p->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
7165f939c36SMauro Carvalho Chehab 	}
7175f939c36SMauro Carvalho Chehab 
71853d41728SMauro Carvalho Chehab 	return 0;
71953d41728SMauro Carvalho Chehab }
72053d41728SMauro Carvalho Chehab 
lgdt3303_read_status(struct dvb_frontend * fe,enum fe_status * status)72153d41728SMauro Carvalho Chehab static int lgdt3303_read_status(struct dvb_frontend *fe,
72253d41728SMauro Carvalho Chehab 				enum fe_status *status)
72353d41728SMauro Carvalho Chehab {
72453d41728SMauro Carvalho Chehab 	struct lgdt330x_state *state = fe->demodulator_priv;
72519bdd0d6SMauro Carvalho Chehab 	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
72653d41728SMauro Carvalho Chehab 	u8 buf[3];
7275f939c36SMauro Carvalho Chehab 	int err;
72853d41728SMauro Carvalho Chehab 
72953d41728SMauro Carvalho Chehab 	*status = 0; /* Reset status result */
73053d41728SMauro Carvalho Chehab 
73153d41728SMauro Carvalho Chehab 	/* lgdt3303 AGC status register */
73253d41728SMauro Carvalho Chehab 	err = i2c_read_demod_bytes(state, 0x58, buf, 1);
73353d41728SMauro Carvalho Chehab 	if (err < 0)
73453d41728SMauro Carvalho Chehab 		return err;
73553d41728SMauro Carvalho Chehab 
73653d41728SMauro Carvalho Chehab 	dprintk(state, "AGC_STATUS = 0x%02x\n", buf[0]);
73753d41728SMauro Carvalho Chehab 	if ((buf[0] & 0x21) == 0x01) {
73853d41728SMauro Carvalho Chehab 		/*
73953d41728SMauro Carvalho Chehab 		 * Test input signal does not exist flag
74053d41728SMauro Carvalho Chehab 		 * as well as the AGC lock flag.
74153d41728SMauro Carvalho Chehab 		 */
74253d41728SMauro Carvalho Chehab 		*status |= FE_HAS_SIGNAL;
74353d41728SMauro Carvalho Chehab 	}
74453d41728SMauro Carvalho Chehab 
74553d41728SMauro Carvalho Chehab 	/* Carrier Recovery Lock Status Register */
74653d41728SMauro Carvalho Chehab 	i2c_read_demod_bytes(state, CARRIER_LOCK, buf, 1);
74753d41728SMauro Carvalho Chehab 	dprintk(state, "CARRIER_LOCK = 0x%02x\n", buf[0]);
74853d41728SMauro Carvalho Chehab 	switch (state->current_modulation) {
74953d41728SMauro Carvalho Chehab 	case QAM_256:
75053d41728SMauro Carvalho Chehab 	case QAM_64:
75153d41728SMauro Carvalho Chehab 		/* Need to understand why there are 3 lock levels here */
75253d41728SMauro Carvalho Chehab 		if ((buf[0] & 0x07) == 0x07)
75353d41728SMauro Carvalho Chehab 			*status |= FE_HAS_CARRIER;
75453d41728SMauro Carvalho Chehab 		else
75553d41728SMauro Carvalho Chehab 			break;
75653d41728SMauro Carvalho Chehab 		i2c_read_demod_bytes(state, 0x8a, buf, 1);
75753d41728SMauro Carvalho Chehab 		dprintk(state, "QAM LOCK = 0x%02x\n", buf[0]);
75853d41728SMauro Carvalho Chehab 
75953d41728SMauro Carvalho Chehab 		if ((buf[0] & 0x04) == 0x04)
76053d41728SMauro Carvalho Chehab 			*status |= FE_HAS_SYNC;
76153d41728SMauro Carvalho Chehab 		if ((buf[0] & 0x01) == 0x01)
76253d41728SMauro Carvalho Chehab 			*status |= FE_HAS_LOCK;
76353d41728SMauro Carvalho Chehab 		if ((buf[0] & 0x08) == 0x08)
76453d41728SMauro Carvalho Chehab 			*status |= FE_HAS_VITERBI;
76553d41728SMauro Carvalho Chehab 		break;
76653d41728SMauro Carvalho Chehab 	case VSB_8:
76753d41728SMauro Carvalho Chehab 		if ((buf[0] & 0x80) == 0x80)
76853d41728SMauro Carvalho Chehab 			*status |= FE_HAS_CARRIER;
76953d41728SMauro Carvalho Chehab 		else
77053d41728SMauro Carvalho Chehab 			break;
77153d41728SMauro Carvalho Chehab 		i2c_read_demod_bytes(state, 0x38, buf, 1);
77253d41728SMauro Carvalho Chehab 		dprintk(state, "8-VSB LOCK = 0x%02x\n", buf[0]);
77353d41728SMauro Carvalho Chehab 
77453d41728SMauro Carvalho Chehab 		if ((buf[0] & 0x02) == 0x00)
77553d41728SMauro Carvalho Chehab 			*status |= FE_HAS_SYNC;
7761b4fd9deSFrench, Nicholas A 		if ((buf[0] & 0x01) == 0x01)
77753d41728SMauro Carvalho Chehab 			*status |= FE_HAS_VITERBI | FE_HAS_LOCK;
77853d41728SMauro Carvalho Chehab 		break;
77953d41728SMauro Carvalho Chehab 	default:
78053d41728SMauro Carvalho Chehab 		dev_warn(&state->client->dev,
78153d41728SMauro Carvalho Chehab 			 "%s: Modulation set to unsupported value\n",
78253d41728SMauro Carvalho Chehab 			 __func__);
78353d41728SMauro Carvalho Chehab 	}
78419bdd0d6SMauro Carvalho Chehab 
7855f939c36SMauro Carvalho Chehab 	if (!(*status & FE_HAS_LOCK)) {
7865f939c36SMauro Carvalho Chehab 		p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
7875f939c36SMauro Carvalho Chehab 		p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
7885f939c36SMauro Carvalho Chehab 		p->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
7895f939c36SMauro Carvalho Chehab 		return 0;
7905f939c36SMauro Carvalho Chehab 	}
7915f939c36SMauro Carvalho Chehab 
7925f939c36SMauro Carvalho Chehab 	if (state->last_stats_time &&
7935f939c36SMauro Carvalho Chehab 	    time_is_after_jiffies(state->last_stats_time))
7945f939c36SMauro Carvalho Chehab 		return 0;
7955f939c36SMauro Carvalho Chehab 
7965f939c36SMauro Carvalho Chehab 	state->last_stats_time = jiffies + msecs_to_jiffies(1000);
7975f939c36SMauro Carvalho Chehab 
7985f939c36SMauro Carvalho Chehab 	err = lgdt3303_read_snr(fe);
7995f939c36SMauro Carvalho Chehab 	if (!err) {
80019bdd0d6SMauro Carvalho Chehab 		p->cnr.stat[0].scale = FE_SCALE_DECIBEL;
80119bdd0d6SMauro Carvalho Chehab 		p->cnr.stat[0].svalue = (((u64)state->snr) * 1000) >> 24;
80219bdd0d6SMauro Carvalho Chehab 	} else {
80319bdd0d6SMauro Carvalho Chehab 		p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
80419bdd0d6SMauro Carvalho Chehab 	}
80519bdd0d6SMauro Carvalho Chehab 
8065f939c36SMauro Carvalho Chehab 	err = i2c_read_demod_bytes(state, LGDT3303_PACKET_ERR_COUNTER1,
8075f939c36SMauro Carvalho Chehab 					   buf, sizeof(buf));
8085f939c36SMauro Carvalho Chehab 	if (!err) {
8095f939c36SMauro Carvalho Chehab 		state->ucblocks = (buf[0] << 8) | buf[1];
8105f939c36SMauro Carvalho Chehab 
8115f939c36SMauro Carvalho Chehab 		dprintk(state, "UCB = 0x%02x\n", state->ucblocks);
8125f939c36SMauro Carvalho Chehab 
8135f939c36SMauro Carvalho Chehab 		p->block_error.stat[0].uvalue += state->ucblocks;
8145f939c36SMauro Carvalho Chehab 		/* FIXME: what's the basis for block count */
8155f939c36SMauro Carvalho Chehab 		p->block_count.stat[0].uvalue += 10000;
8165f939c36SMauro Carvalho Chehab 
8175f939c36SMauro Carvalho Chehab 		p->block_error.stat[0].scale = FE_SCALE_COUNTER;
8185f939c36SMauro Carvalho Chehab 		p->block_count.stat[0].scale = FE_SCALE_COUNTER;
8195f939c36SMauro Carvalho Chehab 	} else {
8205f939c36SMauro Carvalho Chehab 		p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
8215f939c36SMauro Carvalho Chehab 		p->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
8225f939c36SMauro Carvalho Chehab 	}
8235f939c36SMauro Carvalho Chehab 
82453d41728SMauro Carvalho Chehab 	return 0;
82553d41728SMauro Carvalho Chehab }
82653d41728SMauro Carvalho Chehab 
827467845a1SMauro Carvalho Chehab static int
lgdt330x_get_tune_settings(struct dvb_frontend * fe,struct dvb_frontend_tune_settings * fe_tune_settings)828467845a1SMauro Carvalho Chehab lgdt330x_get_tune_settings(struct dvb_frontend *fe,
829467845a1SMauro Carvalho Chehab 			   struct dvb_frontend_tune_settings *fe_tune_settings)
8309a0bf528SMauro Carvalho Chehab {
8319a0bf528SMauro Carvalho Chehab 	/* I have no idea about this - it may not be needed */
8329a0bf528SMauro Carvalho Chehab 	fe_tune_settings->min_delay_ms = 500;
8339a0bf528SMauro Carvalho Chehab 	fe_tune_settings->step_size = 0;
8349a0bf528SMauro Carvalho Chehab 	fe_tune_settings->max_drift = 0;
8359a0bf528SMauro Carvalho Chehab 	return 0;
8369a0bf528SMauro Carvalho Chehab }
8379a0bf528SMauro Carvalho Chehab 
lgdt330x_release(struct dvb_frontend * fe)8389a0bf528SMauro Carvalho Chehab static void lgdt330x_release(struct dvb_frontend *fe)
8399a0bf528SMauro Carvalho Chehab {
840467845a1SMauro Carvalho Chehab 	struct lgdt330x_state *state = fe->demodulator_priv;
84123ba635dSMauro Carvalho Chehab 	struct i2c_client *client = state->client;
842467845a1SMauro Carvalho Chehab 
84323ba635dSMauro Carvalho Chehab 	dev_dbg(&client->dev, "\n");
84423ba635dSMauro Carvalho Chehab 
84523ba635dSMauro Carvalho Chehab 	i2c_unregister_device(client);
84623ba635dSMauro Carvalho Chehab }
84723ba635dSMauro Carvalho Chehab 
lgdt330x_get_dvb_frontend(struct i2c_client * client)84823ba635dSMauro Carvalho Chehab static struct dvb_frontend *lgdt330x_get_dvb_frontend(struct i2c_client *client)
84923ba635dSMauro Carvalho Chehab {
85023ba635dSMauro Carvalho Chehab 	struct lgdt330x_state *state = i2c_get_clientdata(client);
85123ba635dSMauro Carvalho Chehab 
85223ba635dSMauro Carvalho Chehab 	dev_dbg(&client->dev, "\n");
85323ba635dSMauro Carvalho Chehab 
85423ba635dSMauro Carvalho Chehab 	return &state->frontend;
8559a0bf528SMauro Carvalho Chehab }
8569a0bf528SMauro Carvalho Chehab 
857bd336e63SMax Kellermann static const struct dvb_frontend_ops lgdt3302_ops;
858bd336e63SMax Kellermann static const struct dvb_frontend_ops lgdt3303_ops;
8599a0bf528SMauro Carvalho Chehab 
lgdt330x_probe(struct i2c_client * client)8600bada33eSUwe Kleine-König static int lgdt330x_probe(struct i2c_client *client)
8619a0bf528SMauro Carvalho Chehab {
8629a0bf528SMauro Carvalho Chehab 	struct lgdt330x_state *state = NULL;
8639a0bf528SMauro Carvalho Chehab 	u8 buf[1];
8649a0bf528SMauro Carvalho Chehab 
8659a0bf528SMauro Carvalho Chehab 	/* Allocate memory for the internal state */
866467845a1SMauro Carvalho Chehab 	state = kzalloc(sizeof(*state), GFP_KERNEL);
867467845a1SMauro Carvalho Chehab 	if (!state)
8689a0bf528SMauro Carvalho Chehab 		goto error;
8699a0bf528SMauro Carvalho Chehab 
8709a0bf528SMauro Carvalho Chehab 	/* Setup the state */
87123ba635dSMauro Carvalho Chehab 	memcpy(&state->config, client->dev.platform_data,
87223ba635dSMauro Carvalho Chehab 	       sizeof(state->config));
87323ba635dSMauro Carvalho Chehab 	i2c_set_clientdata(client, state);
87423ba635dSMauro Carvalho Chehab 	state->client = client;
8759a0bf528SMauro Carvalho Chehab 
8769a0bf528SMauro Carvalho Chehab 	/* Create dvb_frontend */
87723ba635dSMauro Carvalho Chehab 	switch (state->config.demod_chip) {
8789a0bf528SMauro Carvalho Chehab 	case LGDT3302:
879467845a1SMauro Carvalho Chehab 		memcpy(&state->frontend.ops, &lgdt3302_ops,
880467845a1SMauro Carvalho Chehab 		       sizeof(struct dvb_frontend_ops));
8819a0bf528SMauro Carvalho Chehab 		break;
8829a0bf528SMauro Carvalho Chehab 	case LGDT3303:
883467845a1SMauro Carvalho Chehab 		memcpy(&state->frontend.ops, &lgdt3303_ops,
884467845a1SMauro Carvalho Chehab 		       sizeof(struct dvb_frontend_ops));
8859a0bf528SMauro Carvalho Chehab 		break;
8869a0bf528SMauro Carvalho Chehab 	default:
8879a0bf528SMauro Carvalho Chehab 		goto error;
8889a0bf528SMauro Carvalho Chehab 	}
8899a0bf528SMauro Carvalho Chehab 	state->frontend.demodulator_priv = state;
8909a0bf528SMauro Carvalho Chehab 
89123ba635dSMauro Carvalho Chehab 	/* Setup get frontend callback */
89223ba635dSMauro Carvalho Chehab 	state->config.get_dvb_frontend = lgdt330x_get_dvb_frontend;
89323ba635dSMauro Carvalho Chehab 
8949a0bf528SMauro Carvalho Chehab 	/* Verify communication with demod chip */
8959a0bf528SMauro Carvalho Chehab 	if (i2c_read_demod_bytes(state, 2, buf, 1))
8969a0bf528SMauro Carvalho Chehab 		goto error;
8979a0bf528SMauro Carvalho Chehab 
8989a0bf528SMauro Carvalho Chehab 	state->current_frequency = -1;
8999a0bf528SMauro Carvalho Chehab 	state->current_modulation = -1;
9009a0bf528SMauro Carvalho Chehab 
90123ba635dSMauro Carvalho Chehab 	dev_info(&state->client->dev,
90223ba635dSMauro Carvalho Chehab 		"Demod loaded for LGDT330%s chip\n",
90323ba635dSMauro Carvalho Chehab 		state->config.demod_chip == LGDT3302 ? "2" : "3");
904ff093612SMauro Carvalho Chehab 
90523ba635dSMauro Carvalho Chehab 	return 0;
9069a0bf528SMauro Carvalho Chehab 
9079a0bf528SMauro Carvalho Chehab error:
9089a0bf528SMauro Carvalho Chehab 	kfree(state);
90989eaaf2dSMauro Carvalho Chehab 	if (debug)
91089eaaf2dSMauro Carvalho Chehab 		dev_printk(KERN_DEBUG, &client->dev, "Error loading lgdt330x driver\n");
91123ba635dSMauro Carvalho Chehab 	return -ENODEV;
91223ba635dSMauro Carvalho Chehab }
lgdt330x_attach(const struct lgdt330x_config * _config,u8 demod_address,struct i2c_adapter * i2c)91323ba635dSMauro Carvalho Chehab struct dvb_frontend *lgdt330x_attach(const struct lgdt330x_config *_config,
91423ba635dSMauro Carvalho Chehab 				     u8 demod_address,
91523ba635dSMauro Carvalho Chehab 				     struct i2c_adapter *i2c)
91623ba635dSMauro Carvalho Chehab {
91723ba635dSMauro Carvalho Chehab 	struct i2c_client *client;
91823ba635dSMauro Carvalho Chehab 	struct i2c_board_info board_info = {};
91923ba635dSMauro Carvalho Chehab 	struct lgdt330x_config config = *_config;
92023ba635dSMauro Carvalho Chehab 
921c0decac1SMauro Carvalho Chehab 	strscpy(board_info.type, "lgdt330x", sizeof(board_info.type));
92223ba635dSMauro Carvalho Chehab 	board_info.addr = demod_address;
92323ba635dSMauro Carvalho Chehab 	board_info.platform_data = &config;
9244f7f5e03SWolfram Sang 	client = i2c_new_client_device(i2c, &board_info);
9254f7f5e03SWolfram Sang 	if (!i2c_client_has_driver(client))
9269a0bf528SMauro Carvalho Chehab 		return NULL;
92723ba635dSMauro Carvalho Chehab 
92823ba635dSMauro Carvalho Chehab 	return lgdt330x_get_dvb_frontend(client);
9299a0bf528SMauro Carvalho Chehab }
930*86495af1SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(lgdt330x_attach);
9319a0bf528SMauro Carvalho Chehab 
932bd336e63SMax Kellermann static const struct dvb_frontend_ops lgdt3302_ops = {
9339a0bf528SMauro Carvalho Chehab 	.delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
9349a0bf528SMauro Carvalho Chehab 	.info = {
9359a0bf528SMauro Carvalho Chehab 		.name = "LG Electronics LGDT3302 VSB/QAM Frontend",
936f1b1eabfSMauro Carvalho Chehab 		.frequency_min_hz =  54 * MHz,
937f1b1eabfSMauro Carvalho Chehab 		.frequency_max_hz = 858 * MHz,
938f1b1eabfSMauro Carvalho Chehab 		.frequency_stepsize_hz = 62500,
9399a0bf528SMauro Carvalho Chehab 		.symbol_rate_min    = 5056941,	/* QAM 64 */
9409a0bf528SMauro Carvalho Chehab 		.symbol_rate_max    = 10762000,	/* VSB 8  */
9419a0bf528SMauro Carvalho Chehab 		.caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
9429a0bf528SMauro Carvalho Chehab 	},
9439a0bf528SMauro Carvalho Chehab 	.init                 = lgdt330x_init,
9449a0bf528SMauro Carvalho Chehab 	.set_frontend         = lgdt330x_set_parameters,
9459a0bf528SMauro Carvalho Chehab 	.get_frontend         = lgdt330x_get_frontend,
9469a0bf528SMauro Carvalho Chehab 	.get_tune_settings    = lgdt330x_get_tune_settings,
9479a0bf528SMauro Carvalho Chehab 	.read_status          = lgdt3302_read_status,
9489a0bf528SMauro Carvalho Chehab 	.read_signal_strength = lgdt330x_read_signal_strength,
94919bdd0d6SMauro Carvalho Chehab 	.read_snr             = lgdt330x_read_snr,
9509a0bf528SMauro Carvalho Chehab 	.read_ucblocks        = lgdt330x_read_ucblocks,
9519a0bf528SMauro Carvalho Chehab 	.release              = lgdt330x_release,
9529a0bf528SMauro Carvalho Chehab };
9539a0bf528SMauro Carvalho Chehab 
954bd336e63SMax Kellermann static const struct dvb_frontend_ops lgdt3303_ops = {
9559a0bf528SMauro Carvalho Chehab 	.delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
9569a0bf528SMauro Carvalho Chehab 	.info = {
9579a0bf528SMauro Carvalho Chehab 		.name = "LG Electronics LGDT3303 VSB/QAM Frontend",
958f1b1eabfSMauro Carvalho Chehab 		.frequency_min_hz =  54 * MHz,
959f1b1eabfSMauro Carvalho Chehab 		.frequency_max_hz = 858 * MHz,
960f1b1eabfSMauro Carvalho Chehab 		.frequency_stepsize_hz = 62500,
9619a0bf528SMauro Carvalho Chehab 		.symbol_rate_min    = 5056941,	/* QAM 64 */
9629a0bf528SMauro Carvalho Chehab 		.symbol_rate_max    = 10762000,	/* VSB 8  */
9639a0bf528SMauro Carvalho Chehab 		.caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
9649a0bf528SMauro Carvalho Chehab 	},
9659a0bf528SMauro Carvalho Chehab 	.init                 = lgdt330x_init,
9669a0bf528SMauro Carvalho Chehab 	.set_frontend         = lgdt330x_set_parameters,
9679a0bf528SMauro Carvalho Chehab 	.get_frontend         = lgdt330x_get_frontend,
9689a0bf528SMauro Carvalho Chehab 	.get_tune_settings    = lgdt330x_get_tune_settings,
9699a0bf528SMauro Carvalho Chehab 	.read_status          = lgdt3303_read_status,
9709a0bf528SMauro Carvalho Chehab 	.read_signal_strength = lgdt330x_read_signal_strength,
97119bdd0d6SMauro Carvalho Chehab 	.read_snr             = lgdt330x_read_snr,
9729a0bf528SMauro Carvalho Chehab 	.read_ucblocks        = lgdt330x_read_ucblocks,
9739a0bf528SMauro Carvalho Chehab 	.release              = lgdt330x_release,
9749a0bf528SMauro Carvalho Chehab };
9759a0bf528SMauro Carvalho Chehab 
lgdt330x_remove(struct i2c_client * client)976ed5c2f5fSUwe Kleine-König static void lgdt330x_remove(struct i2c_client *client)
97723ba635dSMauro Carvalho Chehab {
97823ba635dSMauro Carvalho Chehab 	struct lgdt330x_state *state = i2c_get_clientdata(client);
97923ba635dSMauro Carvalho Chehab 
98023ba635dSMauro Carvalho Chehab 	dev_dbg(&client->dev, "\n");
98123ba635dSMauro Carvalho Chehab 
98223ba635dSMauro Carvalho Chehab 	kfree(state);
98323ba635dSMauro Carvalho Chehab }
98423ba635dSMauro Carvalho Chehab 
98523ba635dSMauro Carvalho Chehab static const struct i2c_device_id lgdt330x_id_table[] = {
98623ba635dSMauro Carvalho Chehab 	{"lgdt330x", 0},
98723ba635dSMauro Carvalho Chehab 	{}
98823ba635dSMauro Carvalho Chehab };
98923ba635dSMauro Carvalho Chehab MODULE_DEVICE_TABLE(i2c, lgdt330x_id_table);
99023ba635dSMauro Carvalho Chehab 
99123ba635dSMauro Carvalho Chehab static struct i2c_driver lgdt330x_driver = {
99223ba635dSMauro Carvalho Chehab 	.driver = {
99323ba635dSMauro Carvalho Chehab 		.name	= "lgdt330x",
99423ba635dSMauro Carvalho Chehab 		.suppress_bind_attrs = true,
99523ba635dSMauro Carvalho Chehab 	},
996aaeb31c0SUwe Kleine-König 	.probe		= lgdt330x_probe,
99723ba635dSMauro Carvalho Chehab 	.remove		= lgdt330x_remove,
99823ba635dSMauro Carvalho Chehab 	.id_table	= lgdt330x_id_table,
99923ba635dSMauro Carvalho Chehab };
100023ba635dSMauro Carvalho Chehab 
100123ba635dSMauro Carvalho Chehab module_i2c_driver(lgdt330x_driver);
100223ba635dSMauro Carvalho Chehab 
100323ba635dSMauro Carvalho Chehab 
10049a0bf528SMauro Carvalho Chehab MODULE_DESCRIPTION("LGDT330X (ATSC 8VSB & ITU-T J.83 AnnexB 64/256 QAM) Demodulator Driver");
10059a0bf528SMauro Carvalho Chehab MODULE_AUTHOR("Wilson Michaels");
10069a0bf528SMauro Carvalho Chehab MODULE_LICENSE("GPL");
1007