19a0bf528SMauro Carvalho Chehab /*
29a0bf528SMauro Carvalho Chehab  *    Support for LG2160 - ATSC/MH
39a0bf528SMauro Carvalho Chehab  *
49a0bf528SMauro Carvalho Chehab  *    Copyright (C) 2010 Michael Krufky <mkrufky@linuxtv.org>
59a0bf528SMauro Carvalho Chehab  *
69a0bf528SMauro Carvalho Chehab  *    This program is free software; you can redistribute it and/or modify
79a0bf528SMauro Carvalho Chehab  *    it under the terms of the GNU General Public License as published by
89a0bf528SMauro Carvalho Chehab  *    the Free Software Foundation; either version 2 of the License, or
99a0bf528SMauro Carvalho Chehab  *    (at your option) any later version.
109a0bf528SMauro Carvalho Chehab  *
119a0bf528SMauro Carvalho Chehab  *    This program is distributed in the hope that it will be useful,
129a0bf528SMauro Carvalho Chehab  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
139a0bf528SMauro Carvalho Chehab  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
149a0bf528SMauro Carvalho Chehab  *    GNU General Public License for more details.
159a0bf528SMauro Carvalho Chehab  *
169a0bf528SMauro Carvalho Chehab  *    You should have received a copy of the GNU General Public License
179a0bf528SMauro Carvalho Chehab  *    along with this program; if not, write to the Free Software
189a0bf528SMauro Carvalho Chehab  *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
199a0bf528SMauro Carvalho Chehab  *
209a0bf528SMauro Carvalho Chehab  */
219a0bf528SMauro Carvalho Chehab 
229a0bf528SMauro Carvalho Chehab #include <linux/jiffies.h>
239a0bf528SMauro Carvalho Chehab #include <linux/dvb/frontend.h>
249a0bf528SMauro Carvalho Chehab #include "lg2160.h"
259a0bf528SMauro Carvalho Chehab 
269a0bf528SMauro Carvalho Chehab static int debug;
279a0bf528SMauro Carvalho Chehab module_param(debug, int, 0644);
289a0bf528SMauro Carvalho Chehab MODULE_PARM_DESC(debug, "set debug level (info=1, reg=2 (or-able))");
299a0bf528SMauro Carvalho Chehab 
309a0bf528SMauro Carvalho Chehab #define DBG_INFO 1
319a0bf528SMauro Carvalho Chehab #define DBG_REG  2
329a0bf528SMauro Carvalho Chehab 
339a0bf528SMauro Carvalho Chehab #define lg_printk(kern, fmt, arg...)					\
349a0bf528SMauro Carvalho Chehab 	printk(kern "%s: " fmt, __func__, ##arg)
359a0bf528SMauro Carvalho Chehab 
369a0bf528SMauro Carvalho Chehab #define lg_info(fmt, arg...)	printk(KERN_INFO "lg2160: " fmt, ##arg)
379a0bf528SMauro Carvalho Chehab #define lg_warn(fmt, arg...)	lg_printk(KERN_WARNING,       fmt, ##arg)
389a0bf528SMauro Carvalho Chehab #define lg_err(fmt, arg...)	lg_printk(KERN_ERR,           fmt, ##arg)
399a0bf528SMauro Carvalho Chehab #define lg_dbg(fmt, arg...) if (debug & DBG_INFO)			\
409a0bf528SMauro Carvalho Chehab 				lg_printk(KERN_DEBUG,         fmt, ##arg)
419a0bf528SMauro Carvalho Chehab #define lg_reg(fmt, arg...) if (debug & DBG_REG)			\
429a0bf528SMauro Carvalho Chehab 				lg_printk(KERN_DEBUG,         fmt, ##arg)
439a0bf528SMauro Carvalho Chehab 
449a0bf528SMauro Carvalho Chehab #define lg_fail(ret)							\
459a0bf528SMauro Carvalho Chehab ({									\
469a0bf528SMauro Carvalho Chehab 	int __ret;							\
479a0bf528SMauro Carvalho Chehab 	__ret = (ret < 0);						\
489a0bf528SMauro Carvalho Chehab 	if (__ret)							\
499a0bf528SMauro Carvalho Chehab 		lg_err("error %d on line %d\n",	ret, __LINE__);		\
509a0bf528SMauro Carvalho Chehab 	__ret;								\
519a0bf528SMauro Carvalho Chehab })
529a0bf528SMauro Carvalho Chehab 
539a0bf528SMauro Carvalho Chehab struct lg216x_state {
549a0bf528SMauro Carvalho Chehab 	struct i2c_adapter *i2c_adap;
559a0bf528SMauro Carvalho Chehab 	const struct lg2160_config *cfg;
569a0bf528SMauro Carvalho Chehab 
579a0bf528SMauro Carvalho Chehab 	struct dvb_frontend frontend;
589a0bf528SMauro Carvalho Chehab 
599a0bf528SMauro Carvalho Chehab 	u32 current_frequency;
609a0bf528SMauro Carvalho Chehab 	u8 parade_id;
619a0bf528SMauro Carvalho Chehab 	u8 fic_ver;
629a0bf528SMauro Carvalho Chehab 	unsigned int last_reset;
639a0bf528SMauro Carvalho Chehab };
649a0bf528SMauro Carvalho Chehab 
659a0bf528SMauro Carvalho Chehab /* ------------------------------------------------------------------------ */
669a0bf528SMauro Carvalho Chehab 
679a0bf528SMauro Carvalho Chehab static int lg216x_write_reg(struct lg216x_state *state, u16 reg, u8 val)
689a0bf528SMauro Carvalho Chehab {
699a0bf528SMauro Carvalho Chehab 	int ret;
709a0bf528SMauro Carvalho Chehab 	u8 buf[] = { reg >> 8, reg & 0xff, val };
719a0bf528SMauro Carvalho Chehab 	struct i2c_msg msg = {
729a0bf528SMauro Carvalho Chehab 		.addr = state->cfg->i2c_addr, .flags = 0,
739a0bf528SMauro Carvalho Chehab 		.buf = buf, .len = 3,
749a0bf528SMauro Carvalho Chehab 	};
759a0bf528SMauro Carvalho Chehab 
769a0bf528SMauro Carvalho Chehab 	lg_reg("reg: 0x%04x, val: 0x%02x\n", reg, val);
779a0bf528SMauro Carvalho Chehab 
789a0bf528SMauro Carvalho Chehab 	ret = i2c_transfer(state->i2c_adap, &msg, 1);
799a0bf528SMauro Carvalho Chehab 
809a0bf528SMauro Carvalho Chehab 	if (ret != 1) {
819a0bf528SMauro Carvalho Chehab 		lg_err("error (addr %02x %02x <- %02x, err = %i)\n",
829a0bf528SMauro Carvalho Chehab 		       msg.buf[0], msg.buf[1], msg.buf[2], ret);
839a0bf528SMauro Carvalho Chehab 		if (ret < 0)
849a0bf528SMauro Carvalho Chehab 			return ret;
859a0bf528SMauro Carvalho Chehab 		else
869a0bf528SMauro Carvalho Chehab 			return -EREMOTEIO;
879a0bf528SMauro Carvalho Chehab 	}
889a0bf528SMauro Carvalho Chehab 	return 0;
899a0bf528SMauro Carvalho Chehab }
909a0bf528SMauro Carvalho Chehab 
919a0bf528SMauro Carvalho Chehab static int lg216x_read_reg(struct lg216x_state *state, u16 reg, u8 *val)
929a0bf528SMauro Carvalho Chehab {
939a0bf528SMauro Carvalho Chehab 	int ret;
949a0bf528SMauro Carvalho Chehab 	u8 reg_buf[] = { reg >> 8, reg & 0xff };
959a0bf528SMauro Carvalho Chehab 	struct i2c_msg msg[] = {
969a0bf528SMauro Carvalho Chehab 		{ .addr = state->cfg->i2c_addr,
979a0bf528SMauro Carvalho Chehab 		  .flags = 0, .buf = reg_buf, .len = 2 },
989a0bf528SMauro Carvalho Chehab 		{ .addr = state->cfg->i2c_addr,
999a0bf528SMauro Carvalho Chehab 		  .flags = I2C_M_RD, .buf = val, .len = 1 },
1009a0bf528SMauro Carvalho Chehab 	};
1019a0bf528SMauro Carvalho Chehab 
1029a0bf528SMauro Carvalho Chehab 	lg_reg("reg: 0x%04x\n", reg);
1039a0bf528SMauro Carvalho Chehab 
1049a0bf528SMauro Carvalho Chehab 	ret = i2c_transfer(state->i2c_adap, msg, 2);
1059a0bf528SMauro Carvalho Chehab 
1069a0bf528SMauro Carvalho Chehab 	if (ret != 2) {
1079a0bf528SMauro Carvalho Chehab 		lg_err("error (addr %02x reg %04x error (ret == %i)\n",
1089a0bf528SMauro Carvalho Chehab 		       state->cfg->i2c_addr, reg, ret);
1099a0bf528SMauro Carvalho Chehab 		if (ret < 0)
1109a0bf528SMauro Carvalho Chehab 			return ret;
1119a0bf528SMauro Carvalho Chehab 		else
1129a0bf528SMauro Carvalho Chehab 			return -EREMOTEIO;
1139a0bf528SMauro Carvalho Chehab 	}
1149a0bf528SMauro Carvalho Chehab 	return 0;
1159a0bf528SMauro Carvalho Chehab }
1169a0bf528SMauro Carvalho Chehab 
1179a0bf528SMauro Carvalho Chehab struct lg216x_reg {
1189a0bf528SMauro Carvalho Chehab 	u16 reg;
1199a0bf528SMauro Carvalho Chehab 	u8 val;
1209a0bf528SMauro Carvalho Chehab };
1219a0bf528SMauro Carvalho Chehab 
1229a0bf528SMauro Carvalho Chehab static int lg216x_write_regs(struct lg216x_state *state,
1239a0bf528SMauro Carvalho Chehab 			     struct lg216x_reg *regs, int len)
1249a0bf528SMauro Carvalho Chehab {
1259a0bf528SMauro Carvalho Chehab 	int i, ret;
1269a0bf528SMauro Carvalho Chehab 
1279a0bf528SMauro Carvalho Chehab 	lg_reg("writing %d registers...\n", len);
1289a0bf528SMauro Carvalho Chehab 
1299a0bf528SMauro Carvalho Chehab 	for (i = 0; i < len; i++) {
1309a0bf528SMauro Carvalho Chehab 		ret = lg216x_write_reg(state, regs[i].reg, regs[i].val);
1319a0bf528SMauro Carvalho Chehab 		if (lg_fail(ret))
1329a0bf528SMauro Carvalho Chehab 			return ret;
1339a0bf528SMauro Carvalho Chehab 	}
1349a0bf528SMauro Carvalho Chehab 	return 0;
1359a0bf528SMauro Carvalho Chehab }
1369a0bf528SMauro Carvalho Chehab 
1379a0bf528SMauro Carvalho Chehab static int lg216x_set_reg_bit(struct lg216x_state *state,
1389a0bf528SMauro Carvalho Chehab 			      u16 reg, int bit, int onoff)
1399a0bf528SMauro Carvalho Chehab {
1409a0bf528SMauro Carvalho Chehab 	u8 val;
1419a0bf528SMauro Carvalho Chehab 	int ret;
1429a0bf528SMauro Carvalho Chehab 
1439a0bf528SMauro Carvalho Chehab 	lg_reg("reg: 0x%04x, bit: %d, level: %d\n", reg, bit, onoff);
1449a0bf528SMauro Carvalho Chehab 
1459a0bf528SMauro Carvalho Chehab 	ret = lg216x_read_reg(state, reg, &val);
1469a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
1479a0bf528SMauro Carvalho Chehab 		goto fail;
1489a0bf528SMauro Carvalho Chehab 
1499a0bf528SMauro Carvalho Chehab 	val &= ~(1 << bit);
1509a0bf528SMauro Carvalho Chehab 	val |= (onoff & 1) << bit;
1519a0bf528SMauro Carvalho Chehab 
1529a0bf528SMauro Carvalho Chehab 	ret = lg216x_write_reg(state, reg, val);
1539a0bf528SMauro Carvalho Chehab 	lg_fail(ret);
1549a0bf528SMauro Carvalho Chehab fail:
1559a0bf528SMauro Carvalho Chehab 	return ret;
1569a0bf528SMauro Carvalho Chehab }
1579a0bf528SMauro Carvalho Chehab 
1589a0bf528SMauro Carvalho Chehab /* ------------------------------------------------------------------------ */
1599a0bf528SMauro Carvalho Chehab 
1609a0bf528SMauro Carvalho Chehab static int lg216x_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
1619a0bf528SMauro Carvalho Chehab {
1629a0bf528SMauro Carvalho Chehab 	struct lg216x_state *state = fe->demodulator_priv;
1639a0bf528SMauro Carvalho Chehab 	int ret;
1649a0bf528SMauro Carvalho Chehab 
1659a0bf528SMauro Carvalho Chehab 	if (state->cfg->deny_i2c_rptr)
1669a0bf528SMauro Carvalho Chehab 		return 0;
1679a0bf528SMauro Carvalho Chehab 
1689a0bf528SMauro Carvalho Chehab 	lg_dbg("(%d)\n", enable);
1699a0bf528SMauro Carvalho Chehab 
1709a0bf528SMauro Carvalho Chehab 	ret = lg216x_set_reg_bit(state, 0x0000, 0, enable ? 0 : 1);
1719a0bf528SMauro Carvalho Chehab 
1729a0bf528SMauro Carvalho Chehab 	msleep(1);
1739a0bf528SMauro Carvalho Chehab 
1749a0bf528SMauro Carvalho Chehab 	return ret;
1759a0bf528SMauro Carvalho Chehab }
1769a0bf528SMauro Carvalho Chehab 
1779a0bf528SMauro Carvalho Chehab static int lg216x_soft_reset(struct lg216x_state *state)
1789a0bf528SMauro Carvalho Chehab {
1799a0bf528SMauro Carvalho Chehab 	int ret;
1809a0bf528SMauro Carvalho Chehab 
1819a0bf528SMauro Carvalho Chehab 	lg_dbg("\n");
1829a0bf528SMauro Carvalho Chehab 
1839a0bf528SMauro Carvalho Chehab 	ret = lg216x_write_reg(state, 0x0002, 0x00);
1849a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
1859a0bf528SMauro Carvalho Chehab 		goto fail;
1869a0bf528SMauro Carvalho Chehab 
1879a0bf528SMauro Carvalho Chehab 	msleep(20);
1889a0bf528SMauro Carvalho Chehab 	ret = lg216x_write_reg(state, 0x0002, 0x01);
1899a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
1909a0bf528SMauro Carvalho Chehab 		goto fail;
1919a0bf528SMauro Carvalho Chehab 
1929a0bf528SMauro Carvalho Chehab 	state->last_reset = jiffies_to_msecs(jiffies);
1939a0bf528SMauro Carvalho Chehab fail:
1949a0bf528SMauro Carvalho Chehab 	return ret;
1959a0bf528SMauro Carvalho Chehab }
1969a0bf528SMauro Carvalho Chehab 
1979a0bf528SMauro Carvalho Chehab static int lg216x_initialize(struct lg216x_state *state)
1989a0bf528SMauro Carvalho Chehab {
1999a0bf528SMauro Carvalho Chehab 	int ret;
2009a0bf528SMauro Carvalho Chehab 
2019a0bf528SMauro Carvalho Chehab 	static struct lg216x_reg lg2160_init[] = {
2029a0bf528SMauro Carvalho Chehab #if 0
2039a0bf528SMauro Carvalho Chehab 		{ .reg = 0x0015, .val = 0xe6 },
2049a0bf528SMauro Carvalho Chehab #else
2059a0bf528SMauro Carvalho Chehab 		{ .reg = 0x0015, .val = 0xf7 },
2069a0bf528SMauro Carvalho Chehab 		{ .reg = 0x001b, .val = 0x52 },
2079a0bf528SMauro Carvalho Chehab 		{ .reg = 0x0208, .val = 0x00 },
2089a0bf528SMauro Carvalho Chehab 		{ .reg = 0x0209, .val = 0x82 },
2099a0bf528SMauro Carvalho Chehab 		{ .reg = 0x0210, .val = 0xf9 },
2109a0bf528SMauro Carvalho Chehab 		{ .reg = 0x020a, .val = 0x00 },
2119a0bf528SMauro Carvalho Chehab 		{ .reg = 0x020b, .val = 0x82 },
2129a0bf528SMauro Carvalho Chehab 		{ .reg = 0x020d, .val = 0x28 },
2139a0bf528SMauro Carvalho Chehab 		{ .reg = 0x020f, .val = 0x14 },
2149a0bf528SMauro Carvalho Chehab #endif
2159a0bf528SMauro Carvalho Chehab 	};
2169a0bf528SMauro Carvalho Chehab 
2179a0bf528SMauro Carvalho Chehab 	static struct lg216x_reg lg2161_init[] = {
2189a0bf528SMauro Carvalho Chehab 		{ .reg = 0x0000, .val = 0x41 },
2199a0bf528SMauro Carvalho Chehab 		{ .reg = 0x0001, .val = 0xfb },
2209a0bf528SMauro Carvalho Chehab 		{ .reg = 0x0216, .val = 0x00 },
2219a0bf528SMauro Carvalho Chehab 		{ .reg = 0x0219, .val = 0x00 },
2229a0bf528SMauro Carvalho Chehab 		{ .reg = 0x021b, .val = 0x55 },
2239a0bf528SMauro Carvalho Chehab 		{ .reg = 0x0606, .val = 0x0a },
2249a0bf528SMauro Carvalho Chehab 	};
2259a0bf528SMauro Carvalho Chehab 
2269a0bf528SMauro Carvalho Chehab 	switch (state->cfg->lg_chip) {
2279a0bf528SMauro Carvalho Chehab 	case LG2160:
2289a0bf528SMauro Carvalho Chehab 		ret = lg216x_write_regs(state,
2299a0bf528SMauro Carvalho Chehab 					lg2160_init, ARRAY_SIZE(lg2160_init));
2309a0bf528SMauro Carvalho Chehab 		break;
2319a0bf528SMauro Carvalho Chehab 	case LG2161:
2329a0bf528SMauro Carvalho Chehab 		ret = lg216x_write_regs(state,
2339a0bf528SMauro Carvalho Chehab 					lg2161_init, ARRAY_SIZE(lg2161_init));
2349a0bf528SMauro Carvalho Chehab 		break;
2359a0bf528SMauro Carvalho Chehab 	default:
2369a0bf528SMauro Carvalho Chehab 		ret = -EINVAL;
2379a0bf528SMauro Carvalho Chehab 		break;
2389a0bf528SMauro Carvalho Chehab 	}
2399a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
2409a0bf528SMauro Carvalho Chehab 		goto fail;
2419a0bf528SMauro Carvalho Chehab 
2429a0bf528SMauro Carvalho Chehab 	ret = lg216x_soft_reset(state);
2439a0bf528SMauro Carvalho Chehab 	lg_fail(ret);
2449a0bf528SMauro Carvalho Chehab fail:
2459a0bf528SMauro Carvalho Chehab 	return ret;
2469a0bf528SMauro Carvalho Chehab }
2479a0bf528SMauro Carvalho Chehab 
2489a0bf528SMauro Carvalho Chehab /* ------------------------------------------------------------------------ */
2499a0bf528SMauro Carvalho Chehab 
2509a0bf528SMauro Carvalho Chehab static int lg216x_set_if(struct lg216x_state *state)
2519a0bf528SMauro Carvalho Chehab {
2529a0bf528SMauro Carvalho Chehab 	u8 val;
2539a0bf528SMauro Carvalho Chehab 	int ret;
2549a0bf528SMauro Carvalho Chehab 
2559a0bf528SMauro Carvalho Chehab 	lg_dbg("%d KHz\n", state->cfg->if_khz);
2569a0bf528SMauro Carvalho Chehab 
2579a0bf528SMauro Carvalho Chehab 	ret = lg216x_read_reg(state, 0x0132, &val);
2589a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
2599a0bf528SMauro Carvalho Chehab 		goto fail;
2609a0bf528SMauro Carvalho Chehab 
2619a0bf528SMauro Carvalho Chehab 	val &= 0xfb;
2629a0bf528SMauro Carvalho Chehab 	val |= (0 == state->cfg->if_khz) ? 0x04 : 0x00;
2639a0bf528SMauro Carvalho Chehab 
2649a0bf528SMauro Carvalho Chehab 	ret = lg216x_write_reg(state, 0x0132, val);
2659a0bf528SMauro Carvalho Chehab 	lg_fail(ret);
2669a0bf528SMauro Carvalho Chehab 
2679a0bf528SMauro Carvalho Chehab 	/* if NOT zero IF, 6 MHz is the default */
2689a0bf528SMauro Carvalho Chehab fail:
2699a0bf528SMauro Carvalho Chehab 	return ret;
2709a0bf528SMauro Carvalho Chehab }
2719a0bf528SMauro Carvalho Chehab 
2729a0bf528SMauro Carvalho Chehab /* ------------------------------------------------------------------------ */
2739a0bf528SMauro Carvalho Chehab 
2749a0bf528SMauro Carvalho Chehab static int lg2160_agc_fix(struct lg216x_state *state,
2759a0bf528SMauro Carvalho Chehab 			  int if_agc_fix, int rf_agc_fix)
2769a0bf528SMauro Carvalho Chehab {
2779a0bf528SMauro Carvalho Chehab 	u8 val;
2789a0bf528SMauro Carvalho Chehab 	int ret;
2799a0bf528SMauro Carvalho Chehab 
2809a0bf528SMauro Carvalho Chehab 	ret = lg216x_read_reg(state, 0x0100, &val);
2819a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
2829a0bf528SMauro Carvalho Chehab 		goto fail;
2839a0bf528SMauro Carvalho Chehab 
2849a0bf528SMauro Carvalho Chehab 	val &= 0xf3;
2859a0bf528SMauro Carvalho Chehab 	val |= (if_agc_fix) ? 0x08 : 0x00;
2869a0bf528SMauro Carvalho Chehab 	val |= (rf_agc_fix) ? 0x04 : 0x00;
2879a0bf528SMauro Carvalho Chehab 
2889a0bf528SMauro Carvalho Chehab 	ret = lg216x_write_reg(state, 0x0100, val);
2899a0bf528SMauro Carvalho Chehab 	lg_fail(ret);
2909a0bf528SMauro Carvalho Chehab fail:
2919a0bf528SMauro Carvalho Chehab 	return ret;
2929a0bf528SMauro Carvalho Chehab }
2939a0bf528SMauro Carvalho Chehab 
2949a0bf528SMauro Carvalho Chehab #if 0
2959a0bf528SMauro Carvalho Chehab static int lg2160_agc_freeze(struct lg216x_state *state,
2969a0bf528SMauro Carvalho Chehab 			     int if_agc_freeze, int rf_agc_freeze)
2979a0bf528SMauro Carvalho Chehab {
2989a0bf528SMauro Carvalho Chehab 	u8 val;
2999a0bf528SMauro Carvalho Chehab 	int ret;
3009a0bf528SMauro Carvalho Chehab 
3019a0bf528SMauro Carvalho Chehab 	ret = lg216x_read_reg(state, 0x0100, &val);
3029a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
3039a0bf528SMauro Carvalho Chehab 		goto fail;
3049a0bf528SMauro Carvalho Chehab 
3059a0bf528SMauro Carvalho Chehab 	val &= 0xcf;
3069a0bf528SMauro Carvalho Chehab 	val |= (if_agc_freeze) ? 0x20 : 0x00;
3079a0bf528SMauro Carvalho Chehab 	val |= (rf_agc_freeze) ? 0x10 : 0x00;
3089a0bf528SMauro Carvalho Chehab 
3099a0bf528SMauro Carvalho Chehab 	ret = lg216x_write_reg(state, 0x0100, val);
3109a0bf528SMauro Carvalho Chehab 	lg_fail(ret);
3119a0bf528SMauro Carvalho Chehab fail:
3129a0bf528SMauro Carvalho Chehab 	return ret;
3139a0bf528SMauro Carvalho Chehab }
3149a0bf528SMauro Carvalho Chehab #endif
3159a0bf528SMauro Carvalho Chehab 
3169a0bf528SMauro Carvalho Chehab static int lg2160_agc_polarity(struct lg216x_state *state,
3179a0bf528SMauro Carvalho Chehab 			       int if_agc_polarity, int rf_agc_polarity)
3189a0bf528SMauro Carvalho Chehab {
3199a0bf528SMauro Carvalho Chehab 	u8 val;
3209a0bf528SMauro Carvalho Chehab 	int ret;
3219a0bf528SMauro Carvalho Chehab 
3229a0bf528SMauro Carvalho Chehab 	ret = lg216x_read_reg(state, 0x0100, &val);
3239a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
3249a0bf528SMauro Carvalho Chehab 		goto fail;
3259a0bf528SMauro Carvalho Chehab 
3269a0bf528SMauro Carvalho Chehab 	val &= 0xfc;
3279a0bf528SMauro Carvalho Chehab 	val |= (if_agc_polarity) ? 0x02 : 0x00;
3289a0bf528SMauro Carvalho Chehab 	val |= (rf_agc_polarity) ? 0x01 : 0x00;
3299a0bf528SMauro Carvalho Chehab 
3309a0bf528SMauro Carvalho Chehab 	ret = lg216x_write_reg(state, 0x0100, val);
3319a0bf528SMauro Carvalho Chehab 	lg_fail(ret);
3329a0bf528SMauro Carvalho Chehab fail:
3339a0bf528SMauro Carvalho Chehab 	return ret;
3349a0bf528SMauro Carvalho Chehab }
3359a0bf528SMauro Carvalho Chehab 
3369a0bf528SMauro Carvalho Chehab static int lg2160_tuner_pwr_save_polarity(struct lg216x_state *state,
3379a0bf528SMauro Carvalho Chehab 					  int polarity)
3389a0bf528SMauro Carvalho Chehab {
3399a0bf528SMauro Carvalho Chehab 	u8 val;
3409a0bf528SMauro Carvalho Chehab 	int ret;
3419a0bf528SMauro Carvalho Chehab 
3429a0bf528SMauro Carvalho Chehab 	ret = lg216x_read_reg(state, 0x0008, &val);
3439a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
3449a0bf528SMauro Carvalho Chehab 		goto fail;
3459a0bf528SMauro Carvalho Chehab 
3469a0bf528SMauro Carvalho Chehab 	val &= 0xfe;
3479a0bf528SMauro Carvalho Chehab 	val |= (polarity) ? 0x01 : 0x00;
3489a0bf528SMauro Carvalho Chehab 
3499a0bf528SMauro Carvalho Chehab 	ret = lg216x_write_reg(state, 0x0008, val);
3509a0bf528SMauro Carvalho Chehab 	lg_fail(ret);
3519a0bf528SMauro Carvalho Chehab fail:
3529a0bf528SMauro Carvalho Chehab 	return ret;
3539a0bf528SMauro Carvalho Chehab }
3549a0bf528SMauro Carvalho Chehab 
3559a0bf528SMauro Carvalho Chehab static int lg2160_spectrum_polarity(struct lg216x_state *state,
3569a0bf528SMauro Carvalho Chehab 				    int inverted)
3579a0bf528SMauro Carvalho Chehab {
3589a0bf528SMauro Carvalho Chehab 	u8 val;
3599a0bf528SMauro Carvalho Chehab 	int ret;
3609a0bf528SMauro Carvalho Chehab 
3619a0bf528SMauro Carvalho Chehab 	ret = lg216x_read_reg(state, 0x0132, &val);
3629a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
3639a0bf528SMauro Carvalho Chehab 		goto fail;
3649a0bf528SMauro Carvalho Chehab 
3659a0bf528SMauro Carvalho Chehab 	val &= 0xfd;
3669a0bf528SMauro Carvalho Chehab 	val |= (inverted) ? 0x02 : 0x00;
3679a0bf528SMauro Carvalho Chehab 
3689a0bf528SMauro Carvalho Chehab 	ret = lg216x_write_reg(state, 0x0132, val);
3699a0bf528SMauro Carvalho Chehab 	lg_fail(ret);
3709a0bf528SMauro Carvalho Chehab fail:
3719a0bf528SMauro Carvalho Chehab 	return lg216x_soft_reset(state);
3729a0bf528SMauro Carvalho Chehab }
3739a0bf528SMauro Carvalho Chehab 
3749a0bf528SMauro Carvalho Chehab static int lg2160_tuner_pwr_save(struct lg216x_state *state, int onoff)
3759a0bf528SMauro Carvalho Chehab {
3769a0bf528SMauro Carvalho Chehab 	u8 val;
3779a0bf528SMauro Carvalho Chehab 	int ret;
3789a0bf528SMauro Carvalho Chehab 
3799a0bf528SMauro Carvalho Chehab 	ret = lg216x_read_reg(state, 0x0007, &val);
3809a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
3819a0bf528SMauro Carvalho Chehab 		goto fail;
3829a0bf528SMauro Carvalho Chehab 
3839a0bf528SMauro Carvalho Chehab 	val &= 0xbf;
3849a0bf528SMauro Carvalho Chehab 	val |= (onoff) ? 0x40 : 0x00;
3859a0bf528SMauro Carvalho Chehab 
3869a0bf528SMauro Carvalho Chehab 	ret = lg216x_write_reg(state, 0x0007, val);
3879a0bf528SMauro Carvalho Chehab 	lg_fail(ret);
3889a0bf528SMauro Carvalho Chehab fail:
3899a0bf528SMauro Carvalho Chehab 	return ret;
3909a0bf528SMauro Carvalho Chehab }
3919a0bf528SMauro Carvalho Chehab 
3929a0bf528SMauro Carvalho Chehab static int lg216x_set_parade(struct lg216x_state *state, int id)
3939a0bf528SMauro Carvalho Chehab {
3949a0bf528SMauro Carvalho Chehab 	int ret;
3959a0bf528SMauro Carvalho Chehab 
3969a0bf528SMauro Carvalho Chehab 	ret = lg216x_write_reg(state, 0x013e, id & 0x7f);
3979a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
3989a0bf528SMauro Carvalho Chehab 		goto fail;
3999a0bf528SMauro Carvalho Chehab 
4009a0bf528SMauro Carvalho Chehab 	state->parade_id = id & 0x7f;
4019a0bf528SMauro Carvalho Chehab fail:
4029a0bf528SMauro Carvalho Chehab 	return ret;
4039a0bf528SMauro Carvalho Chehab }
4049a0bf528SMauro Carvalho Chehab 
4059a0bf528SMauro Carvalho Chehab static int lg216x_set_ensemble(struct lg216x_state *state, int id)
4069a0bf528SMauro Carvalho Chehab {
4079a0bf528SMauro Carvalho Chehab 	int ret;
4089a0bf528SMauro Carvalho Chehab 	u16 reg;
4099a0bf528SMauro Carvalho Chehab 	u8 val;
4109a0bf528SMauro Carvalho Chehab 
4119a0bf528SMauro Carvalho Chehab 	switch (state->cfg->lg_chip) {
4129a0bf528SMauro Carvalho Chehab 	case LG2160:
4139a0bf528SMauro Carvalho Chehab 		reg = 0x0400;
4149a0bf528SMauro Carvalho Chehab 		break;
4159a0bf528SMauro Carvalho Chehab 	case LG2161:
4169a0bf528SMauro Carvalho Chehab 	default:
4179a0bf528SMauro Carvalho Chehab 		reg = 0x0500;
4189a0bf528SMauro Carvalho Chehab 		break;
4199a0bf528SMauro Carvalho Chehab 	}
4209a0bf528SMauro Carvalho Chehab 
4219a0bf528SMauro Carvalho Chehab 	ret = lg216x_read_reg(state, reg, &val);
4229a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
4239a0bf528SMauro Carvalho Chehab 		goto fail;
4249a0bf528SMauro Carvalho Chehab 
4259a0bf528SMauro Carvalho Chehab 	val &= 0xfe;
4269a0bf528SMauro Carvalho Chehab 	val |= (id) ? 0x01 : 0x00;
4279a0bf528SMauro Carvalho Chehab 
4289a0bf528SMauro Carvalho Chehab 	ret = lg216x_write_reg(state, reg, val);
4299a0bf528SMauro Carvalho Chehab 	lg_fail(ret);
4309a0bf528SMauro Carvalho Chehab fail:
4319a0bf528SMauro Carvalho Chehab 	return ret;
4329a0bf528SMauro Carvalho Chehab }
4339a0bf528SMauro Carvalho Chehab 
4349a0bf528SMauro Carvalho Chehab static int lg2160_set_spi_clock(struct lg216x_state *state)
4359a0bf528SMauro Carvalho Chehab {
4369a0bf528SMauro Carvalho Chehab 	u8 val;
4379a0bf528SMauro Carvalho Chehab 	int ret;
4389a0bf528SMauro Carvalho Chehab 
4399a0bf528SMauro Carvalho Chehab 	ret = lg216x_read_reg(state, 0x0014, &val);
4409a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
4419a0bf528SMauro Carvalho Chehab 		goto fail;
4429a0bf528SMauro Carvalho Chehab 
4439a0bf528SMauro Carvalho Chehab 	val &= 0xf3;
4449a0bf528SMauro Carvalho Chehab 	val |= (state->cfg->spi_clock << 2);
4459a0bf528SMauro Carvalho Chehab 
4469a0bf528SMauro Carvalho Chehab 	ret = lg216x_write_reg(state, 0x0014, val);
4479a0bf528SMauro Carvalho Chehab 	lg_fail(ret);
4489a0bf528SMauro Carvalho Chehab fail:
4499a0bf528SMauro Carvalho Chehab 	return ret;
4509a0bf528SMauro Carvalho Chehab }
4519a0bf528SMauro Carvalho Chehab 
4529a0bf528SMauro Carvalho Chehab static int lg2161_set_output_interface(struct lg216x_state *state)
4539a0bf528SMauro Carvalho Chehab {
4549a0bf528SMauro Carvalho Chehab 	u8 val;
4559a0bf528SMauro Carvalho Chehab 	int ret;
4569a0bf528SMauro Carvalho Chehab 
4579a0bf528SMauro Carvalho Chehab 	ret = lg216x_read_reg(state, 0x0014, &val);
4589a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
4599a0bf528SMauro Carvalho Chehab 		goto fail;
4609a0bf528SMauro Carvalho Chehab 
4619a0bf528SMauro Carvalho Chehab 	val &= ~0x07;
4629a0bf528SMauro Carvalho Chehab 	val |= state->cfg->output_if; /* FIXME: needs sanity check */
4639a0bf528SMauro Carvalho Chehab 
4649a0bf528SMauro Carvalho Chehab 	ret = lg216x_write_reg(state, 0x0014, val);
4659a0bf528SMauro Carvalho Chehab 	lg_fail(ret);
4669a0bf528SMauro Carvalho Chehab fail:
4679a0bf528SMauro Carvalho Chehab 	return ret;
4689a0bf528SMauro Carvalho Chehab }
4699a0bf528SMauro Carvalho Chehab 
4709a0bf528SMauro Carvalho Chehab static int lg216x_enable_fic(struct lg216x_state *state, int onoff)
4719a0bf528SMauro Carvalho Chehab {
4729a0bf528SMauro Carvalho Chehab 	int ret;
4739a0bf528SMauro Carvalho Chehab 
4749a0bf528SMauro Carvalho Chehab 	ret = lg216x_write_reg(state, 0x0017, 0x23);
4759a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
4769a0bf528SMauro Carvalho Chehab 		goto fail;
4779a0bf528SMauro Carvalho Chehab 
4789a0bf528SMauro Carvalho Chehab 	ret = lg216x_write_reg(state, 0x0016, 0xfc);
4799a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
4809a0bf528SMauro Carvalho Chehab 		goto fail;
4819a0bf528SMauro Carvalho Chehab 
4829a0bf528SMauro Carvalho Chehab 	switch (state->cfg->lg_chip) {
4839a0bf528SMauro Carvalho Chehab 	case LG2160:
4849a0bf528SMauro Carvalho Chehab 		ret = lg216x_write_reg(state, 0x0016,
4859a0bf528SMauro Carvalho Chehab 				       0xfc | ((onoff) ? 0x02 : 0x00));
4869a0bf528SMauro Carvalho Chehab 		break;
4879a0bf528SMauro Carvalho Chehab 	case LG2161:
4889a0bf528SMauro Carvalho Chehab 		ret = lg216x_write_reg(state, 0x0016, (onoff) ? 0x10 : 0x00);
4899a0bf528SMauro Carvalho Chehab 		break;
4909a0bf528SMauro Carvalho Chehab 	}
4919a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
4929a0bf528SMauro Carvalho Chehab 		goto fail;
4939a0bf528SMauro Carvalho Chehab 
4949a0bf528SMauro Carvalho Chehab 	ret = lg216x_initialize(state);
4959a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
4969a0bf528SMauro Carvalho Chehab 		goto fail;
4979a0bf528SMauro Carvalho Chehab 
4989a0bf528SMauro Carvalho Chehab 	if (onoff) {
4999a0bf528SMauro Carvalho Chehab 		ret = lg216x_write_reg(state, 0x0017, 0x03);
5009a0bf528SMauro Carvalho Chehab 		lg_fail(ret);
5019a0bf528SMauro Carvalho Chehab 	}
5029a0bf528SMauro Carvalho Chehab fail:
5039a0bf528SMauro Carvalho Chehab 	return ret;
5049a0bf528SMauro Carvalho Chehab }
5059a0bf528SMauro Carvalho Chehab 
5069a0bf528SMauro Carvalho Chehab /* ------------------------------------------------------------------------ */
5079a0bf528SMauro Carvalho Chehab 
5089a0bf528SMauro Carvalho Chehab static int lg216x_get_fic_version(struct lg216x_state *state, u8 *ficver)
5099a0bf528SMauro Carvalho Chehab {
5109a0bf528SMauro Carvalho Chehab 	u8 val;
5119a0bf528SMauro Carvalho Chehab 	int ret;
5129a0bf528SMauro Carvalho Chehab 
5139a0bf528SMauro Carvalho Chehab 	*ficver = 0xff; /* invalid value */
5149a0bf528SMauro Carvalho Chehab 
5159a0bf528SMauro Carvalho Chehab 	ret = lg216x_read_reg(state, 0x0128, &val);
5169a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
5179a0bf528SMauro Carvalho Chehab 		goto fail;
5189a0bf528SMauro Carvalho Chehab 
5199a0bf528SMauro Carvalho Chehab 	*ficver = (val >> 3) & 0x1f;
5209a0bf528SMauro Carvalho Chehab fail:
5219a0bf528SMauro Carvalho Chehab 	return ret;
5229a0bf528SMauro Carvalho Chehab }
5239a0bf528SMauro Carvalho Chehab 
5249a0bf528SMauro Carvalho Chehab #if 0
5259a0bf528SMauro Carvalho Chehab static int lg2160_get_parade_id(struct lg216x_state *state, u8 *id)
5269a0bf528SMauro Carvalho Chehab {
5279a0bf528SMauro Carvalho Chehab 	u8 val;
5289a0bf528SMauro Carvalho Chehab 	int ret;
5299a0bf528SMauro Carvalho Chehab 
5309a0bf528SMauro Carvalho Chehab 	*id = 0xff; /* invalid value */
5319a0bf528SMauro Carvalho Chehab 
5329a0bf528SMauro Carvalho Chehab 	ret = lg216x_read_reg(state, 0x0123, &val);
5339a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
5349a0bf528SMauro Carvalho Chehab 		goto fail;
5359a0bf528SMauro Carvalho Chehab 
5369a0bf528SMauro Carvalho Chehab 	*id = val & 0x7f;
5379a0bf528SMauro Carvalho Chehab fail:
5389a0bf528SMauro Carvalho Chehab 	return ret;
5399a0bf528SMauro Carvalho Chehab }
5409a0bf528SMauro Carvalho Chehab #endif
5419a0bf528SMauro Carvalho Chehab 
5429a0bf528SMauro Carvalho Chehab static int lg216x_get_nog(struct lg216x_state *state, u8 *nog)
5439a0bf528SMauro Carvalho Chehab {
5449a0bf528SMauro Carvalho Chehab 	u8 val;
5459a0bf528SMauro Carvalho Chehab 	int ret;
5469a0bf528SMauro Carvalho Chehab 
5479a0bf528SMauro Carvalho Chehab 	*nog = 0xff; /* invalid value */
5489a0bf528SMauro Carvalho Chehab 
5499a0bf528SMauro Carvalho Chehab 	ret = lg216x_read_reg(state, 0x0124, &val);
5509a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
5519a0bf528SMauro Carvalho Chehab 		goto fail;
5529a0bf528SMauro Carvalho Chehab 
5539a0bf528SMauro Carvalho Chehab 	*nog = ((val >> 4) & 0x07) + 1;
5549a0bf528SMauro Carvalho Chehab fail:
5559a0bf528SMauro Carvalho Chehab 	return ret;
5569a0bf528SMauro Carvalho Chehab }
5579a0bf528SMauro Carvalho Chehab 
5589a0bf528SMauro Carvalho Chehab static int lg216x_get_tnog(struct lg216x_state *state, u8 *tnog)
5599a0bf528SMauro Carvalho Chehab {
5609a0bf528SMauro Carvalho Chehab 	u8 val;
5619a0bf528SMauro Carvalho Chehab 	int ret;
5629a0bf528SMauro Carvalho Chehab 
5639a0bf528SMauro Carvalho Chehab 	*tnog = 0xff; /* invalid value */
5649a0bf528SMauro Carvalho Chehab 
5659a0bf528SMauro Carvalho Chehab 	ret = lg216x_read_reg(state, 0x0125, &val);
5669a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
5679a0bf528SMauro Carvalho Chehab 		goto fail;
5689a0bf528SMauro Carvalho Chehab 
5699a0bf528SMauro Carvalho Chehab 	*tnog = val & 0x1f;
5709a0bf528SMauro Carvalho Chehab fail:
5719a0bf528SMauro Carvalho Chehab 	return ret;
5729a0bf528SMauro Carvalho Chehab }
5739a0bf528SMauro Carvalho Chehab 
5749a0bf528SMauro Carvalho Chehab static int lg216x_get_sgn(struct lg216x_state *state, u8 *sgn)
5759a0bf528SMauro Carvalho Chehab {
5769a0bf528SMauro Carvalho Chehab 	u8 val;
5779a0bf528SMauro Carvalho Chehab 	int ret;
5789a0bf528SMauro Carvalho Chehab 
5799a0bf528SMauro Carvalho Chehab 	*sgn = 0xff; /* invalid value */
5809a0bf528SMauro Carvalho Chehab 
5819a0bf528SMauro Carvalho Chehab 	ret = lg216x_read_reg(state, 0x0124, &val);
5829a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
5839a0bf528SMauro Carvalho Chehab 		goto fail;
5849a0bf528SMauro Carvalho Chehab 
5859a0bf528SMauro Carvalho Chehab 	*sgn = val & 0x0f;
5869a0bf528SMauro Carvalho Chehab fail:
5879a0bf528SMauro Carvalho Chehab 	return ret;
5889a0bf528SMauro Carvalho Chehab }
5899a0bf528SMauro Carvalho Chehab 
5909a0bf528SMauro Carvalho Chehab static int lg216x_get_prc(struct lg216x_state *state, u8 *prc)
5919a0bf528SMauro Carvalho Chehab {
5929a0bf528SMauro Carvalho Chehab 	u8 val;
5939a0bf528SMauro Carvalho Chehab 	int ret;
5949a0bf528SMauro Carvalho Chehab 
5959a0bf528SMauro Carvalho Chehab 	*prc = 0xff; /* invalid value */
5969a0bf528SMauro Carvalho Chehab 
5979a0bf528SMauro Carvalho Chehab 	ret = lg216x_read_reg(state, 0x0125, &val);
5989a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
5999a0bf528SMauro Carvalho Chehab 		goto fail;
6009a0bf528SMauro Carvalho Chehab 
6019a0bf528SMauro Carvalho Chehab 	*prc = ((val >> 5) & 0x07) + 1;
6029a0bf528SMauro Carvalho Chehab fail:
6039a0bf528SMauro Carvalho Chehab 	return ret;
6049a0bf528SMauro Carvalho Chehab }
6059a0bf528SMauro Carvalho Chehab 
6069a0bf528SMauro Carvalho Chehab /* ------------------------------------------------------------------------ */
6079a0bf528SMauro Carvalho Chehab 
6089a0bf528SMauro Carvalho Chehab static int lg216x_get_rs_frame_mode(struct lg216x_state *state,
6099a0bf528SMauro Carvalho Chehab 				    enum atscmh_rs_frame_mode *rs_framemode)
6109a0bf528SMauro Carvalho Chehab {
6119a0bf528SMauro Carvalho Chehab 	u8 val;
6129a0bf528SMauro Carvalho Chehab 	int ret;
6139a0bf528SMauro Carvalho Chehab 
6149a0bf528SMauro Carvalho Chehab 	switch (state->cfg->lg_chip) {
6159a0bf528SMauro Carvalho Chehab 	case LG2160:
6169a0bf528SMauro Carvalho Chehab 		ret = lg216x_read_reg(state, 0x0410, &val);
6179a0bf528SMauro Carvalho Chehab 		break;
6189a0bf528SMauro Carvalho Chehab 	case LG2161:
6199a0bf528SMauro Carvalho Chehab 		ret = lg216x_read_reg(state, 0x0513, &val);
6209a0bf528SMauro Carvalho Chehab 		break;
6219a0bf528SMauro Carvalho Chehab 	default:
6229a0bf528SMauro Carvalho Chehab 		ret = -EINVAL;
6239a0bf528SMauro Carvalho Chehab 	}
6249a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
6259a0bf528SMauro Carvalho Chehab 		goto fail;
6269a0bf528SMauro Carvalho Chehab 
6279a0bf528SMauro Carvalho Chehab 	switch ((val >> 4) & 0x03) {
6289a0bf528SMauro Carvalho Chehab #if 1
6299a0bf528SMauro Carvalho Chehab 	default:
6309a0bf528SMauro Carvalho Chehab #endif
6319a0bf528SMauro Carvalho Chehab 	case 0x00:
6329a0bf528SMauro Carvalho Chehab 		*rs_framemode = ATSCMH_RSFRAME_PRI_ONLY;
6339a0bf528SMauro Carvalho Chehab 		break;
6349a0bf528SMauro Carvalho Chehab 	case 0x01:
6359a0bf528SMauro Carvalho Chehab 		*rs_framemode = ATSCMH_RSFRAME_PRI_SEC;
6369a0bf528SMauro Carvalho Chehab 		break;
6379a0bf528SMauro Carvalho Chehab #if 0
6389a0bf528SMauro Carvalho Chehab 	default:
6399a0bf528SMauro Carvalho Chehab 		*rs_framemode = ATSCMH_RSFRAME_RES;
6409a0bf528SMauro Carvalho Chehab 		break;
6419a0bf528SMauro Carvalho Chehab #endif
6429a0bf528SMauro Carvalho Chehab 	}
6439a0bf528SMauro Carvalho Chehab fail:
6449a0bf528SMauro Carvalho Chehab 	return ret;
6459a0bf528SMauro Carvalho Chehab }
6469a0bf528SMauro Carvalho Chehab 
6479a0bf528SMauro Carvalho Chehab static
6489a0bf528SMauro Carvalho Chehab int lg216x_get_rs_frame_ensemble(struct lg216x_state *state,
6499a0bf528SMauro Carvalho Chehab 				 enum atscmh_rs_frame_ensemble *rs_frame_ens)
6509a0bf528SMauro Carvalho Chehab {
6519a0bf528SMauro Carvalho Chehab 	u8 val;
6529a0bf528SMauro Carvalho Chehab 	int ret;
6539a0bf528SMauro Carvalho Chehab 
6549a0bf528SMauro Carvalho Chehab 	switch (state->cfg->lg_chip) {
6559a0bf528SMauro Carvalho Chehab 	case LG2160:
6569a0bf528SMauro Carvalho Chehab 		ret = lg216x_read_reg(state, 0x0400, &val);
6579a0bf528SMauro Carvalho Chehab 		break;
6589a0bf528SMauro Carvalho Chehab 	case LG2161:
6599a0bf528SMauro Carvalho Chehab 		ret = lg216x_read_reg(state, 0x0500, &val);
6609a0bf528SMauro Carvalho Chehab 		break;
6619a0bf528SMauro Carvalho Chehab 	default:
6629a0bf528SMauro Carvalho Chehab 		ret = -EINVAL;
6639a0bf528SMauro Carvalho Chehab 	}
6649a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
6659a0bf528SMauro Carvalho Chehab 		goto fail;
6669a0bf528SMauro Carvalho Chehab 
6679a0bf528SMauro Carvalho Chehab 	val &= 0x01;
6689a0bf528SMauro Carvalho Chehab 	*rs_frame_ens = (enum atscmh_rs_frame_ensemble) val;
6699a0bf528SMauro Carvalho Chehab fail:
6709a0bf528SMauro Carvalho Chehab 	return ret;
6719a0bf528SMauro Carvalho Chehab }
6729a0bf528SMauro Carvalho Chehab 
6739a0bf528SMauro Carvalho Chehab static int lg216x_get_rs_code_mode(struct lg216x_state *state,
6749a0bf528SMauro Carvalho Chehab 				   enum atscmh_rs_code_mode *rs_code_pri,
6759a0bf528SMauro Carvalho Chehab 				   enum atscmh_rs_code_mode *rs_code_sec)
6769a0bf528SMauro Carvalho Chehab {
6779a0bf528SMauro Carvalho Chehab 	u8 val;
6789a0bf528SMauro Carvalho Chehab 	int ret;
6799a0bf528SMauro Carvalho Chehab 
6809a0bf528SMauro Carvalho Chehab 	switch (state->cfg->lg_chip) {
6819a0bf528SMauro Carvalho Chehab 	case LG2160:
6829a0bf528SMauro Carvalho Chehab 		ret = lg216x_read_reg(state, 0x0410, &val);
6839a0bf528SMauro Carvalho Chehab 		break;
6849a0bf528SMauro Carvalho Chehab 	case LG2161:
6859a0bf528SMauro Carvalho Chehab 		ret = lg216x_read_reg(state, 0x0513, &val);
6869a0bf528SMauro Carvalho Chehab 		break;
6879a0bf528SMauro Carvalho Chehab 	default:
6889a0bf528SMauro Carvalho Chehab 		ret = -EINVAL;
6899a0bf528SMauro Carvalho Chehab 	}
6909a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
6919a0bf528SMauro Carvalho Chehab 		goto fail;
6929a0bf528SMauro Carvalho Chehab 
6939a0bf528SMauro Carvalho Chehab 	*rs_code_pri = (enum atscmh_rs_code_mode) ((val >> 2) & 0x03);
6949a0bf528SMauro Carvalho Chehab 	*rs_code_sec = (enum atscmh_rs_code_mode) (val & 0x03);
6959a0bf528SMauro Carvalho Chehab fail:
6969a0bf528SMauro Carvalho Chehab 	return ret;
6979a0bf528SMauro Carvalho Chehab }
6989a0bf528SMauro Carvalho Chehab 
6999a0bf528SMauro Carvalho Chehab static int lg216x_get_sccc_block_mode(struct lg216x_state *state,
7009a0bf528SMauro Carvalho Chehab 				      enum atscmh_sccc_block_mode *sccc_block)
7019a0bf528SMauro Carvalho Chehab {
7029a0bf528SMauro Carvalho Chehab 	u8 val;
7039a0bf528SMauro Carvalho Chehab 	int ret;
7049a0bf528SMauro Carvalho Chehab 
7059a0bf528SMauro Carvalho Chehab 	switch (state->cfg->lg_chip) {
7069a0bf528SMauro Carvalho Chehab 	case LG2160:
7079a0bf528SMauro Carvalho Chehab 		ret = lg216x_read_reg(state, 0x0315, &val);
7089a0bf528SMauro Carvalho Chehab 		break;
7099a0bf528SMauro Carvalho Chehab 	case LG2161:
7109a0bf528SMauro Carvalho Chehab 		ret = lg216x_read_reg(state, 0x0511, &val);
7119a0bf528SMauro Carvalho Chehab 		break;
7129a0bf528SMauro Carvalho Chehab 	default:
7139a0bf528SMauro Carvalho Chehab 		ret = -EINVAL;
7149a0bf528SMauro Carvalho Chehab 	}
7159a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
7169a0bf528SMauro Carvalho Chehab 		goto fail;
7179a0bf528SMauro Carvalho Chehab 
7189a0bf528SMauro Carvalho Chehab 	switch (val & 0x03) {
7199a0bf528SMauro Carvalho Chehab 	case 0x00:
7209a0bf528SMauro Carvalho Chehab 		*sccc_block = ATSCMH_SCCC_BLK_SEP;
7219a0bf528SMauro Carvalho Chehab 		break;
7229a0bf528SMauro Carvalho Chehab 	case 0x01:
7239a0bf528SMauro Carvalho Chehab 		*sccc_block = ATSCMH_SCCC_BLK_COMB;
7249a0bf528SMauro Carvalho Chehab 		break;
7259a0bf528SMauro Carvalho Chehab 	default:
7269a0bf528SMauro Carvalho Chehab 		*sccc_block = ATSCMH_SCCC_BLK_RES;
7279a0bf528SMauro Carvalho Chehab 		break;
7289a0bf528SMauro Carvalho Chehab 	}
7299a0bf528SMauro Carvalho Chehab fail:
7309a0bf528SMauro Carvalho Chehab 	return ret;
7319a0bf528SMauro Carvalho Chehab }
7329a0bf528SMauro Carvalho Chehab 
7339a0bf528SMauro Carvalho Chehab static int lg216x_get_sccc_code_mode(struct lg216x_state *state,
7349a0bf528SMauro Carvalho Chehab 				     enum atscmh_sccc_code_mode *mode_a,
7359a0bf528SMauro Carvalho Chehab 				     enum atscmh_sccc_code_mode *mode_b,
7369a0bf528SMauro Carvalho Chehab 				     enum atscmh_sccc_code_mode *mode_c,
7379a0bf528SMauro Carvalho Chehab 				     enum atscmh_sccc_code_mode *mode_d)
7389a0bf528SMauro Carvalho Chehab {
7399a0bf528SMauro Carvalho Chehab 	u8 val;
7409a0bf528SMauro Carvalho Chehab 	int ret;
7419a0bf528SMauro Carvalho Chehab 
7429a0bf528SMauro Carvalho Chehab 	switch (state->cfg->lg_chip) {
7439a0bf528SMauro Carvalho Chehab 	case LG2160:
7449a0bf528SMauro Carvalho Chehab 		ret = lg216x_read_reg(state, 0x0316, &val);
7459a0bf528SMauro Carvalho Chehab 		break;
7469a0bf528SMauro Carvalho Chehab 	case LG2161:
7479a0bf528SMauro Carvalho Chehab 		ret = lg216x_read_reg(state, 0x0512, &val);
7489a0bf528SMauro Carvalho Chehab 		break;
7499a0bf528SMauro Carvalho Chehab 	default:
7509a0bf528SMauro Carvalho Chehab 		ret = -EINVAL;
7519a0bf528SMauro Carvalho Chehab 	}
7529a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
7539a0bf528SMauro Carvalho Chehab 		goto fail;
7549a0bf528SMauro Carvalho Chehab 
7559a0bf528SMauro Carvalho Chehab 	switch ((val >> 6) & 0x03) {
7569a0bf528SMauro Carvalho Chehab 	case 0x00:
7579a0bf528SMauro Carvalho Chehab 		*mode_a = ATSCMH_SCCC_CODE_HLF;
7589a0bf528SMauro Carvalho Chehab 		break;
7599a0bf528SMauro Carvalho Chehab 	case 0x01:
7609a0bf528SMauro Carvalho Chehab 		*mode_a = ATSCMH_SCCC_CODE_QTR;
7619a0bf528SMauro Carvalho Chehab 		break;
7629a0bf528SMauro Carvalho Chehab 	default:
7639a0bf528SMauro Carvalho Chehab 		*mode_a = ATSCMH_SCCC_CODE_RES;
7649a0bf528SMauro Carvalho Chehab 		break;
7659a0bf528SMauro Carvalho Chehab 	}
7669a0bf528SMauro Carvalho Chehab 
7679a0bf528SMauro Carvalho Chehab 	switch ((val >> 4) & 0x03) {
7689a0bf528SMauro Carvalho Chehab 	case 0x00:
7699a0bf528SMauro Carvalho Chehab 		*mode_b = ATSCMH_SCCC_CODE_HLF;
7709a0bf528SMauro Carvalho Chehab 		break;
7719a0bf528SMauro Carvalho Chehab 	case 0x01:
7729a0bf528SMauro Carvalho Chehab 		*mode_b = ATSCMH_SCCC_CODE_QTR;
7739a0bf528SMauro Carvalho Chehab 		break;
7749a0bf528SMauro Carvalho Chehab 	default:
7759a0bf528SMauro Carvalho Chehab 		*mode_b = ATSCMH_SCCC_CODE_RES;
7769a0bf528SMauro Carvalho Chehab 		break;
7779a0bf528SMauro Carvalho Chehab 	}
7789a0bf528SMauro Carvalho Chehab 
7799a0bf528SMauro Carvalho Chehab 	switch ((val >> 2) & 0x03) {
7809a0bf528SMauro Carvalho Chehab 	case 0x00:
7819a0bf528SMauro Carvalho Chehab 		*mode_c = ATSCMH_SCCC_CODE_HLF;
7829a0bf528SMauro Carvalho Chehab 		break;
7839a0bf528SMauro Carvalho Chehab 	case 0x01:
7849a0bf528SMauro Carvalho Chehab 		*mode_c = ATSCMH_SCCC_CODE_QTR;
7859a0bf528SMauro Carvalho Chehab 		break;
7869a0bf528SMauro Carvalho Chehab 	default:
7879a0bf528SMauro Carvalho Chehab 		*mode_c = ATSCMH_SCCC_CODE_RES;
7889a0bf528SMauro Carvalho Chehab 		break;
7899a0bf528SMauro Carvalho Chehab 	}
7909a0bf528SMauro Carvalho Chehab 
7919a0bf528SMauro Carvalho Chehab 	switch (val & 0x03) {
7929a0bf528SMauro Carvalho Chehab 	case 0x00:
7939a0bf528SMauro Carvalho Chehab 		*mode_d = ATSCMH_SCCC_CODE_HLF;
7949a0bf528SMauro Carvalho Chehab 		break;
7959a0bf528SMauro Carvalho Chehab 	case 0x01:
7969a0bf528SMauro Carvalho Chehab 		*mode_d = ATSCMH_SCCC_CODE_QTR;
7979a0bf528SMauro Carvalho Chehab 		break;
7989a0bf528SMauro Carvalho Chehab 	default:
7999a0bf528SMauro Carvalho Chehab 		*mode_d = ATSCMH_SCCC_CODE_RES;
8009a0bf528SMauro Carvalho Chehab 		break;
8019a0bf528SMauro Carvalho Chehab 	}
8029a0bf528SMauro Carvalho Chehab fail:
8039a0bf528SMauro Carvalho Chehab 	return ret;
8049a0bf528SMauro Carvalho Chehab }
8059a0bf528SMauro Carvalho Chehab 
8069a0bf528SMauro Carvalho Chehab /* ------------------------------------------------------------------------ */
8079a0bf528SMauro Carvalho Chehab 
8089a0bf528SMauro Carvalho Chehab #if 0
8099a0bf528SMauro Carvalho Chehab static int lg216x_read_fic_err_count(struct lg216x_state *state, u8 *err)
8109a0bf528SMauro Carvalho Chehab {
8119a0bf528SMauro Carvalho Chehab 	u8 fic_err;
8129a0bf528SMauro Carvalho Chehab 	int ret;
8139a0bf528SMauro Carvalho Chehab 
8149a0bf528SMauro Carvalho Chehab 	*err = 0;
8159a0bf528SMauro Carvalho Chehab 
8169a0bf528SMauro Carvalho Chehab 	switch (state->cfg->lg_chip) {
8179a0bf528SMauro Carvalho Chehab 	case LG2160:
8189a0bf528SMauro Carvalho Chehab 		ret = lg216x_read_reg(state, 0x0012, &fic_err);
8199a0bf528SMauro Carvalho Chehab 		break;
8209a0bf528SMauro Carvalho Chehab 	case LG2161:
8219a0bf528SMauro Carvalho Chehab 		ret = lg216x_read_reg(state, 0x001e, &fic_err);
8229a0bf528SMauro Carvalho Chehab 		break;
8239a0bf528SMauro Carvalho Chehab 	}
8249a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
8259a0bf528SMauro Carvalho Chehab 		goto fail;
8269a0bf528SMauro Carvalho Chehab 
8279a0bf528SMauro Carvalho Chehab 	*err = fic_err;
8289a0bf528SMauro Carvalho Chehab fail:
8299a0bf528SMauro Carvalho Chehab 	return ret;
8309a0bf528SMauro Carvalho Chehab }
8319a0bf528SMauro Carvalho Chehab 
8329a0bf528SMauro Carvalho Chehab static int lg2160_read_crc_err_count(struct lg216x_state *state, u16 *err)
8339a0bf528SMauro Carvalho Chehab {
8349a0bf528SMauro Carvalho Chehab 	u8 crc_err1, crc_err2;
8359a0bf528SMauro Carvalho Chehab 	int ret;
8369a0bf528SMauro Carvalho Chehab 
8379a0bf528SMauro Carvalho Chehab 	*err = 0;
8389a0bf528SMauro Carvalho Chehab 
8399a0bf528SMauro Carvalho Chehab 	ret = lg216x_read_reg(state, 0x0411, &crc_err1);
8409a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
8419a0bf528SMauro Carvalho Chehab 		goto fail;
8429a0bf528SMauro Carvalho Chehab 
8439a0bf528SMauro Carvalho Chehab 	ret = lg216x_read_reg(state, 0x0412, &crc_err2);
8449a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
8459a0bf528SMauro Carvalho Chehab 		goto fail;
8469a0bf528SMauro Carvalho Chehab 
8479a0bf528SMauro Carvalho Chehab 	*err = (u16)(((crc_err2 & 0x0f) << 8) | crc_err1);
8489a0bf528SMauro Carvalho Chehab fail:
8499a0bf528SMauro Carvalho Chehab 	return ret;
8509a0bf528SMauro Carvalho Chehab }
8519a0bf528SMauro Carvalho Chehab 
8529a0bf528SMauro Carvalho Chehab static int lg2161_read_crc_err_count(struct lg216x_state *state, u16 *err)
8539a0bf528SMauro Carvalho Chehab {
8549a0bf528SMauro Carvalho Chehab 	u8 crc_err;
8559a0bf528SMauro Carvalho Chehab 	int ret;
8569a0bf528SMauro Carvalho Chehab 
8579a0bf528SMauro Carvalho Chehab 	*err = 0;
8589a0bf528SMauro Carvalho Chehab 
8599a0bf528SMauro Carvalho Chehab 	ret = lg216x_read_reg(state, 0x0612, &crc_err);
8609a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
8619a0bf528SMauro Carvalho Chehab 		goto fail;
8629a0bf528SMauro Carvalho Chehab 
8639a0bf528SMauro Carvalho Chehab 	*err = (u16)crc_err;
8649a0bf528SMauro Carvalho Chehab fail:
8659a0bf528SMauro Carvalho Chehab 	return ret;
8669a0bf528SMauro Carvalho Chehab }
8679a0bf528SMauro Carvalho Chehab 
8689a0bf528SMauro Carvalho Chehab static int lg216x_read_crc_err_count(struct lg216x_state *state, u16 *err)
8699a0bf528SMauro Carvalho Chehab {
8709a0bf528SMauro Carvalho Chehab 	int ret;
8719a0bf528SMauro Carvalho Chehab 	switch (state->cfg->lg_chip) {
8729a0bf528SMauro Carvalho Chehab 	case LG2160:
8739a0bf528SMauro Carvalho Chehab 		ret = lg2160_read_crc_err_count(state, err);
8749a0bf528SMauro Carvalho Chehab 		break;
8759a0bf528SMauro Carvalho Chehab 	case LG2161:
8769a0bf528SMauro Carvalho Chehab 		ret = lg2161_read_crc_err_count(state, err);
8779a0bf528SMauro Carvalho Chehab 		break;
8789a0bf528SMauro Carvalho Chehab 	default:
8799a0bf528SMauro Carvalho Chehab 		ret = -EINVAL;
8809a0bf528SMauro Carvalho Chehab 		break;
8819a0bf528SMauro Carvalho Chehab 	}
8829a0bf528SMauro Carvalho Chehab 	return ret;
8839a0bf528SMauro Carvalho Chehab }
8849a0bf528SMauro Carvalho Chehab 
8859a0bf528SMauro Carvalho Chehab static int lg2160_read_rs_err_count(struct lg216x_state *state, u16 *err)
8869a0bf528SMauro Carvalho Chehab {
8879a0bf528SMauro Carvalho Chehab 	u8 rs_err1, rs_err2;
8889a0bf528SMauro Carvalho Chehab 	int ret;
8899a0bf528SMauro Carvalho Chehab 
8909a0bf528SMauro Carvalho Chehab 	*err = 0;
8919a0bf528SMauro Carvalho Chehab 
8929a0bf528SMauro Carvalho Chehab 	ret = lg216x_read_reg(state, 0x0413, &rs_err1);
8939a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
8949a0bf528SMauro Carvalho Chehab 		goto fail;
8959a0bf528SMauro Carvalho Chehab 
8969a0bf528SMauro Carvalho Chehab 	ret = lg216x_read_reg(state, 0x0414, &rs_err2);
8979a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
8989a0bf528SMauro Carvalho Chehab 		goto fail;
8999a0bf528SMauro Carvalho Chehab 
9009a0bf528SMauro Carvalho Chehab 	*err = (u16)(((rs_err2 & 0x0f) << 8) | rs_err1);
9019a0bf528SMauro Carvalho Chehab fail:
9029a0bf528SMauro Carvalho Chehab 	return ret;
9039a0bf528SMauro Carvalho Chehab }
9049a0bf528SMauro Carvalho Chehab 
9059a0bf528SMauro Carvalho Chehab static int lg2161_read_rs_err_count(struct lg216x_state *state, u16 *err)
9069a0bf528SMauro Carvalho Chehab {
9079a0bf528SMauro Carvalho Chehab 	u8 rs_err1, rs_err2;
9089a0bf528SMauro Carvalho Chehab 	int ret;
9099a0bf528SMauro Carvalho Chehab 
9109a0bf528SMauro Carvalho Chehab 	*err = 0;
9119a0bf528SMauro Carvalho Chehab 
9129a0bf528SMauro Carvalho Chehab 	ret = lg216x_read_reg(state, 0x0613, &rs_err1);
9139a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
9149a0bf528SMauro Carvalho Chehab 		goto fail;
9159a0bf528SMauro Carvalho Chehab 
9169a0bf528SMauro Carvalho Chehab 	ret = lg216x_read_reg(state, 0x0614, &rs_err2);
9179a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
9189a0bf528SMauro Carvalho Chehab 		goto fail;
9199a0bf528SMauro Carvalho Chehab 
9209a0bf528SMauro Carvalho Chehab 	*err = (u16)((rs_err1 << 8) | rs_err2);
9219a0bf528SMauro Carvalho Chehab fail:
9229a0bf528SMauro Carvalho Chehab 	return ret;
9239a0bf528SMauro Carvalho Chehab }
9249a0bf528SMauro Carvalho Chehab 
9259a0bf528SMauro Carvalho Chehab static int lg216x_read_rs_err_count(struct lg216x_state *state, u16 *err)
9269a0bf528SMauro Carvalho Chehab {
9279a0bf528SMauro Carvalho Chehab 	int ret;
9289a0bf528SMauro Carvalho Chehab 	switch (state->cfg->lg_chip) {
9299a0bf528SMauro Carvalho Chehab 	case LG2160:
9309a0bf528SMauro Carvalho Chehab 		ret = lg2160_read_rs_err_count(state, err);
9319a0bf528SMauro Carvalho Chehab 		break;
9329a0bf528SMauro Carvalho Chehab 	case LG2161:
9339a0bf528SMauro Carvalho Chehab 		ret = lg2161_read_rs_err_count(state, err);
9349a0bf528SMauro Carvalho Chehab 		break;
9359a0bf528SMauro Carvalho Chehab 	default:
9369a0bf528SMauro Carvalho Chehab 		ret = -EINVAL;
9379a0bf528SMauro Carvalho Chehab 		break;
9389a0bf528SMauro Carvalho Chehab 	}
9399a0bf528SMauro Carvalho Chehab 	return ret;
9409a0bf528SMauro Carvalho Chehab }
9419a0bf528SMauro Carvalho Chehab #endif
9429a0bf528SMauro Carvalho Chehab 
9439a0bf528SMauro Carvalho Chehab /* ------------------------------------------------------------------------ */
9449a0bf528SMauro Carvalho Chehab 
9457e3e68bcSMauro Carvalho Chehab static int lg216x_get_frontend(struct dvb_frontend *fe,
9467e3e68bcSMauro Carvalho Chehab 			       struct dtv_frontend_properties *c)
9479a0bf528SMauro Carvalho Chehab {
9489a0bf528SMauro Carvalho Chehab 	struct lg216x_state *state = fe->demodulator_priv;
9499a0bf528SMauro Carvalho Chehab 	int ret;
9509a0bf528SMauro Carvalho Chehab 
9519a0bf528SMauro Carvalho Chehab 	lg_dbg("\n");
9529a0bf528SMauro Carvalho Chehab 
9537e3e68bcSMauro Carvalho Chehab 	c->modulation = VSB_8;
9547e3e68bcSMauro Carvalho Chehab 	c->frequency = state->current_frequency;
9557e3e68bcSMauro Carvalho Chehab 	c->delivery_system = SYS_ATSCMH;
9569a0bf528SMauro Carvalho Chehab 
9579a0bf528SMauro Carvalho Chehab 	ret = lg216x_get_fic_version(state,
9587e3e68bcSMauro Carvalho Chehab 				     &c->atscmh_fic_ver);
9599a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
9609a0bf528SMauro Carvalho Chehab 		goto fail;
9617e3e68bcSMauro Carvalho Chehab 	if (state->fic_ver != c->atscmh_fic_ver) {
9627e3e68bcSMauro Carvalho Chehab 		state->fic_ver = c->atscmh_fic_ver;
9639a0bf528SMauro Carvalho Chehab 
9649a0bf528SMauro Carvalho Chehab #if 0
9659a0bf528SMauro Carvalho Chehab 		ret = lg2160_get_parade_id(state,
9667e3e68bcSMauro Carvalho Chehab 				&c->atscmh_parade_id);
9679a0bf528SMauro Carvalho Chehab 		if (lg_fail(ret))
9689a0bf528SMauro Carvalho Chehab 			goto fail;
9699a0bf528SMauro Carvalho Chehab /* #else */
9707e3e68bcSMauro Carvalho Chehab 		c->atscmh_parade_id = state->parade_id;
9719a0bf528SMauro Carvalho Chehab #endif
9729a0bf528SMauro Carvalho Chehab 		ret = lg216x_get_nog(state,
9737e3e68bcSMauro Carvalho Chehab 				     &c->atscmh_nog);
9749a0bf528SMauro Carvalho Chehab 		if (lg_fail(ret))
9759a0bf528SMauro Carvalho Chehab 			goto fail;
9769a0bf528SMauro Carvalho Chehab 		ret = lg216x_get_tnog(state,
9777e3e68bcSMauro Carvalho Chehab 				      &c->atscmh_tnog);
9789a0bf528SMauro Carvalho Chehab 		if (lg_fail(ret))
9799a0bf528SMauro Carvalho Chehab 			goto fail;
9809a0bf528SMauro Carvalho Chehab 		ret = lg216x_get_sgn(state,
9817e3e68bcSMauro Carvalho Chehab 				     &c->atscmh_sgn);
9829a0bf528SMauro Carvalho Chehab 		if (lg_fail(ret))
9839a0bf528SMauro Carvalho Chehab 			goto fail;
9849a0bf528SMauro Carvalho Chehab 		ret = lg216x_get_prc(state,
9857e3e68bcSMauro Carvalho Chehab 				     &c->atscmh_prc);
9869a0bf528SMauro Carvalho Chehab 		if (lg_fail(ret))
9879a0bf528SMauro Carvalho Chehab 			goto fail;
9889a0bf528SMauro Carvalho Chehab 
9899a0bf528SMauro Carvalho Chehab 		ret = lg216x_get_rs_frame_mode(state,
9909a0bf528SMauro Carvalho Chehab 			(enum atscmh_rs_frame_mode *)
9917e3e68bcSMauro Carvalho Chehab 			&c->atscmh_rs_frame_mode);
9929a0bf528SMauro Carvalho Chehab 		if (lg_fail(ret))
9939a0bf528SMauro Carvalho Chehab 			goto fail;
9949a0bf528SMauro Carvalho Chehab 		ret = lg216x_get_rs_frame_ensemble(state,
9959a0bf528SMauro Carvalho Chehab 			(enum atscmh_rs_frame_ensemble *)
9967e3e68bcSMauro Carvalho Chehab 			&c->atscmh_rs_frame_ensemble);
9979a0bf528SMauro Carvalho Chehab 		if (lg_fail(ret))
9989a0bf528SMauro Carvalho Chehab 			goto fail;
9999a0bf528SMauro Carvalho Chehab 		ret = lg216x_get_rs_code_mode(state,
10009a0bf528SMauro Carvalho Chehab 			(enum atscmh_rs_code_mode *)
10017e3e68bcSMauro Carvalho Chehab 			&c->atscmh_rs_code_mode_pri,
10029a0bf528SMauro Carvalho Chehab 			(enum atscmh_rs_code_mode *)
10037e3e68bcSMauro Carvalho Chehab 			&c->atscmh_rs_code_mode_sec);
10049a0bf528SMauro Carvalho Chehab 		if (lg_fail(ret))
10059a0bf528SMauro Carvalho Chehab 			goto fail;
10069a0bf528SMauro Carvalho Chehab 		ret = lg216x_get_sccc_block_mode(state,
10079a0bf528SMauro Carvalho Chehab 			(enum atscmh_sccc_block_mode *)
10087e3e68bcSMauro Carvalho Chehab 			&c->atscmh_sccc_block_mode);
10099a0bf528SMauro Carvalho Chehab 		if (lg_fail(ret))
10109a0bf528SMauro Carvalho Chehab 			goto fail;
10119a0bf528SMauro Carvalho Chehab 		ret = lg216x_get_sccc_code_mode(state,
10129a0bf528SMauro Carvalho Chehab 			(enum atscmh_sccc_code_mode *)
10137e3e68bcSMauro Carvalho Chehab 			&c->atscmh_sccc_code_mode_a,
10149a0bf528SMauro Carvalho Chehab 			(enum atscmh_sccc_code_mode *)
10157e3e68bcSMauro Carvalho Chehab 			&c->atscmh_sccc_code_mode_b,
10169a0bf528SMauro Carvalho Chehab 			(enum atscmh_sccc_code_mode *)
10177e3e68bcSMauro Carvalho Chehab 			&c->atscmh_sccc_code_mode_c,
10189a0bf528SMauro Carvalho Chehab 			(enum atscmh_sccc_code_mode *)
10197e3e68bcSMauro Carvalho Chehab 			&c->atscmh_sccc_code_mode_d);
10209a0bf528SMauro Carvalho Chehab 		if (lg_fail(ret))
10219a0bf528SMauro Carvalho Chehab 			goto fail;
10229a0bf528SMauro Carvalho Chehab 	}
10239a0bf528SMauro Carvalho Chehab #if 0
10249a0bf528SMauro Carvalho Chehab 	ret = lg216x_read_fic_err_count(state,
10257e3e68bcSMauro Carvalho Chehab 				(u8 *)&c->atscmh_fic_err);
10269a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
10279a0bf528SMauro Carvalho Chehab 		goto fail;
10289a0bf528SMauro Carvalho Chehab 	ret = lg216x_read_crc_err_count(state,
10297e3e68bcSMauro Carvalho Chehab 				&c->atscmh_crc_err);
10309a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
10319a0bf528SMauro Carvalho Chehab 		goto fail;
10329a0bf528SMauro Carvalho Chehab 	ret = lg216x_read_rs_err_count(state,
10337e3e68bcSMauro Carvalho Chehab 				&c->atscmh_rs_err);
10349a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
10359a0bf528SMauro Carvalho Chehab 		goto fail;
10369a0bf528SMauro Carvalho Chehab 
10379a0bf528SMauro Carvalho Chehab 	switch (state->cfg->lg_chip) {
10389a0bf528SMauro Carvalho Chehab 	case LG2160:
10397e3e68bcSMauro Carvalho Chehab 		if (((c->atscmh_rs_err >= 240) &&
10407e3e68bcSMauro Carvalho Chehab 		     (c->atscmh_crc_err >= 240)) &&
10419a0bf528SMauro Carvalho Chehab 		    ((jiffies_to_msecs(jiffies) - state->last_reset) > 6000))
10429a0bf528SMauro Carvalho Chehab 			ret = lg216x_soft_reset(state);
10439a0bf528SMauro Carvalho Chehab 		break;
10449a0bf528SMauro Carvalho Chehab 	case LG2161:
10459a0bf528SMauro Carvalho Chehab 		/* no fix needed here (as far as we know) */
10469a0bf528SMauro Carvalho Chehab 		ret = 0;
10479a0bf528SMauro Carvalho Chehab 		break;
10489a0bf528SMauro Carvalho Chehab 	}
10499a0bf528SMauro Carvalho Chehab 	lg_fail(ret);
10509a0bf528SMauro Carvalho Chehab #endif
10519a0bf528SMauro Carvalho Chehab fail:
10529a0bf528SMauro Carvalho Chehab 	return ret;
10539a0bf528SMauro Carvalho Chehab }
10549a0bf528SMauro Carvalho Chehab 
10559a0bf528SMauro Carvalho Chehab static int lg216x_get_property(struct dvb_frontend *fe,
10569a0bf528SMauro Carvalho Chehab 			       struct dtv_property *tvp)
10579a0bf528SMauro Carvalho Chehab {
10587e3e68bcSMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
10597e3e68bcSMauro Carvalho Chehab 
10609a0bf528SMauro Carvalho Chehab 	return (DTV_ATSCMH_FIC_VER == tvp->cmd) ?
10617e3e68bcSMauro Carvalho Chehab 		lg216x_get_frontend(fe, c) : 0;
10629a0bf528SMauro Carvalho Chehab }
10639a0bf528SMauro Carvalho Chehab 
10649a0bf528SMauro Carvalho Chehab 
10659a0bf528SMauro Carvalho Chehab static int lg2160_set_frontend(struct dvb_frontend *fe)
10669a0bf528SMauro Carvalho Chehab {
10679a0bf528SMauro Carvalho Chehab 	struct lg216x_state *state = fe->demodulator_priv;
10687e3e68bcSMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
10699a0bf528SMauro Carvalho Chehab 	int ret;
10709a0bf528SMauro Carvalho Chehab 
10719a0bf528SMauro Carvalho Chehab 	lg_dbg("(%d)\n", fe->dtv_property_cache.frequency);
10729a0bf528SMauro Carvalho Chehab 
10739a0bf528SMauro Carvalho Chehab 	if (fe->ops.tuner_ops.set_params) {
10749a0bf528SMauro Carvalho Chehab 		ret = fe->ops.tuner_ops.set_params(fe);
10759a0bf528SMauro Carvalho Chehab 		if (fe->ops.i2c_gate_ctrl)
10769a0bf528SMauro Carvalho Chehab 			fe->ops.i2c_gate_ctrl(fe, 0);
10779a0bf528SMauro Carvalho Chehab 		if (lg_fail(ret))
10789a0bf528SMauro Carvalho Chehab 			goto fail;
10799a0bf528SMauro Carvalho Chehab 		state->current_frequency = fe->dtv_property_cache.frequency;
10809a0bf528SMauro Carvalho Chehab 	}
10819a0bf528SMauro Carvalho Chehab 
10829a0bf528SMauro Carvalho Chehab 	ret = lg2160_agc_fix(state, 0, 0);
10839a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
10849a0bf528SMauro Carvalho Chehab 		goto fail;
10859a0bf528SMauro Carvalho Chehab 	ret = lg2160_agc_polarity(state, 0, 0);
10869a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
10879a0bf528SMauro Carvalho Chehab 		goto fail;
10889a0bf528SMauro Carvalho Chehab 	ret = lg2160_tuner_pwr_save_polarity(state, 1);
10899a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
10909a0bf528SMauro Carvalho Chehab 		goto fail;
10919a0bf528SMauro Carvalho Chehab 	ret = lg216x_set_if(state);
10929a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
10939a0bf528SMauro Carvalho Chehab 		goto fail;
10949a0bf528SMauro Carvalho Chehab 	ret = lg2160_spectrum_polarity(state, state->cfg->spectral_inversion);
10959a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
10969a0bf528SMauro Carvalho Chehab 		goto fail;
10979a0bf528SMauro Carvalho Chehab 
10989a0bf528SMauro Carvalho Chehab 	/* be tuned before this point */
10999a0bf528SMauro Carvalho Chehab 	ret = lg216x_soft_reset(state);
11009a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
11019a0bf528SMauro Carvalho Chehab 		goto fail;
11029a0bf528SMauro Carvalho Chehab 
11039a0bf528SMauro Carvalho Chehab 	ret = lg2160_tuner_pwr_save(state, 0);
11049a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
11059a0bf528SMauro Carvalho Chehab 		goto fail;
11069a0bf528SMauro Carvalho Chehab 
11079a0bf528SMauro Carvalho Chehab 	switch (state->cfg->lg_chip) {
11089a0bf528SMauro Carvalho Chehab 	case LG2160:
11099a0bf528SMauro Carvalho Chehab 		ret = lg2160_set_spi_clock(state);
11109a0bf528SMauro Carvalho Chehab 		if (lg_fail(ret))
11119a0bf528SMauro Carvalho Chehab 			goto fail;
11129a0bf528SMauro Carvalho Chehab 		break;
11139a0bf528SMauro Carvalho Chehab 	case LG2161:
11149a0bf528SMauro Carvalho Chehab 		ret = lg2161_set_output_interface(state);
11159a0bf528SMauro Carvalho Chehab 		if (lg_fail(ret))
11169a0bf528SMauro Carvalho Chehab 			goto fail;
11179a0bf528SMauro Carvalho Chehab 		break;
11189a0bf528SMauro Carvalho Chehab 	}
11199a0bf528SMauro Carvalho Chehab 
11209a0bf528SMauro Carvalho Chehab 	ret = lg216x_set_parade(state, fe->dtv_property_cache.atscmh_parade_id);
11219a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
11229a0bf528SMauro Carvalho Chehab 		goto fail;
11239a0bf528SMauro Carvalho Chehab 
11249a0bf528SMauro Carvalho Chehab 	ret = lg216x_set_ensemble(state,
11259a0bf528SMauro Carvalho Chehab 			fe->dtv_property_cache.atscmh_rs_frame_ensemble);
11269a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
11279a0bf528SMauro Carvalho Chehab 		goto fail;
11289a0bf528SMauro Carvalho Chehab 
11299a0bf528SMauro Carvalho Chehab 	ret = lg216x_initialize(state);
11309a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
11319a0bf528SMauro Carvalho Chehab 		goto fail;
11329a0bf528SMauro Carvalho Chehab 
11339a0bf528SMauro Carvalho Chehab 	ret = lg216x_enable_fic(state, 1);
11349a0bf528SMauro Carvalho Chehab 	lg_fail(ret);
11359a0bf528SMauro Carvalho Chehab 
11367e3e68bcSMauro Carvalho Chehab 	lg216x_get_frontend(fe, c);
11379a0bf528SMauro Carvalho Chehab fail:
11389a0bf528SMauro Carvalho Chehab 	return ret;
11399a0bf528SMauro Carvalho Chehab }
11409a0bf528SMauro Carvalho Chehab 
11419a0bf528SMauro Carvalho Chehab /* ------------------------------------------------------------------------ */
11429a0bf528SMauro Carvalho Chehab 
11439a0bf528SMauro Carvalho Chehab static int lg2160_read_lock_status(struct lg216x_state *state,
11449a0bf528SMauro Carvalho Chehab 				   int *acq_lock, int *sync_lock)
11459a0bf528SMauro Carvalho Chehab {
11469a0bf528SMauro Carvalho Chehab 	u8 val;
11479a0bf528SMauro Carvalho Chehab 	int ret;
11489a0bf528SMauro Carvalho Chehab 
11499a0bf528SMauro Carvalho Chehab 	*acq_lock = 0;
11509a0bf528SMauro Carvalho Chehab 	*sync_lock = 0;
11519a0bf528SMauro Carvalho Chehab 
11529a0bf528SMauro Carvalho Chehab 	ret = lg216x_read_reg(state, 0x011b, &val);
11539a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
11549a0bf528SMauro Carvalho Chehab 		goto fail;
11559a0bf528SMauro Carvalho Chehab 
11569a0bf528SMauro Carvalho Chehab 	*sync_lock = (val & 0x20) ? 0 : 1;
11579a0bf528SMauro Carvalho Chehab 	*acq_lock  = (val & 0x40) ? 0 : 1;
11589a0bf528SMauro Carvalho Chehab fail:
11599a0bf528SMauro Carvalho Chehab 	return ret;
11609a0bf528SMauro Carvalho Chehab }
11619a0bf528SMauro Carvalho Chehab 
11629a0bf528SMauro Carvalho Chehab #ifdef USE_LG2161_LOCK_BITS
11639a0bf528SMauro Carvalho Chehab static int lg2161_read_lock_status(struct lg216x_state *state,
11649a0bf528SMauro Carvalho Chehab 				   int *acq_lock, int *sync_lock)
11659a0bf528SMauro Carvalho Chehab {
11669a0bf528SMauro Carvalho Chehab 	u8 val;
11679a0bf528SMauro Carvalho Chehab 	int ret;
11689a0bf528SMauro Carvalho Chehab 
11699a0bf528SMauro Carvalho Chehab 	*acq_lock = 0;
11709a0bf528SMauro Carvalho Chehab 	*sync_lock = 0;
11719a0bf528SMauro Carvalho Chehab 
11729a0bf528SMauro Carvalho Chehab 	ret = lg216x_read_reg(state, 0x0304, &val);
11739a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
11749a0bf528SMauro Carvalho Chehab 		goto fail;
11759a0bf528SMauro Carvalho Chehab 
11769a0bf528SMauro Carvalho Chehab 	*sync_lock = (val & 0x80) ? 0 : 1;
11779a0bf528SMauro Carvalho Chehab 
11789a0bf528SMauro Carvalho Chehab 	ret = lg216x_read_reg(state, 0x011b, &val);
11799a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
11809a0bf528SMauro Carvalho Chehab 		goto fail;
11819a0bf528SMauro Carvalho Chehab 
11829a0bf528SMauro Carvalho Chehab 	*acq_lock  = (val & 0x40) ? 0 : 1;
11839a0bf528SMauro Carvalho Chehab fail:
11849a0bf528SMauro Carvalho Chehab 	return ret;
11859a0bf528SMauro Carvalho Chehab }
11869a0bf528SMauro Carvalho Chehab #endif
11879a0bf528SMauro Carvalho Chehab 
11889a0bf528SMauro Carvalho Chehab static int lg216x_read_lock_status(struct lg216x_state *state,
11899a0bf528SMauro Carvalho Chehab 				   int *acq_lock, int *sync_lock)
11909a0bf528SMauro Carvalho Chehab {
11919a0bf528SMauro Carvalho Chehab #ifdef USE_LG2161_LOCK_BITS
11929a0bf528SMauro Carvalho Chehab 	int ret;
11939a0bf528SMauro Carvalho Chehab 	switch (state->cfg->lg_chip) {
11949a0bf528SMauro Carvalho Chehab 	case LG2160:
11959a0bf528SMauro Carvalho Chehab 		ret = lg2160_read_lock_status(state, acq_lock, sync_lock);
11969a0bf528SMauro Carvalho Chehab 		break;
11979a0bf528SMauro Carvalho Chehab 	case LG2161:
11989a0bf528SMauro Carvalho Chehab 		ret = lg2161_read_lock_status(state, acq_lock, sync_lock);
11999a0bf528SMauro Carvalho Chehab 		break;
12009a0bf528SMauro Carvalho Chehab 	default:
12019a0bf528SMauro Carvalho Chehab 		ret = -EINVAL;
12029a0bf528SMauro Carvalho Chehab 		break;
12039a0bf528SMauro Carvalho Chehab 	}
12049a0bf528SMauro Carvalho Chehab 	return ret;
12059a0bf528SMauro Carvalho Chehab #else
12069a0bf528SMauro Carvalho Chehab 	return lg2160_read_lock_status(state, acq_lock, sync_lock);
12079a0bf528SMauro Carvalho Chehab #endif
12089a0bf528SMauro Carvalho Chehab }
12099a0bf528SMauro Carvalho Chehab 
12100df289a2SMauro Carvalho Chehab static int lg216x_read_status(struct dvb_frontend *fe, enum fe_status *status)
12119a0bf528SMauro Carvalho Chehab {
12129a0bf528SMauro Carvalho Chehab 	struct lg216x_state *state = fe->demodulator_priv;
12139a0bf528SMauro Carvalho Chehab 	int ret, acq_lock, sync_lock;
12149a0bf528SMauro Carvalho Chehab 
12159a0bf528SMauro Carvalho Chehab 	*status = 0;
12169a0bf528SMauro Carvalho Chehab 
12179a0bf528SMauro Carvalho Chehab 	ret = lg216x_read_lock_status(state, &acq_lock, &sync_lock);
12189a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
12199a0bf528SMauro Carvalho Chehab 		goto fail;
12209a0bf528SMauro Carvalho Chehab 
12219a0bf528SMauro Carvalho Chehab 	lg_dbg("%s%s\n",
12229a0bf528SMauro Carvalho Chehab 	       acq_lock  ? "SIGNALEXIST " : "",
12239a0bf528SMauro Carvalho Chehab 	       sync_lock ? "SYNCLOCK"     : "");
12249a0bf528SMauro Carvalho Chehab 
12259a0bf528SMauro Carvalho Chehab 	if (acq_lock)
12269a0bf528SMauro Carvalho Chehab 		*status |= FE_HAS_SIGNAL;
12279a0bf528SMauro Carvalho Chehab 	if (sync_lock)
12289a0bf528SMauro Carvalho Chehab 		*status |= FE_HAS_SYNC;
12299a0bf528SMauro Carvalho Chehab 
12309a0bf528SMauro Carvalho Chehab 	if (*status)
12319a0bf528SMauro Carvalho Chehab 		*status |= FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_LOCK;
12329a0bf528SMauro Carvalho Chehab 
12339a0bf528SMauro Carvalho Chehab fail:
12349a0bf528SMauro Carvalho Chehab 	return ret;
12359a0bf528SMauro Carvalho Chehab }
12369a0bf528SMauro Carvalho Chehab 
12379a0bf528SMauro Carvalho Chehab /* ------------------------------------------------------------------------ */
12389a0bf528SMauro Carvalho Chehab 
12399a0bf528SMauro Carvalho Chehab static int lg2160_read_snr(struct dvb_frontend *fe, u16 *snr)
12409a0bf528SMauro Carvalho Chehab {
12419a0bf528SMauro Carvalho Chehab 	struct lg216x_state *state = fe->demodulator_priv;
12429a0bf528SMauro Carvalho Chehab 	u8 snr1, snr2;
12439a0bf528SMauro Carvalho Chehab 	int ret;
12449a0bf528SMauro Carvalho Chehab 
12459a0bf528SMauro Carvalho Chehab 	*snr = 0;
12469a0bf528SMauro Carvalho Chehab 
12479a0bf528SMauro Carvalho Chehab 	ret = lg216x_read_reg(state, 0x0202, &snr1);
12489a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
12499a0bf528SMauro Carvalho Chehab 		goto fail;
12509a0bf528SMauro Carvalho Chehab 
12519a0bf528SMauro Carvalho Chehab 	ret = lg216x_read_reg(state, 0x0203, &snr2);
12529a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
12539a0bf528SMauro Carvalho Chehab 		goto fail;
12549a0bf528SMauro Carvalho Chehab 
12559a0bf528SMauro Carvalho Chehab 	if ((snr1 == 0xba) || (snr2 == 0xdf))
12569a0bf528SMauro Carvalho Chehab 		*snr = 0;
12579a0bf528SMauro Carvalho Chehab 	else
12589a0bf528SMauro Carvalho Chehab #if 1
12599a0bf528SMauro Carvalho Chehab 	*snr =  ((snr1 >> 4) * 100) + ((snr1 & 0x0f) * 10) + (snr2 >> 4);
12609a0bf528SMauro Carvalho Chehab #else /* BCD */
12619a0bf528SMauro Carvalho Chehab 	*snr =  (snr2 | (snr1 << 8));
12629a0bf528SMauro Carvalho Chehab #endif
12639a0bf528SMauro Carvalho Chehab fail:
12649a0bf528SMauro Carvalho Chehab 	return ret;
12659a0bf528SMauro Carvalho Chehab }
12669a0bf528SMauro Carvalho Chehab 
12679a0bf528SMauro Carvalho Chehab static int lg2161_read_snr(struct dvb_frontend *fe, u16 *snr)
12689a0bf528SMauro Carvalho Chehab {
12699a0bf528SMauro Carvalho Chehab 	struct lg216x_state *state = fe->demodulator_priv;
12709a0bf528SMauro Carvalho Chehab 	u8 snr1, snr2;
12719a0bf528SMauro Carvalho Chehab 	int ret;
12729a0bf528SMauro Carvalho Chehab 
12739a0bf528SMauro Carvalho Chehab 	*snr = 0;
12749a0bf528SMauro Carvalho Chehab 
12759a0bf528SMauro Carvalho Chehab 	ret = lg216x_read_reg(state, 0x0302, &snr1);
12769a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
12779a0bf528SMauro Carvalho Chehab 		goto fail;
12789a0bf528SMauro Carvalho Chehab 
12799a0bf528SMauro Carvalho Chehab 	ret = lg216x_read_reg(state, 0x0303, &snr2);
12809a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
12819a0bf528SMauro Carvalho Chehab 		goto fail;
12829a0bf528SMauro Carvalho Chehab 
12839a0bf528SMauro Carvalho Chehab 	if ((snr1 == 0xba) || (snr2 == 0xfd))
12849a0bf528SMauro Carvalho Chehab 		*snr = 0;
12859a0bf528SMauro Carvalho Chehab 	else
12869a0bf528SMauro Carvalho Chehab 
12879a0bf528SMauro Carvalho Chehab 	*snr =  ((snr1 >> 4) * 100) + ((snr1 & 0x0f) * 10) + (snr2 & 0x0f);
12889a0bf528SMauro Carvalho Chehab fail:
12899a0bf528SMauro Carvalho Chehab 	return ret;
12909a0bf528SMauro Carvalho Chehab }
12919a0bf528SMauro Carvalho Chehab 
12929a0bf528SMauro Carvalho Chehab static int lg216x_read_signal_strength(struct dvb_frontend *fe,
12939a0bf528SMauro Carvalho Chehab 				       u16 *strength)
12949a0bf528SMauro Carvalho Chehab {
12959a0bf528SMauro Carvalho Chehab #if 0
12969a0bf528SMauro Carvalho Chehab 	/* borrowed from lgdt330x.c
12979a0bf528SMauro Carvalho Chehab 	 *
12989a0bf528SMauro Carvalho Chehab 	 * Calculate strength from SNR up to 35dB
12999a0bf528SMauro Carvalho Chehab 	 * Even though the SNR can go higher than 35dB,
13009a0bf528SMauro Carvalho Chehab 	 * there is some comfort factor in having a range of
13019a0bf528SMauro Carvalho Chehab 	 * strong signals that can show at 100%
13029a0bf528SMauro Carvalho Chehab 	 */
13039a0bf528SMauro Carvalho Chehab 	struct lg216x_state *state = fe->demodulator_priv;
13049a0bf528SMauro Carvalho Chehab 	u16 snr;
13059a0bf528SMauro Carvalho Chehab 	int ret;
13069a0bf528SMauro Carvalho Chehab #endif
13079a0bf528SMauro Carvalho Chehab 	*strength = 0;
13089a0bf528SMauro Carvalho Chehab #if 0
13099a0bf528SMauro Carvalho Chehab 	ret = fe->ops.read_snr(fe, &snr);
13109a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
13119a0bf528SMauro Carvalho Chehab 		goto fail;
13129a0bf528SMauro Carvalho Chehab 	/* Rather than use the 8.8 value snr, use state->snr which is 8.24 */
13139a0bf528SMauro Carvalho Chehab 	/* scale the range 0 - 35*2^24 into 0 - 65535 */
13149a0bf528SMauro Carvalho Chehab 	if (state->snr >= 8960 * 0x10000)
13159a0bf528SMauro Carvalho Chehab 		*strength = 0xffff;
13169a0bf528SMauro Carvalho Chehab 	else
13179a0bf528SMauro Carvalho Chehab 		*strength = state->snr / 8960;
13189a0bf528SMauro Carvalho Chehab fail:
13199a0bf528SMauro Carvalho Chehab 	return ret;
13209a0bf528SMauro Carvalho Chehab #else
13219a0bf528SMauro Carvalho Chehab 	return 0;
13229a0bf528SMauro Carvalho Chehab #endif
13239a0bf528SMauro Carvalho Chehab }
13249a0bf528SMauro Carvalho Chehab 
13259a0bf528SMauro Carvalho Chehab /* ------------------------------------------------------------------------ */
13269a0bf528SMauro Carvalho Chehab 
13279a0bf528SMauro Carvalho Chehab static int lg216x_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
13289a0bf528SMauro Carvalho Chehab {
13299a0bf528SMauro Carvalho Chehab #if 0
13309a0bf528SMauro Carvalho Chehab 	struct lg216x_state *state = fe->demodulator_priv;
13319a0bf528SMauro Carvalho Chehab 	int ret;
13329a0bf528SMauro Carvalho Chehab 
13339a0bf528SMauro Carvalho Chehab 	ret = lg216x_read_rs_err_count(state,
13349a0bf528SMauro Carvalho Chehab 				       &fe->dtv_property_cache.atscmh_rs_err);
13359a0bf528SMauro Carvalho Chehab 	if (lg_fail(ret))
13369a0bf528SMauro Carvalho Chehab 		goto fail;
13379a0bf528SMauro Carvalho Chehab 
13389a0bf528SMauro Carvalho Chehab 	*ucblocks = fe->dtv_property_cache.atscmh_rs_err;
13399a0bf528SMauro Carvalho Chehab fail:
13409a0bf528SMauro Carvalho Chehab #else
13419a0bf528SMauro Carvalho Chehab 	*ucblocks = 0;
13429a0bf528SMauro Carvalho Chehab #endif
13439a0bf528SMauro Carvalho Chehab 	return 0;
13449a0bf528SMauro Carvalho Chehab }
13459a0bf528SMauro Carvalho Chehab 
13469a0bf528SMauro Carvalho Chehab static int lg216x_get_tune_settings(struct dvb_frontend *fe,
13479a0bf528SMauro Carvalho Chehab 				    struct dvb_frontend_tune_settings
13489a0bf528SMauro Carvalho Chehab 				    *fe_tune_settings)
13499a0bf528SMauro Carvalho Chehab {
13509a0bf528SMauro Carvalho Chehab 	fe_tune_settings->min_delay_ms = 500;
13519a0bf528SMauro Carvalho Chehab 	lg_dbg("\n");
13529a0bf528SMauro Carvalho Chehab 	return 0;
13539a0bf528SMauro Carvalho Chehab }
13549a0bf528SMauro Carvalho Chehab 
13559a0bf528SMauro Carvalho Chehab static void lg216x_release(struct dvb_frontend *fe)
13569a0bf528SMauro Carvalho Chehab {
13579a0bf528SMauro Carvalho Chehab 	struct lg216x_state *state = fe->demodulator_priv;
13589a0bf528SMauro Carvalho Chehab 	lg_dbg("\n");
13599a0bf528SMauro Carvalho Chehab 	kfree(state);
13609a0bf528SMauro Carvalho Chehab }
13619a0bf528SMauro Carvalho Chehab 
13629a0bf528SMauro Carvalho Chehab static struct dvb_frontend_ops lg2160_ops = {
13639a0bf528SMauro Carvalho Chehab 	.delsys = { SYS_ATSCMH },
13649a0bf528SMauro Carvalho Chehab 	.info = {
13659a0bf528SMauro Carvalho Chehab 		.name = "LG Electronics LG2160 ATSC/MH Frontend",
13669a0bf528SMauro Carvalho Chehab 		.frequency_min      = 54000000,
13679a0bf528SMauro Carvalho Chehab 		.frequency_max      = 858000000,
13689a0bf528SMauro Carvalho Chehab 		.frequency_stepsize = 62500,
13699a0bf528SMauro Carvalho Chehab 	},
13709a0bf528SMauro Carvalho Chehab 	.i2c_gate_ctrl        = lg216x_i2c_gate_ctrl,
13719a0bf528SMauro Carvalho Chehab #if 0
13729a0bf528SMauro Carvalho Chehab 	.init                 = lg216x_init,
13739a0bf528SMauro Carvalho Chehab 	.sleep                = lg216x_sleep,
13749a0bf528SMauro Carvalho Chehab #endif
13759a0bf528SMauro Carvalho Chehab 	.get_property         = lg216x_get_property,
13769a0bf528SMauro Carvalho Chehab 
13779a0bf528SMauro Carvalho Chehab 	.set_frontend         = lg2160_set_frontend,
13789a0bf528SMauro Carvalho Chehab 	.get_frontend         = lg216x_get_frontend,
13799a0bf528SMauro Carvalho Chehab 	.get_tune_settings    = lg216x_get_tune_settings,
13809a0bf528SMauro Carvalho Chehab 	.read_status          = lg216x_read_status,
13819a0bf528SMauro Carvalho Chehab #if 0
13829a0bf528SMauro Carvalho Chehab 	.read_ber             = lg216x_read_ber,
13839a0bf528SMauro Carvalho Chehab #endif
13849a0bf528SMauro Carvalho Chehab 	.read_signal_strength = lg216x_read_signal_strength,
13859a0bf528SMauro Carvalho Chehab 	.read_snr             = lg2160_read_snr,
13869a0bf528SMauro Carvalho Chehab 	.read_ucblocks        = lg216x_read_ucblocks,
13879a0bf528SMauro Carvalho Chehab 	.release              = lg216x_release,
13889a0bf528SMauro Carvalho Chehab };
13899a0bf528SMauro Carvalho Chehab 
13909a0bf528SMauro Carvalho Chehab static struct dvb_frontend_ops lg2161_ops = {
13919a0bf528SMauro Carvalho Chehab 	.delsys = { SYS_ATSCMH },
13929a0bf528SMauro Carvalho Chehab 	.info = {
13939a0bf528SMauro Carvalho Chehab 		.name = "LG Electronics LG2161 ATSC/MH Frontend",
13949a0bf528SMauro Carvalho Chehab 		.frequency_min      = 54000000,
13959a0bf528SMauro Carvalho Chehab 		.frequency_max      = 858000000,
13969a0bf528SMauro Carvalho Chehab 		.frequency_stepsize = 62500,
13979a0bf528SMauro Carvalho Chehab 	},
13989a0bf528SMauro Carvalho Chehab 	.i2c_gate_ctrl        = lg216x_i2c_gate_ctrl,
13999a0bf528SMauro Carvalho Chehab #if 0
14009a0bf528SMauro Carvalho Chehab 	.init                 = lg216x_init,
14019a0bf528SMauro Carvalho Chehab 	.sleep                = lg216x_sleep,
14029a0bf528SMauro Carvalho Chehab #endif
14039a0bf528SMauro Carvalho Chehab 	.get_property         = lg216x_get_property,
14049a0bf528SMauro Carvalho Chehab 
14059a0bf528SMauro Carvalho Chehab 	.set_frontend         = lg2160_set_frontend,
14069a0bf528SMauro Carvalho Chehab 	.get_frontend         = lg216x_get_frontend,
14079a0bf528SMauro Carvalho Chehab 	.get_tune_settings    = lg216x_get_tune_settings,
14089a0bf528SMauro Carvalho Chehab 	.read_status          = lg216x_read_status,
14099a0bf528SMauro Carvalho Chehab #if 0
14109a0bf528SMauro Carvalho Chehab 	.read_ber             = lg216x_read_ber,
14119a0bf528SMauro Carvalho Chehab #endif
14129a0bf528SMauro Carvalho Chehab 	.read_signal_strength = lg216x_read_signal_strength,
14139a0bf528SMauro Carvalho Chehab 	.read_snr             = lg2161_read_snr,
14149a0bf528SMauro Carvalho Chehab 	.read_ucblocks        = lg216x_read_ucblocks,
14159a0bf528SMauro Carvalho Chehab 	.release              = lg216x_release,
14169a0bf528SMauro Carvalho Chehab };
14179a0bf528SMauro Carvalho Chehab 
14189a0bf528SMauro Carvalho Chehab struct dvb_frontend *lg2160_attach(const struct lg2160_config *config,
14199a0bf528SMauro Carvalho Chehab 				   struct i2c_adapter *i2c_adap)
14209a0bf528SMauro Carvalho Chehab {
14219a0bf528SMauro Carvalho Chehab 	struct lg216x_state *state = NULL;
14229a0bf528SMauro Carvalho Chehab 
14239a0bf528SMauro Carvalho Chehab 	lg_dbg("(%d-%04x)\n",
14249a0bf528SMauro Carvalho Chehab 	       i2c_adap ? i2c_adapter_id(i2c_adap) : 0,
14259a0bf528SMauro Carvalho Chehab 	       config ? config->i2c_addr : 0);
14269a0bf528SMauro Carvalho Chehab 
14279a0bf528SMauro Carvalho Chehab 	state = kzalloc(sizeof(struct lg216x_state), GFP_KERNEL);
14281a5d2da1SPeter Senna Tschudin 	if (!state)
14291a5d2da1SPeter Senna Tschudin 		return NULL;
14309a0bf528SMauro Carvalho Chehab 
14319a0bf528SMauro Carvalho Chehab 	state->cfg = config;
14329a0bf528SMauro Carvalho Chehab 	state->i2c_adap = i2c_adap;
14339a0bf528SMauro Carvalho Chehab 	state->fic_ver = 0xff;
14349a0bf528SMauro Carvalho Chehab 	state->parade_id = 0xff;
14359a0bf528SMauro Carvalho Chehab 
14369a0bf528SMauro Carvalho Chehab 	switch (config->lg_chip) {
14379a0bf528SMauro Carvalho Chehab 	default:
14389a0bf528SMauro Carvalho Chehab 		lg_warn("invalid chip requested, defaulting to LG2160");
14399a0bf528SMauro Carvalho Chehab 		/* fall-thru */
14409a0bf528SMauro Carvalho Chehab 	case LG2160:
14419a0bf528SMauro Carvalho Chehab 		memcpy(&state->frontend.ops, &lg2160_ops,
14429a0bf528SMauro Carvalho Chehab 		       sizeof(struct dvb_frontend_ops));
14439a0bf528SMauro Carvalho Chehab 		break;
14449a0bf528SMauro Carvalho Chehab 	case LG2161:
14459a0bf528SMauro Carvalho Chehab 		memcpy(&state->frontend.ops, &lg2161_ops,
14469a0bf528SMauro Carvalho Chehab 		       sizeof(struct dvb_frontend_ops));
14479a0bf528SMauro Carvalho Chehab 		break;
14489a0bf528SMauro Carvalho Chehab 	}
14499a0bf528SMauro Carvalho Chehab 
14509a0bf528SMauro Carvalho Chehab 	state->frontend.demodulator_priv = state;
14519a0bf528SMauro Carvalho Chehab 	state->current_frequency = -1;
14529a0bf528SMauro Carvalho Chehab 	/* parade 1 by default */
14539a0bf528SMauro Carvalho Chehab 	state->frontend.dtv_property_cache.atscmh_parade_id = 1;
14549a0bf528SMauro Carvalho Chehab 
14559a0bf528SMauro Carvalho Chehab 	return &state->frontend;
14569a0bf528SMauro Carvalho Chehab }
14579a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(lg2160_attach);
14589a0bf528SMauro Carvalho Chehab 
14599a0bf528SMauro Carvalho Chehab MODULE_DESCRIPTION("LG Electronics LG216x ATSC/MH Demodulator Driver");
14609a0bf528SMauro Carvalho Chehab MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
14619a0bf528SMauro Carvalho Chehab MODULE_LICENSE("GPL");
14629a0bf528SMauro Carvalho Chehab MODULE_VERSION("0.3");
1463