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