19a0bf528SMauro Carvalho Chehab /*
29a0bf528SMauro Carvalho Chehab     Driver for ST STV0299 demodulator
39a0bf528SMauro Carvalho Chehab 
49a0bf528SMauro Carvalho Chehab     Copyright (C) 2001-2002 Convergence Integrated Media GmbH
59a0bf528SMauro Carvalho Chehab 	<ralph@convergence.de>,
69a0bf528SMauro Carvalho Chehab 	<holger@convergence.de>,
79a0bf528SMauro Carvalho Chehab 	<js@convergence.de>
89a0bf528SMauro Carvalho Chehab 
99a0bf528SMauro Carvalho Chehab 
109a0bf528SMauro Carvalho Chehab     Philips SU1278/SH
119a0bf528SMauro Carvalho Chehab 
129a0bf528SMauro Carvalho Chehab     Copyright (C) 2002 by Peter Schildmann <peter.schildmann@web.de>
139a0bf528SMauro Carvalho Chehab 
149a0bf528SMauro Carvalho Chehab 
159a0bf528SMauro Carvalho Chehab     LG TDQF-S001F
169a0bf528SMauro Carvalho Chehab 
179a0bf528SMauro Carvalho Chehab     Copyright (C) 2002 Felix Domke <tmbinc@elitedvb.net>
189a0bf528SMauro Carvalho Chehab 		     & Andreas Oberritter <obi@linuxtv.org>
199a0bf528SMauro Carvalho Chehab 
209a0bf528SMauro Carvalho Chehab 
219a0bf528SMauro Carvalho Chehab     Support for Samsung TBMU24112IMB used on Technisat SkyStar2 rev. 2.6B
229a0bf528SMauro Carvalho Chehab 
239a0bf528SMauro Carvalho Chehab     Copyright (C) 2003 Vadim Catana <skystar@moldova.cc>:
249a0bf528SMauro Carvalho Chehab 
259a0bf528SMauro Carvalho Chehab     Support for Philips SU1278 on Technotrend hardware
269a0bf528SMauro Carvalho Chehab 
279a0bf528SMauro Carvalho Chehab     Copyright (C) 2004 Andrew de Quincey <adq_dvb@lidskialf.net>
289a0bf528SMauro Carvalho Chehab 
299a0bf528SMauro Carvalho Chehab     This program is free software; you can redistribute it and/or modify
309a0bf528SMauro Carvalho Chehab     it under the terms of the GNU General Public License as published by
319a0bf528SMauro Carvalho Chehab     the Free Software Foundation; either version 2 of the License, or
329a0bf528SMauro Carvalho Chehab     (at your option) any later version.
339a0bf528SMauro Carvalho Chehab 
349a0bf528SMauro Carvalho Chehab     This program is distributed in the hope that it will be useful,
359a0bf528SMauro Carvalho Chehab     but WITHOUT ANY WARRANTY; without even the implied warranty of
369a0bf528SMauro Carvalho Chehab     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
379a0bf528SMauro Carvalho Chehab     GNU General Public License for more details.
389a0bf528SMauro Carvalho Chehab 
399a0bf528SMauro Carvalho Chehab     You should have received a copy of the GNU General Public License
409a0bf528SMauro Carvalho Chehab     along with this program; if not, write to the Free Software
419a0bf528SMauro Carvalho Chehab     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
429a0bf528SMauro Carvalho Chehab 
439a0bf528SMauro Carvalho Chehab */
449a0bf528SMauro Carvalho Chehab 
459a0bf528SMauro Carvalho Chehab #include <linux/init.h>
469a0bf528SMauro Carvalho Chehab #include <linux/kernel.h>
479056a23bSTina Ruchandani #include <linux/ktime.h>
489a0bf528SMauro Carvalho Chehab #include <linux/module.h>
499a0bf528SMauro Carvalho Chehab #include <linux/string.h>
509a0bf528SMauro Carvalho Chehab #include <linux/slab.h>
519a0bf528SMauro Carvalho Chehab #include <linux/jiffies.h>
529a0bf528SMauro Carvalho Chehab #include <asm/div64.h>
539a0bf528SMauro Carvalho Chehab 
549a0bf528SMauro Carvalho Chehab #include "dvb_frontend.h"
559a0bf528SMauro Carvalho Chehab #include "stv0299.h"
569a0bf528SMauro Carvalho Chehab 
579a0bf528SMauro Carvalho Chehab struct stv0299_state {
589a0bf528SMauro Carvalho Chehab 	struct i2c_adapter* i2c;
599a0bf528SMauro Carvalho Chehab 	const struct stv0299_config* config;
609a0bf528SMauro Carvalho Chehab 	struct dvb_frontend frontend;
619a0bf528SMauro Carvalho Chehab 
629a0bf528SMauro Carvalho Chehab 	u8 initialised:1;
639a0bf528SMauro Carvalho Chehab 	u32 tuner_frequency;
649a0bf528SMauro Carvalho Chehab 	u32 symbol_rate;
650df289a2SMauro Carvalho Chehab 	enum fe_code_rate fec_inner;
669a0bf528SMauro Carvalho Chehab 	int errmode;
679a0bf528SMauro Carvalho Chehab 	u32 ucblocks;
689a0bf528SMauro Carvalho Chehab 	u8 mcr_reg;
699a0bf528SMauro Carvalho Chehab };
709a0bf528SMauro Carvalho Chehab 
719a0bf528SMauro Carvalho Chehab #define STATUS_BER 0
729a0bf528SMauro Carvalho Chehab #define STATUS_UCBLOCKS 1
739a0bf528SMauro Carvalho Chehab 
749a0bf528SMauro Carvalho Chehab static int debug;
759a0bf528SMauro Carvalho Chehab static int debug_legacy_dish_switch;
769a0bf528SMauro Carvalho Chehab #define dprintk(args...) \
779a0bf528SMauro Carvalho Chehab 	do { \
789a0bf528SMauro Carvalho Chehab 		if (debug) printk(KERN_DEBUG "stv0299: " args); \
799a0bf528SMauro Carvalho Chehab 	} while (0)
809a0bf528SMauro Carvalho Chehab 
819a0bf528SMauro Carvalho Chehab 
829a0bf528SMauro Carvalho Chehab static int stv0299_writeregI (struct stv0299_state* state, u8 reg, u8 data)
839a0bf528SMauro Carvalho Chehab {
849a0bf528SMauro Carvalho Chehab 	int ret;
859a0bf528SMauro Carvalho Chehab 	u8 buf [] = { reg, data };
869a0bf528SMauro Carvalho Chehab 	struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
879a0bf528SMauro Carvalho Chehab 
889a0bf528SMauro Carvalho Chehab 	ret = i2c_transfer (state->i2c, &msg, 1);
899a0bf528SMauro Carvalho Chehab 
909a0bf528SMauro Carvalho Chehab 	if (ret != 1)
914bd69e7bSMauro Carvalho Chehab 		dprintk("%s: writereg error (reg == 0x%02x, val == 0x%02x, ret == %i)\n",
924bd69e7bSMauro Carvalho Chehab 			__func__, reg, data, ret);
939a0bf528SMauro Carvalho Chehab 
949a0bf528SMauro Carvalho Chehab 	return (ret != 1) ? -EREMOTEIO : 0;
959a0bf528SMauro Carvalho Chehab }
969a0bf528SMauro Carvalho Chehab 
979a0bf528SMauro Carvalho Chehab static int stv0299_write(struct dvb_frontend* fe, const u8 buf[], int len)
989a0bf528SMauro Carvalho Chehab {
999a0bf528SMauro Carvalho Chehab 	struct stv0299_state* state = fe->demodulator_priv;
1009a0bf528SMauro Carvalho Chehab 
1019a0bf528SMauro Carvalho Chehab 	if (len != 2)
1029a0bf528SMauro Carvalho Chehab 		return -EINVAL;
1039a0bf528SMauro Carvalho Chehab 
1049a0bf528SMauro Carvalho Chehab 	return stv0299_writeregI(state, buf[0], buf[1]);
1059a0bf528SMauro Carvalho Chehab }
1069a0bf528SMauro Carvalho Chehab 
1079a0bf528SMauro Carvalho Chehab static u8 stv0299_readreg (struct stv0299_state* state, u8 reg)
1089a0bf528SMauro Carvalho Chehab {
1099a0bf528SMauro Carvalho Chehab 	int ret;
1109a0bf528SMauro Carvalho Chehab 	u8 b0 [] = { reg };
1119a0bf528SMauro Carvalho Chehab 	u8 b1 [] = { 0 };
1129a0bf528SMauro Carvalho Chehab 	struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 },
1139a0bf528SMauro Carvalho Chehab 			   { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
1149a0bf528SMauro Carvalho Chehab 
1159a0bf528SMauro Carvalho Chehab 	ret = i2c_transfer (state->i2c, msg, 2);
1169a0bf528SMauro Carvalho Chehab 
1179a0bf528SMauro Carvalho Chehab 	if (ret != 2)
1189a0bf528SMauro Carvalho Chehab 		dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n",
1199a0bf528SMauro Carvalho Chehab 				__func__, reg, ret);
1209a0bf528SMauro Carvalho Chehab 
1219a0bf528SMauro Carvalho Chehab 	return b1[0];
1229a0bf528SMauro Carvalho Chehab }
1239a0bf528SMauro Carvalho Chehab 
1249a0bf528SMauro Carvalho Chehab static int stv0299_readregs (struct stv0299_state* state, u8 reg1, u8 *b, u8 len)
1259a0bf528SMauro Carvalho Chehab {
1269a0bf528SMauro Carvalho Chehab 	int ret;
1279a0bf528SMauro Carvalho Chehab 	struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = &reg1, .len = 1 },
1289a0bf528SMauro Carvalho Chehab 			   { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b, .len = len } };
1299a0bf528SMauro Carvalho Chehab 
1309a0bf528SMauro Carvalho Chehab 	ret = i2c_transfer (state->i2c, msg, 2);
1319a0bf528SMauro Carvalho Chehab 
1329a0bf528SMauro Carvalho Chehab 	if (ret != 2)
1339a0bf528SMauro Carvalho Chehab 		dprintk("%s: readreg error (ret == %i)\n", __func__, ret);
1349a0bf528SMauro Carvalho Chehab 
1359a0bf528SMauro Carvalho Chehab 	return ret == 2 ? 0 : ret;
1369a0bf528SMauro Carvalho Chehab }
1379a0bf528SMauro Carvalho Chehab 
1380df289a2SMauro Carvalho Chehab static int stv0299_set_FEC(struct stv0299_state *state, enum fe_code_rate fec)
1399a0bf528SMauro Carvalho Chehab {
1409a0bf528SMauro Carvalho Chehab 	dprintk ("%s\n", __func__);
1419a0bf528SMauro Carvalho Chehab 
1429a0bf528SMauro Carvalho Chehab 	switch (fec) {
1439a0bf528SMauro Carvalho Chehab 	case FEC_AUTO:
1449a0bf528SMauro Carvalho Chehab 	{
1459a0bf528SMauro Carvalho Chehab 		return stv0299_writeregI (state, 0x31, 0x1f);
1469a0bf528SMauro Carvalho Chehab 	}
1479a0bf528SMauro Carvalho Chehab 	case FEC_1_2:
1489a0bf528SMauro Carvalho Chehab 	{
1499a0bf528SMauro Carvalho Chehab 		return stv0299_writeregI (state, 0x31, 0x01);
1509a0bf528SMauro Carvalho Chehab 	}
1519a0bf528SMauro Carvalho Chehab 	case FEC_2_3:
1529a0bf528SMauro Carvalho Chehab 	{
1539a0bf528SMauro Carvalho Chehab 		return stv0299_writeregI (state, 0x31, 0x02);
1549a0bf528SMauro Carvalho Chehab 	}
1559a0bf528SMauro Carvalho Chehab 	case FEC_3_4:
1569a0bf528SMauro Carvalho Chehab 	{
1579a0bf528SMauro Carvalho Chehab 		return stv0299_writeregI (state, 0x31, 0x04);
1589a0bf528SMauro Carvalho Chehab 	}
1599a0bf528SMauro Carvalho Chehab 	case FEC_5_6:
1609a0bf528SMauro Carvalho Chehab 	{
1619a0bf528SMauro Carvalho Chehab 		return stv0299_writeregI (state, 0x31, 0x08);
1629a0bf528SMauro Carvalho Chehab 	}
1639a0bf528SMauro Carvalho Chehab 	case FEC_7_8:
1649a0bf528SMauro Carvalho Chehab 	{
1659a0bf528SMauro Carvalho Chehab 		return stv0299_writeregI (state, 0x31, 0x10);
1669a0bf528SMauro Carvalho Chehab 	}
1679a0bf528SMauro Carvalho Chehab 	default:
1689a0bf528SMauro Carvalho Chehab 	{
1699a0bf528SMauro Carvalho Chehab 		return -EINVAL;
1709a0bf528SMauro Carvalho Chehab 	}
1719a0bf528SMauro Carvalho Chehab     }
1729a0bf528SMauro Carvalho Chehab }
1739a0bf528SMauro Carvalho Chehab 
1740df289a2SMauro Carvalho Chehab static enum fe_code_rate stv0299_get_fec(struct stv0299_state *state)
1759a0bf528SMauro Carvalho Chehab {
1760df289a2SMauro Carvalho Chehab 	static enum fe_code_rate fec_tab[] = { FEC_2_3, FEC_3_4, FEC_5_6,
1779a0bf528SMauro Carvalho Chehab 					       FEC_7_8, FEC_1_2 };
1789a0bf528SMauro Carvalho Chehab 	u8 index;
1799a0bf528SMauro Carvalho Chehab 
1809a0bf528SMauro Carvalho Chehab 	dprintk ("%s\n", __func__);
1819a0bf528SMauro Carvalho Chehab 
1829a0bf528SMauro Carvalho Chehab 	index = stv0299_readreg (state, 0x1b);
1839a0bf528SMauro Carvalho Chehab 	index &= 0x7;
1849a0bf528SMauro Carvalho Chehab 
1859a0bf528SMauro Carvalho Chehab 	if (index > 4)
1869a0bf528SMauro Carvalho Chehab 		return FEC_AUTO;
1879a0bf528SMauro Carvalho Chehab 
1889a0bf528SMauro Carvalho Chehab 	return fec_tab [index];
1899a0bf528SMauro Carvalho Chehab }
1909a0bf528SMauro Carvalho Chehab 
1919a0bf528SMauro Carvalho Chehab static int stv0299_wait_diseqc_fifo (struct stv0299_state* state, int timeout)
1929a0bf528SMauro Carvalho Chehab {
1939a0bf528SMauro Carvalho Chehab 	unsigned long start = jiffies;
1949a0bf528SMauro Carvalho Chehab 
1959a0bf528SMauro Carvalho Chehab 	dprintk ("%s\n", __func__);
1969a0bf528SMauro Carvalho Chehab 
1979a0bf528SMauro Carvalho Chehab 	while (stv0299_readreg(state, 0x0a) & 1) {
1989a0bf528SMauro Carvalho Chehab 		if (jiffies - start > timeout) {
1999a0bf528SMauro Carvalho Chehab 			dprintk ("%s: timeout!!\n", __func__);
2009a0bf528SMauro Carvalho Chehab 			return -ETIMEDOUT;
2019a0bf528SMauro Carvalho Chehab 		}
2029a0bf528SMauro Carvalho Chehab 		msleep(10);
203c2c1b415SPeter Senna Tschudin 	}
2049a0bf528SMauro Carvalho Chehab 
2059a0bf528SMauro Carvalho Chehab 	return 0;
2069a0bf528SMauro Carvalho Chehab }
2079a0bf528SMauro Carvalho Chehab 
2089a0bf528SMauro Carvalho Chehab static int stv0299_wait_diseqc_idle (struct stv0299_state* state, int timeout)
2099a0bf528SMauro Carvalho Chehab {
2109a0bf528SMauro Carvalho Chehab 	unsigned long start = jiffies;
2119a0bf528SMauro Carvalho Chehab 
2129a0bf528SMauro Carvalho Chehab 	dprintk ("%s\n", __func__);
2139a0bf528SMauro Carvalho Chehab 
2149a0bf528SMauro Carvalho Chehab 	while ((stv0299_readreg(state, 0x0a) & 3) != 2 ) {
2159a0bf528SMauro Carvalho Chehab 		if (jiffies - start > timeout) {
2169a0bf528SMauro Carvalho Chehab 			dprintk ("%s: timeout!!\n", __func__);
2179a0bf528SMauro Carvalho Chehab 			return -ETIMEDOUT;
2189a0bf528SMauro Carvalho Chehab 		}
2199a0bf528SMauro Carvalho Chehab 		msleep(10);
220c2c1b415SPeter Senna Tschudin 	}
2219a0bf528SMauro Carvalho Chehab 
2229a0bf528SMauro Carvalho Chehab 	return 0;
2239a0bf528SMauro Carvalho Chehab }
2249a0bf528SMauro Carvalho Chehab 
2259a0bf528SMauro Carvalho Chehab static int stv0299_set_symbolrate (struct dvb_frontend* fe, u32 srate)
2269a0bf528SMauro Carvalho Chehab {
2279a0bf528SMauro Carvalho Chehab 	struct stv0299_state* state = fe->demodulator_priv;
2289a0bf528SMauro Carvalho Chehab 	u64 big = srate;
2299a0bf528SMauro Carvalho Chehab 	u32 ratio;
2309a0bf528SMauro Carvalho Chehab 
2319a0bf528SMauro Carvalho Chehab 	// check rate is within limits
2329a0bf528SMauro Carvalho Chehab 	if ((srate < 1000000) || (srate > 45000000)) return -EINVAL;
2339a0bf528SMauro Carvalho Chehab 
2349a0bf528SMauro Carvalho Chehab 	// calculate value to program
2359a0bf528SMauro Carvalho Chehab 	big = big << 20;
2369a0bf528SMauro Carvalho Chehab 	big += (state->config->mclk-1); // round correctly
2379a0bf528SMauro Carvalho Chehab 	do_div(big, state->config->mclk);
2389a0bf528SMauro Carvalho Chehab 	ratio = big << 4;
2399a0bf528SMauro Carvalho Chehab 
2409a0bf528SMauro Carvalho Chehab 	return state->config->set_symbol_rate(fe, srate, ratio);
2419a0bf528SMauro Carvalho Chehab }
2429a0bf528SMauro Carvalho Chehab 
2439a0bf528SMauro Carvalho Chehab static int stv0299_get_symbolrate (struct stv0299_state* state)
2449a0bf528SMauro Carvalho Chehab {
2459a0bf528SMauro Carvalho Chehab 	u32 Mclk = state->config->mclk / 4096L;
2469a0bf528SMauro Carvalho Chehab 	u32 srate;
2479a0bf528SMauro Carvalho Chehab 	s32 offset;
2489a0bf528SMauro Carvalho Chehab 	u8 sfr[3];
2499a0bf528SMauro Carvalho Chehab 	s8 rtf;
2509a0bf528SMauro Carvalho Chehab 
2519a0bf528SMauro Carvalho Chehab 	dprintk ("%s\n", __func__);
2529a0bf528SMauro Carvalho Chehab 
2539a0bf528SMauro Carvalho Chehab 	stv0299_readregs (state, 0x1f, sfr, 3);
2549a0bf528SMauro Carvalho Chehab 	stv0299_readregs (state, 0x1a, (u8 *)&rtf, 1);
2559a0bf528SMauro Carvalho Chehab 
2569a0bf528SMauro Carvalho Chehab 	srate = (sfr[0] << 8) | sfr[1];
2579a0bf528SMauro Carvalho Chehab 	srate *= Mclk;
2589a0bf528SMauro Carvalho Chehab 	srate /= 16;
2599a0bf528SMauro Carvalho Chehab 	srate += (sfr[2] >> 4) * Mclk / 256;
2609a0bf528SMauro Carvalho Chehab 	offset = (s32) rtf * (srate / 4096L);
2619a0bf528SMauro Carvalho Chehab 	offset /= 128;
2629a0bf528SMauro Carvalho Chehab 
2639a0bf528SMauro Carvalho Chehab 	dprintk ("%s : srate = %i\n", __func__, srate);
2649a0bf528SMauro Carvalho Chehab 	dprintk ("%s : ofset = %i\n", __func__, offset);
2659a0bf528SMauro Carvalho Chehab 
2669a0bf528SMauro Carvalho Chehab 	srate += offset;
2679a0bf528SMauro Carvalho Chehab 
2689a0bf528SMauro Carvalho Chehab 	srate += 1000;
2699a0bf528SMauro Carvalho Chehab 	srate /= 2000;
2709a0bf528SMauro Carvalho Chehab 	srate *= 2000;
2719a0bf528SMauro Carvalho Chehab 
2729a0bf528SMauro Carvalho Chehab 	return srate;
2739a0bf528SMauro Carvalho Chehab }
2749a0bf528SMauro Carvalho Chehab 
2759a0bf528SMauro Carvalho Chehab static int stv0299_send_diseqc_msg (struct dvb_frontend* fe,
2769a0bf528SMauro Carvalho Chehab 				    struct dvb_diseqc_master_cmd *m)
2779a0bf528SMauro Carvalho Chehab {
2789a0bf528SMauro Carvalho Chehab 	struct stv0299_state* state = fe->demodulator_priv;
2799a0bf528SMauro Carvalho Chehab 	u8 val;
2809a0bf528SMauro Carvalho Chehab 	int i;
2819a0bf528SMauro Carvalho Chehab 
2829a0bf528SMauro Carvalho Chehab 	dprintk ("%s\n", __func__);
2839a0bf528SMauro Carvalho Chehab 
2849a0bf528SMauro Carvalho Chehab 	if (stv0299_wait_diseqc_idle (state, 100) < 0)
2859a0bf528SMauro Carvalho Chehab 		return -ETIMEDOUT;
2869a0bf528SMauro Carvalho Chehab 
2879a0bf528SMauro Carvalho Chehab 	val = stv0299_readreg (state, 0x08);
2889a0bf528SMauro Carvalho Chehab 
2899a0bf528SMauro Carvalho Chehab 	if (stv0299_writeregI (state, 0x08, (val & ~0x7) | 0x6))  /* DiSEqC mode */
2909a0bf528SMauro Carvalho Chehab 		return -EREMOTEIO;
2919a0bf528SMauro Carvalho Chehab 
2929a0bf528SMauro Carvalho Chehab 	for (i=0; i<m->msg_len; i++) {
2939a0bf528SMauro Carvalho Chehab 		if (stv0299_wait_diseqc_fifo (state, 100) < 0)
2949a0bf528SMauro Carvalho Chehab 			return -ETIMEDOUT;
2959a0bf528SMauro Carvalho Chehab 
2969a0bf528SMauro Carvalho Chehab 		if (stv0299_writeregI (state, 0x09, m->msg[i]))
2979a0bf528SMauro Carvalho Chehab 			return -EREMOTEIO;
2989a0bf528SMauro Carvalho Chehab 	}
2999a0bf528SMauro Carvalho Chehab 
3009a0bf528SMauro Carvalho Chehab 	if (stv0299_wait_diseqc_idle (state, 100) < 0)
3019a0bf528SMauro Carvalho Chehab 		return -ETIMEDOUT;
3029a0bf528SMauro Carvalho Chehab 
3039a0bf528SMauro Carvalho Chehab 	return 0;
3049a0bf528SMauro Carvalho Chehab }
3059a0bf528SMauro Carvalho Chehab 
3060df289a2SMauro Carvalho Chehab static int stv0299_send_diseqc_burst(struct dvb_frontend *fe,
3070df289a2SMauro Carvalho Chehab 				     enum fe_sec_mini_cmd burst)
3089a0bf528SMauro Carvalho Chehab {
3099a0bf528SMauro Carvalho Chehab 	struct stv0299_state* state = fe->demodulator_priv;
3109a0bf528SMauro Carvalho Chehab 	u8 val;
3119a0bf528SMauro Carvalho Chehab 
3129a0bf528SMauro Carvalho Chehab 	dprintk ("%s\n", __func__);
3139a0bf528SMauro Carvalho Chehab 
3149a0bf528SMauro Carvalho Chehab 	if (stv0299_wait_diseqc_idle (state, 100) < 0)
3159a0bf528SMauro Carvalho Chehab 		return -ETIMEDOUT;
3169a0bf528SMauro Carvalho Chehab 
3179a0bf528SMauro Carvalho Chehab 	val = stv0299_readreg (state, 0x08);
3189a0bf528SMauro Carvalho Chehab 
3199a0bf528SMauro Carvalho Chehab 	if (stv0299_writeregI (state, 0x08, (val & ~0x7) | 0x2))	/* burst mode */
3209a0bf528SMauro Carvalho Chehab 		return -EREMOTEIO;
3219a0bf528SMauro Carvalho Chehab 
3229a0bf528SMauro Carvalho Chehab 	if (stv0299_writeregI (state, 0x09, burst == SEC_MINI_A ? 0x00 : 0xff))
3239a0bf528SMauro Carvalho Chehab 		return -EREMOTEIO;
3249a0bf528SMauro Carvalho Chehab 
3259a0bf528SMauro Carvalho Chehab 	if (stv0299_wait_diseqc_idle (state, 100) < 0)
3269a0bf528SMauro Carvalho Chehab 		return -ETIMEDOUT;
3279a0bf528SMauro Carvalho Chehab 
3289a0bf528SMauro Carvalho Chehab 	if (stv0299_writeregI (state, 0x08, val))
3299a0bf528SMauro Carvalho Chehab 		return -EREMOTEIO;
3309a0bf528SMauro Carvalho Chehab 
3319a0bf528SMauro Carvalho Chehab 	return 0;
3329a0bf528SMauro Carvalho Chehab }
3339a0bf528SMauro Carvalho Chehab 
3340df289a2SMauro Carvalho Chehab static int stv0299_set_tone(struct dvb_frontend *fe,
3350df289a2SMauro Carvalho Chehab 			    enum fe_sec_tone_mode tone)
3369a0bf528SMauro Carvalho Chehab {
3379a0bf528SMauro Carvalho Chehab 	struct stv0299_state* state = fe->demodulator_priv;
3389a0bf528SMauro Carvalho Chehab 	u8 val;
3399a0bf528SMauro Carvalho Chehab 
3409a0bf528SMauro Carvalho Chehab 	if (stv0299_wait_diseqc_idle (state, 100) < 0)
3419a0bf528SMauro Carvalho Chehab 		return -ETIMEDOUT;
3429a0bf528SMauro Carvalho Chehab 
3439a0bf528SMauro Carvalho Chehab 	val = stv0299_readreg (state, 0x08);
3449a0bf528SMauro Carvalho Chehab 
3459a0bf528SMauro Carvalho Chehab 	switch (tone) {
3469a0bf528SMauro Carvalho Chehab 	case SEC_TONE_ON:
3479a0bf528SMauro Carvalho Chehab 		return stv0299_writeregI (state, 0x08, val | 0x3);
3489a0bf528SMauro Carvalho Chehab 
3499a0bf528SMauro Carvalho Chehab 	case SEC_TONE_OFF:
3509a0bf528SMauro Carvalho Chehab 		return stv0299_writeregI (state, 0x08, (val & ~0x3) | 0x02);
3519a0bf528SMauro Carvalho Chehab 
3529a0bf528SMauro Carvalho Chehab 	default:
3539a0bf528SMauro Carvalho Chehab 		return -EINVAL;
3549a0bf528SMauro Carvalho Chehab 	}
3559a0bf528SMauro Carvalho Chehab }
3569a0bf528SMauro Carvalho Chehab 
3570df289a2SMauro Carvalho Chehab static int stv0299_set_voltage(struct dvb_frontend *fe,
3580df289a2SMauro Carvalho Chehab 			       enum fe_sec_voltage voltage)
3599a0bf528SMauro Carvalho Chehab {
3609a0bf528SMauro Carvalho Chehab 	struct stv0299_state* state = fe->demodulator_priv;
3619a0bf528SMauro Carvalho Chehab 	u8 reg0x08;
3629a0bf528SMauro Carvalho Chehab 	u8 reg0x0c;
3639a0bf528SMauro Carvalho Chehab 
3649a0bf528SMauro Carvalho Chehab 	dprintk("%s: %s\n", __func__,
3659a0bf528SMauro Carvalho Chehab 		voltage == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" :
3669a0bf528SMauro Carvalho Chehab 		voltage == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??");
3679a0bf528SMauro Carvalho Chehab 
3689a0bf528SMauro Carvalho Chehab 	reg0x08 = stv0299_readreg (state, 0x08);
3699a0bf528SMauro Carvalho Chehab 	reg0x0c = stv0299_readreg (state, 0x0c);
3709a0bf528SMauro Carvalho Chehab 
3719a0bf528SMauro Carvalho Chehab 	/**
3729a0bf528SMauro Carvalho Chehab 	 *  H/V switching over OP0, OP1 and OP2 are LNB power enable bits
3739a0bf528SMauro Carvalho Chehab 	 */
3749a0bf528SMauro Carvalho Chehab 	reg0x0c &= 0x0f;
3759a0bf528SMauro Carvalho Chehab 	reg0x08 = (reg0x08 & 0x3f) | (state->config->lock_output << 6);
3769a0bf528SMauro Carvalho Chehab 
3779a0bf528SMauro Carvalho Chehab 	switch (voltage) {
3789a0bf528SMauro Carvalho Chehab 	case SEC_VOLTAGE_13:
3799a0bf528SMauro Carvalho Chehab 		if (state->config->volt13_op0_op1 == STV0299_VOLT13_OP0)
3809a0bf528SMauro Carvalho Chehab 			reg0x0c |= 0x10; /* OP1 off, OP0 on */
3819a0bf528SMauro Carvalho Chehab 		else
3829a0bf528SMauro Carvalho Chehab 			reg0x0c |= 0x40; /* OP1 on, OP0 off */
3839a0bf528SMauro Carvalho Chehab 		break;
3849a0bf528SMauro Carvalho Chehab 	case SEC_VOLTAGE_18:
3859a0bf528SMauro Carvalho Chehab 		reg0x0c |= 0x50; /* OP1 on, OP0 on */
3869a0bf528SMauro Carvalho Chehab 		break;
3879a0bf528SMauro Carvalho Chehab 	case SEC_VOLTAGE_OFF:
3889a0bf528SMauro Carvalho Chehab 		/* LNB power off! */
3899a0bf528SMauro Carvalho Chehab 		reg0x08 = 0x00;
3909a0bf528SMauro Carvalho Chehab 		reg0x0c = 0x00;
3919a0bf528SMauro Carvalho Chehab 		break;
3929a0bf528SMauro Carvalho Chehab 	default:
3939a0bf528SMauro Carvalho Chehab 		return -EINVAL;
394c2c1b415SPeter Senna Tschudin 	}
3959a0bf528SMauro Carvalho Chehab 
3969a0bf528SMauro Carvalho Chehab 	if (state->config->op0_off)
3979a0bf528SMauro Carvalho Chehab 		reg0x0c &= ~0x10;
3989a0bf528SMauro Carvalho Chehab 
3999a0bf528SMauro Carvalho Chehab 	stv0299_writeregI(state, 0x08, reg0x08);
4009a0bf528SMauro Carvalho Chehab 	return stv0299_writeregI(state, 0x0c, reg0x0c);
4019a0bf528SMauro Carvalho Chehab }
4029a0bf528SMauro Carvalho Chehab 
4039a0bf528SMauro Carvalho Chehab static int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, unsigned long cmd)
4049a0bf528SMauro Carvalho Chehab {
4059a0bf528SMauro Carvalho Chehab 	struct stv0299_state* state = fe->demodulator_priv;
4069a0bf528SMauro Carvalho Chehab 	u8 reg0x08;
4079a0bf528SMauro Carvalho Chehab 	u8 reg0x0c;
4089a0bf528SMauro Carvalho Chehab 	u8 lv_mask = 0x40;
4099a0bf528SMauro Carvalho Chehab 	u8 last = 1;
4109a0bf528SMauro Carvalho Chehab 	int i;
4119056a23bSTina Ruchandani 	ktime_t nexttime;
4129056a23bSTina Ruchandani 	ktime_t tv[10];
4139a0bf528SMauro Carvalho Chehab 
4149a0bf528SMauro Carvalho Chehab 	reg0x08 = stv0299_readreg (state, 0x08);
4159a0bf528SMauro Carvalho Chehab 	reg0x0c = stv0299_readreg (state, 0x0c);
4169a0bf528SMauro Carvalho Chehab 	reg0x0c &= 0x0f;
4179a0bf528SMauro Carvalho Chehab 	stv0299_writeregI (state, 0x08, (reg0x08 & 0x3f) | (state->config->lock_output << 6));
4189a0bf528SMauro Carvalho Chehab 	if (state->config->volt13_op0_op1 == STV0299_VOLT13_OP0)
4199a0bf528SMauro Carvalho Chehab 		lv_mask = 0x10;
4209a0bf528SMauro Carvalho Chehab 
4219a0bf528SMauro Carvalho Chehab 	cmd = cmd << 1;
4229a0bf528SMauro Carvalho Chehab 	if (debug_legacy_dish_switch)
4239a0bf528SMauro Carvalho Chehab 		printk ("%s switch command: 0x%04lx\n",__func__, cmd);
4249a0bf528SMauro Carvalho Chehab 
4256b3f9998SAbhilash Jindal 	nexttime = ktime_get_boottime();
4269a0bf528SMauro Carvalho Chehab 	if (debug_legacy_dish_switch)
427ee45ddc1SEzequiel Garcia 		tv[0] = nexttime;
4289a0bf528SMauro Carvalho Chehab 	stv0299_writeregI (state, 0x0c, reg0x0c | 0x50); /* set LNB to 18V */
4299a0bf528SMauro Carvalho Chehab 
4309a0bf528SMauro Carvalho Chehab 	dvb_frontend_sleep_until(&nexttime, 32000);
4319a0bf528SMauro Carvalho Chehab 
4329a0bf528SMauro Carvalho Chehab 	for (i=0; i<9; i++) {
4339a0bf528SMauro Carvalho Chehab 		if (debug_legacy_dish_switch)
4346b3f9998SAbhilash Jindal 			tv[i+1] = ktime_get_boottime();
4359a0bf528SMauro Carvalho Chehab 		if((cmd & 0x01) != last) {
4369a0bf528SMauro Carvalho Chehab 			/* set voltage to (last ? 13V : 18V) */
4379a0bf528SMauro Carvalho Chehab 			stv0299_writeregI (state, 0x0c, reg0x0c | (last ? lv_mask : 0x50));
4389a0bf528SMauro Carvalho Chehab 			last = (last) ? 0 : 1;
4399a0bf528SMauro Carvalho Chehab 		}
4409a0bf528SMauro Carvalho Chehab 
4419a0bf528SMauro Carvalho Chehab 		cmd = cmd >> 1;
4429a0bf528SMauro Carvalho Chehab 
4439a0bf528SMauro Carvalho Chehab 		if (i != 8)
4449a0bf528SMauro Carvalho Chehab 			dvb_frontend_sleep_until(&nexttime, 8000);
4459a0bf528SMauro Carvalho Chehab 	}
4469a0bf528SMauro Carvalho Chehab 	if (debug_legacy_dish_switch) {
4479a0bf528SMauro Carvalho Chehab 		printk ("%s(%d): switch delay (should be 32k followed by all 8k\n",
4489a0bf528SMauro Carvalho Chehab 			__func__, fe->dvb->num);
4499a0bf528SMauro Carvalho Chehab 		for (i = 1; i < 10; i++)
4509056a23bSTina Ruchandani 			printk("%d: %d\n", i,
4519056a23bSTina Ruchandani 			       (int) ktime_us_delta(tv[i], tv[i-1]));
4529a0bf528SMauro Carvalho Chehab 	}
4539a0bf528SMauro Carvalho Chehab 
4549a0bf528SMauro Carvalho Chehab 	return 0;
4559a0bf528SMauro Carvalho Chehab }
4569a0bf528SMauro Carvalho Chehab 
4579a0bf528SMauro Carvalho Chehab static int stv0299_init (struct dvb_frontend* fe)
4589a0bf528SMauro Carvalho Chehab {
4599a0bf528SMauro Carvalho Chehab 	struct stv0299_state* state = fe->demodulator_priv;
4609a0bf528SMauro Carvalho Chehab 	int i;
4619a0bf528SMauro Carvalho Chehab 	u8 reg;
4629a0bf528SMauro Carvalho Chehab 	u8 val;
4639a0bf528SMauro Carvalho Chehab 
4649a0bf528SMauro Carvalho Chehab 	dprintk("stv0299: init chip\n");
4659a0bf528SMauro Carvalho Chehab 
4669a0bf528SMauro Carvalho Chehab 	stv0299_writeregI(state, 0x02, 0x30 | state->mcr_reg);
4679a0bf528SMauro Carvalho Chehab 	msleep(50);
4689a0bf528SMauro Carvalho Chehab 
4699a0bf528SMauro Carvalho Chehab 	for (i = 0; ; i += 2)  {
4709a0bf528SMauro Carvalho Chehab 		reg = state->config->inittab[i];
4719a0bf528SMauro Carvalho Chehab 		val = state->config->inittab[i+1];
4729a0bf528SMauro Carvalho Chehab 		if (reg == 0xff && val == 0xff)
4739a0bf528SMauro Carvalho Chehab 			break;
4749a0bf528SMauro Carvalho Chehab 		if (reg == 0x0c && state->config->op0_off)
4759a0bf528SMauro Carvalho Chehab 			val &= ~0x10;
4769a0bf528SMauro Carvalho Chehab 		if (reg == 0x2)
4779a0bf528SMauro Carvalho Chehab 			state->mcr_reg = val & 0xf;
4789a0bf528SMauro Carvalho Chehab 		stv0299_writeregI(state, reg, val);
4799a0bf528SMauro Carvalho Chehab 	}
4809a0bf528SMauro Carvalho Chehab 
4819a0bf528SMauro Carvalho Chehab 	return 0;
4829a0bf528SMauro Carvalho Chehab }
4839a0bf528SMauro Carvalho Chehab 
4840df289a2SMauro Carvalho Chehab static int stv0299_read_status(struct dvb_frontend *fe,
4850df289a2SMauro Carvalho Chehab 			       enum fe_status *status)
4869a0bf528SMauro Carvalho Chehab {
4879a0bf528SMauro Carvalho Chehab 	struct stv0299_state* state = fe->demodulator_priv;
4889a0bf528SMauro Carvalho Chehab 
4899a0bf528SMauro Carvalho Chehab 	u8 signal = 0xff - stv0299_readreg (state, 0x18);
4909a0bf528SMauro Carvalho Chehab 	u8 sync = stv0299_readreg (state, 0x1b);
4919a0bf528SMauro Carvalho Chehab 
4929a0bf528SMauro Carvalho Chehab 	dprintk ("%s : FE_READ_STATUS : VSTATUS: 0x%02x\n", __func__, sync);
4939a0bf528SMauro Carvalho Chehab 	*status = 0;
4949a0bf528SMauro Carvalho Chehab 
4959a0bf528SMauro Carvalho Chehab 	if (signal > 10)
4969a0bf528SMauro Carvalho Chehab 		*status |= FE_HAS_SIGNAL;
4979a0bf528SMauro Carvalho Chehab 
4989a0bf528SMauro Carvalho Chehab 	if (sync & 0x80)
4999a0bf528SMauro Carvalho Chehab 		*status |= FE_HAS_CARRIER;
5009a0bf528SMauro Carvalho Chehab 
5019a0bf528SMauro Carvalho Chehab 	if (sync & 0x10)
5029a0bf528SMauro Carvalho Chehab 		*status |= FE_HAS_VITERBI;
5039a0bf528SMauro Carvalho Chehab 
5049a0bf528SMauro Carvalho Chehab 	if (sync & 0x08)
5059a0bf528SMauro Carvalho Chehab 		*status |= FE_HAS_SYNC;
5069a0bf528SMauro Carvalho Chehab 
5079a0bf528SMauro Carvalho Chehab 	if ((sync & 0x98) == 0x98)
5089a0bf528SMauro Carvalho Chehab 		*status |= FE_HAS_LOCK;
5099a0bf528SMauro Carvalho Chehab 
5109a0bf528SMauro Carvalho Chehab 	return 0;
5119a0bf528SMauro Carvalho Chehab }
5129a0bf528SMauro Carvalho Chehab 
5139a0bf528SMauro Carvalho Chehab static int stv0299_read_ber(struct dvb_frontend* fe, u32* ber)
5149a0bf528SMauro Carvalho Chehab {
5159a0bf528SMauro Carvalho Chehab 	struct stv0299_state* state = fe->demodulator_priv;
5169a0bf528SMauro Carvalho Chehab 
5179a0bf528SMauro Carvalho Chehab 	if (state->errmode != STATUS_BER)
5189a0bf528SMauro Carvalho Chehab 		return -ENOSYS;
5199a0bf528SMauro Carvalho Chehab 
5209a0bf528SMauro Carvalho Chehab 	*ber = stv0299_readreg(state, 0x1e) | (stv0299_readreg(state, 0x1d) << 8);
5219a0bf528SMauro Carvalho Chehab 
5229a0bf528SMauro Carvalho Chehab 	return 0;
5239a0bf528SMauro Carvalho Chehab }
5249a0bf528SMauro Carvalho Chehab 
5259a0bf528SMauro Carvalho Chehab static int stv0299_read_signal_strength(struct dvb_frontend* fe, u16* strength)
5269a0bf528SMauro Carvalho Chehab {
5279a0bf528SMauro Carvalho Chehab 	struct stv0299_state* state = fe->demodulator_priv;
5289a0bf528SMauro Carvalho Chehab 
5299a0bf528SMauro Carvalho Chehab 	s32 signal =  0xffff - ((stv0299_readreg (state, 0x18) << 8)
5309a0bf528SMauro Carvalho Chehab 			       | stv0299_readreg (state, 0x19));
5319a0bf528SMauro Carvalho Chehab 
5329a0bf528SMauro Carvalho Chehab 	dprintk ("%s : FE_READ_SIGNAL_STRENGTH : AGC2I: 0x%02x%02x, signal=0x%04x\n", __func__,
5339a0bf528SMauro Carvalho Chehab 		 stv0299_readreg (state, 0x18),
5349a0bf528SMauro Carvalho Chehab 		 stv0299_readreg (state, 0x19), (int) signal);
5359a0bf528SMauro Carvalho Chehab 
5369a0bf528SMauro Carvalho Chehab 	signal = signal * 5 / 4;
5379a0bf528SMauro Carvalho Chehab 	*strength = (signal > 0xffff) ? 0xffff : (signal < 0) ? 0 : signal;
5389a0bf528SMauro Carvalho Chehab 
5399a0bf528SMauro Carvalho Chehab 	return 0;
5409a0bf528SMauro Carvalho Chehab }
5419a0bf528SMauro Carvalho Chehab 
5429a0bf528SMauro Carvalho Chehab static int stv0299_read_snr(struct dvb_frontend* fe, u16* snr)
5439a0bf528SMauro Carvalho Chehab {
5449a0bf528SMauro Carvalho Chehab 	struct stv0299_state* state = fe->demodulator_priv;
5459a0bf528SMauro Carvalho Chehab 
5469a0bf528SMauro Carvalho Chehab 	s32 xsnr = 0xffff - ((stv0299_readreg (state, 0x24) << 8)
5479a0bf528SMauro Carvalho Chehab 			   | stv0299_readreg (state, 0x25));
5489a0bf528SMauro Carvalho Chehab 	xsnr = 3 * (xsnr - 0xa100);
5499a0bf528SMauro Carvalho Chehab 	*snr = (xsnr > 0xffff) ? 0xffff : (xsnr < 0) ? 0 : xsnr;
5509a0bf528SMauro Carvalho Chehab 
5519a0bf528SMauro Carvalho Chehab 	return 0;
5529a0bf528SMauro Carvalho Chehab }
5539a0bf528SMauro Carvalho Chehab 
5549a0bf528SMauro Carvalho Chehab static int stv0299_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
5559a0bf528SMauro Carvalho Chehab {
5569a0bf528SMauro Carvalho Chehab 	struct stv0299_state* state = fe->demodulator_priv;
5579a0bf528SMauro Carvalho Chehab 
5589a0bf528SMauro Carvalho Chehab 	if (state->errmode != STATUS_UCBLOCKS)
5599a0bf528SMauro Carvalho Chehab 		return -ENOSYS;
5609a0bf528SMauro Carvalho Chehab 
5619a0bf528SMauro Carvalho Chehab 	state->ucblocks += stv0299_readreg(state, 0x1e);
5629a0bf528SMauro Carvalho Chehab 	state->ucblocks += (stv0299_readreg(state, 0x1d) << 8);
5639a0bf528SMauro Carvalho Chehab 	*ucblocks = state->ucblocks;
5649a0bf528SMauro Carvalho Chehab 
5659a0bf528SMauro Carvalho Chehab 	return 0;
5669a0bf528SMauro Carvalho Chehab }
5679a0bf528SMauro Carvalho Chehab 
5689a0bf528SMauro Carvalho Chehab static int stv0299_set_frontend(struct dvb_frontend *fe)
5699a0bf528SMauro Carvalho Chehab {
5709a0bf528SMauro Carvalho Chehab 	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
5719a0bf528SMauro Carvalho Chehab 	struct stv0299_state* state = fe->demodulator_priv;
5729a0bf528SMauro Carvalho Chehab 	int invval = 0;
5739a0bf528SMauro Carvalho Chehab 
5749a0bf528SMauro Carvalho Chehab 	dprintk ("%s : FE_SET_FRONTEND\n", __func__);
5759a0bf528SMauro Carvalho Chehab 	if (state->config->set_ts_params)
5769a0bf528SMauro Carvalho Chehab 		state->config->set_ts_params(fe, 0);
5779a0bf528SMauro Carvalho Chehab 
5789a0bf528SMauro Carvalho Chehab 	// set the inversion
5799a0bf528SMauro Carvalho Chehab 	if (p->inversion == INVERSION_OFF) invval = 0;
5809a0bf528SMauro Carvalho Chehab 	else if (p->inversion == INVERSION_ON) invval = 1;
5819a0bf528SMauro Carvalho Chehab 	else {
5829a0bf528SMauro Carvalho Chehab 		printk("stv0299 does not support auto-inversion\n");
5839a0bf528SMauro Carvalho Chehab 		return -EINVAL;
5849a0bf528SMauro Carvalho Chehab 	}
5859a0bf528SMauro Carvalho Chehab 	if (state->config->invert) invval = (~invval) & 1;
5869a0bf528SMauro Carvalho Chehab 	stv0299_writeregI(state, 0x0c, (stv0299_readreg(state, 0x0c) & 0xfe) | invval);
5879a0bf528SMauro Carvalho Chehab 
5889a0bf528SMauro Carvalho Chehab 	if (fe->ops.tuner_ops.set_params) {
5899a0bf528SMauro Carvalho Chehab 		fe->ops.tuner_ops.set_params(fe);
5909a0bf528SMauro Carvalho Chehab 		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
5919a0bf528SMauro Carvalho Chehab 	}
5929a0bf528SMauro Carvalho Chehab 
5939a0bf528SMauro Carvalho Chehab 	stv0299_set_FEC(state, p->fec_inner);
5949a0bf528SMauro Carvalho Chehab 	stv0299_set_symbolrate(fe, p->symbol_rate);
5959a0bf528SMauro Carvalho Chehab 	stv0299_writeregI(state, 0x22, 0x00);
5969a0bf528SMauro Carvalho Chehab 	stv0299_writeregI(state, 0x23, 0x00);
5979a0bf528SMauro Carvalho Chehab 
5989a0bf528SMauro Carvalho Chehab 	state->tuner_frequency = p->frequency;
5999a0bf528SMauro Carvalho Chehab 	state->fec_inner = p->fec_inner;
6009a0bf528SMauro Carvalho Chehab 	state->symbol_rate = p->symbol_rate;
6019a0bf528SMauro Carvalho Chehab 
6029a0bf528SMauro Carvalho Chehab 	return 0;
6039a0bf528SMauro Carvalho Chehab }
6049a0bf528SMauro Carvalho Chehab 
6057e3e68bcSMauro Carvalho Chehab static int stv0299_get_frontend(struct dvb_frontend *fe,
6067e3e68bcSMauro Carvalho Chehab 				struct dtv_frontend_properties *p)
6079a0bf528SMauro Carvalho Chehab {
6089a0bf528SMauro Carvalho Chehab 	struct stv0299_state* state = fe->demodulator_priv;
6099a0bf528SMauro Carvalho Chehab 	s32 derot_freq;
6109a0bf528SMauro Carvalho Chehab 	int invval;
6119a0bf528SMauro Carvalho Chehab 
6129a0bf528SMauro Carvalho Chehab 	derot_freq = (s32)(s16) ((stv0299_readreg (state, 0x22) << 8)
6139a0bf528SMauro Carvalho Chehab 				| stv0299_readreg (state, 0x23));
6149a0bf528SMauro Carvalho Chehab 
6159a0bf528SMauro Carvalho Chehab 	derot_freq *= (state->config->mclk >> 16);
6169a0bf528SMauro Carvalho Chehab 	derot_freq += 500;
6179a0bf528SMauro Carvalho Chehab 	derot_freq /= 1000;
6189a0bf528SMauro Carvalho Chehab 
6199a0bf528SMauro Carvalho Chehab 	p->frequency += derot_freq;
6209a0bf528SMauro Carvalho Chehab 
6219a0bf528SMauro Carvalho Chehab 	invval = stv0299_readreg (state, 0x0c) & 1;
6229a0bf528SMauro Carvalho Chehab 	if (state->config->invert) invval = (~invval) & 1;
6239a0bf528SMauro Carvalho Chehab 	p->inversion = invval ? INVERSION_ON : INVERSION_OFF;
6249a0bf528SMauro Carvalho Chehab 
6259a0bf528SMauro Carvalho Chehab 	p->fec_inner = stv0299_get_fec(state);
6269a0bf528SMauro Carvalho Chehab 	p->symbol_rate = stv0299_get_symbolrate(state);
6279a0bf528SMauro Carvalho Chehab 
6289a0bf528SMauro Carvalho Chehab 	return 0;
6299a0bf528SMauro Carvalho Chehab }
6309a0bf528SMauro Carvalho Chehab 
6319a0bf528SMauro Carvalho Chehab static int stv0299_sleep(struct dvb_frontend* fe)
6329a0bf528SMauro Carvalho Chehab {
6339a0bf528SMauro Carvalho Chehab 	struct stv0299_state* state = fe->demodulator_priv;
6349a0bf528SMauro Carvalho Chehab 
6359a0bf528SMauro Carvalho Chehab 	stv0299_writeregI(state, 0x02, 0xb0 | state->mcr_reg);
6369a0bf528SMauro Carvalho Chehab 	state->initialised = 0;
6379a0bf528SMauro Carvalho Chehab 
6389a0bf528SMauro Carvalho Chehab 	return 0;
6399a0bf528SMauro Carvalho Chehab }
6409a0bf528SMauro Carvalho Chehab 
6419a0bf528SMauro Carvalho Chehab static int stv0299_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
6429a0bf528SMauro Carvalho Chehab {
6439a0bf528SMauro Carvalho Chehab 	struct stv0299_state* state = fe->demodulator_priv;
6449a0bf528SMauro Carvalho Chehab 
6459a0bf528SMauro Carvalho Chehab 	if (enable) {
6469a0bf528SMauro Carvalho Chehab 		stv0299_writeregI(state, 0x05, 0xb5);
6479a0bf528SMauro Carvalho Chehab 	} else {
6489a0bf528SMauro Carvalho Chehab 		stv0299_writeregI(state, 0x05, 0x35);
6499a0bf528SMauro Carvalho Chehab 	}
6509a0bf528SMauro Carvalho Chehab 	udelay(1);
6519a0bf528SMauro Carvalho Chehab 	return 0;
6529a0bf528SMauro Carvalho Chehab }
6539a0bf528SMauro Carvalho Chehab 
6549a0bf528SMauro Carvalho Chehab static int stv0299_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
6559a0bf528SMauro Carvalho Chehab {
6569a0bf528SMauro Carvalho Chehab 	struct stv0299_state* state = fe->demodulator_priv;
6579a0bf528SMauro Carvalho Chehab 	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
6589a0bf528SMauro Carvalho Chehab 
6599a0bf528SMauro Carvalho Chehab 	fesettings->min_delay_ms = state->config->min_delay_ms;
6609a0bf528SMauro Carvalho Chehab 	if (p->symbol_rate < 10000000) {
6619a0bf528SMauro Carvalho Chehab 		fesettings->step_size = p->symbol_rate / 32000;
6629a0bf528SMauro Carvalho Chehab 		fesettings->max_drift = 5000;
6639a0bf528SMauro Carvalho Chehab 	} else {
6649a0bf528SMauro Carvalho Chehab 		fesettings->step_size = p->symbol_rate / 16000;
6659a0bf528SMauro Carvalho Chehab 		fesettings->max_drift = p->symbol_rate / 2000;
6669a0bf528SMauro Carvalho Chehab 	}
6679a0bf528SMauro Carvalho Chehab 	return 0;
6689a0bf528SMauro Carvalho Chehab }
6699a0bf528SMauro Carvalho Chehab 
6709a0bf528SMauro Carvalho Chehab static void stv0299_release(struct dvb_frontend* fe)
6719a0bf528SMauro Carvalho Chehab {
6729a0bf528SMauro Carvalho Chehab 	struct stv0299_state* state = fe->demodulator_priv;
6739a0bf528SMauro Carvalho Chehab 	kfree(state);
6749a0bf528SMauro Carvalho Chehab }
6759a0bf528SMauro Carvalho Chehab 
676bd336e63SMax Kellermann static const struct dvb_frontend_ops stv0299_ops;
6779a0bf528SMauro Carvalho Chehab 
6789a0bf528SMauro Carvalho Chehab struct dvb_frontend* stv0299_attach(const struct stv0299_config* config,
6799a0bf528SMauro Carvalho Chehab 				    struct i2c_adapter* i2c)
6809a0bf528SMauro Carvalho Chehab {
6819a0bf528SMauro Carvalho Chehab 	struct stv0299_state* state = NULL;
6829a0bf528SMauro Carvalho Chehab 	int id;
6839a0bf528SMauro Carvalho Chehab 
6849a0bf528SMauro Carvalho Chehab 	/* allocate memory for the internal state */
6859a0bf528SMauro Carvalho Chehab 	state = kzalloc(sizeof(struct stv0299_state), GFP_KERNEL);
6869a0bf528SMauro Carvalho Chehab 	if (state == NULL) goto error;
6879a0bf528SMauro Carvalho Chehab 
6889a0bf528SMauro Carvalho Chehab 	/* setup the state */
6899a0bf528SMauro Carvalho Chehab 	state->config = config;
6909a0bf528SMauro Carvalho Chehab 	state->i2c = i2c;
6919a0bf528SMauro Carvalho Chehab 	state->initialised = 0;
6929a0bf528SMauro Carvalho Chehab 	state->tuner_frequency = 0;
6939a0bf528SMauro Carvalho Chehab 	state->symbol_rate = 0;
6949a0bf528SMauro Carvalho Chehab 	state->fec_inner = 0;
6959a0bf528SMauro Carvalho Chehab 	state->errmode = STATUS_BER;
6969a0bf528SMauro Carvalho Chehab 
6979a0bf528SMauro Carvalho Chehab 	/* check if the demod is there */
6989a0bf528SMauro Carvalho Chehab 	stv0299_writeregI(state, 0x02, 0x30); /* standby off */
6999a0bf528SMauro Carvalho Chehab 	msleep(200);
7009a0bf528SMauro Carvalho Chehab 	id = stv0299_readreg(state, 0x00);
7019a0bf528SMauro Carvalho Chehab 
7029a0bf528SMauro Carvalho Chehab 	/* register 0x00 contains 0xa1 for STV0299 and STV0299B */
7039a0bf528SMauro Carvalho Chehab 	/* register 0x00 might contain 0x80 when returning from standby */
7049a0bf528SMauro Carvalho Chehab 	if (id != 0xa1 && id != 0x80) goto error;
7059a0bf528SMauro Carvalho Chehab 
7069a0bf528SMauro Carvalho Chehab 	/* create dvb_frontend */
7079a0bf528SMauro Carvalho Chehab 	memcpy(&state->frontend.ops, &stv0299_ops, sizeof(struct dvb_frontend_ops));
7089a0bf528SMauro Carvalho Chehab 	state->frontend.demodulator_priv = state;
7099a0bf528SMauro Carvalho Chehab 	return &state->frontend;
7109a0bf528SMauro Carvalho Chehab 
7119a0bf528SMauro Carvalho Chehab error:
7129a0bf528SMauro Carvalho Chehab 	kfree(state);
7139a0bf528SMauro Carvalho Chehab 	return NULL;
7149a0bf528SMauro Carvalho Chehab }
7159a0bf528SMauro Carvalho Chehab 
716bd336e63SMax Kellermann static const struct dvb_frontend_ops stv0299_ops = {
7179a0bf528SMauro Carvalho Chehab 	.delsys = { SYS_DVBS },
7189a0bf528SMauro Carvalho Chehab 	.info = {
7199a0bf528SMauro Carvalho Chehab 		.name			= "ST STV0299 DVB-S",
7209a0bf528SMauro Carvalho Chehab 		.frequency_min		= 950000,
7219a0bf528SMauro Carvalho Chehab 		.frequency_max		= 2150000,
7229a0bf528SMauro Carvalho Chehab 		.frequency_stepsize	= 125,	 /* kHz for QPSK frontends */
7239a0bf528SMauro Carvalho Chehab 		.frequency_tolerance	= 0,
7249a0bf528SMauro Carvalho Chehab 		.symbol_rate_min	= 1000000,
7259a0bf528SMauro Carvalho Chehab 		.symbol_rate_max	= 45000000,
7269a0bf528SMauro Carvalho Chehab 		.symbol_rate_tolerance	= 500,	/* ppm */
7279a0bf528SMauro Carvalho Chehab 		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
7289a0bf528SMauro Carvalho Chehab 		      FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
7299a0bf528SMauro Carvalho Chehab 		      FE_CAN_QPSK |
7309a0bf528SMauro Carvalho Chehab 		      FE_CAN_FEC_AUTO
7319a0bf528SMauro Carvalho Chehab 	},
7329a0bf528SMauro Carvalho Chehab 
7339a0bf528SMauro Carvalho Chehab 	.release = stv0299_release,
7349a0bf528SMauro Carvalho Chehab 
7359a0bf528SMauro Carvalho Chehab 	.init = stv0299_init,
7369a0bf528SMauro Carvalho Chehab 	.sleep = stv0299_sleep,
7379a0bf528SMauro Carvalho Chehab 	.write = stv0299_write,
7389a0bf528SMauro Carvalho Chehab 	.i2c_gate_ctrl = stv0299_i2c_gate_ctrl,
7399a0bf528SMauro Carvalho Chehab 
7409a0bf528SMauro Carvalho Chehab 	.set_frontend = stv0299_set_frontend,
7419a0bf528SMauro Carvalho Chehab 	.get_frontend = stv0299_get_frontend,
7429a0bf528SMauro Carvalho Chehab 	.get_tune_settings = stv0299_get_tune_settings,
7439a0bf528SMauro Carvalho Chehab 
7449a0bf528SMauro Carvalho Chehab 	.read_status = stv0299_read_status,
7459a0bf528SMauro Carvalho Chehab 	.read_ber = stv0299_read_ber,
7469a0bf528SMauro Carvalho Chehab 	.read_signal_strength = stv0299_read_signal_strength,
7479a0bf528SMauro Carvalho Chehab 	.read_snr = stv0299_read_snr,
7489a0bf528SMauro Carvalho Chehab 	.read_ucblocks = stv0299_read_ucblocks,
7499a0bf528SMauro Carvalho Chehab 
7509a0bf528SMauro Carvalho Chehab 	.diseqc_send_master_cmd = stv0299_send_diseqc_msg,
7519a0bf528SMauro Carvalho Chehab 	.diseqc_send_burst = stv0299_send_diseqc_burst,
7529a0bf528SMauro Carvalho Chehab 	.set_tone = stv0299_set_tone,
7539a0bf528SMauro Carvalho Chehab 	.set_voltage = stv0299_set_voltage,
7549a0bf528SMauro Carvalho Chehab 	.dishnetwork_send_legacy_command = stv0299_send_legacy_dish_cmd,
7559a0bf528SMauro Carvalho Chehab };
7569a0bf528SMauro Carvalho Chehab 
7579a0bf528SMauro Carvalho Chehab module_param(debug_legacy_dish_switch, int, 0444);
7589a0bf528SMauro Carvalho Chehab MODULE_PARM_DESC(debug_legacy_dish_switch, "Enable timing analysis for Dish Network legacy switches");
7599a0bf528SMauro Carvalho Chehab 
7609a0bf528SMauro Carvalho Chehab module_param(debug, int, 0644);
7619a0bf528SMauro Carvalho Chehab MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
7629a0bf528SMauro Carvalho Chehab 
7639a0bf528SMauro Carvalho Chehab MODULE_DESCRIPTION("ST STV0299 DVB Demodulator driver");
7644bd69e7bSMauro Carvalho Chehab MODULE_AUTHOR("Ralph Metzler, Holger Waechtler, Peter Schildmann, Felix Domke, Andreas Oberritter, Andrew de Quincey, Kenneth Aafly");
7659a0bf528SMauro Carvalho Chehab MODULE_LICENSE("GPL");
7669a0bf528SMauro Carvalho Chehab 
7679a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(stv0299_attach);
768