xref: /linux/drivers/media/dvb-frontends/lgdt3305.c (revision 86495af1171e1feec79faa9b64c05c89f46e41d1)
1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
29a0bf528SMauro Carvalho Chehab /*
39a0bf528SMauro Carvalho Chehab  *    Support for LG Electronics LGDT3304 and LGDT3305 - VSB/QAM
49a0bf528SMauro Carvalho Chehab  *
59a0bf528SMauro Carvalho Chehab  *    Copyright (C) 2008, 2009, 2010 Michael Krufky <mkrufky@linuxtv.org>
69a0bf528SMauro Carvalho Chehab  *
79a0bf528SMauro Carvalho Chehab  *    LGDT3304 support by Jarod Wilson <jarod@redhat.com>
89a0bf528SMauro Carvalho Chehab  */
99a0bf528SMauro Carvalho Chehab 
109a0bf528SMauro Carvalho Chehab #include <asm/div64.h>
119a0bf528SMauro Carvalho Chehab #include <linux/dvb/frontend.h>
129a0bf528SMauro Carvalho Chehab #include <linux/slab.h>
13f97fa3dcSAndy Shevchenko #include <linux/int_log.h>
149a0bf528SMauro Carvalho Chehab #include "lgdt3305.h"
159a0bf528SMauro Carvalho Chehab 
169a0bf528SMauro Carvalho Chehab static int debug;
179a0bf528SMauro Carvalho Chehab module_param(debug, int, 0644);
189a0bf528SMauro Carvalho Chehab MODULE_PARM_DESC(debug, "set debug level (info=1, reg=2 (or-able))");
199a0bf528SMauro Carvalho Chehab 
209a0bf528SMauro Carvalho Chehab #define DBG_INFO 1
219a0bf528SMauro Carvalho Chehab #define DBG_REG  2
229a0bf528SMauro Carvalho Chehab 
239a0bf528SMauro Carvalho Chehab #define lg_printk(kern, fmt, arg...)					\
249a0bf528SMauro Carvalho Chehab 	printk(kern "%s: " fmt, __func__, ##arg)
259a0bf528SMauro Carvalho Chehab 
269a0bf528SMauro Carvalho Chehab #define lg_info(fmt, arg...)	printk(KERN_INFO "lgdt3305: " fmt, ##arg)
279a0bf528SMauro Carvalho Chehab #define lg_warn(fmt, arg...)	lg_printk(KERN_WARNING,       fmt, ##arg)
289a0bf528SMauro Carvalho Chehab #define lg_err(fmt, arg...)	lg_printk(KERN_ERR,           fmt, ##arg)
299a0bf528SMauro Carvalho Chehab #define lg_dbg(fmt, arg...) if (debug & DBG_INFO)			\
309a0bf528SMauro Carvalho Chehab 				lg_printk(KERN_DEBUG,         fmt, ##arg)
319a0bf528SMauro Carvalho Chehab #define lg_reg(fmt, arg...) if (debug & DBG_REG)			\
329a0bf528SMauro Carvalho Chehab 				lg_printk(KERN_DEBUG,         fmt, ##arg)
339a0bf528SMauro Carvalho Chehab 
349a0bf528SMauro Carvalho Chehab #define lg_fail(ret)							\
359a0bf528SMauro Carvalho Chehab ({									\
369a0bf528SMauro Carvalho Chehab 	int __ret;							\
379a0bf528SMauro Carvalho Chehab 	__ret = (ret < 0);						\
389a0bf528SMauro Carvalho Chehab 	if (__ret)							\
399a0bf528SMauro Carvalho Chehab 		lg_err("error %d on line %d\n",	ret, __LINE__);		\
409a0bf528SMauro Carvalho Chehab 	__ret;								\
419a0bf528SMauro Carvalho Chehab })
429a0bf528SMauro Carvalho Chehab 
439a0bf528SMauro Carvalho Chehab struct lgdt3305_state {
449a0bf528SMauro Carvalho Chehab 	struct i2c_adapter *i2c_adap;
459a0bf528SMauro Carvalho Chehab 	const struct lgdt3305_config *cfg;
469a0bf528SMauro Carvalho Chehab 
479a0bf528SMauro Carvalho Chehab 	struct dvb_frontend frontend;
489a0bf528SMauro Carvalho Chehab 
490df289a2SMauro Carvalho Chehab 	enum fe_modulation current_modulation;
509a0bf528SMauro Carvalho Chehab 	u32 current_frequency;
519a0bf528SMauro Carvalho Chehab 	u32 snr;
529a0bf528SMauro Carvalho Chehab };
539a0bf528SMauro Carvalho Chehab 
549a0bf528SMauro Carvalho Chehab /* ------------------------------------------------------------------------ */
559a0bf528SMauro Carvalho Chehab 
569a0bf528SMauro Carvalho Chehab /* FIXME: verify & document the LGDT3304 registers */
579a0bf528SMauro Carvalho Chehab 
589a0bf528SMauro Carvalho Chehab #define LGDT3305_GEN_CTRL_1                   0x0000
599a0bf528SMauro Carvalho Chehab #define LGDT3305_GEN_CTRL_2                   0x0001
609a0bf528SMauro Carvalho Chehab #define LGDT3305_GEN_CTRL_3                   0x0002
619a0bf528SMauro Carvalho Chehab #define LGDT3305_GEN_STATUS                   0x0003
629a0bf528SMauro Carvalho Chehab #define LGDT3305_GEN_CONTROL                  0x0007
639a0bf528SMauro Carvalho Chehab #define LGDT3305_GEN_CTRL_4                   0x000a
649a0bf528SMauro Carvalho Chehab #define LGDT3305_DGTL_AGC_REF_1               0x0012
659a0bf528SMauro Carvalho Chehab #define LGDT3305_DGTL_AGC_REF_2               0x0013
669a0bf528SMauro Carvalho Chehab #define LGDT3305_CR_CTR_FREQ_1                0x0106
679a0bf528SMauro Carvalho Chehab #define LGDT3305_CR_CTR_FREQ_2                0x0107
689a0bf528SMauro Carvalho Chehab #define LGDT3305_CR_CTR_FREQ_3                0x0108
699a0bf528SMauro Carvalho Chehab #define LGDT3305_CR_CTR_FREQ_4                0x0109
709a0bf528SMauro Carvalho Chehab #define LGDT3305_CR_MSE_1                     0x011b
719a0bf528SMauro Carvalho Chehab #define LGDT3305_CR_MSE_2                     0x011c
729a0bf528SMauro Carvalho Chehab #define LGDT3305_CR_LOCK_STATUS               0x011d
739a0bf528SMauro Carvalho Chehab #define LGDT3305_CR_CTRL_7                    0x0126
749a0bf528SMauro Carvalho Chehab #define LGDT3305_AGC_POWER_REF_1              0x0300
759a0bf528SMauro Carvalho Chehab #define LGDT3305_AGC_POWER_REF_2              0x0301
769a0bf528SMauro Carvalho Chehab #define LGDT3305_AGC_DELAY_PT_1               0x0302
779a0bf528SMauro Carvalho Chehab #define LGDT3305_AGC_DELAY_PT_2               0x0303
789a0bf528SMauro Carvalho Chehab #define LGDT3305_RFAGC_LOOP_FLTR_BW_1         0x0306
799a0bf528SMauro Carvalho Chehab #define LGDT3305_RFAGC_LOOP_FLTR_BW_2         0x0307
809a0bf528SMauro Carvalho Chehab #define LGDT3305_IFBW_1                       0x0308
819a0bf528SMauro Carvalho Chehab #define LGDT3305_IFBW_2                       0x0309
829a0bf528SMauro Carvalho Chehab #define LGDT3305_AGC_CTRL_1                   0x030c
839a0bf528SMauro Carvalho Chehab #define LGDT3305_AGC_CTRL_4                   0x0314
849a0bf528SMauro Carvalho Chehab #define LGDT3305_EQ_MSE_1                     0x0413
859a0bf528SMauro Carvalho Chehab #define LGDT3305_EQ_MSE_2                     0x0414
869a0bf528SMauro Carvalho Chehab #define LGDT3305_EQ_MSE_3                     0x0415
879a0bf528SMauro Carvalho Chehab #define LGDT3305_PT_MSE_1                     0x0417
889a0bf528SMauro Carvalho Chehab #define LGDT3305_PT_MSE_2                     0x0418
899a0bf528SMauro Carvalho Chehab #define LGDT3305_PT_MSE_3                     0x0419
909a0bf528SMauro Carvalho Chehab #define LGDT3305_FEC_BLOCK_CTRL               0x0504
919a0bf528SMauro Carvalho Chehab #define LGDT3305_FEC_LOCK_STATUS              0x050a
929a0bf528SMauro Carvalho Chehab #define LGDT3305_FEC_PKT_ERR_1                0x050c
939a0bf528SMauro Carvalho Chehab #define LGDT3305_FEC_PKT_ERR_2                0x050d
949a0bf528SMauro Carvalho Chehab #define LGDT3305_TP_CTRL_1                    0x050e
959a0bf528SMauro Carvalho Chehab #define LGDT3305_BERT_PERIOD                  0x0801
969a0bf528SMauro Carvalho Chehab #define LGDT3305_BERT_ERROR_COUNT_1           0x080a
979a0bf528SMauro Carvalho Chehab #define LGDT3305_BERT_ERROR_COUNT_2           0x080b
989a0bf528SMauro Carvalho Chehab #define LGDT3305_BERT_ERROR_COUNT_3           0x080c
999a0bf528SMauro Carvalho Chehab #define LGDT3305_BERT_ERROR_COUNT_4           0x080d
1009a0bf528SMauro Carvalho Chehab 
1019a0bf528SMauro Carvalho Chehab static int lgdt3305_write_reg(struct lgdt3305_state *state, u16 reg, u8 val)
1029a0bf528SMauro Carvalho Chehab {
1039a0bf528SMauro Carvalho Chehab 	int ret;
1049a0bf528SMauro Carvalho Chehab 	u8 buf[] = { reg >> 8, reg & 0xff, val };
1059a0bf528SMauro Carvalho Chehab 	struct i2c_msg msg = {
1069a0bf528SMauro Carvalho Chehab 		.addr = state->cfg->i2c_addr, .flags = 0,
1079a0bf528SMauro Carvalho Chehab 		.buf = buf, .len = 3,
1089a0bf528SMauro Carvalho Chehab 	};
1099a0bf528SMauro Carvalho Chehab 
1109a0bf528SMauro Carvalho Chehab 	lg_reg("reg: 0x%04x, val: 0x%02x\n", reg, val);
1119a0bf528SMauro Carvalho Chehab 
1129a0bf528SMauro Carvalho Chehab 	ret = i2c_transfer(state->i2c_adap, &msg, 1);
1139a0bf528SMauro Carvalho Chehab 
1149a0bf528SMauro Carvalho Chehab 	if (ret != 1) {
1159a0bf528SMauro Carvalho Chehab 		lg_err("error (addr %02x %02x <- %02x, err = %i)\n",
1169a0bf528SMauro Carvalho Chehab 		       msg.buf[0], msg.buf[1], msg.buf[2], ret);
1179a0bf528SMauro Carvalho Chehab 		if (ret < 0)
1189a0bf528SMauro Carvalho Chehab 			return ret;
1199a0bf528SMauro Carvalho Chehab 		else
1209a0bf528SMauro Carvalho Chehab 			return -EREMOTEIO;
1219a0bf528SMauro Carvalho Chehab 	}
1229a0bf528SMauro Carvalho Chehab 	return 0;
1239a0bf528SMauro Carvalho Chehab }
1249a0bf528SMauro Carvalho Chehab 
1259a0bf528SMauro Carvalho Chehab static int lgdt3305_read_reg(struct lgdt3305_state *state, u16 reg, u8 *val)
1269a0bf528SMauro Carvalho Chehab {
1279a0bf528SMauro Carvalho Chehab 	int ret;
1289a0bf528SMauro Carvalho Chehab 	u8 reg_buf[] = { reg >> 8, reg & 0xff };
1299a0bf528SMauro Carvalho Chehab 	struct i2c_msg msg[] = {
1309a0bf528SMauro Carvalho Chehab 		{ .addr = state->cfg->i2c_addr,
1319a0bf528SMauro Carvalho Chehab 		  .flags = 0, .buf = reg_buf, .len = 2 },
1329a0bf528SMauro Carvalho Chehab 		{ .addr = state->cfg->i2c_addr,
1339a0bf528SMauro Carvalho Chehab 		  .flags = I2C_M_RD, .buf = val, .len = 1 },
1349a0bf528SMauro Carvalho Chehab 	};
1359a0bf528SMauro Carvalho Chehab 
1369a0bf528SMauro Carvalho Chehab 	lg_reg("reg: 0x%04x\n", reg);
1379a0bf528SMauro Carvalho Chehab 
1389a0bf528SMauro Carvalho Chehab 	ret = i2c_transfer(state->i2c_adap, msg, 2);
1399a0bf528SMauro Carvalho Chehab 
1409a0bf528SMauro Carvalho Chehab 	if (ret != 2) {
1419a0bf528SMauro Carvalho Chehab 		lg_err("error (addr %02x reg %04x error (ret == %i)\n",
1429a0bf528SMauro Carvalho Chehab 		       state->cfg->i2c_addr, reg, ret);
1439a0bf528SMauro Carvalho Chehab 		if (ret < 0)
1449a0bf528SMauro Carvalho Chehab 			return ret;
1459a0bf528SMauro Carvalho Chehab 		else
1469a0bf528SMauro Carvalho Chehab 			return -EREMOTEIO;
1479a0bf528SMauro Carvalho Chehab 	}
1489a0bf528SMauro Carvalho Chehab 	return 0;
1499a0bf528SMauro Carvalho Chehab }
1509a0bf528SMauro Carvalho Chehab 
1519a0bf528SMauro Carvalho Chehab #define read_reg(state, reg)						\
1529a0bf528SMauro Carvalho Chehab ({									\
1539a0bf528SMauro Carvalho Chehab 	u8 __val;							\
1549a0bf528SMauro Carvalho Chehab 	int ret = lgdt3305_read_reg(state, reg, &__val);		\
1559a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))						\
1569a0bf528SMauro Carvalho Chehab 		__val = 0;						\
1579a0bf528SMauro Carvalho Chehab 	__val;								\
1589a0bf528SMauro Carvalho Chehab })
1599a0bf528SMauro Carvalho Chehab 
1609a0bf528SMauro Carvalho Chehab static int lgdt3305_set_reg_bit(struct lgdt3305_state *state,
1619a0bf528SMauro Carvalho Chehab 				u16 reg, int bit, int onoff)
1629a0bf528SMauro Carvalho Chehab {
1639a0bf528SMauro Carvalho Chehab 	u8 val;
1649a0bf528SMauro Carvalho Chehab 	int ret;
1659a0bf528SMauro Carvalho Chehab 
1669a0bf528SMauro Carvalho Chehab 	lg_reg("reg: 0x%04x, bit: %d, level: %d\n", reg, bit, onoff);
1679a0bf528SMauro Carvalho Chehab 
1689a0bf528SMauro Carvalho Chehab 	ret = lgdt3305_read_reg(state, reg, &val);
1699a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
1709a0bf528SMauro Carvalho Chehab 		goto fail;
1719a0bf528SMauro Carvalho Chehab 
1729a0bf528SMauro Carvalho Chehab 	val &= ~(1 << bit);
1739a0bf528SMauro Carvalho Chehab 	val |= (onoff & 1) << bit;
1749a0bf528SMauro Carvalho Chehab 
1759a0bf528SMauro Carvalho Chehab 	ret = lgdt3305_write_reg(state, reg, val);
1769a0bf528SMauro Carvalho Chehab fail:
1779a0bf528SMauro Carvalho Chehab 	return ret;
1789a0bf528SMauro Carvalho Chehab }
1799a0bf528SMauro Carvalho Chehab 
1809a0bf528SMauro Carvalho Chehab struct lgdt3305_reg {
1819a0bf528SMauro Carvalho Chehab 	u16 reg;
1829a0bf528SMauro Carvalho Chehab 	u8 val;
1839a0bf528SMauro Carvalho Chehab };
1849a0bf528SMauro Carvalho Chehab 
1859a0bf528SMauro Carvalho Chehab static int lgdt3305_write_regs(struct lgdt3305_state *state,
1869a0bf528SMauro Carvalho Chehab 			       struct lgdt3305_reg *regs, int len)
1879a0bf528SMauro Carvalho Chehab {
1889a0bf528SMauro Carvalho Chehab 	int i, ret;
1899a0bf528SMauro Carvalho Chehab 
1909a0bf528SMauro Carvalho Chehab 	lg_reg("writing %d registers...\n", len);
1919a0bf528SMauro Carvalho Chehab 
1929a0bf528SMauro Carvalho Chehab 	for (i = 0; i < len - 1; i++) {
1939a0bf528SMauro Carvalho Chehab 		ret = lgdt3305_write_reg(state, regs[i].reg, regs[i].val);
1949a0bf528SMauro Carvalho Chehab 		if (lg_fail(ret))
1959a0bf528SMauro Carvalho Chehab 			return ret;
1969a0bf528SMauro Carvalho Chehab 	}
1979a0bf528SMauro Carvalho Chehab 	return 0;
1989a0bf528SMauro Carvalho Chehab }
1999a0bf528SMauro Carvalho Chehab 
2009a0bf528SMauro Carvalho Chehab /* ------------------------------------------------------------------------ */
2019a0bf528SMauro Carvalho Chehab 
2029a0bf528SMauro Carvalho Chehab static int lgdt3305_soft_reset(struct lgdt3305_state *state)
2039a0bf528SMauro Carvalho Chehab {
2049a0bf528SMauro Carvalho Chehab 	int ret;
2059a0bf528SMauro Carvalho Chehab 
2069a0bf528SMauro Carvalho Chehab 	lg_dbg("\n");
2079a0bf528SMauro Carvalho Chehab 
2089a0bf528SMauro Carvalho Chehab 	ret = lgdt3305_set_reg_bit(state, LGDT3305_GEN_CTRL_3, 0, 0);
2099a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
2109a0bf528SMauro Carvalho Chehab 		goto fail;
2119a0bf528SMauro Carvalho Chehab 
2129a0bf528SMauro Carvalho Chehab 	msleep(20);
2139a0bf528SMauro Carvalho Chehab 	ret = lgdt3305_set_reg_bit(state, LGDT3305_GEN_CTRL_3, 0, 1);
2149a0bf528SMauro Carvalho Chehab fail:
2159a0bf528SMauro Carvalho Chehab 	return ret;
2169a0bf528SMauro Carvalho Chehab }
2179a0bf528SMauro Carvalho Chehab 
2189a0bf528SMauro Carvalho Chehab static inline int lgdt3305_mpeg_mode(struct lgdt3305_state *state,
2199a0bf528SMauro Carvalho Chehab 				     enum lgdt3305_mpeg_mode mode)
2209a0bf528SMauro Carvalho Chehab {
2219a0bf528SMauro Carvalho Chehab 	lg_dbg("(%d)\n", mode);
2229a0bf528SMauro Carvalho Chehab 	return lgdt3305_set_reg_bit(state, LGDT3305_TP_CTRL_1, 5, mode);
2239a0bf528SMauro Carvalho Chehab }
2249a0bf528SMauro Carvalho Chehab 
225bdba90dfSMichael Ira Krufky static int lgdt3305_mpeg_mode_polarity(struct lgdt3305_state *state)
2269a0bf528SMauro Carvalho Chehab {
2279a0bf528SMauro Carvalho Chehab 	u8 val;
2289a0bf528SMauro Carvalho Chehab 	int ret;
229bdba90dfSMichael Ira Krufky 	enum lgdt3305_tp_clock_edge edge = state->cfg->tpclk_edge;
23027f7ef7cSMichael Ira Krufky 	enum lgdt3305_tp_clock_mode mode = state->cfg->tpclk_mode;
231bdba90dfSMichael Ira Krufky 	enum lgdt3305_tp_valid_polarity valid = state->cfg->tpvalid_polarity;
2329a0bf528SMauro Carvalho Chehab 
2339a0bf528SMauro Carvalho Chehab 	lg_dbg("edge = %d, valid = %d\n", edge, valid);
2349a0bf528SMauro Carvalho Chehab 
2359a0bf528SMauro Carvalho Chehab 	ret = lgdt3305_read_reg(state, LGDT3305_TP_CTRL_1, &val);
2369a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
2379a0bf528SMauro Carvalho Chehab 		goto fail;
2389a0bf528SMauro Carvalho Chehab 
2399a0bf528SMauro Carvalho Chehab 	val &= ~0x09;
2409a0bf528SMauro Carvalho Chehab 
2419a0bf528SMauro Carvalho Chehab 	if (edge)
2429a0bf528SMauro Carvalho Chehab 		val |= 0x08;
24327f7ef7cSMichael Ira Krufky 	if (mode)
24427f7ef7cSMichael Ira Krufky 		val |= 0x40;
2459a0bf528SMauro Carvalho Chehab 	if (valid)
2469a0bf528SMauro Carvalho Chehab 		val |= 0x01;
2479a0bf528SMauro Carvalho Chehab 
2489a0bf528SMauro Carvalho Chehab 	ret = lgdt3305_write_reg(state, LGDT3305_TP_CTRL_1, val);
2499a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
2509a0bf528SMauro Carvalho Chehab 		goto fail;
2519a0bf528SMauro Carvalho Chehab 
2529a0bf528SMauro Carvalho Chehab 	ret = lgdt3305_soft_reset(state);
2539a0bf528SMauro Carvalho Chehab fail:
2549a0bf528SMauro Carvalho Chehab 	return ret;
2559a0bf528SMauro Carvalho Chehab }
2569a0bf528SMauro Carvalho Chehab 
2579a0bf528SMauro Carvalho Chehab static int lgdt3305_set_modulation(struct lgdt3305_state *state,
2589a0bf528SMauro Carvalho Chehab 				   struct dtv_frontend_properties *p)
2599a0bf528SMauro Carvalho Chehab {
2609a0bf528SMauro Carvalho Chehab 	u8 opermode;
2619a0bf528SMauro Carvalho Chehab 	int ret;
2629a0bf528SMauro Carvalho Chehab 
2639a0bf528SMauro Carvalho Chehab 	lg_dbg("\n");
2649a0bf528SMauro Carvalho Chehab 
2659a0bf528SMauro Carvalho Chehab 	ret = lgdt3305_read_reg(state, LGDT3305_GEN_CTRL_1, &opermode);
2669a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
2679a0bf528SMauro Carvalho Chehab 		goto fail;
2689a0bf528SMauro Carvalho Chehab 
2699a0bf528SMauro Carvalho Chehab 	opermode &= ~0x03;
2709a0bf528SMauro Carvalho Chehab 
2719a0bf528SMauro Carvalho Chehab 	switch (p->modulation) {
2729a0bf528SMauro Carvalho Chehab 	case VSB_8:
2739a0bf528SMauro Carvalho Chehab 		opermode |= 0x03;
2749a0bf528SMauro Carvalho Chehab 		break;
2759a0bf528SMauro Carvalho Chehab 	case QAM_64:
2769a0bf528SMauro Carvalho Chehab 		opermode |= 0x00;
2779a0bf528SMauro Carvalho Chehab 		break;
2789a0bf528SMauro Carvalho Chehab 	case QAM_256:
2799a0bf528SMauro Carvalho Chehab 		opermode |= 0x01;
2809a0bf528SMauro Carvalho Chehab 		break;
2819a0bf528SMauro Carvalho Chehab 	default:
2829a0bf528SMauro Carvalho Chehab 		return -EINVAL;
2839a0bf528SMauro Carvalho Chehab 	}
2849a0bf528SMauro Carvalho Chehab 	ret = lgdt3305_write_reg(state, LGDT3305_GEN_CTRL_1, opermode);
2859a0bf528SMauro Carvalho Chehab fail:
2869a0bf528SMauro Carvalho Chehab 	return ret;
2879a0bf528SMauro Carvalho Chehab }
2889a0bf528SMauro Carvalho Chehab 
2899a0bf528SMauro Carvalho Chehab static int lgdt3305_set_filter_extension(struct lgdt3305_state *state,
2909a0bf528SMauro Carvalho Chehab 					 struct dtv_frontend_properties *p)
2919a0bf528SMauro Carvalho Chehab {
2929a0bf528SMauro Carvalho Chehab 	int val;
2939a0bf528SMauro Carvalho Chehab 
2949a0bf528SMauro Carvalho Chehab 	switch (p->modulation) {
2959a0bf528SMauro Carvalho Chehab 	case VSB_8:
2969a0bf528SMauro Carvalho Chehab 		val = 0;
2979a0bf528SMauro Carvalho Chehab 		break;
2989a0bf528SMauro Carvalho Chehab 	case QAM_64:
2999a0bf528SMauro Carvalho Chehab 	case QAM_256:
3009a0bf528SMauro Carvalho Chehab 		val = 1;
3019a0bf528SMauro Carvalho Chehab 		break;
3029a0bf528SMauro Carvalho Chehab 	default:
3039a0bf528SMauro Carvalho Chehab 		return -EINVAL;
3049a0bf528SMauro Carvalho Chehab 	}
3059a0bf528SMauro Carvalho Chehab 	lg_dbg("val = %d\n", val);
3069a0bf528SMauro Carvalho Chehab 
3079a0bf528SMauro Carvalho Chehab 	return lgdt3305_set_reg_bit(state, 0x043f, 2, val);
3089a0bf528SMauro Carvalho Chehab }
3099a0bf528SMauro Carvalho Chehab 
3109a0bf528SMauro Carvalho Chehab /* ------------------------------------------------------------------------ */
3119a0bf528SMauro Carvalho Chehab 
3129a0bf528SMauro Carvalho Chehab static int lgdt3305_passband_digital_agc(struct lgdt3305_state *state,
3139a0bf528SMauro Carvalho Chehab 					 struct dtv_frontend_properties *p)
3149a0bf528SMauro Carvalho Chehab {
3159a0bf528SMauro Carvalho Chehab 	u16 agc_ref;
3169a0bf528SMauro Carvalho Chehab 
3179a0bf528SMauro Carvalho Chehab 	switch (p->modulation) {
3189a0bf528SMauro Carvalho Chehab 	case VSB_8:
3199a0bf528SMauro Carvalho Chehab 		agc_ref = 0x32c4;
3209a0bf528SMauro Carvalho Chehab 		break;
3219a0bf528SMauro Carvalho Chehab 	case QAM_64:
3229a0bf528SMauro Carvalho Chehab 		agc_ref = 0x2a00;
3239a0bf528SMauro Carvalho Chehab 		break;
3249a0bf528SMauro Carvalho Chehab 	case QAM_256:
3259a0bf528SMauro Carvalho Chehab 		agc_ref = 0x2a80;
3269a0bf528SMauro Carvalho Chehab 		break;
3279a0bf528SMauro Carvalho Chehab 	default:
3289a0bf528SMauro Carvalho Chehab 		return -EINVAL;
3299a0bf528SMauro Carvalho Chehab 	}
3309a0bf528SMauro Carvalho Chehab 
3319a0bf528SMauro Carvalho Chehab 	lg_dbg("agc ref: 0x%04x\n", agc_ref);
3329a0bf528SMauro Carvalho Chehab 
3339a0bf528SMauro Carvalho Chehab 	lgdt3305_write_reg(state, LGDT3305_DGTL_AGC_REF_1, agc_ref >> 8);
3349a0bf528SMauro Carvalho Chehab 	lgdt3305_write_reg(state, LGDT3305_DGTL_AGC_REF_2, agc_ref & 0xff);
3359a0bf528SMauro Carvalho Chehab 
3369a0bf528SMauro Carvalho Chehab 	return 0;
3379a0bf528SMauro Carvalho Chehab }
3389a0bf528SMauro Carvalho Chehab 
3399a0bf528SMauro Carvalho Chehab static int lgdt3305_rfagc_loop(struct lgdt3305_state *state,
3409a0bf528SMauro Carvalho Chehab 			       struct dtv_frontend_properties *p)
3419a0bf528SMauro Carvalho Chehab {
3429a0bf528SMauro Carvalho Chehab 	u16 ifbw, rfbw, agcdelay;
3439a0bf528SMauro Carvalho Chehab 
3449a0bf528SMauro Carvalho Chehab 	switch (p->modulation) {
3459a0bf528SMauro Carvalho Chehab 	case VSB_8:
3469a0bf528SMauro Carvalho Chehab 		agcdelay = 0x04c0;
3479a0bf528SMauro Carvalho Chehab 		rfbw     = 0x8000;
3489a0bf528SMauro Carvalho Chehab 		ifbw     = 0x8000;
3499a0bf528SMauro Carvalho Chehab 		break;
3509a0bf528SMauro Carvalho Chehab 	case QAM_64:
3519a0bf528SMauro Carvalho Chehab 	case QAM_256:
3529a0bf528SMauro Carvalho Chehab 		agcdelay = 0x046b;
3539a0bf528SMauro Carvalho Chehab 		rfbw     = 0x8889;
3549a0bf528SMauro Carvalho Chehab 		/* FIXME: investigate optimal ifbw & rfbw values for the
3559a0bf528SMauro Carvalho Chehab 		 *        DT3304 and re-write this switch..case block */
3569a0bf528SMauro Carvalho Chehab 		if (state->cfg->demod_chip == LGDT3304)
3579a0bf528SMauro Carvalho Chehab 			ifbw = 0x6666;
3589a0bf528SMauro Carvalho Chehab 		else /* (state->cfg->demod_chip == LGDT3305) */
3599a0bf528SMauro Carvalho Chehab 			ifbw = 0x8888;
3609a0bf528SMauro Carvalho Chehab 		break;
3619a0bf528SMauro Carvalho Chehab 	default:
3629a0bf528SMauro Carvalho Chehab 		return -EINVAL;
3639a0bf528SMauro Carvalho Chehab 	}
3649a0bf528SMauro Carvalho Chehab 
3659a0bf528SMauro Carvalho Chehab 	if (state->cfg->rf_agc_loop) {
3669a0bf528SMauro Carvalho Chehab 		lg_dbg("agcdelay: 0x%04x, rfbw: 0x%04x\n", agcdelay, rfbw);
3679a0bf528SMauro Carvalho Chehab 
3689a0bf528SMauro Carvalho Chehab 		/* rf agc loop filter bandwidth */
3699a0bf528SMauro Carvalho Chehab 		lgdt3305_write_reg(state, LGDT3305_AGC_DELAY_PT_1,
3709a0bf528SMauro Carvalho Chehab 				   agcdelay >> 8);
3719a0bf528SMauro Carvalho Chehab 		lgdt3305_write_reg(state, LGDT3305_AGC_DELAY_PT_2,
3729a0bf528SMauro Carvalho Chehab 				   agcdelay & 0xff);
3739a0bf528SMauro Carvalho Chehab 
3749a0bf528SMauro Carvalho Chehab 		lgdt3305_write_reg(state, LGDT3305_RFAGC_LOOP_FLTR_BW_1,
3759a0bf528SMauro Carvalho Chehab 				   rfbw >> 8);
3769a0bf528SMauro Carvalho Chehab 		lgdt3305_write_reg(state, LGDT3305_RFAGC_LOOP_FLTR_BW_2,
3779a0bf528SMauro Carvalho Chehab 				   rfbw & 0xff);
3789a0bf528SMauro Carvalho Chehab 	} else {
3799a0bf528SMauro Carvalho Chehab 		lg_dbg("ifbw: 0x%04x\n", ifbw);
3809a0bf528SMauro Carvalho Chehab 
3819a0bf528SMauro Carvalho Chehab 		/* if agc loop filter bandwidth */
3829a0bf528SMauro Carvalho Chehab 		lgdt3305_write_reg(state, LGDT3305_IFBW_1, ifbw >> 8);
3839a0bf528SMauro Carvalho Chehab 		lgdt3305_write_reg(state, LGDT3305_IFBW_2, ifbw & 0xff);
3849a0bf528SMauro Carvalho Chehab 	}
3859a0bf528SMauro Carvalho Chehab 
3869a0bf528SMauro Carvalho Chehab 	return 0;
3879a0bf528SMauro Carvalho Chehab }
3889a0bf528SMauro Carvalho Chehab 
3899a0bf528SMauro Carvalho Chehab static int lgdt3305_agc_setup(struct lgdt3305_state *state,
3909a0bf528SMauro Carvalho Chehab 			      struct dtv_frontend_properties *p)
3919a0bf528SMauro Carvalho Chehab {
3929a0bf528SMauro Carvalho Chehab 	int lockdten, acqen;
3939a0bf528SMauro Carvalho Chehab 
3949a0bf528SMauro Carvalho Chehab 	switch (p->modulation) {
3959a0bf528SMauro Carvalho Chehab 	case VSB_8:
3969a0bf528SMauro Carvalho Chehab 		lockdten = 0;
3979a0bf528SMauro Carvalho Chehab 		acqen = 0;
3989a0bf528SMauro Carvalho Chehab 		break;
3999a0bf528SMauro Carvalho Chehab 	case QAM_64:
4009a0bf528SMauro Carvalho Chehab 	case QAM_256:
4019a0bf528SMauro Carvalho Chehab 		lockdten = 1;
4029a0bf528SMauro Carvalho Chehab 		acqen = 1;
4039a0bf528SMauro Carvalho Chehab 		break;
4049a0bf528SMauro Carvalho Chehab 	default:
4059a0bf528SMauro Carvalho Chehab 		return -EINVAL;
4069a0bf528SMauro Carvalho Chehab 	}
4079a0bf528SMauro Carvalho Chehab 
4089a0bf528SMauro Carvalho Chehab 	lg_dbg("lockdten = %d, acqen = %d\n", lockdten, acqen);
4099a0bf528SMauro Carvalho Chehab 
4109a0bf528SMauro Carvalho Chehab 	/* control agc function */
4119a0bf528SMauro Carvalho Chehab 	switch (state->cfg->demod_chip) {
4129a0bf528SMauro Carvalho Chehab 	case LGDT3304:
4139a0bf528SMauro Carvalho Chehab 		lgdt3305_write_reg(state, 0x0314, 0xe1 | lockdten << 1);
4149a0bf528SMauro Carvalho Chehab 		lgdt3305_set_reg_bit(state, 0x030e, 2, acqen);
4159a0bf528SMauro Carvalho Chehab 		break;
4169a0bf528SMauro Carvalho Chehab 	case LGDT3305:
4179a0bf528SMauro Carvalho Chehab 		lgdt3305_write_reg(state, LGDT3305_AGC_CTRL_4, 0xe1 | lockdten << 1);
4189a0bf528SMauro Carvalho Chehab 		lgdt3305_set_reg_bit(state, LGDT3305_AGC_CTRL_1, 2, acqen);
4199a0bf528SMauro Carvalho Chehab 		break;
4209a0bf528SMauro Carvalho Chehab 	default:
4219a0bf528SMauro Carvalho Chehab 		return -EINVAL;
4229a0bf528SMauro Carvalho Chehab 	}
4239a0bf528SMauro Carvalho Chehab 
4249a0bf528SMauro Carvalho Chehab 	return lgdt3305_rfagc_loop(state, p);
4259a0bf528SMauro Carvalho Chehab }
4269a0bf528SMauro Carvalho Chehab 
4279a0bf528SMauro Carvalho Chehab static int lgdt3305_set_agc_power_ref(struct lgdt3305_state *state,
4289a0bf528SMauro Carvalho Chehab 				      struct dtv_frontend_properties *p)
4299a0bf528SMauro Carvalho Chehab {
4309a0bf528SMauro Carvalho Chehab 	u16 usref = 0;
4319a0bf528SMauro Carvalho Chehab 
4329a0bf528SMauro Carvalho Chehab 	switch (p->modulation) {
4339a0bf528SMauro Carvalho Chehab 	case VSB_8:
4349a0bf528SMauro Carvalho Chehab 		if (state->cfg->usref_8vsb)
4359a0bf528SMauro Carvalho Chehab 			usref = state->cfg->usref_8vsb;
4369a0bf528SMauro Carvalho Chehab 		break;
4379a0bf528SMauro Carvalho Chehab 	case QAM_64:
4389a0bf528SMauro Carvalho Chehab 		if (state->cfg->usref_qam64)
4399a0bf528SMauro Carvalho Chehab 			usref = state->cfg->usref_qam64;
4409a0bf528SMauro Carvalho Chehab 		break;
4419a0bf528SMauro Carvalho Chehab 	case QAM_256:
4429a0bf528SMauro Carvalho Chehab 		if (state->cfg->usref_qam256)
4439a0bf528SMauro Carvalho Chehab 			usref = state->cfg->usref_qam256;
4449a0bf528SMauro Carvalho Chehab 		break;
4459a0bf528SMauro Carvalho Chehab 	default:
4469a0bf528SMauro Carvalho Chehab 		return -EINVAL;
4479a0bf528SMauro Carvalho Chehab 	}
4489a0bf528SMauro Carvalho Chehab 
4499a0bf528SMauro Carvalho Chehab 	if (usref) {
4509a0bf528SMauro Carvalho Chehab 		lg_dbg("set manual mode: 0x%04x\n", usref);
4519a0bf528SMauro Carvalho Chehab 
4529a0bf528SMauro Carvalho Chehab 		lgdt3305_set_reg_bit(state, LGDT3305_AGC_CTRL_1, 3, 1);
4539a0bf528SMauro Carvalho Chehab 
4549a0bf528SMauro Carvalho Chehab 		lgdt3305_write_reg(state, LGDT3305_AGC_POWER_REF_1,
4559a0bf528SMauro Carvalho Chehab 				   0xff & (usref >> 8));
4569a0bf528SMauro Carvalho Chehab 		lgdt3305_write_reg(state, LGDT3305_AGC_POWER_REF_2,
4579a0bf528SMauro Carvalho Chehab 				   0xff & (usref >> 0));
4589a0bf528SMauro Carvalho Chehab 	}
4599a0bf528SMauro Carvalho Chehab 	return 0;
4609a0bf528SMauro Carvalho Chehab }
4619a0bf528SMauro Carvalho Chehab 
4629a0bf528SMauro Carvalho Chehab /* ------------------------------------------------------------------------ */
4639a0bf528SMauro Carvalho Chehab 
4649a0bf528SMauro Carvalho Chehab static int lgdt3305_spectral_inversion(struct lgdt3305_state *state,
4659a0bf528SMauro Carvalho Chehab 				       struct dtv_frontend_properties *p,
4669a0bf528SMauro Carvalho Chehab 				       int inversion)
4679a0bf528SMauro Carvalho Chehab {
4689a0bf528SMauro Carvalho Chehab 	int ret;
4699a0bf528SMauro Carvalho Chehab 
4709a0bf528SMauro Carvalho Chehab 	lg_dbg("(%d)\n", inversion);
4719a0bf528SMauro Carvalho Chehab 
4729a0bf528SMauro Carvalho Chehab 	switch (p->modulation) {
4739a0bf528SMauro Carvalho Chehab 	case VSB_8:
4749a0bf528SMauro Carvalho Chehab 		ret = lgdt3305_write_reg(state, LGDT3305_CR_CTRL_7,
4759a0bf528SMauro Carvalho Chehab 					 inversion ? 0xf9 : 0x79);
4769a0bf528SMauro Carvalho Chehab 		break;
4779a0bf528SMauro Carvalho Chehab 	case QAM_64:
4789a0bf528SMauro Carvalho Chehab 	case QAM_256:
4799a0bf528SMauro Carvalho Chehab 		ret = lgdt3305_write_reg(state, LGDT3305_FEC_BLOCK_CTRL,
4809a0bf528SMauro Carvalho Chehab 					 inversion ? 0xfd : 0xff);
4819a0bf528SMauro Carvalho Chehab 		break;
4829a0bf528SMauro Carvalho Chehab 	default:
4839a0bf528SMauro Carvalho Chehab 		ret = -EINVAL;
4849a0bf528SMauro Carvalho Chehab 	}
4859a0bf528SMauro Carvalho Chehab 	return ret;
4869a0bf528SMauro Carvalho Chehab }
4879a0bf528SMauro Carvalho Chehab 
4889a0bf528SMauro Carvalho Chehab static int lgdt3305_set_if(struct lgdt3305_state *state,
4899a0bf528SMauro Carvalho Chehab 			   struct dtv_frontend_properties *p)
4909a0bf528SMauro Carvalho Chehab {
4919a0bf528SMauro Carvalho Chehab 	u16 if_freq_khz;
4929a0bf528SMauro Carvalho Chehab 	u8 nco1, nco2, nco3, nco4;
4939a0bf528SMauro Carvalho Chehab 	u64 nco;
4949a0bf528SMauro Carvalho Chehab 
4959a0bf528SMauro Carvalho Chehab 	switch (p->modulation) {
4969a0bf528SMauro Carvalho Chehab 	case VSB_8:
4979a0bf528SMauro Carvalho Chehab 		if_freq_khz = state->cfg->vsb_if_khz;
4989a0bf528SMauro Carvalho Chehab 		break;
4999a0bf528SMauro Carvalho Chehab 	case QAM_64:
5009a0bf528SMauro Carvalho Chehab 	case QAM_256:
5019a0bf528SMauro Carvalho Chehab 		if_freq_khz = state->cfg->qam_if_khz;
5029a0bf528SMauro Carvalho Chehab 		break;
5039a0bf528SMauro Carvalho Chehab 	default:
5049a0bf528SMauro Carvalho Chehab 		return -EINVAL;
5059a0bf528SMauro Carvalho Chehab 	}
5069a0bf528SMauro Carvalho Chehab 
5079a0bf528SMauro Carvalho Chehab 	nco = if_freq_khz / 10;
5089a0bf528SMauro Carvalho Chehab 
5099a0bf528SMauro Carvalho Chehab 	switch (p->modulation) {
5109a0bf528SMauro Carvalho Chehab 	case VSB_8:
5119a0bf528SMauro Carvalho Chehab 		nco <<= 24;
5129a0bf528SMauro Carvalho Chehab 		do_div(nco, 625);
5139a0bf528SMauro Carvalho Chehab 		break;
5149a0bf528SMauro Carvalho Chehab 	case QAM_64:
5159a0bf528SMauro Carvalho Chehab 	case QAM_256:
5169a0bf528SMauro Carvalho Chehab 		nco <<= 28;
5179a0bf528SMauro Carvalho Chehab 		do_div(nco, 625);
5189a0bf528SMauro Carvalho Chehab 		break;
5199a0bf528SMauro Carvalho Chehab 	default:
5209a0bf528SMauro Carvalho Chehab 		return -EINVAL;
5219a0bf528SMauro Carvalho Chehab 	}
5229a0bf528SMauro Carvalho Chehab 
5239a0bf528SMauro Carvalho Chehab 	nco1 = (nco >> 24) & 0x3f;
5249a0bf528SMauro Carvalho Chehab 	nco1 |= 0x40;
5259a0bf528SMauro Carvalho Chehab 	nco2 = (nco >> 16) & 0xff;
5269a0bf528SMauro Carvalho Chehab 	nco3 = (nco >> 8) & 0xff;
5279a0bf528SMauro Carvalho Chehab 	nco4 = nco & 0xff;
5289a0bf528SMauro Carvalho Chehab 
5299a0bf528SMauro Carvalho Chehab 	lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_1, nco1);
5309a0bf528SMauro Carvalho Chehab 	lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_2, nco2);
5319a0bf528SMauro Carvalho Chehab 	lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_3, nco3);
5329a0bf528SMauro Carvalho Chehab 	lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_4, nco4);
5339a0bf528SMauro Carvalho Chehab 
5349a0bf528SMauro Carvalho Chehab 	lg_dbg("%d KHz -> [%02x%02x%02x%02x]\n",
5359a0bf528SMauro Carvalho Chehab 	       if_freq_khz, nco1, nco2, nco3, nco4);
5369a0bf528SMauro Carvalho Chehab 
5379a0bf528SMauro Carvalho Chehab 	return 0;
5389a0bf528SMauro Carvalho Chehab }
5399a0bf528SMauro Carvalho Chehab 
5409a0bf528SMauro Carvalho Chehab /* ------------------------------------------------------------------------ */
5419a0bf528SMauro Carvalho Chehab 
5429a0bf528SMauro Carvalho Chehab static int lgdt3305_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
5439a0bf528SMauro Carvalho Chehab {
5449a0bf528SMauro Carvalho Chehab 	struct lgdt3305_state *state = fe->demodulator_priv;
5459a0bf528SMauro Carvalho Chehab 
5469a0bf528SMauro Carvalho Chehab 	if (state->cfg->deny_i2c_rptr)
5479a0bf528SMauro Carvalho Chehab 		return 0;
5489a0bf528SMauro Carvalho Chehab 
5499a0bf528SMauro Carvalho Chehab 	lg_dbg("(%d)\n", enable);
5509a0bf528SMauro Carvalho Chehab 
5519a0bf528SMauro Carvalho Chehab 	return lgdt3305_set_reg_bit(state, LGDT3305_GEN_CTRL_2, 5,
5529a0bf528SMauro Carvalho Chehab 				    enable ? 0 : 1);
5539a0bf528SMauro Carvalho Chehab }
5549a0bf528SMauro Carvalho Chehab 
5559a0bf528SMauro Carvalho Chehab static int lgdt3305_sleep(struct dvb_frontend *fe)
5569a0bf528SMauro Carvalho Chehab {
5579a0bf528SMauro Carvalho Chehab 	struct lgdt3305_state *state = fe->demodulator_priv;
5589a0bf528SMauro Carvalho Chehab 	u8 gen_ctrl_3, gen_ctrl_4;
5599a0bf528SMauro Carvalho Chehab 
5609a0bf528SMauro Carvalho Chehab 	lg_dbg("\n");
5619a0bf528SMauro Carvalho Chehab 
5629a0bf528SMauro Carvalho Chehab 	gen_ctrl_3 = read_reg(state, LGDT3305_GEN_CTRL_3);
5639a0bf528SMauro Carvalho Chehab 	gen_ctrl_4 = read_reg(state, LGDT3305_GEN_CTRL_4);
5649a0bf528SMauro Carvalho Chehab 
5659a0bf528SMauro Carvalho Chehab 	/* hold in software reset while sleeping */
5669a0bf528SMauro Carvalho Chehab 	gen_ctrl_3 &= ~0x01;
5679a0bf528SMauro Carvalho Chehab 	/* tristate the IF-AGC pin */
5689a0bf528SMauro Carvalho Chehab 	gen_ctrl_3 |=  0x02;
5699a0bf528SMauro Carvalho Chehab 	/* tristate the RF-AGC pin */
5709a0bf528SMauro Carvalho Chehab 	gen_ctrl_3 |=  0x04;
5719a0bf528SMauro Carvalho Chehab 
5729a0bf528SMauro Carvalho Chehab 	/* disable vsb/qam module */
5739a0bf528SMauro Carvalho Chehab 	gen_ctrl_4 &= ~0x01;
5749a0bf528SMauro Carvalho Chehab 	/* disable adc module */
5759a0bf528SMauro Carvalho Chehab 	gen_ctrl_4 &= ~0x02;
5769a0bf528SMauro Carvalho Chehab 
5779a0bf528SMauro Carvalho Chehab 	lgdt3305_write_reg(state, LGDT3305_GEN_CTRL_3, gen_ctrl_3);
5789a0bf528SMauro Carvalho Chehab 	lgdt3305_write_reg(state, LGDT3305_GEN_CTRL_4, gen_ctrl_4);
5799a0bf528SMauro Carvalho Chehab 
5809a0bf528SMauro Carvalho Chehab 	return 0;
5819a0bf528SMauro Carvalho Chehab }
5829a0bf528SMauro Carvalho Chehab 
5839a0bf528SMauro Carvalho Chehab static int lgdt3305_init(struct dvb_frontend *fe)
5849a0bf528SMauro Carvalho Chehab {
5859a0bf528SMauro Carvalho Chehab 	struct lgdt3305_state *state = fe->demodulator_priv;
5869a0bf528SMauro Carvalho Chehab 	int ret;
5879a0bf528SMauro Carvalho Chehab 
5889a0bf528SMauro Carvalho Chehab 	static struct lgdt3305_reg lgdt3304_init_data[] = {
5899a0bf528SMauro Carvalho Chehab 		{ .reg = LGDT3305_GEN_CTRL_1,           .val = 0x03, },
5909a0bf528SMauro Carvalho Chehab 		{ .reg = 0x000d,                        .val = 0x02, },
5919a0bf528SMauro Carvalho Chehab 		{ .reg = 0x000e,                        .val = 0x02, },
5929a0bf528SMauro Carvalho Chehab 		{ .reg = LGDT3305_DGTL_AGC_REF_1,       .val = 0x32, },
5939a0bf528SMauro Carvalho Chehab 		{ .reg = LGDT3305_DGTL_AGC_REF_2,       .val = 0xc4, },
5949a0bf528SMauro Carvalho Chehab 		{ .reg = LGDT3305_CR_CTR_FREQ_1,        .val = 0x00, },
5959a0bf528SMauro Carvalho Chehab 		{ .reg = LGDT3305_CR_CTR_FREQ_2,        .val = 0x00, },
5969a0bf528SMauro Carvalho Chehab 		{ .reg = LGDT3305_CR_CTR_FREQ_3,        .val = 0x00, },
5979a0bf528SMauro Carvalho Chehab 		{ .reg = LGDT3305_CR_CTR_FREQ_4,        .val = 0x00, },
5989a0bf528SMauro Carvalho Chehab 		{ .reg = LGDT3305_CR_CTRL_7,            .val = 0xf9, },
5999a0bf528SMauro Carvalho Chehab 		{ .reg = 0x0112,                        .val = 0x17, },
6009a0bf528SMauro Carvalho Chehab 		{ .reg = 0x0113,                        .val = 0x15, },
6019a0bf528SMauro Carvalho Chehab 		{ .reg = 0x0114,                        .val = 0x18, },
6029a0bf528SMauro Carvalho Chehab 		{ .reg = 0x0115,                        .val = 0xff, },
6039a0bf528SMauro Carvalho Chehab 		{ .reg = 0x0116,                        .val = 0x3c, },
6049a0bf528SMauro Carvalho Chehab 		{ .reg = 0x0214,                        .val = 0x67, },
6059a0bf528SMauro Carvalho Chehab 		{ .reg = 0x0424,                        .val = 0x8d, },
6069a0bf528SMauro Carvalho Chehab 		{ .reg = 0x0427,                        .val = 0x12, },
6079a0bf528SMauro Carvalho Chehab 		{ .reg = 0x0428,                        .val = 0x4f, },
6089a0bf528SMauro Carvalho Chehab 		{ .reg = LGDT3305_IFBW_1,               .val = 0x80, },
6099a0bf528SMauro Carvalho Chehab 		{ .reg = LGDT3305_IFBW_2,               .val = 0x00, },
6109a0bf528SMauro Carvalho Chehab 		{ .reg = 0x030a,                        .val = 0x08, },
6119a0bf528SMauro Carvalho Chehab 		{ .reg = 0x030b,                        .val = 0x9b, },
6129a0bf528SMauro Carvalho Chehab 		{ .reg = 0x030d,                        .val = 0x00, },
6139a0bf528SMauro Carvalho Chehab 		{ .reg = 0x030e,                        .val = 0x1c, },
6149a0bf528SMauro Carvalho Chehab 		{ .reg = 0x0314,                        .val = 0xe1, },
6159a0bf528SMauro Carvalho Chehab 		{ .reg = 0x000d,                        .val = 0x82, },
6169a0bf528SMauro Carvalho Chehab 		{ .reg = LGDT3305_TP_CTRL_1,            .val = 0x5b, },
6179a0bf528SMauro Carvalho Chehab 		{ .reg = LGDT3305_TP_CTRL_1,            .val = 0x5b, },
6189a0bf528SMauro Carvalho Chehab 	};
6199a0bf528SMauro Carvalho Chehab 
6209a0bf528SMauro Carvalho Chehab 	static struct lgdt3305_reg lgdt3305_init_data[] = {
6219a0bf528SMauro Carvalho Chehab 		{ .reg = LGDT3305_GEN_CTRL_1,           .val = 0x03, },
6229a0bf528SMauro Carvalho Chehab 		{ .reg = LGDT3305_GEN_CTRL_2,           .val = 0xb0, },
6239a0bf528SMauro Carvalho Chehab 		{ .reg = LGDT3305_GEN_CTRL_3,           .val = 0x01, },
6249a0bf528SMauro Carvalho Chehab 		{ .reg = LGDT3305_GEN_CONTROL,          .val = 0x6f, },
6259a0bf528SMauro Carvalho Chehab 		{ .reg = LGDT3305_GEN_CTRL_4,           .val = 0x03, },
6269a0bf528SMauro Carvalho Chehab 		{ .reg = LGDT3305_DGTL_AGC_REF_1,       .val = 0x32, },
6279a0bf528SMauro Carvalho Chehab 		{ .reg = LGDT3305_DGTL_AGC_REF_2,       .val = 0xc4, },
6289a0bf528SMauro Carvalho Chehab 		{ .reg = LGDT3305_CR_CTR_FREQ_1,        .val = 0x00, },
6299a0bf528SMauro Carvalho Chehab 		{ .reg = LGDT3305_CR_CTR_FREQ_2,        .val = 0x00, },
6309a0bf528SMauro Carvalho Chehab 		{ .reg = LGDT3305_CR_CTR_FREQ_3,        .val = 0x00, },
6319a0bf528SMauro Carvalho Chehab 		{ .reg = LGDT3305_CR_CTR_FREQ_4,        .val = 0x00, },
6329a0bf528SMauro Carvalho Chehab 		{ .reg = LGDT3305_CR_CTRL_7,            .val = 0x79, },
6339a0bf528SMauro Carvalho Chehab 		{ .reg = LGDT3305_AGC_POWER_REF_1,      .val = 0x32, },
6349a0bf528SMauro Carvalho Chehab 		{ .reg = LGDT3305_AGC_POWER_REF_2,      .val = 0xc4, },
6359a0bf528SMauro Carvalho Chehab 		{ .reg = LGDT3305_AGC_DELAY_PT_1,       .val = 0x0d, },
6369a0bf528SMauro Carvalho Chehab 		{ .reg = LGDT3305_AGC_DELAY_PT_2,       .val = 0x30, },
6379a0bf528SMauro Carvalho Chehab 		{ .reg = LGDT3305_RFAGC_LOOP_FLTR_BW_1, .val = 0x80, },
6389a0bf528SMauro Carvalho Chehab 		{ .reg = LGDT3305_RFAGC_LOOP_FLTR_BW_2, .val = 0x00, },
6399a0bf528SMauro Carvalho Chehab 		{ .reg = LGDT3305_IFBW_1,               .val = 0x80, },
6409a0bf528SMauro Carvalho Chehab 		{ .reg = LGDT3305_IFBW_2,               .val = 0x00, },
6419a0bf528SMauro Carvalho Chehab 		{ .reg = LGDT3305_AGC_CTRL_1,           .val = 0x30, },
6429a0bf528SMauro Carvalho Chehab 		{ .reg = LGDT3305_AGC_CTRL_4,           .val = 0x61, },
6439a0bf528SMauro Carvalho Chehab 		{ .reg = LGDT3305_FEC_BLOCK_CTRL,       .val = 0xff, },
6449a0bf528SMauro Carvalho Chehab 		{ .reg = LGDT3305_TP_CTRL_1,            .val = 0x1b, },
6459a0bf528SMauro Carvalho Chehab 	};
6469a0bf528SMauro Carvalho Chehab 
6479a0bf528SMauro Carvalho Chehab 	lg_dbg("\n");
6489a0bf528SMauro Carvalho Chehab 
6499a0bf528SMauro Carvalho Chehab 	switch (state->cfg->demod_chip) {
6509a0bf528SMauro Carvalho Chehab 	case LGDT3304:
6519a0bf528SMauro Carvalho Chehab 		ret = lgdt3305_write_regs(state, lgdt3304_init_data,
6529a0bf528SMauro Carvalho Chehab 					  ARRAY_SIZE(lgdt3304_init_data));
6539a0bf528SMauro Carvalho Chehab 		break;
6549a0bf528SMauro Carvalho Chehab 	case LGDT3305:
6559a0bf528SMauro Carvalho Chehab 		ret = lgdt3305_write_regs(state, lgdt3305_init_data,
6569a0bf528SMauro Carvalho Chehab 					  ARRAY_SIZE(lgdt3305_init_data));
6579a0bf528SMauro Carvalho Chehab 		break;
6589a0bf528SMauro Carvalho Chehab 	default:
6599a0bf528SMauro Carvalho Chehab 		ret = -EINVAL;
6609a0bf528SMauro Carvalho Chehab 	}
6619a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
6629a0bf528SMauro Carvalho Chehab 		goto fail;
6639a0bf528SMauro Carvalho Chehab 
6649a0bf528SMauro Carvalho Chehab 	ret = lgdt3305_soft_reset(state);
6659a0bf528SMauro Carvalho Chehab fail:
6669a0bf528SMauro Carvalho Chehab 	return ret;
6679a0bf528SMauro Carvalho Chehab }
6689a0bf528SMauro Carvalho Chehab 
6699a0bf528SMauro Carvalho Chehab static int lgdt3304_set_parameters(struct dvb_frontend *fe)
6709a0bf528SMauro Carvalho Chehab {
6719a0bf528SMauro Carvalho Chehab 	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
6729a0bf528SMauro Carvalho Chehab 	struct lgdt3305_state *state = fe->demodulator_priv;
6739a0bf528SMauro Carvalho Chehab 	int ret;
6749a0bf528SMauro Carvalho Chehab 
6759a0bf528SMauro Carvalho Chehab 	lg_dbg("(%d, %d)\n", p->frequency, p->modulation);
6769a0bf528SMauro Carvalho Chehab 
6779a0bf528SMauro Carvalho Chehab 	if (fe->ops.tuner_ops.set_params) {
6789a0bf528SMauro Carvalho Chehab 		ret = fe->ops.tuner_ops.set_params(fe);
6799a0bf528SMauro Carvalho Chehab 		if (fe->ops.i2c_gate_ctrl)
6809a0bf528SMauro Carvalho Chehab 			fe->ops.i2c_gate_ctrl(fe, 0);
6819a0bf528SMauro Carvalho Chehab 		if (lg_fail(ret))
6829a0bf528SMauro Carvalho Chehab 			goto fail;
6839a0bf528SMauro Carvalho Chehab 		state->current_frequency = p->frequency;
6849a0bf528SMauro Carvalho Chehab 	}
6859a0bf528SMauro Carvalho Chehab 
6869a0bf528SMauro Carvalho Chehab 	ret = lgdt3305_set_modulation(state, p);
6879a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
6889a0bf528SMauro Carvalho Chehab 		goto fail;
6899a0bf528SMauro Carvalho Chehab 
6909a0bf528SMauro Carvalho Chehab 	ret = lgdt3305_passband_digital_agc(state, p);
6919a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
6929a0bf528SMauro Carvalho Chehab 		goto fail;
6939a0bf528SMauro Carvalho Chehab 
6949a0bf528SMauro Carvalho Chehab 	ret = lgdt3305_agc_setup(state, p);
6959a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
6969a0bf528SMauro Carvalho Chehab 		goto fail;
6979a0bf528SMauro Carvalho Chehab 
6989a0bf528SMauro Carvalho Chehab 	/* reg 0x030d is 3304-only... seen in vsb and qam usbsnoops... */
6999a0bf528SMauro Carvalho Chehab 	switch (p->modulation) {
7009a0bf528SMauro Carvalho Chehab 	case VSB_8:
7019a0bf528SMauro Carvalho Chehab 		lgdt3305_write_reg(state, 0x030d, 0x00);
7029a0bf528SMauro Carvalho Chehab 		lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_1, 0x4f);
7039a0bf528SMauro Carvalho Chehab 		lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_2, 0x0c);
7049a0bf528SMauro Carvalho Chehab 		lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_3, 0xac);
7059a0bf528SMauro Carvalho Chehab 		lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_4, 0xba);
7069a0bf528SMauro Carvalho Chehab 		break;
7079a0bf528SMauro Carvalho Chehab 	case QAM_64:
7089a0bf528SMauro Carvalho Chehab 	case QAM_256:
7099a0bf528SMauro Carvalho Chehab 		lgdt3305_write_reg(state, 0x030d, 0x14);
7109a0bf528SMauro Carvalho Chehab 		ret = lgdt3305_set_if(state, p);
7119a0bf528SMauro Carvalho Chehab 		if (lg_fail(ret))
7129a0bf528SMauro Carvalho Chehab 			goto fail;
7139a0bf528SMauro Carvalho Chehab 		break;
7149a0bf528SMauro Carvalho Chehab 	default:
7159a0bf528SMauro Carvalho Chehab 		return -EINVAL;
7169a0bf528SMauro Carvalho Chehab 	}
7179a0bf528SMauro Carvalho Chehab 
7189a0bf528SMauro Carvalho Chehab 
7199a0bf528SMauro Carvalho Chehab 	ret = lgdt3305_spectral_inversion(state, p,
7209a0bf528SMauro Carvalho Chehab 					  state->cfg->spectral_inversion
7219a0bf528SMauro Carvalho Chehab 					  ? 1 : 0);
7229a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
7239a0bf528SMauro Carvalho Chehab 		goto fail;
7249a0bf528SMauro Carvalho Chehab 
7259a0bf528SMauro Carvalho Chehab 	state->current_modulation = p->modulation;
7269a0bf528SMauro Carvalho Chehab 
7279a0bf528SMauro Carvalho Chehab 	ret = lgdt3305_mpeg_mode(state, state->cfg->mpeg_mode);
7289a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
7299a0bf528SMauro Carvalho Chehab 		goto fail;
7309a0bf528SMauro Carvalho Chehab 
7319a0bf528SMauro Carvalho Chehab 	/* lgdt3305_mpeg_mode_polarity calls lgdt3305_soft_reset */
732bdba90dfSMichael Ira Krufky 	ret = lgdt3305_mpeg_mode_polarity(state);
7339a0bf528SMauro Carvalho Chehab fail:
7349a0bf528SMauro Carvalho Chehab 	return ret;
7359a0bf528SMauro Carvalho Chehab }
7369a0bf528SMauro Carvalho Chehab 
7379a0bf528SMauro Carvalho Chehab static int lgdt3305_set_parameters(struct dvb_frontend *fe)
7389a0bf528SMauro Carvalho Chehab {
7399a0bf528SMauro Carvalho Chehab 	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
7409a0bf528SMauro Carvalho Chehab 	struct lgdt3305_state *state = fe->demodulator_priv;
7419a0bf528SMauro Carvalho Chehab 	int ret;
7429a0bf528SMauro Carvalho Chehab 
7439a0bf528SMauro Carvalho Chehab 	lg_dbg("(%d, %d)\n", p->frequency, p->modulation);
7449a0bf528SMauro Carvalho Chehab 
7459a0bf528SMauro Carvalho Chehab 	if (fe->ops.tuner_ops.set_params) {
7469a0bf528SMauro Carvalho Chehab 		ret = fe->ops.tuner_ops.set_params(fe);
7479a0bf528SMauro Carvalho Chehab 		if (fe->ops.i2c_gate_ctrl)
7489a0bf528SMauro Carvalho Chehab 			fe->ops.i2c_gate_ctrl(fe, 0);
7499a0bf528SMauro Carvalho Chehab 		if (lg_fail(ret))
7509a0bf528SMauro Carvalho Chehab 			goto fail;
7519a0bf528SMauro Carvalho Chehab 		state->current_frequency = p->frequency;
7529a0bf528SMauro Carvalho Chehab 	}
7539a0bf528SMauro Carvalho Chehab 
7549a0bf528SMauro Carvalho Chehab 	ret = lgdt3305_set_modulation(state, p);
7559a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
7569a0bf528SMauro Carvalho Chehab 		goto fail;
7579a0bf528SMauro Carvalho Chehab 
7589a0bf528SMauro Carvalho Chehab 	ret = lgdt3305_passband_digital_agc(state, p);
7599a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
7609a0bf528SMauro Carvalho Chehab 		goto fail;
7619a0bf528SMauro Carvalho Chehab 	ret = lgdt3305_set_agc_power_ref(state, p);
7629a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
7639a0bf528SMauro Carvalho Chehab 		goto fail;
7649a0bf528SMauro Carvalho Chehab 	ret = lgdt3305_agc_setup(state, p);
7659a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
7669a0bf528SMauro Carvalho Chehab 		goto fail;
7679a0bf528SMauro Carvalho Chehab 
7689a0bf528SMauro Carvalho Chehab 	/* low if */
7699a0bf528SMauro Carvalho Chehab 	ret = lgdt3305_write_reg(state, LGDT3305_GEN_CONTROL, 0x2f);
7709a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
7719a0bf528SMauro Carvalho Chehab 		goto fail;
7729a0bf528SMauro Carvalho Chehab 	ret = lgdt3305_set_reg_bit(state, LGDT3305_CR_CTR_FREQ_1, 6, 1);
7739a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
7749a0bf528SMauro Carvalho Chehab 		goto fail;
7759a0bf528SMauro Carvalho Chehab 
7769a0bf528SMauro Carvalho Chehab 	ret = lgdt3305_set_if(state, p);
7779a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
7789a0bf528SMauro Carvalho Chehab 		goto fail;
7799a0bf528SMauro Carvalho Chehab 	ret = lgdt3305_spectral_inversion(state, p,
7809a0bf528SMauro Carvalho Chehab 					  state->cfg->spectral_inversion
7819a0bf528SMauro Carvalho Chehab 					  ? 1 : 0);
7829a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
7839a0bf528SMauro Carvalho Chehab 		goto fail;
7849a0bf528SMauro Carvalho Chehab 
7859a0bf528SMauro Carvalho Chehab 	ret = lgdt3305_set_filter_extension(state, p);
7869a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
7879a0bf528SMauro Carvalho Chehab 		goto fail;
7889a0bf528SMauro Carvalho Chehab 
7899a0bf528SMauro Carvalho Chehab 	state->current_modulation = p->modulation;
7909a0bf528SMauro Carvalho Chehab 
7919a0bf528SMauro Carvalho Chehab 	ret = lgdt3305_mpeg_mode(state, state->cfg->mpeg_mode);
7929a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
7939a0bf528SMauro Carvalho Chehab 		goto fail;
7949a0bf528SMauro Carvalho Chehab 
7959a0bf528SMauro Carvalho Chehab 	/* lgdt3305_mpeg_mode_polarity calls lgdt3305_soft_reset */
796bdba90dfSMichael Ira Krufky 	ret = lgdt3305_mpeg_mode_polarity(state);
7979a0bf528SMauro Carvalho Chehab fail:
7989a0bf528SMauro Carvalho Chehab 	return ret;
7999a0bf528SMauro Carvalho Chehab }
8009a0bf528SMauro Carvalho Chehab 
8017e3e68bcSMauro Carvalho Chehab static int lgdt3305_get_frontend(struct dvb_frontend *fe,
8027e3e68bcSMauro Carvalho Chehab 				 struct dtv_frontend_properties *p)
8039a0bf528SMauro Carvalho Chehab {
8049a0bf528SMauro Carvalho Chehab 	struct lgdt3305_state *state = fe->demodulator_priv;
8059a0bf528SMauro Carvalho Chehab 
8069a0bf528SMauro Carvalho Chehab 	lg_dbg("\n");
8079a0bf528SMauro Carvalho Chehab 
8089a0bf528SMauro Carvalho Chehab 	p->modulation = state->current_modulation;
8099a0bf528SMauro Carvalho Chehab 	p->frequency = state->current_frequency;
8109a0bf528SMauro Carvalho Chehab 	return 0;
8119a0bf528SMauro Carvalho Chehab }
8129a0bf528SMauro Carvalho Chehab 
8139a0bf528SMauro Carvalho Chehab /* ------------------------------------------------------------------------ */
8149a0bf528SMauro Carvalho Chehab 
8159a0bf528SMauro Carvalho Chehab static int lgdt3305_read_cr_lock_status(struct lgdt3305_state *state,
8169a0bf528SMauro Carvalho Chehab 					int *locked)
8179a0bf528SMauro Carvalho Chehab {
8189a0bf528SMauro Carvalho Chehab 	u8 val;
8199a0bf528SMauro Carvalho Chehab 	int ret;
8209a0bf528SMauro Carvalho Chehab 	char *cr_lock_state = "";
8219a0bf528SMauro Carvalho Chehab 
8229a0bf528SMauro Carvalho Chehab 	*locked = 0;
8239a0bf528SMauro Carvalho Chehab 
8249a0bf528SMauro Carvalho Chehab 	ret = lgdt3305_read_reg(state, LGDT3305_CR_LOCK_STATUS, &val);
8259a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
8269a0bf528SMauro Carvalho Chehab 		goto fail;
8279a0bf528SMauro Carvalho Chehab 
8289a0bf528SMauro Carvalho Chehab 	switch (state->current_modulation) {
8299a0bf528SMauro Carvalho Chehab 	case QAM_256:
8309a0bf528SMauro Carvalho Chehab 	case QAM_64:
8319a0bf528SMauro Carvalho Chehab 		if (val & (1 << 1))
8329a0bf528SMauro Carvalho Chehab 			*locked = 1;
8339a0bf528SMauro Carvalho Chehab 
8349a0bf528SMauro Carvalho Chehab 		switch (val & 0x07) {
8359a0bf528SMauro Carvalho Chehab 		case 0:
8369a0bf528SMauro Carvalho Chehab 			cr_lock_state = "QAM UNLOCK";
8379a0bf528SMauro Carvalho Chehab 			break;
8389a0bf528SMauro Carvalho Chehab 		case 4:
8399a0bf528SMauro Carvalho Chehab 			cr_lock_state = "QAM 1stLock";
8409a0bf528SMauro Carvalho Chehab 			break;
8419a0bf528SMauro Carvalho Chehab 		case 6:
8429a0bf528SMauro Carvalho Chehab 			cr_lock_state = "QAM 2ndLock";
8439a0bf528SMauro Carvalho Chehab 			break;
8449a0bf528SMauro Carvalho Chehab 		case 7:
8459a0bf528SMauro Carvalho Chehab 			cr_lock_state = "QAM FinalLock";
8469a0bf528SMauro Carvalho Chehab 			break;
8479a0bf528SMauro Carvalho Chehab 		default:
8489a0bf528SMauro Carvalho Chehab 			cr_lock_state = "CLOCKQAM-INVALID!";
8499a0bf528SMauro Carvalho Chehab 			break;
8509a0bf528SMauro Carvalho Chehab 		}
8519a0bf528SMauro Carvalho Chehab 		break;
8529a0bf528SMauro Carvalho Chehab 	case VSB_8:
8539a0bf528SMauro Carvalho Chehab 		if (val & (1 << 7)) {
8549a0bf528SMauro Carvalho Chehab 			*locked = 1;
8559a0bf528SMauro Carvalho Chehab 			cr_lock_state = "CLOCKVSB";
8569a0bf528SMauro Carvalho Chehab 		}
8579a0bf528SMauro Carvalho Chehab 		break;
8589a0bf528SMauro Carvalho Chehab 	default:
8599a0bf528SMauro Carvalho Chehab 		ret = -EINVAL;
8609a0bf528SMauro Carvalho Chehab 	}
8619a0bf528SMauro Carvalho Chehab 	lg_dbg("(%d) %s\n", *locked, cr_lock_state);
8629a0bf528SMauro Carvalho Chehab fail:
8639a0bf528SMauro Carvalho Chehab 	return ret;
8649a0bf528SMauro Carvalho Chehab }
8659a0bf528SMauro Carvalho Chehab 
8669a0bf528SMauro Carvalho Chehab static int lgdt3305_read_fec_lock_status(struct lgdt3305_state *state,
8679a0bf528SMauro Carvalho Chehab 					 int *locked)
8689a0bf528SMauro Carvalho Chehab {
8699a0bf528SMauro Carvalho Chehab 	u8 val;
8709a0bf528SMauro Carvalho Chehab 	int ret, mpeg_lock, fec_lock, viterbi_lock;
8719a0bf528SMauro Carvalho Chehab 
8729a0bf528SMauro Carvalho Chehab 	*locked = 0;
8739a0bf528SMauro Carvalho Chehab 
8749a0bf528SMauro Carvalho Chehab 	switch (state->current_modulation) {
8759a0bf528SMauro Carvalho Chehab 	case QAM_256:
8769a0bf528SMauro Carvalho Chehab 	case QAM_64:
8779a0bf528SMauro Carvalho Chehab 		ret = lgdt3305_read_reg(state,
8789a0bf528SMauro Carvalho Chehab 					LGDT3305_FEC_LOCK_STATUS, &val);
8799a0bf528SMauro Carvalho Chehab 		if (lg_fail(ret))
8809a0bf528SMauro Carvalho Chehab 			goto fail;
8819a0bf528SMauro Carvalho Chehab 
8829a0bf528SMauro Carvalho Chehab 		mpeg_lock    = (val & (1 << 0)) ? 1 : 0;
8839a0bf528SMauro Carvalho Chehab 		fec_lock     = (val & (1 << 2)) ? 1 : 0;
8849a0bf528SMauro Carvalho Chehab 		viterbi_lock = (val & (1 << 3)) ? 1 : 0;
8859a0bf528SMauro Carvalho Chehab 
8869a0bf528SMauro Carvalho Chehab 		*locked = mpeg_lock && fec_lock && viterbi_lock;
8879a0bf528SMauro Carvalho Chehab 
8889a0bf528SMauro Carvalho Chehab 		lg_dbg("(%d) %s%s%s\n", *locked,
8899a0bf528SMauro Carvalho Chehab 		       mpeg_lock    ? "mpeg lock  "  : "",
8909a0bf528SMauro Carvalho Chehab 		       fec_lock     ? "fec lock  "   : "",
8919a0bf528SMauro Carvalho Chehab 		       viterbi_lock ? "viterbi lock" : "");
8929a0bf528SMauro Carvalho Chehab 		break;
8939a0bf528SMauro Carvalho Chehab 	case VSB_8:
8949a0bf528SMauro Carvalho Chehab 	default:
8959a0bf528SMauro Carvalho Chehab 		ret = -EINVAL;
8969a0bf528SMauro Carvalho Chehab 	}
8979a0bf528SMauro Carvalho Chehab fail:
8989a0bf528SMauro Carvalho Chehab 	return ret;
8999a0bf528SMauro Carvalho Chehab }
9009a0bf528SMauro Carvalho Chehab 
9010df289a2SMauro Carvalho Chehab static int lgdt3305_read_status(struct dvb_frontend *fe, enum fe_status *status)
9029a0bf528SMauro Carvalho Chehab {
9039a0bf528SMauro Carvalho Chehab 	struct lgdt3305_state *state = fe->demodulator_priv;
9049a0bf528SMauro Carvalho Chehab 	u8 val;
9059a0bf528SMauro Carvalho Chehab 	int ret, signal, inlock, nofecerr, snrgood,
9069a0bf528SMauro Carvalho Chehab 		cr_lock, fec_lock, sync_lock;
9079a0bf528SMauro Carvalho Chehab 
9089a0bf528SMauro Carvalho Chehab 	*status = 0;
9099a0bf528SMauro Carvalho Chehab 
9109a0bf528SMauro Carvalho Chehab 	ret = lgdt3305_read_reg(state, LGDT3305_GEN_STATUS, &val);
9119a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
9129a0bf528SMauro Carvalho Chehab 		goto fail;
9139a0bf528SMauro Carvalho Chehab 
9149a0bf528SMauro Carvalho Chehab 	signal    = (val & (1 << 4)) ? 1 : 0;
9159a0bf528SMauro Carvalho Chehab 	inlock    = (val & (1 << 3)) ? 0 : 1;
9169a0bf528SMauro Carvalho Chehab 	sync_lock = (val & (1 << 2)) ? 1 : 0;
9179a0bf528SMauro Carvalho Chehab 	nofecerr  = (val & (1 << 1)) ? 1 : 0;
9189a0bf528SMauro Carvalho Chehab 	snrgood   = (val & (1 << 0)) ? 1 : 0;
9199a0bf528SMauro Carvalho Chehab 
9209a0bf528SMauro Carvalho Chehab 	lg_dbg("%s%s%s%s%s\n",
9219a0bf528SMauro Carvalho Chehab 	       signal    ? "SIGNALEXIST " : "",
9229a0bf528SMauro Carvalho Chehab 	       inlock    ? "INLOCK "      : "",
9239a0bf528SMauro Carvalho Chehab 	       sync_lock ? "SYNCLOCK "    : "",
9249a0bf528SMauro Carvalho Chehab 	       nofecerr  ? "NOFECERR "    : "",
9259a0bf528SMauro Carvalho Chehab 	       snrgood   ? "SNRGOOD "     : "");
9269a0bf528SMauro Carvalho Chehab 
9279a0bf528SMauro Carvalho Chehab 	ret = lgdt3305_read_cr_lock_status(state, &cr_lock);
9289a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
9299a0bf528SMauro Carvalho Chehab 		goto fail;
9309a0bf528SMauro Carvalho Chehab 
9319a0bf528SMauro Carvalho Chehab 	if (signal)
9329a0bf528SMauro Carvalho Chehab 		*status |= FE_HAS_SIGNAL;
9339a0bf528SMauro Carvalho Chehab 	if (cr_lock)
9349a0bf528SMauro Carvalho Chehab 		*status |= FE_HAS_CARRIER;
9359a0bf528SMauro Carvalho Chehab 	if (nofecerr)
9369a0bf528SMauro Carvalho Chehab 		*status |= FE_HAS_VITERBI;
9379a0bf528SMauro Carvalho Chehab 	if (sync_lock)
9389a0bf528SMauro Carvalho Chehab 		*status |= FE_HAS_SYNC;
9399a0bf528SMauro Carvalho Chehab 
9409a0bf528SMauro Carvalho Chehab 	switch (state->current_modulation) {
9419a0bf528SMauro Carvalho Chehab 	case QAM_256:
9429a0bf528SMauro Carvalho Chehab 	case QAM_64:
9439a0bf528SMauro Carvalho Chehab 		/* signal bit is unreliable on the DT3304 in QAM mode */
9449a0bf528SMauro Carvalho Chehab 		if (((LGDT3304 == state->cfg->demod_chip)) && (cr_lock))
9459a0bf528SMauro Carvalho Chehab 			*status |= FE_HAS_SIGNAL;
9469a0bf528SMauro Carvalho Chehab 
9479a0bf528SMauro Carvalho Chehab 		ret = lgdt3305_read_fec_lock_status(state, &fec_lock);
9489a0bf528SMauro Carvalho Chehab 		if (lg_fail(ret))
9499a0bf528SMauro Carvalho Chehab 			goto fail;
9509a0bf528SMauro Carvalho Chehab 
9519a0bf528SMauro Carvalho Chehab 		if (fec_lock)
9529a0bf528SMauro Carvalho Chehab 			*status |= FE_HAS_LOCK;
9539a0bf528SMauro Carvalho Chehab 		break;
9549a0bf528SMauro Carvalho Chehab 	case VSB_8:
9559a0bf528SMauro Carvalho Chehab 		if (inlock)
9569a0bf528SMauro Carvalho Chehab 			*status |= FE_HAS_LOCK;
9579a0bf528SMauro Carvalho Chehab 		break;
9589a0bf528SMauro Carvalho Chehab 	default:
9599a0bf528SMauro Carvalho Chehab 		ret = -EINVAL;
9609a0bf528SMauro Carvalho Chehab 	}
9619a0bf528SMauro Carvalho Chehab fail:
9629a0bf528SMauro Carvalho Chehab 	return ret;
9639a0bf528SMauro Carvalho Chehab }
9649a0bf528SMauro Carvalho Chehab 
9659a0bf528SMauro Carvalho Chehab /* ------------------------------------------------------------------------ */
9669a0bf528SMauro Carvalho Chehab 
9679a0bf528SMauro Carvalho Chehab /* borrowed from lgdt330x.c */
9689a0bf528SMauro Carvalho Chehab static u32 calculate_snr(u32 mse, u32 c)
9699a0bf528SMauro Carvalho Chehab {
9709a0bf528SMauro Carvalho Chehab 	if (mse == 0) /* no signal */
9719a0bf528SMauro Carvalho Chehab 		return 0;
9729a0bf528SMauro Carvalho Chehab 
9739a0bf528SMauro Carvalho Chehab 	mse = intlog10(mse);
9749a0bf528SMauro Carvalho Chehab 	if (mse > c) {
9759a0bf528SMauro Carvalho Chehab 		/* Negative SNR, which is possible, but realisticly the
9769a0bf528SMauro Carvalho Chehab 		demod will lose lock before the signal gets this bad.  The
9779a0bf528SMauro Carvalho Chehab 		API only allows for unsigned values, so just return 0 */
9789a0bf528SMauro Carvalho Chehab 		return 0;
9799a0bf528SMauro Carvalho Chehab 	}
9809a0bf528SMauro Carvalho Chehab 	return 10*(c - mse);
9819a0bf528SMauro Carvalho Chehab }
9829a0bf528SMauro Carvalho Chehab 
9839a0bf528SMauro Carvalho Chehab static int lgdt3305_read_snr(struct dvb_frontend *fe, u16 *snr)
9849a0bf528SMauro Carvalho Chehab {
9859a0bf528SMauro Carvalho Chehab 	struct lgdt3305_state *state = fe->demodulator_priv;
9869a0bf528SMauro Carvalho Chehab 	u32 noise;	/* noise value */
9879a0bf528SMauro Carvalho Chehab 	u32 c;		/* per-modulation SNR calculation constant */
9889a0bf528SMauro Carvalho Chehab 
9899a0bf528SMauro Carvalho Chehab 	switch (state->current_modulation) {
9909a0bf528SMauro Carvalho Chehab 	case VSB_8:
9919a0bf528SMauro Carvalho Chehab #ifdef USE_PTMSE
9929a0bf528SMauro Carvalho Chehab 		/* Use Phase Tracker Mean-Square Error Register */
9939a0bf528SMauro Carvalho Chehab 		/* SNR for ranges from -13.11 to +44.08 */
9949a0bf528SMauro Carvalho Chehab 		noise =	((read_reg(state, LGDT3305_PT_MSE_1) & 0x07) << 16) |
9959a0bf528SMauro Carvalho Chehab 			(read_reg(state, LGDT3305_PT_MSE_2) << 8) |
9969a0bf528SMauro Carvalho Chehab 			(read_reg(state, LGDT3305_PT_MSE_3) & 0xff);
9979a0bf528SMauro Carvalho Chehab 		c = 73957994; /* log10(25*32^2)*2^24 */
9989a0bf528SMauro Carvalho Chehab #else
9999a0bf528SMauro Carvalho Chehab 		/* Use Equalizer Mean-Square Error Register */
10009a0bf528SMauro Carvalho Chehab 		/* SNR for ranges from -16.12 to +44.08 */
10019a0bf528SMauro Carvalho Chehab 		noise =	((read_reg(state, LGDT3305_EQ_MSE_1) & 0x0f) << 16) |
10029a0bf528SMauro Carvalho Chehab 			(read_reg(state, LGDT3305_EQ_MSE_2) << 8) |
10039a0bf528SMauro Carvalho Chehab 			(read_reg(state, LGDT3305_EQ_MSE_3) & 0xff);
10049a0bf528SMauro Carvalho Chehab 		c = 73957994; /* log10(25*32^2)*2^24 */
10059a0bf528SMauro Carvalho Chehab #endif
10069a0bf528SMauro Carvalho Chehab 		break;
10079a0bf528SMauro Carvalho Chehab 	case QAM_64:
10089a0bf528SMauro Carvalho Chehab 	case QAM_256:
10099a0bf528SMauro Carvalho Chehab 		noise = (read_reg(state, LGDT3305_CR_MSE_1) << 8) |
10109a0bf528SMauro Carvalho Chehab 			(read_reg(state, LGDT3305_CR_MSE_2) & 0xff);
10119a0bf528SMauro Carvalho Chehab 
10129a0bf528SMauro Carvalho Chehab 		c = (state->current_modulation == QAM_64) ?
10139a0bf528SMauro Carvalho Chehab 			97939837 : 98026066;
10149a0bf528SMauro Carvalho Chehab 		/* log10(688128)*2^24 and log10(696320)*2^24 */
10159a0bf528SMauro Carvalho Chehab 		break;
10169a0bf528SMauro Carvalho Chehab 	default:
10179a0bf528SMauro Carvalho Chehab 		return -EINVAL;
10189a0bf528SMauro Carvalho Chehab 	}
10199a0bf528SMauro Carvalho Chehab 	state->snr = calculate_snr(noise, c);
10209a0bf528SMauro Carvalho Chehab 	/* report SNR in dB * 10 */
10219a0bf528SMauro Carvalho Chehab 	*snr = (state->snr / ((1 << 24) / 10));
10229a0bf528SMauro Carvalho Chehab 	lg_dbg("noise = 0x%08x, snr = %d.%02d dB\n", noise,
10239a0bf528SMauro Carvalho Chehab 	       state->snr >> 24, (((state->snr >> 8) & 0xffff) * 100) >> 16);
10249a0bf528SMauro Carvalho Chehab 
10259a0bf528SMauro Carvalho Chehab 	return 0;
10269a0bf528SMauro Carvalho Chehab }
10279a0bf528SMauro Carvalho Chehab 
10289a0bf528SMauro Carvalho Chehab static int lgdt3305_read_signal_strength(struct dvb_frontend *fe,
10299a0bf528SMauro Carvalho Chehab 					 u16 *strength)
10309a0bf528SMauro Carvalho Chehab {
10319a0bf528SMauro Carvalho Chehab 	/* borrowed from lgdt330x.c
10329a0bf528SMauro Carvalho Chehab 	 *
10339a0bf528SMauro Carvalho Chehab 	 * Calculate strength from SNR up to 35dB
10349a0bf528SMauro Carvalho Chehab 	 * Even though the SNR can go higher than 35dB,
10359a0bf528SMauro Carvalho Chehab 	 * there is some comfort factor in having a range of
10369a0bf528SMauro Carvalho Chehab 	 * strong signals that can show at 100%
10379a0bf528SMauro Carvalho Chehab 	 */
10389a0bf528SMauro Carvalho Chehab 	struct lgdt3305_state *state = fe->demodulator_priv;
10399a0bf528SMauro Carvalho Chehab 	u16 snr;
10409a0bf528SMauro Carvalho Chehab 	int ret;
10419a0bf528SMauro Carvalho Chehab 
10429a0bf528SMauro Carvalho Chehab 	*strength = 0;
10439a0bf528SMauro Carvalho Chehab 
10449a0bf528SMauro Carvalho Chehab 	ret = fe->ops.read_snr(fe, &snr);
10459a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
10469a0bf528SMauro Carvalho Chehab 		goto fail;
10479a0bf528SMauro Carvalho Chehab 	/* Rather than use the 8.8 value snr, use state->snr which is 8.24 */
10489a0bf528SMauro Carvalho Chehab 	/* scale the range 0 - 35*2^24 into 0 - 65535 */
10499a0bf528SMauro Carvalho Chehab 	if (state->snr >= 8960 * 0x10000)
10509a0bf528SMauro Carvalho Chehab 		*strength = 0xffff;
10519a0bf528SMauro Carvalho Chehab 	else
10529a0bf528SMauro Carvalho Chehab 		*strength = state->snr / 8960;
10539a0bf528SMauro Carvalho Chehab fail:
10549a0bf528SMauro Carvalho Chehab 	return ret;
10559a0bf528SMauro Carvalho Chehab }
10569a0bf528SMauro Carvalho Chehab 
10579a0bf528SMauro Carvalho Chehab /* ------------------------------------------------------------------------ */
10589a0bf528SMauro Carvalho Chehab 
10599a0bf528SMauro Carvalho Chehab static int lgdt3305_read_ber(struct dvb_frontend *fe, u32 *ber)
10609a0bf528SMauro Carvalho Chehab {
10619a0bf528SMauro Carvalho Chehab 	*ber = 0;
10629a0bf528SMauro Carvalho Chehab 	return 0;
10639a0bf528SMauro Carvalho Chehab }
10649a0bf528SMauro Carvalho Chehab 
10659a0bf528SMauro Carvalho Chehab static int lgdt3305_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
10669a0bf528SMauro Carvalho Chehab {
10679a0bf528SMauro Carvalho Chehab 	struct lgdt3305_state *state = fe->demodulator_priv;
10689a0bf528SMauro Carvalho Chehab 
10699a0bf528SMauro Carvalho Chehab 	*ucblocks =
10709a0bf528SMauro Carvalho Chehab 		(read_reg(state, LGDT3305_FEC_PKT_ERR_1) << 8) |
10719a0bf528SMauro Carvalho Chehab 		(read_reg(state, LGDT3305_FEC_PKT_ERR_2) & 0xff);
10729a0bf528SMauro Carvalho Chehab 
10739a0bf528SMauro Carvalho Chehab 	return 0;
10749a0bf528SMauro Carvalho Chehab }
10759a0bf528SMauro Carvalho Chehab 
10769a0bf528SMauro Carvalho Chehab static int lgdt3305_get_tune_settings(struct dvb_frontend *fe,
10779a0bf528SMauro Carvalho Chehab 				      struct dvb_frontend_tune_settings
10789a0bf528SMauro Carvalho Chehab 					*fe_tune_settings)
10799a0bf528SMauro Carvalho Chehab {
10809a0bf528SMauro Carvalho Chehab 	fe_tune_settings->min_delay_ms = 500;
10819a0bf528SMauro Carvalho Chehab 	lg_dbg("\n");
10829a0bf528SMauro Carvalho Chehab 	return 0;
10839a0bf528SMauro Carvalho Chehab }
10849a0bf528SMauro Carvalho Chehab 
10859a0bf528SMauro Carvalho Chehab static void lgdt3305_release(struct dvb_frontend *fe)
10869a0bf528SMauro Carvalho Chehab {
10879a0bf528SMauro Carvalho Chehab 	struct lgdt3305_state *state = fe->demodulator_priv;
10889a0bf528SMauro Carvalho Chehab 	lg_dbg("\n");
10899a0bf528SMauro Carvalho Chehab 	kfree(state);
10909a0bf528SMauro Carvalho Chehab }
10919a0bf528SMauro Carvalho Chehab 
1092bd336e63SMax Kellermann static const struct dvb_frontend_ops lgdt3304_ops;
1093bd336e63SMax Kellermann static const struct dvb_frontend_ops lgdt3305_ops;
10949a0bf528SMauro Carvalho Chehab 
10959a0bf528SMauro Carvalho Chehab struct dvb_frontend *lgdt3305_attach(const struct lgdt3305_config *config,
10969a0bf528SMauro Carvalho Chehab 				     struct i2c_adapter *i2c_adap)
10979a0bf528SMauro Carvalho Chehab {
10989a0bf528SMauro Carvalho Chehab 	struct lgdt3305_state *state = NULL;
10999a0bf528SMauro Carvalho Chehab 	int ret;
11009a0bf528SMauro Carvalho Chehab 	u8 val;
11019a0bf528SMauro Carvalho Chehab 
11029a0bf528SMauro Carvalho Chehab 	lg_dbg("(%d-%04x)\n",
11039a0bf528SMauro Carvalho Chehab 	       i2c_adap ? i2c_adapter_id(i2c_adap) : 0,
11049a0bf528SMauro Carvalho Chehab 	       config ? config->i2c_addr : 0);
11059a0bf528SMauro Carvalho Chehab 
11069a0bf528SMauro Carvalho Chehab 	state = kzalloc(sizeof(struct lgdt3305_state), GFP_KERNEL);
11079a0bf528SMauro Carvalho Chehab 	if (state == NULL)
11089a0bf528SMauro Carvalho Chehab 		goto fail;
11099a0bf528SMauro Carvalho Chehab 
11109a0bf528SMauro Carvalho Chehab 	state->cfg = config;
11119a0bf528SMauro Carvalho Chehab 	state->i2c_adap = i2c_adap;
11129a0bf528SMauro Carvalho Chehab 
11139a0bf528SMauro Carvalho Chehab 	switch (config->demod_chip) {
11149a0bf528SMauro Carvalho Chehab 	case LGDT3304:
11159a0bf528SMauro Carvalho Chehab 		memcpy(&state->frontend.ops, &lgdt3304_ops,
11169a0bf528SMauro Carvalho Chehab 		       sizeof(struct dvb_frontend_ops));
11179a0bf528SMauro Carvalho Chehab 		break;
11189a0bf528SMauro Carvalho Chehab 	case LGDT3305:
11199a0bf528SMauro Carvalho Chehab 		memcpy(&state->frontend.ops, &lgdt3305_ops,
11209a0bf528SMauro Carvalho Chehab 		       sizeof(struct dvb_frontend_ops));
11219a0bf528SMauro Carvalho Chehab 		break;
11229a0bf528SMauro Carvalho Chehab 	default:
11239a0bf528SMauro Carvalho Chehab 		goto fail;
11249a0bf528SMauro Carvalho Chehab 	}
11259a0bf528SMauro Carvalho Chehab 	state->frontend.demodulator_priv = state;
11269a0bf528SMauro Carvalho Chehab 
11279a0bf528SMauro Carvalho Chehab 	/* verify that we're talking to a lg dt3304/5 */
11289a0bf528SMauro Carvalho Chehab 	ret = lgdt3305_read_reg(state, LGDT3305_GEN_CTRL_2, &val);
11299a0bf528SMauro Carvalho Chehab 	if ((lg_fail(ret)) | (val == 0))
11309a0bf528SMauro Carvalho Chehab 		goto fail;
11319a0bf528SMauro Carvalho Chehab 	ret = lgdt3305_write_reg(state, 0x0808, 0x80);
11329a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
11339a0bf528SMauro Carvalho Chehab 		goto fail;
11349a0bf528SMauro Carvalho Chehab 	ret = lgdt3305_read_reg(state, 0x0808, &val);
11359a0bf528SMauro Carvalho Chehab 	if ((lg_fail(ret)) | (val != 0x80))
11369a0bf528SMauro Carvalho Chehab 		goto fail;
11379a0bf528SMauro Carvalho Chehab 	ret = lgdt3305_write_reg(state, 0x0808, 0x00);
11389a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
11399a0bf528SMauro Carvalho Chehab 		goto fail;
11409a0bf528SMauro Carvalho Chehab 
11419a0bf528SMauro Carvalho Chehab 	state->current_frequency = -1;
11429a0bf528SMauro Carvalho Chehab 	state->current_modulation = -1;
11439a0bf528SMauro Carvalho Chehab 
11449a0bf528SMauro Carvalho Chehab 	return &state->frontend;
11459a0bf528SMauro Carvalho Chehab fail:
11469a0bf528SMauro Carvalho Chehab 	lg_warn("unable to detect %s hardware\n",
11479a0bf528SMauro Carvalho Chehab 		config->demod_chip ? "LGDT3304" : "LGDT3305");
11489a0bf528SMauro Carvalho Chehab 	kfree(state);
11499a0bf528SMauro Carvalho Chehab 	return NULL;
11509a0bf528SMauro Carvalho Chehab }
1151*86495af1SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(lgdt3305_attach);
11529a0bf528SMauro Carvalho Chehab 
1153bd336e63SMax Kellermann static const struct dvb_frontend_ops lgdt3304_ops = {
11549a0bf528SMauro Carvalho Chehab 	.delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
11559a0bf528SMauro Carvalho Chehab 	.info = {
11569a0bf528SMauro Carvalho Chehab 		.name = "LG Electronics LGDT3304 VSB/QAM Frontend",
1157f1b1eabfSMauro Carvalho Chehab 		.frequency_min_hz      =  54 * MHz,
1158f1b1eabfSMauro Carvalho Chehab 		.frequency_max_hz      = 858 * MHz,
1159f1b1eabfSMauro Carvalho Chehab 		.frequency_stepsize_hz = 62500,
11609a0bf528SMauro Carvalho Chehab 		.caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
11619a0bf528SMauro Carvalho Chehab 	},
11629a0bf528SMauro Carvalho Chehab 	.i2c_gate_ctrl        = lgdt3305_i2c_gate_ctrl,
11639a0bf528SMauro Carvalho Chehab 	.init                 = lgdt3305_init,
1164c9af5c15SShuah Khan 	.sleep                = lgdt3305_sleep,
11659a0bf528SMauro Carvalho Chehab 	.set_frontend         = lgdt3304_set_parameters,
11669a0bf528SMauro Carvalho Chehab 	.get_frontend         = lgdt3305_get_frontend,
11679a0bf528SMauro Carvalho Chehab 	.get_tune_settings    = lgdt3305_get_tune_settings,
11689a0bf528SMauro Carvalho Chehab 	.read_status          = lgdt3305_read_status,
11699a0bf528SMauro Carvalho Chehab 	.read_ber             = lgdt3305_read_ber,
11709a0bf528SMauro Carvalho Chehab 	.read_signal_strength = lgdt3305_read_signal_strength,
11719a0bf528SMauro Carvalho Chehab 	.read_snr             = lgdt3305_read_snr,
11729a0bf528SMauro Carvalho Chehab 	.read_ucblocks        = lgdt3305_read_ucblocks,
11739a0bf528SMauro Carvalho Chehab 	.release              = lgdt3305_release,
11749a0bf528SMauro Carvalho Chehab };
11759a0bf528SMauro Carvalho Chehab 
1176bd336e63SMax Kellermann static const struct dvb_frontend_ops lgdt3305_ops = {
11779a0bf528SMauro Carvalho Chehab 	.delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
11789a0bf528SMauro Carvalho Chehab 	.info = {
11799a0bf528SMauro Carvalho Chehab 		.name = "LG Electronics LGDT3305 VSB/QAM Frontend",
1180f1b1eabfSMauro Carvalho Chehab 		.frequency_min_hz      =  54 * MHz,
1181f1b1eabfSMauro Carvalho Chehab 		.frequency_max_hz      = 858 * MHz,
1182f1b1eabfSMauro Carvalho Chehab 		.frequency_stepsize_hz = 62500,
11839a0bf528SMauro Carvalho Chehab 		.caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
11849a0bf528SMauro Carvalho Chehab 	},
11859a0bf528SMauro Carvalho Chehab 	.i2c_gate_ctrl        = lgdt3305_i2c_gate_ctrl,
11869a0bf528SMauro Carvalho Chehab 	.init                 = lgdt3305_init,
11879a0bf528SMauro Carvalho Chehab 	.sleep                = lgdt3305_sleep,
11889a0bf528SMauro Carvalho Chehab 	.set_frontend         = lgdt3305_set_parameters,
11899a0bf528SMauro Carvalho Chehab 	.get_frontend         = lgdt3305_get_frontend,
11909a0bf528SMauro Carvalho Chehab 	.get_tune_settings    = lgdt3305_get_tune_settings,
11919a0bf528SMauro Carvalho Chehab 	.read_status          = lgdt3305_read_status,
11929a0bf528SMauro Carvalho Chehab 	.read_ber             = lgdt3305_read_ber,
11939a0bf528SMauro Carvalho Chehab 	.read_signal_strength = lgdt3305_read_signal_strength,
11949a0bf528SMauro Carvalho Chehab 	.read_snr             = lgdt3305_read_snr,
11959a0bf528SMauro Carvalho Chehab 	.read_ucblocks        = lgdt3305_read_ucblocks,
11969a0bf528SMauro Carvalho Chehab 	.release              = lgdt3305_release,
11979a0bf528SMauro Carvalho Chehab };
11989a0bf528SMauro Carvalho Chehab 
11999a0bf528SMauro Carvalho Chehab MODULE_DESCRIPTION("LG Electronics LGDT3304/5 ATSC/QAM-B Demodulator Driver");
12009a0bf528SMauro Carvalho Chehab MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
12019a0bf528SMauro Carvalho Chehab MODULE_LICENSE("GPL");
12029a0bf528SMauro Carvalho Chehab MODULE_VERSION("0.2");
1203