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