xref: /linux/drivers/media/dvb-frontends/tda18271c2dd.c (revision 8393796dfa4cf5dffcceec464c7789bec3a2f471)
19a0bf528SMauro Carvalho Chehab /*
29a0bf528SMauro Carvalho Chehab  * tda18271c2dd: Driver for the TDA18271C2 tuner
39a0bf528SMauro Carvalho Chehab  *
49a0bf528SMauro Carvalho Chehab  * Copyright (C) 2010 Digital Devices GmbH
59a0bf528SMauro Carvalho Chehab  *
69a0bf528SMauro Carvalho Chehab  *
79a0bf528SMauro Carvalho Chehab  * This program is free software; you can redistribute it and/or
89a0bf528SMauro Carvalho Chehab  * modify it under the terms of the GNU General Public License
99a0bf528SMauro Carvalho Chehab  * version 2 only, as published by the Free Software Foundation.
109a0bf528SMauro Carvalho Chehab  *
119a0bf528SMauro Carvalho Chehab  *
129a0bf528SMauro Carvalho Chehab  * This program is distributed in the hope that it will be useful,
139a0bf528SMauro Carvalho Chehab  * but WITHOUT ANY WARRANTY; without even the implied warranty of
149a0bf528SMauro Carvalho Chehab  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
159a0bf528SMauro Carvalho Chehab  * GNU General Public License for more details.
169a0bf528SMauro Carvalho Chehab  *
179a0bf528SMauro Carvalho Chehab  *
189a0bf528SMauro Carvalho Chehab  * You should have received a copy of the GNU General Public License
199a0bf528SMauro Carvalho Chehab  * along with this program; if not, write to the Free Software
209a0bf528SMauro Carvalho Chehab  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
219a0bf528SMauro Carvalho Chehab  * 02110-1301, USA
229a0bf528SMauro Carvalho Chehab  * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
239a0bf528SMauro Carvalho Chehab  */
249a0bf528SMauro Carvalho Chehab 
259a0bf528SMauro Carvalho Chehab #include <linux/kernel.h>
269a0bf528SMauro Carvalho Chehab #include <linux/module.h>
279a0bf528SMauro Carvalho Chehab #include <linux/moduleparam.h>
289a0bf528SMauro Carvalho Chehab #include <linux/init.h>
299a0bf528SMauro Carvalho Chehab #include <linux/delay.h>
309a0bf528SMauro Carvalho Chehab #include <linux/firmware.h>
319a0bf528SMauro Carvalho Chehab #include <linux/i2c.h>
329a0bf528SMauro Carvalho Chehab #include <asm/div64.h>
339a0bf528SMauro Carvalho Chehab 
349a0bf528SMauro Carvalho Chehab #include "dvb_frontend.h"
354e373217SMauro Carvalho Chehab #include "tda18271c2dd.h"
369a0bf528SMauro Carvalho Chehab 
37*8393796dSMauro Carvalho Chehab /* Max transfer size done by I2C transfer functions */
38*8393796dSMauro Carvalho Chehab #define MAX_XFER_SIZE  64
39*8393796dSMauro Carvalho Chehab 
409a0bf528SMauro Carvalho Chehab struct SStandardParam {
419a0bf528SMauro Carvalho Chehab 	s32   m_IFFrequency;
429a0bf528SMauro Carvalho Chehab 	u32   m_BandWidth;
439a0bf528SMauro Carvalho Chehab 	u8    m_EP3_4_0;
449a0bf528SMauro Carvalho Chehab 	u8    m_EB22;
459a0bf528SMauro Carvalho Chehab };
469a0bf528SMauro Carvalho Chehab 
479a0bf528SMauro Carvalho Chehab struct SMap {
489a0bf528SMauro Carvalho Chehab 	u32   m_Frequency;
499a0bf528SMauro Carvalho Chehab 	u8    m_Param;
509a0bf528SMauro Carvalho Chehab };
519a0bf528SMauro Carvalho Chehab 
529a0bf528SMauro Carvalho Chehab struct SMapI {
539a0bf528SMauro Carvalho Chehab 	u32   m_Frequency;
549a0bf528SMauro Carvalho Chehab 	s32    m_Param;
559a0bf528SMauro Carvalho Chehab };
569a0bf528SMauro Carvalho Chehab 
579a0bf528SMauro Carvalho Chehab struct SMap2 {
589a0bf528SMauro Carvalho Chehab 	u32   m_Frequency;
599a0bf528SMauro Carvalho Chehab 	u8    m_Param1;
609a0bf528SMauro Carvalho Chehab 	u8    m_Param2;
619a0bf528SMauro Carvalho Chehab };
629a0bf528SMauro Carvalho Chehab 
639a0bf528SMauro Carvalho Chehab struct SRFBandMap {
649a0bf528SMauro Carvalho Chehab 	u32   m_RF_max;
659a0bf528SMauro Carvalho Chehab 	u32   m_RF1_Default;
669a0bf528SMauro Carvalho Chehab 	u32   m_RF2_Default;
679a0bf528SMauro Carvalho Chehab 	u32   m_RF3_Default;
689a0bf528SMauro Carvalho Chehab };
699a0bf528SMauro Carvalho Chehab 
709a0bf528SMauro Carvalho Chehab enum ERegister {
719a0bf528SMauro Carvalho Chehab 	ID = 0,
729a0bf528SMauro Carvalho Chehab 	TM,
739a0bf528SMauro Carvalho Chehab 	PL,
749a0bf528SMauro Carvalho Chehab 	EP1, EP2, EP3, EP4, EP5,
759a0bf528SMauro Carvalho Chehab 	CPD, CD1, CD2, CD3,
769a0bf528SMauro Carvalho Chehab 	MPD, MD1, MD2, MD3,
779a0bf528SMauro Carvalho Chehab 	EB1, EB2, EB3, EB4, EB5, EB6, EB7, EB8, EB9, EB10,
789a0bf528SMauro Carvalho Chehab 	EB11, EB12, EB13, EB14, EB15, EB16, EB17, EB18, EB19, EB20,
799a0bf528SMauro Carvalho Chehab 	EB21, EB22, EB23,
809a0bf528SMauro Carvalho Chehab 	NUM_REGS
819a0bf528SMauro Carvalho Chehab };
829a0bf528SMauro Carvalho Chehab 
839a0bf528SMauro Carvalho Chehab struct tda_state {
849a0bf528SMauro Carvalho Chehab 	struct i2c_adapter *i2c;
859a0bf528SMauro Carvalho Chehab 	u8 adr;
869a0bf528SMauro Carvalho Chehab 
879a0bf528SMauro Carvalho Chehab 	u32   m_Frequency;
889a0bf528SMauro Carvalho Chehab 	u32   IF;
899a0bf528SMauro Carvalho Chehab 
909a0bf528SMauro Carvalho Chehab 	u8    m_IFLevelAnalog;
919a0bf528SMauro Carvalho Chehab 	u8    m_IFLevelDigital;
929a0bf528SMauro Carvalho Chehab 	u8    m_IFLevelDVBC;
939a0bf528SMauro Carvalho Chehab 	u8    m_IFLevelDVBT;
949a0bf528SMauro Carvalho Chehab 
959a0bf528SMauro Carvalho Chehab 	u8    m_EP4;
969a0bf528SMauro Carvalho Chehab 	u8    m_EP3_Standby;
979a0bf528SMauro Carvalho Chehab 
989a0bf528SMauro Carvalho Chehab 	bool  m_bMaster;
999a0bf528SMauro Carvalho Chehab 
1009a0bf528SMauro Carvalho Chehab 	s32   m_SettlingTime;
1019a0bf528SMauro Carvalho Chehab 
1029a0bf528SMauro Carvalho Chehab 	u8    m_Regs[NUM_REGS];
1039a0bf528SMauro Carvalho Chehab 
1049a0bf528SMauro Carvalho Chehab 	/* Tracking filter settings for band 0..6 */
1059a0bf528SMauro Carvalho Chehab 	u32   m_RF1[7];
1069a0bf528SMauro Carvalho Chehab 	s32   m_RF_A1[7];
1079a0bf528SMauro Carvalho Chehab 	s32   m_RF_B1[7];
1089a0bf528SMauro Carvalho Chehab 	u32   m_RF2[7];
1099a0bf528SMauro Carvalho Chehab 	s32   m_RF_A2[7];
1109a0bf528SMauro Carvalho Chehab 	s32   m_RF_B2[7];
1119a0bf528SMauro Carvalho Chehab 	u32   m_RF3[7];
1129a0bf528SMauro Carvalho Chehab 
1139a0bf528SMauro Carvalho Chehab 	u8    m_TMValue_RFCal;    /* Calibration temperatur */
1149a0bf528SMauro Carvalho Chehab 
1159a0bf528SMauro Carvalho Chehab 	bool  m_bFMInput;         /* true to use Pin 8 for FM Radio */
1169a0bf528SMauro Carvalho Chehab 
1179a0bf528SMauro Carvalho Chehab };
1189a0bf528SMauro Carvalho Chehab 
1199a0bf528SMauro Carvalho Chehab static int PowerScan(struct tda_state *state,
1209a0bf528SMauro Carvalho Chehab 		     u8 RFBand, u32 RF_in,
1219a0bf528SMauro Carvalho Chehab 		     u32 *pRF_Out, bool *pbcal);
1229a0bf528SMauro Carvalho Chehab 
1239a0bf528SMauro Carvalho Chehab static int i2c_readn(struct i2c_adapter *adapter, u8 adr, u8 *data, int len)
1249a0bf528SMauro Carvalho Chehab {
1259a0bf528SMauro Carvalho Chehab 	struct i2c_msg msgs[1] = {{.addr = adr,  .flags = I2C_M_RD,
1269a0bf528SMauro Carvalho Chehab 				   .buf  = data, .len   = len} };
1279a0bf528SMauro Carvalho Chehab 	return (i2c_transfer(adapter, msgs, 1) == 1) ? 0 : -1;
1289a0bf528SMauro Carvalho Chehab }
1299a0bf528SMauro Carvalho Chehab 
1309a0bf528SMauro Carvalho Chehab static int i2c_write(struct i2c_adapter *adap, u8 adr, u8 *data, int len)
1319a0bf528SMauro Carvalho Chehab {
1329a0bf528SMauro Carvalho Chehab 	struct i2c_msg msg = {.addr = adr, .flags = 0,
1339a0bf528SMauro Carvalho Chehab 			      .buf = data, .len = len};
1349a0bf528SMauro Carvalho Chehab 
1359a0bf528SMauro Carvalho Chehab 	if (i2c_transfer(adap, &msg, 1) != 1) {
1369a0bf528SMauro Carvalho Chehab 		printk(KERN_ERR "tda18271c2dd: i2c write error at addr %i\n", adr);
1379a0bf528SMauro Carvalho Chehab 		return -1;
1389a0bf528SMauro Carvalho Chehab 	}
1399a0bf528SMauro Carvalho Chehab 	return 0;
1409a0bf528SMauro Carvalho Chehab }
1419a0bf528SMauro Carvalho Chehab 
1429a0bf528SMauro Carvalho Chehab static int WriteRegs(struct tda_state *state,
1439a0bf528SMauro Carvalho Chehab 		     u8 SubAddr, u8 *Regs, u16 nRegs)
1449a0bf528SMauro Carvalho Chehab {
145*8393796dSMauro Carvalho Chehab 	u8 data[MAX_XFER_SIZE];
146*8393796dSMauro Carvalho Chehab 
147*8393796dSMauro Carvalho Chehab 	if (1 + nRegs > sizeof(data)) {
148*8393796dSMauro Carvalho Chehab 		printk(KERN_WARNING
149*8393796dSMauro Carvalho Chehab 		       "%s: i2c wr: len=%d is too big!\n",
150*8393796dSMauro Carvalho Chehab 		       KBUILD_MODNAME, nRegs);
151*8393796dSMauro Carvalho Chehab 		return -EINVAL;
152*8393796dSMauro Carvalho Chehab 	}
1539a0bf528SMauro Carvalho Chehab 
1549a0bf528SMauro Carvalho Chehab 	data[0] = SubAddr;
1559a0bf528SMauro Carvalho Chehab 	memcpy(data + 1, Regs, nRegs);
1569a0bf528SMauro Carvalho Chehab 	return i2c_write(state->i2c, state->adr, data, nRegs + 1);
1579a0bf528SMauro Carvalho Chehab }
1589a0bf528SMauro Carvalho Chehab 
1599a0bf528SMauro Carvalho Chehab static int WriteReg(struct tda_state *state, u8 SubAddr, u8 Reg)
1609a0bf528SMauro Carvalho Chehab {
1619a0bf528SMauro Carvalho Chehab 	u8 msg[2] = {SubAddr, Reg};
1629a0bf528SMauro Carvalho Chehab 
1639a0bf528SMauro Carvalho Chehab 	return i2c_write(state->i2c, state->adr, msg, 2);
1649a0bf528SMauro Carvalho Chehab }
1659a0bf528SMauro Carvalho Chehab 
1669a0bf528SMauro Carvalho Chehab static int Read(struct tda_state *state, u8 * Regs)
1679a0bf528SMauro Carvalho Chehab {
1689a0bf528SMauro Carvalho Chehab 	return i2c_readn(state->i2c, state->adr, Regs, 16);
1699a0bf528SMauro Carvalho Chehab }
1709a0bf528SMauro Carvalho Chehab 
1719a0bf528SMauro Carvalho Chehab static int ReadExtented(struct tda_state *state, u8 * Regs)
1729a0bf528SMauro Carvalho Chehab {
1739a0bf528SMauro Carvalho Chehab 	return i2c_readn(state->i2c, state->adr, Regs, NUM_REGS);
1749a0bf528SMauro Carvalho Chehab }
1759a0bf528SMauro Carvalho Chehab 
1769a0bf528SMauro Carvalho Chehab static int UpdateRegs(struct tda_state *state, u8 RegFrom, u8 RegTo)
1779a0bf528SMauro Carvalho Chehab {
1789a0bf528SMauro Carvalho Chehab 	return WriteRegs(state, RegFrom,
1799a0bf528SMauro Carvalho Chehab 			 &state->m_Regs[RegFrom], RegTo-RegFrom+1);
1809a0bf528SMauro Carvalho Chehab }
1819a0bf528SMauro Carvalho Chehab static int UpdateReg(struct tda_state *state, u8 Reg)
1829a0bf528SMauro Carvalho Chehab {
1839a0bf528SMauro Carvalho Chehab 	return WriteReg(state, Reg, state->m_Regs[Reg]);
1849a0bf528SMauro Carvalho Chehab }
1859a0bf528SMauro Carvalho Chehab 
1869a0bf528SMauro Carvalho Chehab #include "tda18271c2dd_maps.h"
1879a0bf528SMauro Carvalho Chehab 
1889a0bf528SMauro Carvalho Chehab static void reset(struct tda_state *state)
1899a0bf528SMauro Carvalho Chehab {
1909a0bf528SMauro Carvalho Chehab 	u32   ulIFLevelAnalog = 0;
1919a0bf528SMauro Carvalho Chehab 	u32   ulIFLevelDigital = 2;
1929a0bf528SMauro Carvalho Chehab 	u32   ulIFLevelDVBC = 7;
1939a0bf528SMauro Carvalho Chehab 	u32   ulIFLevelDVBT = 6;
1949a0bf528SMauro Carvalho Chehab 	u32   ulXTOut = 0;
1959a0bf528SMauro Carvalho Chehab 	u32   ulStandbyMode = 0x06;    /* Send in stdb, but leave osc on */
1969a0bf528SMauro Carvalho Chehab 	u32   ulSlave = 0;
1979a0bf528SMauro Carvalho Chehab 	u32   ulFMInput = 0;
1989a0bf528SMauro Carvalho Chehab 	u32   ulSettlingTime = 100;
1999a0bf528SMauro Carvalho Chehab 
2009a0bf528SMauro Carvalho Chehab 	state->m_Frequency         = 0;
2019a0bf528SMauro Carvalho Chehab 	state->m_SettlingTime = 100;
2029a0bf528SMauro Carvalho Chehab 	state->m_IFLevelAnalog = (ulIFLevelAnalog & 0x07) << 2;
2039a0bf528SMauro Carvalho Chehab 	state->m_IFLevelDigital = (ulIFLevelDigital & 0x07) << 2;
2049a0bf528SMauro Carvalho Chehab 	state->m_IFLevelDVBC = (ulIFLevelDVBC & 0x07) << 2;
2059a0bf528SMauro Carvalho Chehab 	state->m_IFLevelDVBT = (ulIFLevelDVBT & 0x07) << 2;
2069a0bf528SMauro Carvalho Chehab 
2079a0bf528SMauro Carvalho Chehab 	state->m_EP4 = 0x20;
2089a0bf528SMauro Carvalho Chehab 	if (ulXTOut != 0)
2099a0bf528SMauro Carvalho Chehab 		state->m_EP4 |= 0x40;
2109a0bf528SMauro Carvalho Chehab 
2119a0bf528SMauro Carvalho Chehab 	state->m_EP3_Standby = ((ulStandbyMode & 0x07) << 5) | 0x0F;
2129a0bf528SMauro Carvalho Chehab 	state->m_bMaster = (ulSlave == 0);
2139a0bf528SMauro Carvalho Chehab 
2149a0bf528SMauro Carvalho Chehab 	state->m_SettlingTime = ulSettlingTime;
2159a0bf528SMauro Carvalho Chehab 
2169a0bf528SMauro Carvalho Chehab 	state->m_bFMInput = (ulFMInput == 2);
2179a0bf528SMauro Carvalho Chehab }
2189a0bf528SMauro Carvalho Chehab 
2199a0bf528SMauro Carvalho Chehab static bool SearchMap1(struct SMap Map[],
2209a0bf528SMauro Carvalho Chehab 		       u32 Frequency, u8 *pParam)
2219a0bf528SMauro Carvalho Chehab {
2229a0bf528SMauro Carvalho Chehab 	int i = 0;
2239a0bf528SMauro Carvalho Chehab 
2249a0bf528SMauro Carvalho Chehab 	while ((Map[i].m_Frequency != 0) && (Frequency > Map[i].m_Frequency))
2259a0bf528SMauro Carvalho Chehab 		i += 1;
2269a0bf528SMauro Carvalho Chehab 	if (Map[i].m_Frequency == 0)
2279a0bf528SMauro Carvalho Chehab 		return false;
2289a0bf528SMauro Carvalho Chehab 	*pParam = Map[i].m_Param;
2299a0bf528SMauro Carvalho Chehab 	return true;
2309a0bf528SMauro Carvalho Chehab }
2319a0bf528SMauro Carvalho Chehab 
2329a0bf528SMauro Carvalho Chehab static bool SearchMap2(struct SMapI Map[],
2339a0bf528SMauro Carvalho Chehab 		       u32 Frequency, s32 *pParam)
2349a0bf528SMauro Carvalho Chehab {
2359a0bf528SMauro Carvalho Chehab 	int i = 0;
2369a0bf528SMauro Carvalho Chehab 
2379a0bf528SMauro Carvalho Chehab 	while ((Map[i].m_Frequency != 0) &&
2389a0bf528SMauro Carvalho Chehab 	       (Frequency > Map[i].m_Frequency))
2399a0bf528SMauro Carvalho Chehab 		i += 1;
2409a0bf528SMauro Carvalho Chehab 	if (Map[i].m_Frequency == 0)
2419a0bf528SMauro Carvalho Chehab 		return false;
2429a0bf528SMauro Carvalho Chehab 	*pParam = Map[i].m_Param;
2439a0bf528SMauro Carvalho Chehab 	return true;
2449a0bf528SMauro Carvalho Chehab }
2459a0bf528SMauro Carvalho Chehab 
2469a0bf528SMauro Carvalho Chehab static bool SearchMap3(struct SMap2 Map[], u32 Frequency,
2479a0bf528SMauro Carvalho Chehab 		       u8 *pParam1, u8 *pParam2)
2489a0bf528SMauro Carvalho Chehab {
2499a0bf528SMauro Carvalho Chehab 	int i = 0;
2509a0bf528SMauro Carvalho Chehab 
2519a0bf528SMauro Carvalho Chehab 	while ((Map[i].m_Frequency != 0) &&
2529a0bf528SMauro Carvalho Chehab 	       (Frequency > Map[i].m_Frequency))
2539a0bf528SMauro Carvalho Chehab 		i += 1;
2549a0bf528SMauro Carvalho Chehab 	if (Map[i].m_Frequency == 0)
2559a0bf528SMauro Carvalho Chehab 		return false;
2569a0bf528SMauro Carvalho Chehab 	*pParam1 = Map[i].m_Param1;
2579a0bf528SMauro Carvalho Chehab 	*pParam2 = Map[i].m_Param2;
2589a0bf528SMauro Carvalho Chehab 	return true;
2599a0bf528SMauro Carvalho Chehab }
2609a0bf528SMauro Carvalho Chehab 
2619a0bf528SMauro Carvalho Chehab static bool SearchMap4(struct SRFBandMap Map[],
2629a0bf528SMauro Carvalho Chehab 		       u32 Frequency, u8 *pRFBand)
2639a0bf528SMauro Carvalho Chehab {
2649a0bf528SMauro Carvalho Chehab 	int i = 0;
2659a0bf528SMauro Carvalho Chehab 
2669a0bf528SMauro Carvalho Chehab 	while (i < 7 && (Frequency > Map[i].m_RF_max))
2679a0bf528SMauro Carvalho Chehab 		i += 1;
2689a0bf528SMauro Carvalho Chehab 	if (i == 7)
2699a0bf528SMauro Carvalho Chehab 		return false;
2709a0bf528SMauro Carvalho Chehab 	*pRFBand = i;
2719a0bf528SMauro Carvalho Chehab 	return true;
2729a0bf528SMauro Carvalho Chehab }
2739a0bf528SMauro Carvalho Chehab 
2749a0bf528SMauro Carvalho Chehab static int ThermometerRead(struct tda_state *state, u8 *pTM_Value)
2759a0bf528SMauro Carvalho Chehab {
2769a0bf528SMauro Carvalho Chehab 	int status = 0;
2779a0bf528SMauro Carvalho Chehab 
2789a0bf528SMauro Carvalho Chehab 	do {
2799a0bf528SMauro Carvalho Chehab 		u8 Regs[16];
2809a0bf528SMauro Carvalho Chehab 		state->m_Regs[TM] |= 0x10;
2819a0bf528SMauro Carvalho Chehab 		status = UpdateReg(state, TM);
2829a0bf528SMauro Carvalho Chehab 		if (status < 0)
2839a0bf528SMauro Carvalho Chehab 			break;
2849a0bf528SMauro Carvalho Chehab 		status = Read(state, Regs);
2859a0bf528SMauro Carvalho Chehab 		if (status < 0)
2869a0bf528SMauro Carvalho Chehab 			break;
2879a0bf528SMauro Carvalho Chehab 		if (((Regs[TM] & 0x0F) == 0 && (Regs[TM] & 0x20) == 0x20) ||
2889a0bf528SMauro Carvalho Chehab 		    ((Regs[TM] & 0x0F) == 8 && (Regs[TM] & 0x20) == 0x00)) {
2899a0bf528SMauro Carvalho Chehab 			state->m_Regs[TM] ^= 0x20;
2909a0bf528SMauro Carvalho Chehab 			status = UpdateReg(state, TM);
2919a0bf528SMauro Carvalho Chehab 			if (status < 0)
2929a0bf528SMauro Carvalho Chehab 				break;
2939a0bf528SMauro Carvalho Chehab 			msleep(10);
2949a0bf528SMauro Carvalho Chehab 			status = Read(state, Regs);
2959a0bf528SMauro Carvalho Chehab 			if (status < 0)
2969a0bf528SMauro Carvalho Chehab 				break;
2979a0bf528SMauro Carvalho Chehab 		}
2989a0bf528SMauro Carvalho Chehab 		*pTM_Value = (Regs[TM] & 0x20)
2999a0bf528SMauro Carvalho Chehab 				? m_Thermometer_Map_2[Regs[TM] & 0x0F]
3009a0bf528SMauro Carvalho Chehab 				: m_Thermometer_Map_1[Regs[TM] & 0x0F] ;
3019a0bf528SMauro Carvalho Chehab 		state->m_Regs[TM] &= ~0x10;        /* Thermometer off */
3029a0bf528SMauro Carvalho Chehab 		status = UpdateReg(state, TM);
3039a0bf528SMauro Carvalho Chehab 		if (status < 0)
3049a0bf528SMauro Carvalho Chehab 			break;
3059a0bf528SMauro Carvalho Chehab 		state->m_Regs[EP4] &= ~0x03;       /* CAL_mode = 0 ????????? */
3069a0bf528SMauro Carvalho Chehab 		status = UpdateReg(state, EP4);
3079a0bf528SMauro Carvalho Chehab 		if (status < 0)
3089a0bf528SMauro Carvalho Chehab 			break;
3099a0bf528SMauro Carvalho Chehab 	} while (0);
3109a0bf528SMauro Carvalho Chehab 
3119a0bf528SMauro Carvalho Chehab 	return status;
3129a0bf528SMauro Carvalho Chehab }
3139a0bf528SMauro Carvalho Chehab 
3149a0bf528SMauro Carvalho Chehab static int StandBy(struct tda_state *state)
3159a0bf528SMauro Carvalho Chehab {
3169a0bf528SMauro Carvalho Chehab 	int status = 0;
3179a0bf528SMauro Carvalho Chehab 	do {
3189a0bf528SMauro Carvalho Chehab 		state->m_Regs[EB12] &= ~0x20;  /* PD_AGC1_Det = 0 */
3199a0bf528SMauro Carvalho Chehab 		status = UpdateReg(state, EB12);
3209a0bf528SMauro Carvalho Chehab 		if (status < 0)
3219a0bf528SMauro Carvalho Chehab 			break;
3229a0bf528SMauro Carvalho Chehab 		state->m_Regs[EB18] &= ~0x83;  /* AGC1_loop_off = 0, AGC1_Gain = 6 dB */
3239a0bf528SMauro Carvalho Chehab 		status = UpdateReg(state, EB18);
3249a0bf528SMauro Carvalho Chehab 		if (status < 0)
3259a0bf528SMauro Carvalho Chehab 			break;
3269a0bf528SMauro Carvalho Chehab 		state->m_Regs[EB21] |= 0x03; /* AGC2_Gain = -6 dB */
3279a0bf528SMauro Carvalho Chehab 		state->m_Regs[EP3] = state->m_EP3_Standby;
3289a0bf528SMauro Carvalho Chehab 		status = UpdateReg(state, EP3);
3299a0bf528SMauro Carvalho Chehab 		if (status < 0)
3309a0bf528SMauro Carvalho Chehab 			break;
3319a0bf528SMauro Carvalho Chehab 		state->m_Regs[EB23] &= ~0x06; /* ForceLP_Fc2_En = 0, LP_Fc[2] = 0 */
3329a0bf528SMauro Carvalho Chehab 		status = UpdateRegs(state, EB21, EB23);
3339a0bf528SMauro Carvalho Chehab 		if (status < 0)
3349a0bf528SMauro Carvalho Chehab 			break;
3359a0bf528SMauro Carvalho Chehab 	} while (0);
3369a0bf528SMauro Carvalho Chehab 	return status;
3379a0bf528SMauro Carvalho Chehab }
3389a0bf528SMauro Carvalho Chehab 
3399a0bf528SMauro Carvalho Chehab static int CalcMainPLL(struct tda_state *state, u32 freq)
3409a0bf528SMauro Carvalho Chehab {
3419a0bf528SMauro Carvalho Chehab 
3429a0bf528SMauro Carvalho Chehab 	u8  PostDiv;
3439a0bf528SMauro Carvalho Chehab 	u8  Div;
3449a0bf528SMauro Carvalho Chehab 	u64 OscFreq;
3459a0bf528SMauro Carvalho Chehab 	u32 MainDiv;
3469a0bf528SMauro Carvalho Chehab 
3479a0bf528SMauro Carvalho Chehab 	if (!SearchMap3(m_Main_PLL_Map, freq, &PostDiv, &Div))
3489a0bf528SMauro Carvalho Chehab 		return -EINVAL;
3499a0bf528SMauro Carvalho Chehab 
3509a0bf528SMauro Carvalho Chehab 	OscFreq = (u64) freq * (u64) Div;
3519a0bf528SMauro Carvalho Chehab 	OscFreq *= (u64) 16384;
3529a0bf528SMauro Carvalho Chehab 	do_div(OscFreq, (u64)16000000);
3539a0bf528SMauro Carvalho Chehab 	MainDiv = OscFreq;
3549a0bf528SMauro Carvalho Chehab 
3559a0bf528SMauro Carvalho Chehab 	state->m_Regs[MPD] = PostDiv & 0x77;
3569a0bf528SMauro Carvalho Chehab 	state->m_Regs[MD1] = ((MainDiv >> 16) & 0x7F);
3579a0bf528SMauro Carvalho Chehab 	state->m_Regs[MD2] = ((MainDiv >>  8) & 0xFF);
3589a0bf528SMauro Carvalho Chehab 	state->m_Regs[MD3] = (MainDiv & 0xFF);
3599a0bf528SMauro Carvalho Chehab 
3609a0bf528SMauro Carvalho Chehab 	return UpdateRegs(state, MPD, MD3);
3619a0bf528SMauro Carvalho Chehab }
3629a0bf528SMauro Carvalho Chehab 
3639a0bf528SMauro Carvalho Chehab static int CalcCalPLL(struct tda_state *state, u32 freq)
3649a0bf528SMauro Carvalho Chehab {
3659a0bf528SMauro Carvalho Chehab 	u8 PostDiv;
3669a0bf528SMauro Carvalho Chehab 	u8 Div;
3679a0bf528SMauro Carvalho Chehab 	u64 OscFreq;
3689a0bf528SMauro Carvalho Chehab 	u32 CalDiv;
3699a0bf528SMauro Carvalho Chehab 
3709a0bf528SMauro Carvalho Chehab 	if (!SearchMap3(m_Cal_PLL_Map, freq, &PostDiv, &Div))
3719a0bf528SMauro Carvalho Chehab 		return -EINVAL;
3729a0bf528SMauro Carvalho Chehab 
3739a0bf528SMauro Carvalho Chehab 	OscFreq = (u64)freq * (u64)Div;
3749a0bf528SMauro Carvalho Chehab 	/* CalDiv = u32( OscFreq * 16384 / 16000000 ); */
3759a0bf528SMauro Carvalho Chehab 	OscFreq *= (u64)16384;
3769a0bf528SMauro Carvalho Chehab 	do_div(OscFreq, (u64)16000000);
3779a0bf528SMauro Carvalho Chehab 	CalDiv = OscFreq;
3789a0bf528SMauro Carvalho Chehab 
3799a0bf528SMauro Carvalho Chehab 	state->m_Regs[CPD] = PostDiv;
3809a0bf528SMauro Carvalho Chehab 	state->m_Regs[CD1] = ((CalDiv >> 16) & 0xFF);
3819a0bf528SMauro Carvalho Chehab 	state->m_Regs[CD2] = ((CalDiv >>  8) & 0xFF);
3829a0bf528SMauro Carvalho Chehab 	state->m_Regs[CD3] = (CalDiv & 0xFF);
3839a0bf528SMauro Carvalho Chehab 
3849a0bf528SMauro Carvalho Chehab 	return UpdateRegs(state, CPD, CD3);
3859a0bf528SMauro Carvalho Chehab }
3869a0bf528SMauro Carvalho Chehab 
3879a0bf528SMauro Carvalho Chehab static int CalibrateRF(struct tda_state *state,
3889a0bf528SMauro Carvalho Chehab 		       u8 RFBand, u32 freq, s32 *pCprog)
3899a0bf528SMauro Carvalho Chehab {
3909a0bf528SMauro Carvalho Chehab 	int status = 0;
3919a0bf528SMauro Carvalho Chehab 	u8 Regs[NUM_REGS];
3929a0bf528SMauro Carvalho Chehab 	do {
3939a0bf528SMauro Carvalho Chehab 		u8 BP_Filter = 0;
3949a0bf528SMauro Carvalho Chehab 		u8 GainTaper = 0;
3959a0bf528SMauro Carvalho Chehab 		u8 RFC_K = 0;
3969a0bf528SMauro Carvalho Chehab 		u8 RFC_M = 0;
3979a0bf528SMauro Carvalho Chehab 
3989a0bf528SMauro Carvalho Chehab 		state->m_Regs[EP4] &= ~0x03; /* CAL_mode = 0 */
3999a0bf528SMauro Carvalho Chehab 		status = UpdateReg(state, EP4);
4009a0bf528SMauro Carvalho Chehab 		if (status < 0)
4019a0bf528SMauro Carvalho Chehab 			break;
4029a0bf528SMauro Carvalho Chehab 		state->m_Regs[EB18] |= 0x03;  /* AGC1_Gain = 3 */
4039a0bf528SMauro Carvalho Chehab 		status = UpdateReg(state, EB18);
4049a0bf528SMauro Carvalho Chehab 		if (status < 0)
4059a0bf528SMauro Carvalho Chehab 			break;
4069a0bf528SMauro Carvalho Chehab 
4079a0bf528SMauro Carvalho Chehab 		/* Switching off LT (as datasheet says) causes calibration on C1 to fail */
4089a0bf528SMauro Carvalho Chehab 		/* (Readout of Cprog is allways 255) */
4099a0bf528SMauro Carvalho Chehab 		if (state->m_Regs[ID] != 0x83)    /* C1: ID == 83, C2: ID == 84 */
4109a0bf528SMauro Carvalho Chehab 			state->m_Regs[EP3] |= 0x40; /* SM_LT = 1 */
4119a0bf528SMauro Carvalho Chehab 
4129a0bf528SMauro Carvalho Chehab 		if (!(SearchMap1(m_BP_Filter_Map, freq, &BP_Filter) &&
4139a0bf528SMauro Carvalho Chehab 			SearchMap1(m_GainTaper_Map, freq, &GainTaper) &&
4149a0bf528SMauro Carvalho Chehab 			SearchMap3(m_KM_Map, freq, &RFC_K, &RFC_M)))
4159a0bf528SMauro Carvalho Chehab 			return -EINVAL;
4169a0bf528SMauro Carvalho Chehab 
4179a0bf528SMauro Carvalho Chehab 		state->m_Regs[EP1] = (state->m_Regs[EP1] & ~0x07) | BP_Filter;
4189a0bf528SMauro Carvalho Chehab 		state->m_Regs[EP2] = (RFBand << 5) | GainTaper;
4199a0bf528SMauro Carvalho Chehab 
4209a0bf528SMauro Carvalho Chehab 		state->m_Regs[EB13] = (state->m_Regs[EB13] & ~0x7C) | (RFC_K << 4) | (RFC_M << 2);
4219a0bf528SMauro Carvalho Chehab 
4229a0bf528SMauro Carvalho Chehab 		status = UpdateRegs(state, EP1, EP3);
4239a0bf528SMauro Carvalho Chehab 		if (status < 0)
4249a0bf528SMauro Carvalho Chehab 			break;
4259a0bf528SMauro Carvalho Chehab 		status = UpdateReg(state, EB13);
4269a0bf528SMauro Carvalho Chehab 		if (status < 0)
4279a0bf528SMauro Carvalho Chehab 			break;
4289a0bf528SMauro Carvalho Chehab 
4299a0bf528SMauro Carvalho Chehab 		state->m_Regs[EB4] |= 0x20;    /* LO_ForceSrce = 1 */
4309a0bf528SMauro Carvalho Chehab 		status = UpdateReg(state, EB4);
4319a0bf528SMauro Carvalho Chehab 		if (status < 0)
4329a0bf528SMauro Carvalho Chehab 			break;
4339a0bf528SMauro Carvalho Chehab 
4349a0bf528SMauro Carvalho Chehab 		state->m_Regs[EB7] |= 0x20;    /* CAL_ForceSrce = 1 */
4359a0bf528SMauro Carvalho Chehab 		status = UpdateReg(state, EB7);
4369a0bf528SMauro Carvalho Chehab 		if (status < 0)
4379a0bf528SMauro Carvalho Chehab 			break;
4389a0bf528SMauro Carvalho Chehab 
4399a0bf528SMauro Carvalho Chehab 		state->m_Regs[EB14] = 0; /* RFC_Cprog = 0 */
4409a0bf528SMauro Carvalho Chehab 		status = UpdateReg(state, EB14);
4419a0bf528SMauro Carvalho Chehab 		if (status < 0)
4429a0bf528SMauro Carvalho Chehab 			break;
4439a0bf528SMauro Carvalho Chehab 
4449a0bf528SMauro Carvalho Chehab 		state->m_Regs[EB20] &= ~0x20;  /* ForceLock = 0; */
4459a0bf528SMauro Carvalho Chehab 		status = UpdateReg(state, EB20);
4469a0bf528SMauro Carvalho Chehab 		if (status < 0)
4479a0bf528SMauro Carvalho Chehab 			break;
4489a0bf528SMauro Carvalho Chehab 
4499a0bf528SMauro Carvalho Chehab 		state->m_Regs[EP4] |= 0x03;  /* CAL_Mode = 3 */
4509a0bf528SMauro Carvalho Chehab 		status = UpdateRegs(state, EP4, EP5);
4519a0bf528SMauro Carvalho Chehab 		if (status < 0)
4529a0bf528SMauro Carvalho Chehab 			break;
4539a0bf528SMauro Carvalho Chehab 
4549a0bf528SMauro Carvalho Chehab 		status = CalcCalPLL(state, freq);
4559a0bf528SMauro Carvalho Chehab 		if (status < 0)
4569a0bf528SMauro Carvalho Chehab 			break;
4579a0bf528SMauro Carvalho Chehab 		status = CalcMainPLL(state, freq + 1000000);
4589a0bf528SMauro Carvalho Chehab 		if (status < 0)
4599a0bf528SMauro Carvalho Chehab 			break;
4609a0bf528SMauro Carvalho Chehab 
4619a0bf528SMauro Carvalho Chehab 		msleep(5);
4629a0bf528SMauro Carvalho Chehab 		status = UpdateReg(state, EP2);
4639a0bf528SMauro Carvalho Chehab 		if (status < 0)
4649a0bf528SMauro Carvalho Chehab 			break;
4659a0bf528SMauro Carvalho Chehab 		status = UpdateReg(state, EP1);
4669a0bf528SMauro Carvalho Chehab 		if (status < 0)
4679a0bf528SMauro Carvalho Chehab 			break;
4689a0bf528SMauro Carvalho Chehab 		status = UpdateReg(state, EP2);
4699a0bf528SMauro Carvalho Chehab 		if (status < 0)
4709a0bf528SMauro Carvalho Chehab 			break;
4719a0bf528SMauro Carvalho Chehab 		status = UpdateReg(state, EP1);
4729a0bf528SMauro Carvalho Chehab 		if (status < 0)
4739a0bf528SMauro Carvalho Chehab 			break;
4749a0bf528SMauro Carvalho Chehab 
4759a0bf528SMauro Carvalho Chehab 		state->m_Regs[EB4] &= ~0x20;    /* LO_ForceSrce = 0 */
4769a0bf528SMauro Carvalho Chehab 		status = UpdateReg(state, EB4);
4779a0bf528SMauro Carvalho Chehab 		if (status < 0)
4789a0bf528SMauro Carvalho Chehab 			break;
4799a0bf528SMauro Carvalho Chehab 
4809a0bf528SMauro Carvalho Chehab 		state->m_Regs[EB7] &= ~0x20;    /* CAL_ForceSrce = 0 */
4819a0bf528SMauro Carvalho Chehab 		status = UpdateReg(state, EB7);
4829a0bf528SMauro Carvalho Chehab 		if (status < 0)
4839a0bf528SMauro Carvalho Chehab 			break;
4849a0bf528SMauro Carvalho Chehab 		msleep(10);
4859a0bf528SMauro Carvalho Chehab 
4869a0bf528SMauro Carvalho Chehab 		state->m_Regs[EB20] |= 0x20;  /* ForceLock = 1; */
4879a0bf528SMauro Carvalho Chehab 		status = UpdateReg(state, EB20);
4889a0bf528SMauro Carvalho Chehab 		if (status < 0)
4899a0bf528SMauro Carvalho Chehab 			break;
4909a0bf528SMauro Carvalho Chehab 		msleep(60);
4919a0bf528SMauro Carvalho Chehab 
4929a0bf528SMauro Carvalho Chehab 		state->m_Regs[EP4] &= ~0x03;  /* CAL_Mode = 0 */
4939a0bf528SMauro Carvalho Chehab 		state->m_Regs[EP3] &= ~0x40; /* SM_LT = 0 */
4949a0bf528SMauro Carvalho Chehab 		state->m_Regs[EB18] &= ~0x03;  /* AGC1_Gain = 0 */
4959a0bf528SMauro Carvalho Chehab 		status = UpdateReg(state, EB18);
4969a0bf528SMauro Carvalho Chehab 		if (status < 0)
4979a0bf528SMauro Carvalho Chehab 			break;
4989a0bf528SMauro Carvalho Chehab 		status = UpdateRegs(state, EP3, EP4);
4999a0bf528SMauro Carvalho Chehab 		if (status < 0)
5009a0bf528SMauro Carvalho Chehab 			break;
5019a0bf528SMauro Carvalho Chehab 		status = UpdateReg(state, EP1);
5029a0bf528SMauro Carvalho Chehab 		if (status < 0)
5039a0bf528SMauro Carvalho Chehab 			break;
5049a0bf528SMauro Carvalho Chehab 
5059a0bf528SMauro Carvalho Chehab 		status = ReadExtented(state, Regs);
5069a0bf528SMauro Carvalho Chehab 		if (status < 0)
5079a0bf528SMauro Carvalho Chehab 			break;
5089a0bf528SMauro Carvalho Chehab 
5099a0bf528SMauro Carvalho Chehab 		*pCprog = Regs[EB14];
5109a0bf528SMauro Carvalho Chehab 
5119a0bf528SMauro Carvalho Chehab 	} while (0);
5129a0bf528SMauro Carvalho Chehab 	return status;
5139a0bf528SMauro Carvalho Chehab }
5149a0bf528SMauro Carvalho Chehab 
5159a0bf528SMauro Carvalho Chehab static int RFTrackingFiltersInit(struct tda_state *state,
5169a0bf528SMauro Carvalho Chehab 				 u8 RFBand)
5179a0bf528SMauro Carvalho Chehab {
5189a0bf528SMauro Carvalho Chehab 	int status = 0;
5199a0bf528SMauro Carvalho Chehab 
5209a0bf528SMauro Carvalho Chehab 	u32   RF1 = m_RF_Band_Map[RFBand].m_RF1_Default;
5219a0bf528SMauro Carvalho Chehab 	u32   RF2 = m_RF_Band_Map[RFBand].m_RF2_Default;
5229a0bf528SMauro Carvalho Chehab 	u32   RF3 = m_RF_Band_Map[RFBand].m_RF3_Default;
5239a0bf528SMauro Carvalho Chehab 	bool    bcal = false;
5249a0bf528SMauro Carvalho Chehab 
5259a0bf528SMauro Carvalho Chehab 	s32    Cprog_cal1 = 0;
5269a0bf528SMauro Carvalho Chehab 	s32    Cprog_table1 = 0;
5279a0bf528SMauro Carvalho Chehab 	s32    Cprog_cal2 = 0;
5289a0bf528SMauro Carvalho Chehab 	s32    Cprog_table2 = 0;
5299a0bf528SMauro Carvalho Chehab 	s32    Cprog_cal3 = 0;
5309a0bf528SMauro Carvalho Chehab 	s32    Cprog_table3 = 0;
5319a0bf528SMauro Carvalho Chehab 
5329a0bf528SMauro Carvalho Chehab 	state->m_RF_A1[RFBand] = 0;
5339a0bf528SMauro Carvalho Chehab 	state->m_RF_B1[RFBand] = 0;
5349a0bf528SMauro Carvalho Chehab 	state->m_RF_A2[RFBand] = 0;
5359a0bf528SMauro Carvalho Chehab 	state->m_RF_B2[RFBand] = 0;
5369a0bf528SMauro Carvalho Chehab 
5379a0bf528SMauro Carvalho Chehab 	do {
5389a0bf528SMauro Carvalho Chehab 		status = PowerScan(state, RFBand, RF1, &RF1, &bcal);
5399a0bf528SMauro Carvalho Chehab 		if (status < 0)
5409a0bf528SMauro Carvalho Chehab 			break;
5419a0bf528SMauro Carvalho Chehab 		if (bcal) {
5429a0bf528SMauro Carvalho Chehab 			status = CalibrateRF(state, RFBand, RF1, &Cprog_cal1);
5439a0bf528SMauro Carvalho Chehab 			if (status < 0)
5449a0bf528SMauro Carvalho Chehab 				break;
5459a0bf528SMauro Carvalho Chehab 		}
5469a0bf528SMauro Carvalho Chehab 		SearchMap2(m_RF_Cal_Map, RF1, &Cprog_table1);
5479a0bf528SMauro Carvalho Chehab 		if (!bcal)
5489a0bf528SMauro Carvalho Chehab 			Cprog_cal1 = Cprog_table1;
5499a0bf528SMauro Carvalho Chehab 		state->m_RF_B1[RFBand] = Cprog_cal1 - Cprog_table1;
5509a0bf528SMauro Carvalho Chehab 		/* state->m_RF_A1[RF_Band] = ???? */
5519a0bf528SMauro Carvalho Chehab 
5529a0bf528SMauro Carvalho Chehab 		if (RF2 == 0)
5539a0bf528SMauro Carvalho Chehab 			break;
5549a0bf528SMauro Carvalho Chehab 
5559a0bf528SMauro Carvalho Chehab 		status = PowerScan(state, RFBand, RF2, &RF2, &bcal);
5569a0bf528SMauro Carvalho Chehab 		if (status < 0)
5579a0bf528SMauro Carvalho Chehab 			break;
5589a0bf528SMauro Carvalho Chehab 		if (bcal) {
5599a0bf528SMauro Carvalho Chehab 			status = CalibrateRF(state, RFBand, RF2, &Cprog_cal2);
5609a0bf528SMauro Carvalho Chehab 			if (status < 0)
5619a0bf528SMauro Carvalho Chehab 				break;
5629a0bf528SMauro Carvalho Chehab 		}
5639a0bf528SMauro Carvalho Chehab 		SearchMap2(m_RF_Cal_Map, RF2, &Cprog_table2);
5649a0bf528SMauro Carvalho Chehab 		if (!bcal)
5659a0bf528SMauro Carvalho Chehab 			Cprog_cal2 = Cprog_table2;
5669a0bf528SMauro Carvalho Chehab 
5679a0bf528SMauro Carvalho Chehab 		state->m_RF_A1[RFBand] =
5689a0bf528SMauro Carvalho Chehab 			(Cprog_cal2 - Cprog_table2 - Cprog_cal1 + Cprog_table1) /
5699a0bf528SMauro Carvalho Chehab 			((s32)(RF2) - (s32)(RF1));
5709a0bf528SMauro Carvalho Chehab 
5719a0bf528SMauro Carvalho Chehab 		if (RF3 == 0)
5729a0bf528SMauro Carvalho Chehab 			break;
5739a0bf528SMauro Carvalho Chehab 
5749a0bf528SMauro Carvalho Chehab 		status = PowerScan(state, RFBand, RF3, &RF3, &bcal);
5759a0bf528SMauro Carvalho Chehab 		if (status < 0)
5769a0bf528SMauro Carvalho Chehab 			break;
5779a0bf528SMauro Carvalho Chehab 		if (bcal) {
5789a0bf528SMauro Carvalho Chehab 			status = CalibrateRF(state, RFBand, RF3, &Cprog_cal3);
5799a0bf528SMauro Carvalho Chehab 			if (status < 0)
5809a0bf528SMauro Carvalho Chehab 				break;
5819a0bf528SMauro Carvalho Chehab 		}
5829a0bf528SMauro Carvalho Chehab 		SearchMap2(m_RF_Cal_Map, RF3, &Cprog_table3);
5839a0bf528SMauro Carvalho Chehab 		if (!bcal)
5849a0bf528SMauro Carvalho Chehab 			Cprog_cal3 = Cprog_table3;
5859a0bf528SMauro Carvalho Chehab 		state->m_RF_A2[RFBand] = (Cprog_cal3 - Cprog_table3 - Cprog_cal2 + Cprog_table2) / ((s32)(RF3) - (s32)(RF2));
5869a0bf528SMauro Carvalho Chehab 		state->m_RF_B2[RFBand] = Cprog_cal2 - Cprog_table2;
5879a0bf528SMauro Carvalho Chehab 
5889a0bf528SMauro Carvalho Chehab 	} while (0);
5899a0bf528SMauro Carvalho Chehab 
5909a0bf528SMauro Carvalho Chehab 	state->m_RF1[RFBand] = RF1;
5919a0bf528SMauro Carvalho Chehab 	state->m_RF2[RFBand] = RF2;
5929a0bf528SMauro Carvalho Chehab 	state->m_RF3[RFBand] = RF3;
5939a0bf528SMauro Carvalho Chehab 
5949a0bf528SMauro Carvalho Chehab #if 0
5959a0bf528SMauro Carvalho Chehab 	printk(KERN_ERR "tda18271c2dd: %s %d RF1 = %d A1 = %d B1 = %d RF2 = %d A2 = %d B2 = %d RF3 = %d\n", __func__,
5969a0bf528SMauro Carvalho Chehab 	       RFBand, RF1, state->m_RF_A1[RFBand], state->m_RF_B1[RFBand], RF2,
5979a0bf528SMauro Carvalho Chehab 	       state->m_RF_A2[RFBand], state->m_RF_B2[RFBand], RF3);
5989a0bf528SMauro Carvalho Chehab #endif
5999a0bf528SMauro Carvalho Chehab 
6009a0bf528SMauro Carvalho Chehab 	return status;
6019a0bf528SMauro Carvalho Chehab }
6029a0bf528SMauro Carvalho Chehab 
6039a0bf528SMauro Carvalho Chehab static int PowerScan(struct tda_state *state,
6049a0bf528SMauro Carvalho Chehab 		     u8 RFBand, u32 RF_in, u32 *pRF_Out, bool *pbcal)
6059a0bf528SMauro Carvalho Chehab {
6069a0bf528SMauro Carvalho Chehab 	int status = 0;
6079a0bf528SMauro Carvalho Chehab 	do {
6089a0bf528SMauro Carvalho Chehab 		u8   Gain_Taper = 0;
6099a0bf528SMauro Carvalho Chehab 		s32  RFC_Cprog = 0;
6109a0bf528SMauro Carvalho Chehab 		u8   CID_Target = 0;
6119a0bf528SMauro Carvalho Chehab 		u8   CountLimit = 0;
6129a0bf528SMauro Carvalho Chehab 		u32  freq_MainPLL;
6139a0bf528SMauro Carvalho Chehab 		u8   Regs[NUM_REGS];
6149a0bf528SMauro Carvalho Chehab 		u8   CID_Gain;
6159a0bf528SMauro Carvalho Chehab 		s32  Count = 0;
6169a0bf528SMauro Carvalho Chehab 		int  sign  = 1;
6179a0bf528SMauro Carvalho Chehab 		bool wait = false;
6189a0bf528SMauro Carvalho Chehab 
6199a0bf528SMauro Carvalho Chehab 		if (!(SearchMap2(m_RF_Cal_Map, RF_in, &RFC_Cprog) &&
6209a0bf528SMauro Carvalho Chehab 		      SearchMap1(m_GainTaper_Map, RF_in, &Gain_Taper) &&
6219a0bf528SMauro Carvalho Chehab 		      SearchMap3(m_CID_Target_Map, RF_in, &CID_Target, &CountLimit))) {
6229a0bf528SMauro Carvalho Chehab 
6239a0bf528SMauro Carvalho Chehab 			printk(KERN_ERR "tda18271c2dd: %s Search map failed\n", __func__);
6249a0bf528SMauro Carvalho Chehab 			return -EINVAL;
6259a0bf528SMauro Carvalho Chehab 		}
6269a0bf528SMauro Carvalho Chehab 
6279a0bf528SMauro Carvalho Chehab 		state->m_Regs[EP2] = (RFBand << 5) | Gain_Taper;
6289a0bf528SMauro Carvalho Chehab 		state->m_Regs[EB14] = (RFC_Cprog);
6299a0bf528SMauro Carvalho Chehab 		status = UpdateReg(state, EP2);
6309a0bf528SMauro Carvalho Chehab 		if (status < 0)
6319a0bf528SMauro Carvalho Chehab 			break;
6329a0bf528SMauro Carvalho Chehab 		status = UpdateReg(state, EB14);
6339a0bf528SMauro Carvalho Chehab 		if (status < 0)
6349a0bf528SMauro Carvalho Chehab 			break;
6359a0bf528SMauro Carvalho Chehab 
6369a0bf528SMauro Carvalho Chehab 		freq_MainPLL = RF_in + 1000000;
6379a0bf528SMauro Carvalho Chehab 		status = CalcMainPLL(state, freq_MainPLL);
6389a0bf528SMauro Carvalho Chehab 		if (status < 0)
6399a0bf528SMauro Carvalho Chehab 			break;
6409a0bf528SMauro Carvalho Chehab 		msleep(5);
6419a0bf528SMauro Carvalho Chehab 		state->m_Regs[EP4] = (state->m_Regs[EP4] & ~0x03) | 1;    /* CAL_mode = 1 */
6429a0bf528SMauro Carvalho Chehab 		status = UpdateReg(state, EP4);
6439a0bf528SMauro Carvalho Chehab 		if (status < 0)
6449a0bf528SMauro Carvalho Chehab 			break;
6459a0bf528SMauro Carvalho Chehab 		status = UpdateReg(state, EP2);  /* Launch power measurement */
6469a0bf528SMauro Carvalho Chehab 		if (status < 0)
6479a0bf528SMauro Carvalho Chehab 			break;
6489a0bf528SMauro Carvalho Chehab 		status = ReadExtented(state, Regs);
6499a0bf528SMauro Carvalho Chehab 		if (status < 0)
6509a0bf528SMauro Carvalho Chehab 			break;
6519a0bf528SMauro Carvalho Chehab 		CID_Gain = Regs[EB10] & 0x3F;
6529a0bf528SMauro Carvalho Chehab 		state->m_Regs[ID] = Regs[ID];  /* Chip version, (needed for C1 workarround in CalibrateRF) */
6539a0bf528SMauro Carvalho Chehab 
6549a0bf528SMauro Carvalho Chehab 		*pRF_Out = RF_in;
6559a0bf528SMauro Carvalho Chehab 
6569a0bf528SMauro Carvalho Chehab 		while (CID_Gain < CID_Target) {
6579a0bf528SMauro Carvalho Chehab 			freq_MainPLL = RF_in + sign * Count + 1000000;
6589a0bf528SMauro Carvalho Chehab 			status = CalcMainPLL(state, freq_MainPLL);
6599a0bf528SMauro Carvalho Chehab 			if (status < 0)
6609a0bf528SMauro Carvalho Chehab 				break;
6619a0bf528SMauro Carvalho Chehab 			msleep(wait ? 5 : 1);
6629a0bf528SMauro Carvalho Chehab 			wait = false;
6639a0bf528SMauro Carvalho Chehab 			status = UpdateReg(state, EP2);  /* Launch power measurement */
6649a0bf528SMauro Carvalho Chehab 			if (status < 0)
6659a0bf528SMauro Carvalho Chehab 				break;
6669a0bf528SMauro Carvalho Chehab 			status = ReadExtented(state, Regs);
6679a0bf528SMauro Carvalho Chehab 			if (status < 0)
6689a0bf528SMauro Carvalho Chehab 				break;
6699a0bf528SMauro Carvalho Chehab 			CID_Gain = Regs[EB10] & 0x3F;
6709a0bf528SMauro Carvalho Chehab 			Count += 200000;
6719a0bf528SMauro Carvalho Chehab 
6729a0bf528SMauro Carvalho Chehab 			if (Count < CountLimit * 100000)
6739a0bf528SMauro Carvalho Chehab 				continue;
6749a0bf528SMauro Carvalho Chehab 			if (sign < 0)
6759a0bf528SMauro Carvalho Chehab 				break;
6769a0bf528SMauro Carvalho Chehab 
6779a0bf528SMauro Carvalho Chehab 			sign = -sign;
6789a0bf528SMauro Carvalho Chehab 			Count = 200000;
6799a0bf528SMauro Carvalho Chehab 			wait = true;
6809a0bf528SMauro Carvalho Chehab 		}
6819a0bf528SMauro Carvalho Chehab 		status = status;
6829a0bf528SMauro Carvalho Chehab 		if (status < 0)
6839a0bf528SMauro Carvalho Chehab 			break;
6849a0bf528SMauro Carvalho Chehab 		if (CID_Gain >= CID_Target) {
6859a0bf528SMauro Carvalho Chehab 			*pbcal = true;
6869a0bf528SMauro Carvalho Chehab 			*pRF_Out = freq_MainPLL - 1000000;
6879a0bf528SMauro Carvalho Chehab 		} else
6889a0bf528SMauro Carvalho Chehab 			*pbcal = false;
6899a0bf528SMauro Carvalho Chehab 	} while (0);
6909a0bf528SMauro Carvalho Chehab 
6919a0bf528SMauro Carvalho Chehab 	return status;
6929a0bf528SMauro Carvalho Chehab }
6939a0bf528SMauro Carvalho Chehab 
6949a0bf528SMauro Carvalho Chehab static int PowerScanInit(struct tda_state *state)
6959a0bf528SMauro Carvalho Chehab {
6969a0bf528SMauro Carvalho Chehab 	int status = 0;
6979a0bf528SMauro Carvalho Chehab 	do {
6989a0bf528SMauro Carvalho Chehab 		state->m_Regs[EP3] = (state->m_Regs[EP3] & ~0x1F) | 0x12;
6999a0bf528SMauro Carvalho Chehab 		state->m_Regs[EP4] = (state->m_Regs[EP4] & ~0x1F); /* If level = 0, Cal mode = 0 */
7009a0bf528SMauro Carvalho Chehab 		status = UpdateRegs(state, EP3, EP4);
7019a0bf528SMauro Carvalho Chehab 		if (status < 0)
7029a0bf528SMauro Carvalho Chehab 			break;
7039a0bf528SMauro Carvalho Chehab 		state->m_Regs[EB18] = (state->m_Regs[EB18] & ~0x03); /* AGC 1 Gain = 0 */
7049a0bf528SMauro Carvalho Chehab 		status = UpdateReg(state, EB18);
7059a0bf528SMauro Carvalho Chehab 		if (status < 0)
7069a0bf528SMauro Carvalho Chehab 			break;
7079a0bf528SMauro Carvalho Chehab 		state->m_Regs[EB21] = (state->m_Regs[EB21] & ~0x03); /* AGC 2 Gain = 0 (Datasheet = 3) */
7089a0bf528SMauro Carvalho Chehab 		state->m_Regs[EB23] = (state->m_Regs[EB23] | 0x06); /* ForceLP_Fc2_En = 1, LPFc[2] = 1 */
7099a0bf528SMauro Carvalho Chehab 		status = UpdateRegs(state, EB21, EB23);
7109a0bf528SMauro Carvalho Chehab 		if (status < 0)
7119a0bf528SMauro Carvalho Chehab 			break;
7129a0bf528SMauro Carvalho Chehab 	} while (0);
7139a0bf528SMauro Carvalho Chehab 	return status;
7149a0bf528SMauro Carvalho Chehab }
7159a0bf528SMauro Carvalho Chehab 
7169a0bf528SMauro Carvalho Chehab static int CalcRFFilterCurve(struct tda_state *state)
7179a0bf528SMauro Carvalho Chehab {
7189a0bf528SMauro Carvalho Chehab 	int status = 0;
7199a0bf528SMauro Carvalho Chehab 	do {
7209a0bf528SMauro Carvalho Chehab 		msleep(200);      /* Temperature stabilisation */
7219a0bf528SMauro Carvalho Chehab 		status = PowerScanInit(state);
7229a0bf528SMauro Carvalho Chehab 		if (status < 0)
7239a0bf528SMauro Carvalho Chehab 			break;
7249a0bf528SMauro Carvalho Chehab 		status = RFTrackingFiltersInit(state, 0);
7259a0bf528SMauro Carvalho Chehab 		if (status < 0)
7269a0bf528SMauro Carvalho Chehab 			break;
7279a0bf528SMauro Carvalho Chehab 		status = RFTrackingFiltersInit(state, 1);
7289a0bf528SMauro Carvalho Chehab 		if (status < 0)
7299a0bf528SMauro Carvalho Chehab 			break;
7309a0bf528SMauro Carvalho Chehab 		status = RFTrackingFiltersInit(state, 2);
7319a0bf528SMauro Carvalho Chehab 		if (status < 0)
7329a0bf528SMauro Carvalho Chehab 			break;
7339a0bf528SMauro Carvalho Chehab 		status = RFTrackingFiltersInit(state, 3);
7349a0bf528SMauro Carvalho Chehab 		if (status < 0)
7359a0bf528SMauro Carvalho Chehab 			break;
7369a0bf528SMauro Carvalho Chehab 		status = RFTrackingFiltersInit(state, 4);
7379a0bf528SMauro Carvalho Chehab 		if (status < 0)
7389a0bf528SMauro Carvalho Chehab 			break;
7399a0bf528SMauro Carvalho Chehab 		status = RFTrackingFiltersInit(state, 5);
7409a0bf528SMauro Carvalho Chehab 		if (status < 0)
7419a0bf528SMauro Carvalho Chehab 			break;
7429a0bf528SMauro Carvalho Chehab 		status = RFTrackingFiltersInit(state, 6);
7439a0bf528SMauro Carvalho Chehab 		if (status < 0)
7449a0bf528SMauro Carvalho Chehab 			break;
7459a0bf528SMauro Carvalho Chehab 		status = ThermometerRead(state, &state->m_TMValue_RFCal); /* also switches off Cal mode !!! */
7469a0bf528SMauro Carvalho Chehab 		if (status < 0)
7479a0bf528SMauro Carvalho Chehab 			break;
7489a0bf528SMauro Carvalho Chehab 	} while (0);
7499a0bf528SMauro Carvalho Chehab 
7509a0bf528SMauro Carvalho Chehab 	return status;
7519a0bf528SMauro Carvalho Chehab }
7529a0bf528SMauro Carvalho Chehab 
7539a0bf528SMauro Carvalho Chehab static int FixedContentsI2CUpdate(struct tda_state *state)
7549a0bf528SMauro Carvalho Chehab {
7559a0bf528SMauro Carvalho Chehab 	static u8 InitRegs[] = {
7569a0bf528SMauro Carvalho Chehab 		0x08, 0x80, 0xC6,
7579a0bf528SMauro Carvalho Chehab 		0xDF, 0x16, 0x60, 0x80,
7589a0bf528SMauro Carvalho Chehab 		0x80, 0x00, 0x00, 0x00,
7599a0bf528SMauro Carvalho Chehab 		0x00, 0x00, 0x00, 0x00,
7609a0bf528SMauro Carvalho Chehab 		0xFC, 0x01, 0x84, 0x41,
7619a0bf528SMauro Carvalho Chehab 		0x01, 0x84, 0x40, 0x07,
7629a0bf528SMauro Carvalho Chehab 		0x00, 0x00, 0x96, 0x3F,
7639a0bf528SMauro Carvalho Chehab 		0xC1, 0x00, 0x8F, 0x00,
7649a0bf528SMauro Carvalho Chehab 		0x00, 0x8C, 0x00, 0x20,
7659a0bf528SMauro Carvalho Chehab 		0xB3, 0x48, 0xB0,
7669a0bf528SMauro Carvalho Chehab 	};
7679a0bf528SMauro Carvalho Chehab 	int status = 0;
7689a0bf528SMauro Carvalho Chehab 	memcpy(&state->m_Regs[TM], InitRegs, EB23 - TM + 1);
7699a0bf528SMauro Carvalho Chehab 	do {
7709a0bf528SMauro Carvalho Chehab 		status = UpdateRegs(state, TM, EB23);
7719a0bf528SMauro Carvalho Chehab 		if (status < 0)
7729a0bf528SMauro Carvalho Chehab 			break;
7739a0bf528SMauro Carvalho Chehab 
7749a0bf528SMauro Carvalho Chehab 		/* AGC1 gain setup */
7759a0bf528SMauro Carvalho Chehab 		state->m_Regs[EB17] = 0x00;
7769a0bf528SMauro Carvalho Chehab 		status = UpdateReg(state, EB17);
7779a0bf528SMauro Carvalho Chehab 		if (status < 0)
7789a0bf528SMauro Carvalho Chehab 			break;
7799a0bf528SMauro Carvalho Chehab 		state->m_Regs[EB17] = 0x03;
7809a0bf528SMauro Carvalho Chehab 		status = UpdateReg(state, EB17);
7819a0bf528SMauro Carvalho Chehab 		if (status < 0)
7829a0bf528SMauro Carvalho Chehab 			break;
7839a0bf528SMauro Carvalho Chehab 		state->m_Regs[EB17] = 0x43;
7849a0bf528SMauro Carvalho Chehab 		status = UpdateReg(state, EB17);
7859a0bf528SMauro Carvalho Chehab 		if (status < 0)
7869a0bf528SMauro Carvalho Chehab 			break;
7879a0bf528SMauro Carvalho Chehab 		state->m_Regs[EB17] = 0x4C;
7889a0bf528SMauro Carvalho Chehab 		status = UpdateReg(state, EB17);
7899a0bf528SMauro Carvalho Chehab 		if (status < 0)
7909a0bf528SMauro Carvalho Chehab 			break;
7919a0bf528SMauro Carvalho Chehab 
7929a0bf528SMauro Carvalho Chehab 		/* IRC Cal Low band */
7939a0bf528SMauro Carvalho Chehab 		state->m_Regs[EP3] = 0x1F;
7949a0bf528SMauro Carvalho Chehab 		state->m_Regs[EP4] = 0x66;
7959a0bf528SMauro Carvalho Chehab 		state->m_Regs[EP5] = 0x81;
7969a0bf528SMauro Carvalho Chehab 		state->m_Regs[CPD] = 0xCC;
7979a0bf528SMauro Carvalho Chehab 		state->m_Regs[CD1] = 0x6C;
7989a0bf528SMauro Carvalho Chehab 		state->m_Regs[CD2] = 0x00;
7999a0bf528SMauro Carvalho Chehab 		state->m_Regs[CD3] = 0x00;
8009a0bf528SMauro Carvalho Chehab 		state->m_Regs[MPD] = 0xC5;
8019a0bf528SMauro Carvalho Chehab 		state->m_Regs[MD1] = 0x77;
8029a0bf528SMauro Carvalho Chehab 		state->m_Regs[MD2] = 0x08;
8039a0bf528SMauro Carvalho Chehab 		state->m_Regs[MD3] = 0x00;
8049a0bf528SMauro Carvalho Chehab 		status = UpdateRegs(state, EP2, MD3); /* diff between sw and datasheet (ep3-md3) */
8059a0bf528SMauro Carvalho Chehab 		if (status < 0)
8069a0bf528SMauro Carvalho Chehab 			break;
8079a0bf528SMauro Carvalho Chehab 
8089a0bf528SMauro Carvalho Chehab #if 0
8099a0bf528SMauro Carvalho Chehab 		state->m_Regs[EB4] = 0x61;          /* missing in sw */
8109a0bf528SMauro Carvalho Chehab 		status = UpdateReg(state, EB4);
8119a0bf528SMauro Carvalho Chehab 		if (status < 0)
8129a0bf528SMauro Carvalho Chehab 			break;
8139a0bf528SMauro Carvalho Chehab 		msleep(1);
8149a0bf528SMauro Carvalho Chehab 		state->m_Regs[EB4] = 0x41;
8159a0bf528SMauro Carvalho Chehab 		status = UpdateReg(state, EB4);
8169a0bf528SMauro Carvalho Chehab 		if (status < 0)
8179a0bf528SMauro Carvalho Chehab 			break;
8189a0bf528SMauro Carvalho Chehab #endif
8199a0bf528SMauro Carvalho Chehab 
8209a0bf528SMauro Carvalho Chehab 		msleep(5);
8219a0bf528SMauro Carvalho Chehab 		status = UpdateReg(state, EP1);
8229a0bf528SMauro Carvalho Chehab 		if (status < 0)
8239a0bf528SMauro Carvalho Chehab 			break;
8249a0bf528SMauro Carvalho Chehab 		msleep(5);
8259a0bf528SMauro Carvalho Chehab 
8269a0bf528SMauro Carvalho Chehab 		state->m_Regs[EP5] = 0x85;
8279a0bf528SMauro Carvalho Chehab 		state->m_Regs[CPD] = 0xCB;
8289a0bf528SMauro Carvalho Chehab 		state->m_Regs[CD1] = 0x66;
8299a0bf528SMauro Carvalho Chehab 		state->m_Regs[CD2] = 0x70;
8309a0bf528SMauro Carvalho Chehab 		status = UpdateRegs(state, EP3, CD3);
8319a0bf528SMauro Carvalho Chehab 		if (status < 0)
8329a0bf528SMauro Carvalho Chehab 			break;
8339a0bf528SMauro Carvalho Chehab 		msleep(5);
8349a0bf528SMauro Carvalho Chehab 		status = UpdateReg(state, EP2);
8359a0bf528SMauro Carvalho Chehab 		if (status < 0)
8369a0bf528SMauro Carvalho Chehab 			break;
8379a0bf528SMauro Carvalho Chehab 		msleep(30);
8389a0bf528SMauro Carvalho Chehab 
8399a0bf528SMauro Carvalho Chehab 		/* IRC Cal mid band */
8409a0bf528SMauro Carvalho Chehab 		state->m_Regs[EP5] = 0x82;
8419a0bf528SMauro Carvalho Chehab 		state->m_Regs[CPD] = 0xA8;
8429a0bf528SMauro Carvalho Chehab 		state->m_Regs[CD2] = 0x00;
8439a0bf528SMauro Carvalho Chehab 		state->m_Regs[MPD] = 0xA1; /* Datasheet = 0xA9 */
8449a0bf528SMauro Carvalho Chehab 		state->m_Regs[MD1] = 0x73;
8459a0bf528SMauro Carvalho Chehab 		state->m_Regs[MD2] = 0x1A;
8469a0bf528SMauro Carvalho Chehab 		status = UpdateRegs(state, EP3, MD3);
8479a0bf528SMauro Carvalho Chehab 		if (status < 0)
8489a0bf528SMauro Carvalho Chehab 			break;
8499a0bf528SMauro Carvalho Chehab 
8509a0bf528SMauro Carvalho Chehab 		msleep(5);
8519a0bf528SMauro Carvalho Chehab 		status = UpdateReg(state, EP1);
8529a0bf528SMauro Carvalho Chehab 		if (status < 0)
8539a0bf528SMauro Carvalho Chehab 			break;
8549a0bf528SMauro Carvalho Chehab 		msleep(5);
8559a0bf528SMauro Carvalho Chehab 
8569a0bf528SMauro Carvalho Chehab 		state->m_Regs[EP5] = 0x86;
8579a0bf528SMauro Carvalho Chehab 		state->m_Regs[CPD] = 0xA8;
8589a0bf528SMauro Carvalho Chehab 		state->m_Regs[CD1] = 0x66;
8599a0bf528SMauro Carvalho Chehab 		state->m_Regs[CD2] = 0xA0;
8609a0bf528SMauro Carvalho Chehab 		status = UpdateRegs(state, EP3, CD3);
8619a0bf528SMauro Carvalho Chehab 		if (status < 0)
8629a0bf528SMauro Carvalho Chehab 			break;
8639a0bf528SMauro Carvalho Chehab 		msleep(5);
8649a0bf528SMauro Carvalho Chehab 		status = UpdateReg(state, EP2);
8659a0bf528SMauro Carvalho Chehab 		if (status < 0)
8669a0bf528SMauro Carvalho Chehab 			break;
8679a0bf528SMauro Carvalho Chehab 		msleep(30);
8689a0bf528SMauro Carvalho Chehab 
8699a0bf528SMauro Carvalho Chehab 		/* IRC Cal high band */
8709a0bf528SMauro Carvalho Chehab 		state->m_Regs[EP5] = 0x83;
8719a0bf528SMauro Carvalho Chehab 		state->m_Regs[CPD] = 0x98;
8729a0bf528SMauro Carvalho Chehab 		state->m_Regs[CD1] = 0x65;
8739a0bf528SMauro Carvalho Chehab 		state->m_Regs[CD2] = 0x00;
8749a0bf528SMauro Carvalho Chehab 		state->m_Regs[MPD] = 0x91;  /* Datasheet = 0x91 */
8759a0bf528SMauro Carvalho Chehab 		state->m_Regs[MD1] = 0x71;
8769a0bf528SMauro Carvalho Chehab 		state->m_Regs[MD2] = 0xCD;
8779a0bf528SMauro Carvalho Chehab 		status = UpdateRegs(state, EP3, MD3);
8789a0bf528SMauro Carvalho Chehab 		if (status < 0)
8799a0bf528SMauro Carvalho Chehab 			break;
8809a0bf528SMauro Carvalho Chehab 		msleep(5);
8819a0bf528SMauro Carvalho Chehab 		status = UpdateReg(state, EP1);
8829a0bf528SMauro Carvalho Chehab 		if (status < 0)
8839a0bf528SMauro Carvalho Chehab 			break;
8849a0bf528SMauro Carvalho Chehab 		msleep(5);
8859a0bf528SMauro Carvalho Chehab 		state->m_Regs[EP5] = 0x87;
8869a0bf528SMauro Carvalho Chehab 		state->m_Regs[CD1] = 0x65;
8879a0bf528SMauro Carvalho Chehab 		state->m_Regs[CD2] = 0x50;
8889a0bf528SMauro Carvalho Chehab 		status = UpdateRegs(state, EP3, CD3);
8899a0bf528SMauro Carvalho Chehab 		if (status < 0)
8909a0bf528SMauro Carvalho Chehab 			break;
8919a0bf528SMauro Carvalho Chehab 		msleep(5);
8929a0bf528SMauro Carvalho Chehab 		status = UpdateReg(state, EP2);
8939a0bf528SMauro Carvalho Chehab 		if (status < 0)
8949a0bf528SMauro Carvalho Chehab 			break;
8959a0bf528SMauro Carvalho Chehab 		msleep(30);
8969a0bf528SMauro Carvalho Chehab 
8979a0bf528SMauro Carvalho Chehab 		/* Back to normal */
8989a0bf528SMauro Carvalho Chehab 		state->m_Regs[EP4] = 0x64;
8999a0bf528SMauro Carvalho Chehab 		status = UpdateReg(state, EP4);
9009a0bf528SMauro Carvalho Chehab 		if (status < 0)
9019a0bf528SMauro Carvalho Chehab 			break;
9029a0bf528SMauro Carvalho Chehab 		status = UpdateReg(state, EP1);
9039a0bf528SMauro Carvalho Chehab 		if (status < 0)
9049a0bf528SMauro Carvalho Chehab 			break;
9059a0bf528SMauro Carvalho Chehab 
9069a0bf528SMauro Carvalho Chehab 	} while (0);
9079a0bf528SMauro Carvalho Chehab 	return status;
9089a0bf528SMauro Carvalho Chehab }
9099a0bf528SMauro Carvalho Chehab 
9109a0bf528SMauro Carvalho Chehab static int InitCal(struct tda_state *state)
9119a0bf528SMauro Carvalho Chehab {
9129a0bf528SMauro Carvalho Chehab 	int status = 0;
9139a0bf528SMauro Carvalho Chehab 
9149a0bf528SMauro Carvalho Chehab 	do {
9159a0bf528SMauro Carvalho Chehab 		status = FixedContentsI2CUpdate(state);
9169a0bf528SMauro Carvalho Chehab 		if (status < 0)
9179a0bf528SMauro Carvalho Chehab 			break;
9189a0bf528SMauro Carvalho Chehab 		status = CalcRFFilterCurve(state);
9199a0bf528SMauro Carvalho Chehab 		if (status < 0)
9209a0bf528SMauro Carvalho Chehab 			break;
9219a0bf528SMauro Carvalho Chehab 		status = StandBy(state);
9229a0bf528SMauro Carvalho Chehab 		if (status < 0)
9239a0bf528SMauro Carvalho Chehab 			break;
9249a0bf528SMauro Carvalho Chehab 		/* m_bInitDone = true; */
9259a0bf528SMauro Carvalho Chehab 	} while (0);
9269a0bf528SMauro Carvalho Chehab 	return status;
9279a0bf528SMauro Carvalho Chehab };
9289a0bf528SMauro Carvalho Chehab 
9299a0bf528SMauro Carvalho Chehab static int RFTrackingFiltersCorrection(struct tda_state *state,
9309a0bf528SMauro Carvalho Chehab 				       u32 Frequency)
9319a0bf528SMauro Carvalho Chehab {
9329a0bf528SMauro Carvalho Chehab 	int status = 0;
9339a0bf528SMauro Carvalho Chehab 	s32 Cprog_table;
9349a0bf528SMauro Carvalho Chehab 	u8 RFBand;
9359a0bf528SMauro Carvalho Chehab 	u8 dCoverdT;
9369a0bf528SMauro Carvalho Chehab 
9379a0bf528SMauro Carvalho Chehab 	if (!SearchMap2(m_RF_Cal_Map, Frequency, &Cprog_table) ||
9389a0bf528SMauro Carvalho Chehab 	    !SearchMap4(m_RF_Band_Map, Frequency, &RFBand) ||
9399a0bf528SMauro Carvalho Chehab 	    !SearchMap1(m_RF_Cal_DC_Over_DT_Map, Frequency, &dCoverdT))
9409a0bf528SMauro Carvalho Chehab 
9419a0bf528SMauro Carvalho Chehab 		return -EINVAL;
9429a0bf528SMauro Carvalho Chehab 
9439a0bf528SMauro Carvalho Chehab 	do {
9449a0bf528SMauro Carvalho Chehab 		u8 TMValue_Current;
9459a0bf528SMauro Carvalho Chehab 		u32   RF1 = state->m_RF1[RFBand];
9469a0bf528SMauro Carvalho Chehab 		u32   RF2 = state->m_RF1[RFBand];
9479a0bf528SMauro Carvalho Chehab 		u32   RF3 = state->m_RF1[RFBand];
9489a0bf528SMauro Carvalho Chehab 		s32    RF_A1 = state->m_RF_A1[RFBand];
9499a0bf528SMauro Carvalho Chehab 		s32    RF_B1 = state->m_RF_B1[RFBand];
9509a0bf528SMauro Carvalho Chehab 		s32    RF_A2 = state->m_RF_A2[RFBand];
9519a0bf528SMauro Carvalho Chehab 		s32    RF_B2 = state->m_RF_B2[RFBand];
9529a0bf528SMauro Carvalho Chehab 		s32 Capprox = 0;
9539a0bf528SMauro Carvalho Chehab 		int TComp;
9549a0bf528SMauro Carvalho Chehab 
9559a0bf528SMauro Carvalho Chehab 		state->m_Regs[EP3] &= ~0xE0;  /* Power up */
9569a0bf528SMauro Carvalho Chehab 		status = UpdateReg(state, EP3);
9579a0bf528SMauro Carvalho Chehab 		if (status < 0)
9589a0bf528SMauro Carvalho Chehab 			break;
9599a0bf528SMauro Carvalho Chehab 
9609a0bf528SMauro Carvalho Chehab 		status = ThermometerRead(state, &TMValue_Current);
9619a0bf528SMauro Carvalho Chehab 		if (status < 0)
9629a0bf528SMauro Carvalho Chehab 			break;
9639a0bf528SMauro Carvalho Chehab 
9649a0bf528SMauro Carvalho Chehab 		if (RF3 == 0 || Frequency < RF2)
9659a0bf528SMauro Carvalho Chehab 			Capprox = RF_A1 * ((s32)(Frequency) - (s32)(RF1)) + RF_B1 + Cprog_table;
9669a0bf528SMauro Carvalho Chehab 		else
9679a0bf528SMauro Carvalho Chehab 			Capprox = RF_A2 * ((s32)(Frequency) - (s32)(RF2)) + RF_B2 + Cprog_table;
9689a0bf528SMauro Carvalho Chehab 
9699a0bf528SMauro Carvalho Chehab 		TComp = (int)(dCoverdT) * ((int)(TMValue_Current) - (int)(state->m_TMValue_RFCal))/1000;
9709a0bf528SMauro Carvalho Chehab 
9719a0bf528SMauro Carvalho Chehab 		Capprox += TComp;
9729a0bf528SMauro Carvalho Chehab 
9739a0bf528SMauro Carvalho Chehab 		if (Capprox < 0)
9749a0bf528SMauro Carvalho Chehab 			Capprox = 0;
9759a0bf528SMauro Carvalho Chehab 		else if (Capprox > 255)
9769a0bf528SMauro Carvalho Chehab 			Capprox = 255;
9779a0bf528SMauro Carvalho Chehab 
9789a0bf528SMauro Carvalho Chehab 
9799a0bf528SMauro Carvalho Chehab 		/* TODO Temperature compensation. There is defenitely a scale factor */
9809a0bf528SMauro Carvalho Chehab 		/*      missing in the datasheet, so leave it out for now.           */
9819a0bf528SMauro Carvalho Chehab 		state->m_Regs[EB14] = Capprox;
9829a0bf528SMauro Carvalho Chehab 
9839a0bf528SMauro Carvalho Chehab 		status = UpdateReg(state, EB14);
9849a0bf528SMauro Carvalho Chehab 		if (status < 0)
9859a0bf528SMauro Carvalho Chehab 			break;
9869a0bf528SMauro Carvalho Chehab 
9879a0bf528SMauro Carvalho Chehab 	} while (0);
9889a0bf528SMauro Carvalho Chehab 	return status;
9899a0bf528SMauro Carvalho Chehab }
9909a0bf528SMauro Carvalho Chehab 
9919a0bf528SMauro Carvalho Chehab static int ChannelConfiguration(struct tda_state *state,
9929a0bf528SMauro Carvalho Chehab 				u32 Frequency, int Standard)
9939a0bf528SMauro Carvalho Chehab {
9949a0bf528SMauro Carvalho Chehab 
9959a0bf528SMauro Carvalho Chehab 	s32 IntermediateFrequency = m_StandardTable[Standard].m_IFFrequency;
9969a0bf528SMauro Carvalho Chehab 	int status = 0;
9979a0bf528SMauro Carvalho Chehab 
9989a0bf528SMauro Carvalho Chehab 	u8 BP_Filter = 0;
9999a0bf528SMauro Carvalho Chehab 	u8 RF_Band = 0;
10009a0bf528SMauro Carvalho Chehab 	u8 GainTaper = 0;
10019a0bf528SMauro Carvalho Chehab 	u8 IR_Meas = 0;
10029a0bf528SMauro Carvalho Chehab 
10039a0bf528SMauro Carvalho Chehab 	state->IF = IntermediateFrequency;
10049a0bf528SMauro Carvalho Chehab 	/* printk("tda18271c2dd: %s Freq = %d Standard = %d IF = %d\n", __func__, Frequency, Standard, IntermediateFrequency); */
10059a0bf528SMauro Carvalho Chehab 	/* get values from tables */
10069a0bf528SMauro Carvalho Chehab 
10079a0bf528SMauro Carvalho Chehab 	if (!(SearchMap1(m_BP_Filter_Map, Frequency, &BP_Filter) &&
10089a0bf528SMauro Carvalho Chehab 	       SearchMap1(m_GainTaper_Map, Frequency, &GainTaper) &&
10099a0bf528SMauro Carvalho Chehab 	       SearchMap1(m_IR_Meas_Map, Frequency, &IR_Meas) &&
10109a0bf528SMauro Carvalho Chehab 	       SearchMap4(m_RF_Band_Map, Frequency, &RF_Band))) {
10119a0bf528SMauro Carvalho Chehab 
10129a0bf528SMauro Carvalho Chehab 		printk(KERN_ERR "tda18271c2dd: %s SearchMap failed\n", __func__);
10139a0bf528SMauro Carvalho Chehab 		return -EINVAL;
10149a0bf528SMauro Carvalho Chehab 	}
10159a0bf528SMauro Carvalho Chehab 
10169a0bf528SMauro Carvalho Chehab 	do {
10179a0bf528SMauro Carvalho Chehab 		state->m_Regs[EP3] = (state->m_Regs[EP3] & ~0x1F) | m_StandardTable[Standard].m_EP3_4_0;
10189a0bf528SMauro Carvalho Chehab 		state->m_Regs[EP3] &= ~0x04;   /* switch RFAGC to high speed mode */
10199a0bf528SMauro Carvalho Chehab 
10209a0bf528SMauro Carvalho Chehab 		/* m_EP4 default for XToutOn, CAL_Mode (0) */
10219a0bf528SMauro Carvalho Chehab 		state->m_Regs[EP4] = state->m_EP4 | ((Standard > HF_AnalogMax) ? state->m_IFLevelDigital : state->m_IFLevelAnalog);
10229a0bf528SMauro Carvalho Chehab 		/* state->m_Regs[EP4] = state->m_EP4 | state->m_IFLevelDigital; */
10239a0bf528SMauro Carvalho Chehab 		if (Standard <= HF_AnalogMax)
10249a0bf528SMauro Carvalho Chehab 			state->m_Regs[EP4] = state->m_EP4 | state->m_IFLevelAnalog;
10259a0bf528SMauro Carvalho Chehab 		else if (Standard <= HF_ATSC)
10269a0bf528SMauro Carvalho Chehab 			state->m_Regs[EP4] = state->m_EP4 | state->m_IFLevelDVBT;
10279a0bf528SMauro Carvalho Chehab 		else if (Standard <= HF_DVBC)
10289a0bf528SMauro Carvalho Chehab 			state->m_Regs[EP4] = state->m_EP4 | state->m_IFLevelDVBC;
10299a0bf528SMauro Carvalho Chehab 		else
10309a0bf528SMauro Carvalho Chehab 			state->m_Regs[EP4] = state->m_EP4 | state->m_IFLevelDigital;
10319a0bf528SMauro Carvalho Chehab 
10329a0bf528SMauro Carvalho Chehab 		if ((Standard == HF_FM_Radio) && state->m_bFMInput)
10339a0bf528SMauro Carvalho Chehab 			state->m_Regs[EP4] |= 80;
10349a0bf528SMauro Carvalho Chehab 
10359a0bf528SMauro Carvalho Chehab 		state->m_Regs[MPD] &= ~0x80;
10369a0bf528SMauro Carvalho Chehab 		if (Standard > HF_AnalogMax)
10379a0bf528SMauro Carvalho Chehab 			state->m_Regs[MPD] |= 0x80; /* Add IF_notch for digital */
10389a0bf528SMauro Carvalho Chehab 
10399a0bf528SMauro Carvalho Chehab 		state->m_Regs[EB22] = m_StandardTable[Standard].m_EB22;
10409a0bf528SMauro Carvalho Chehab 
10419a0bf528SMauro Carvalho Chehab 		/* Note: This is missing from flowchart in TDA18271 specification ( 1.5 MHz cutoff for FM ) */
10429a0bf528SMauro Carvalho Chehab 		if (Standard == HF_FM_Radio)
10439a0bf528SMauro Carvalho Chehab 			state->m_Regs[EB23] |=  0x06; /* ForceLP_Fc2_En = 1, LPFc[2] = 1 */
10449a0bf528SMauro Carvalho Chehab 		else
10459a0bf528SMauro Carvalho Chehab 			state->m_Regs[EB23] &= ~0x06; /* ForceLP_Fc2_En = 0, LPFc[2] = 0 */
10469a0bf528SMauro Carvalho Chehab 
10479a0bf528SMauro Carvalho Chehab 		status = UpdateRegs(state, EB22, EB23);
10489a0bf528SMauro Carvalho Chehab 		if (status < 0)
10499a0bf528SMauro Carvalho Chehab 			break;
10509a0bf528SMauro Carvalho Chehab 
10519a0bf528SMauro Carvalho Chehab 		state->m_Regs[EP1] = (state->m_Regs[EP1] & ~0x07) | 0x40 | BP_Filter;   /* Dis_Power_level = 1, Filter */
10529a0bf528SMauro Carvalho Chehab 		state->m_Regs[EP5] = (state->m_Regs[EP5] & ~0x07) | IR_Meas;
10539a0bf528SMauro Carvalho Chehab 		state->m_Regs[EP2] = (RF_Band << 5) | GainTaper;
10549a0bf528SMauro Carvalho Chehab 
10559a0bf528SMauro Carvalho Chehab 		state->m_Regs[EB1] = (state->m_Regs[EB1] & ~0x07) |
10569a0bf528SMauro Carvalho Chehab 			(state->m_bMaster ? 0x04 : 0x00); /* CALVCO_FortLOn = MS */
10579a0bf528SMauro Carvalho Chehab 		/* AGC1_always_master = 0 */
10589a0bf528SMauro Carvalho Chehab 		/* AGC_firstn = 0 */
10599a0bf528SMauro Carvalho Chehab 		status = UpdateReg(state, EB1);
10609a0bf528SMauro Carvalho Chehab 		if (status < 0)
10619a0bf528SMauro Carvalho Chehab 			break;
10629a0bf528SMauro Carvalho Chehab 
10639a0bf528SMauro Carvalho Chehab 		if (state->m_bMaster) {
10649a0bf528SMauro Carvalho Chehab 			status = CalcMainPLL(state, Frequency + IntermediateFrequency);
10659a0bf528SMauro Carvalho Chehab 			if (status < 0)
10669a0bf528SMauro Carvalho Chehab 				break;
10679a0bf528SMauro Carvalho Chehab 			status = UpdateRegs(state, TM, EP5);
10689a0bf528SMauro Carvalho Chehab 			if (status < 0)
10699a0bf528SMauro Carvalho Chehab 				break;
10709a0bf528SMauro Carvalho Chehab 			state->m_Regs[EB4] |= 0x20;    /* LO_forceSrce = 1 */
10719a0bf528SMauro Carvalho Chehab 			status = UpdateReg(state, EB4);
10729a0bf528SMauro Carvalho Chehab 			if (status < 0)
10739a0bf528SMauro Carvalho Chehab 				break;
10749a0bf528SMauro Carvalho Chehab 			msleep(1);
10759a0bf528SMauro Carvalho Chehab 			state->m_Regs[EB4] &= ~0x20;   /* LO_forceSrce = 0 */
10769a0bf528SMauro Carvalho Chehab 			status = UpdateReg(state, EB4);
10779a0bf528SMauro Carvalho Chehab 			if (status < 0)
10789a0bf528SMauro Carvalho Chehab 				break;
10799a0bf528SMauro Carvalho Chehab 		} else {
10809a0bf528SMauro Carvalho Chehab 			u8 PostDiv = 0;
10819a0bf528SMauro Carvalho Chehab 			u8 Div;
10829a0bf528SMauro Carvalho Chehab 			status = CalcCalPLL(state, Frequency + IntermediateFrequency);
10839a0bf528SMauro Carvalho Chehab 			if (status < 0)
10849a0bf528SMauro Carvalho Chehab 				break;
10859a0bf528SMauro Carvalho Chehab 
10869a0bf528SMauro Carvalho Chehab 			SearchMap3(m_Cal_PLL_Map, Frequency + IntermediateFrequency, &PostDiv, &Div);
10879a0bf528SMauro Carvalho Chehab 			state->m_Regs[MPD] = (state->m_Regs[MPD] & ~0x7F) | (PostDiv & 0x77);
10889a0bf528SMauro Carvalho Chehab 			status = UpdateReg(state, MPD);
10899a0bf528SMauro Carvalho Chehab 			if (status < 0)
10909a0bf528SMauro Carvalho Chehab 				break;
10919a0bf528SMauro Carvalho Chehab 			status = UpdateRegs(state, TM, EP5);
10929a0bf528SMauro Carvalho Chehab 			if (status < 0)
10939a0bf528SMauro Carvalho Chehab 				break;
10949a0bf528SMauro Carvalho Chehab 
10959a0bf528SMauro Carvalho Chehab 			state->m_Regs[EB7] |= 0x20;    /* CAL_forceSrce = 1 */
10969a0bf528SMauro Carvalho Chehab 			status = UpdateReg(state, EB7);
10979a0bf528SMauro Carvalho Chehab 			if (status < 0)
10989a0bf528SMauro Carvalho Chehab 				break;
10999a0bf528SMauro Carvalho Chehab 			msleep(1);
11009a0bf528SMauro Carvalho Chehab 			state->m_Regs[EB7] &= ~0x20;   /* CAL_forceSrce = 0 */
11019a0bf528SMauro Carvalho Chehab 			status = UpdateReg(state, EB7);
11029a0bf528SMauro Carvalho Chehab 			if (status < 0)
11039a0bf528SMauro Carvalho Chehab 				break;
11049a0bf528SMauro Carvalho Chehab 		}
11059a0bf528SMauro Carvalho Chehab 		msleep(20);
11069a0bf528SMauro Carvalho Chehab 		if (Standard != HF_FM_Radio)
11079a0bf528SMauro Carvalho Chehab 			state->m_Regs[EP3] |= 0x04;    /* RFAGC to normal mode */
11089a0bf528SMauro Carvalho Chehab 		status = UpdateReg(state, EP3);
11099a0bf528SMauro Carvalho Chehab 		if (status < 0)
11109a0bf528SMauro Carvalho Chehab 			break;
11119a0bf528SMauro Carvalho Chehab 
11129a0bf528SMauro Carvalho Chehab 	} while (0);
11139a0bf528SMauro Carvalho Chehab 	return status;
11149a0bf528SMauro Carvalho Chehab }
11159a0bf528SMauro Carvalho Chehab 
11169a0bf528SMauro Carvalho Chehab static int sleep(struct dvb_frontend *fe)
11179a0bf528SMauro Carvalho Chehab {
11189a0bf528SMauro Carvalho Chehab 	struct tda_state *state = fe->tuner_priv;
11199a0bf528SMauro Carvalho Chehab 
11209a0bf528SMauro Carvalho Chehab 	StandBy(state);
11219a0bf528SMauro Carvalho Chehab 	return 0;
11229a0bf528SMauro Carvalho Chehab }
11239a0bf528SMauro Carvalho Chehab 
11249a0bf528SMauro Carvalho Chehab static int init(struct dvb_frontend *fe)
11259a0bf528SMauro Carvalho Chehab {
11269a0bf528SMauro Carvalho Chehab 	return 0;
11279a0bf528SMauro Carvalho Chehab }
11289a0bf528SMauro Carvalho Chehab 
11299a0bf528SMauro Carvalho Chehab static int release(struct dvb_frontend *fe)
11309a0bf528SMauro Carvalho Chehab {
11319a0bf528SMauro Carvalho Chehab 	kfree(fe->tuner_priv);
11329a0bf528SMauro Carvalho Chehab 	fe->tuner_priv = NULL;
11339a0bf528SMauro Carvalho Chehab 	return 0;
11349a0bf528SMauro Carvalho Chehab }
11359a0bf528SMauro Carvalho Chehab 
11369a0bf528SMauro Carvalho Chehab 
11379a0bf528SMauro Carvalho Chehab static int set_params(struct dvb_frontend *fe)
11389a0bf528SMauro Carvalho Chehab {
11399a0bf528SMauro Carvalho Chehab 	struct tda_state *state = fe->tuner_priv;
11409a0bf528SMauro Carvalho Chehab 	int status = 0;
11419a0bf528SMauro Carvalho Chehab 	int Standard;
11429a0bf528SMauro Carvalho Chehab 	u32 bw = fe->dtv_property_cache.bandwidth_hz;
11439a0bf528SMauro Carvalho Chehab 	u32 delsys  = fe->dtv_property_cache.delivery_system;
11449a0bf528SMauro Carvalho Chehab 
11459a0bf528SMauro Carvalho Chehab 	state->m_Frequency = fe->dtv_property_cache.frequency;
11469a0bf528SMauro Carvalho Chehab 
11479a0bf528SMauro Carvalho Chehab 	switch (delsys) {
11489a0bf528SMauro Carvalho Chehab 	case  SYS_DVBT:
11499a0bf528SMauro Carvalho Chehab 	case  SYS_DVBT2:
11509a0bf528SMauro Carvalho Chehab 		switch (bw) {
11519a0bf528SMauro Carvalho Chehab 		case 6000000:
11529a0bf528SMauro Carvalho Chehab 			Standard = HF_DVBT_6MHZ;
11539a0bf528SMauro Carvalho Chehab 			break;
11549a0bf528SMauro Carvalho Chehab 		case 7000000:
11559a0bf528SMauro Carvalho Chehab 			Standard = HF_DVBT_7MHZ;
11569a0bf528SMauro Carvalho Chehab 			break;
11579a0bf528SMauro Carvalho Chehab 		case 8000000:
11589a0bf528SMauro Carvalho Chehab 			Standard = HF_DVBT_8MHZ;
11599a0bf528SMauro Carvalho Chehab 			break;
11609a0bf528SMauro Carvalho Chehab 		default:
11619a0bf528SMauro Carvalho Chehab 			return -EINVAL;
11629a0bf528SMauro Carvalho Chehab 		}
11639a0bf528SMauro Carvalho Chehab 	case SYS_DVBC_ANNEX_A:
11649a0bf528SMauro Carvalho Chehab 	case SYS_DVBC_ANNEX_C:
11659a0bf528SMauro Carvalho Chehab 		if (bw <= 6000000)
11669a0bf528SMauro Carvalho Chehab 			Standard = HF_DVBC_6MHZ;
11679a0bf528SMauro Carvalho Chehab 		else if (bw <= 7000000)
11689a0bf528SMauro Carvalho Chehab 			Standard = HF_DVBC_7MHZ;
11699a0bf528SMauro Carvalho Chehab 		else
11709a0bf528SMauro Carvalho Chehab 			Standard = HF_DVBC_8MHZ;
11719a0bf528SMauro Carvalho Chehab 		break;
11729a0bf528SMauro Carvalho Chehab 	default:
11739a0bf528SMauro Carvalho Chehab 		return -EINVAL;
11749a0bf528SMauro Carvalho Chehab 	}
11759a0bf528SMauro Carvalho Chehab 	do {
11769a0bf528SMauro Carvalho Chehab 		status = RFTrackingFiltersCorrection(state, state->m_Frequency);
11779a0bf528SMauro Carvalho Chehab 		if (status < 0)
11789a0bf528SMauro Carvalho Chehab 			break;
11799a0bf528SMauro Carvalho Chehab 		status = ChannelConfiguration(state, state->m_Frequency,
11809a0bf528SMauro Carvalho Chehab 					      Standard);
11819a0bf528SMauro Carvalho Chehab 		if (status < 0)
11829a0bf528SMauro Carvalho Chehab 			break;
11839a0bf528SMauro Carvalho Chehab 
11849a0bf528SMauro Carvalho Chehab 		msleep(state->m_SettlingTime);  /* Allow AGC's to settle down */
11859a0bf528SMauro Carvalho Chehab 	} while (0);
11869a0bf528SMauro Carvalho Chehab 	return status;
11879a0bf528SMauro Carvalho Chehab }
11889a0bf528SMauro Carvalho Chehab 
11899a0bf528SMauro Carvalho Chehab #if 0
11909a0bf528SMauro Carvalho Chehab static int GetSignalStrength(s32 *pSignalStrength, u32 RFAgc, u32 IFAgc)
11919a0bf528SMauro Carvalho Chehab {
11929a0bf528SMauro Carvalho Chehab 	if (IFAgc < 500) {
11939a0bf528SMauro Carvalho Chehab 		/* Scale this from 0 to 50000 */
11949a0bf528SMauro Carvalho Chehab 		*pSignalStrength = IFAgc * 100;
11959a0bf528SMauro Carvalho Chehab 	} else {
11969a0bf528SMauro Carvalho Chehab 		/* Scale range 500-1500 to 50000-80000 */
11979a0bf528SMauro Carvalho Chehab 		*pSignalStrength = 50000 + (IFAgc - 500) * 30;
11989a0bf528SMauro Carvalho Chehab 	}
11999a0bf528SMauro Carvalho Chehab 
12009a0bf528SMauro Carvalho Chehab 	return 0;
12019a0bf528SMauro Carvalho Chehab }
12029a0bf528SMauro Carvalho Chehab #endif
12039a0bf528SMauro Carvalho Chehab 
12049a0bf528SMauro Carvalho Chehab static int get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
12059a0bf528SMauro Carvalho Chehab {
12069a0bf528SMauro Carvalho Chehab 	struct tda_state *state = fe->tuner_priv;
12079a0bf528SMauro Carvalho Chehab 
12089a0bf528SMauro Carvalho Chehab 	*frequency = state->IF;
12099a0bf528SMauro Carvalho Chehab 	return 0;
12109a0bf528SMauro Carvalho Chehab }
12119a0bf528SMauro Carvalho Chehab 
12129a0bf528SMauro Carvalho Chehab static int get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
12139a0bf528SMauro Carvalho Chehab {
12149a0bf528SMauro Carvalho Chehab 	/* struct tda_state *state = fe->tuner_priv; */
12159a0bf528SMauro Carvalho Chehab 	/* *bandwidth = priv->bandwidth; */
12169a0bf528SMauro Carvalho Chehab 	return 0;
12179a0bf528SMauro Carvalho Chehab }
12189a0bf528SMauro Carvalho Chehab 
12199a0bf528SMauro Carvalho Chehab 
12209a0bf528SMauro Carvalho Chehab static struct dvb_tuner_ops tuner_ops = {
12219a0bf528SMauro Carvalho Chehab 	.info = {
12229a0bf528SMauro Carvalho Chehab 		.name = "NXP TDA18271C2D",
12239a0bf528SMauro Carvalho Chehab 		.frequency_min  =  47125000,
12249a0bf528SMauro Carvalho Chehab 		.frequency_max  = 865000000,
12259a0bf528SMauro Carvalho Chehab 		.frequency_step =     62500
12269a0bf528SMauro Carvalho Chehab 	},
12279a0bf528SMauro Carvalho Chehab 	.init              = init,
12289a0bf528SMauro Carvalho Chehab 	.sleep             = sleep,
12299a0bf528SMauro Carvalho Chehab 	.set_params        = set_params,
12309a0bf528SMauro Carvalho Chehab 	.release           = release,
12319a0bf528SMauro Carvalho Chehab 	.get_if_frequency  = get_if_frequency,
12329a0bf528SMauro Carvalho Chehab 	.get_bandwidth     = get_bandwidth,
12339a0bf528SMauro Carvalho Chehab };
12349a0bf528SMauro Carvalho Chehab 
12359a0bf528SMauro Carvalho Chehab struct dvb_frontend *tda18271c2dd_attach(struct dvb_frontend *fe,
12369a0bf528SMauro Carvalho Chehab 					 struct i2c_adapter *i2c, u8 adr)
12379a0bf528SMauro Carvalho Chehab {
12389a0bf528SMauro Carvalho Chehab 	struct tda_state *state;
12399a0bf528SMauro Carvalho Chehab 
12409a0bf528SMauro Carvalho Chehab 	state = kzalloc(sizeof(struct tda_state), GFP_KERNEL);
12419a0bf528SMauro Carvalho Chehab 	if (!state)
12429a0bf528SMauro Carvalho Chehab 		return NULL;
12439a0bf528SMauro Carvalho Chehab 
12449a0bf528SMauro Carvalho Chehab 	fe->tuner_priv = state;
12459a0bf528SMauro Carvalho Chehab 	state->adr = adr;
12469a0bf528SMauro Carvalho Chehab 	state->i2c = i2c;
12479a0bf528SMauro Carvalho Chehab 	memcpy(&fe->ops.tuner_ops, &tuner_ops, sizeof(struct dvb_tuner_ops));
12489a0bf528SMauro Carvalho Chehab 	reset(state);
12499a0bf528SMauro Carvalho Chehab 	InitCal(state);
12509a0bf528SMauro Carvalho Chehab 
12519a0bf528SMauro Carvalho Chehab 	return fe;
12529a0bf528SMauro Carvalho Chehab }
12539a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL_GPL(tda18271c2dd_attach);
12549a0bf528SMauro Carvalho Chehab 
12559a0bf528SMauro Carvalho Chehab MODULE_DESCRIPTION("TDA18271C2 driver");
12569a0bf528SMauro Carvalho Chehab MODULE_AUTHOR("DD");
12579a0bf528SMauro Carvalho Chehab MODULE_LICENSE("GPL");
1258