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