/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * Copyright (C) 2002,2003 Florian Schirmer <jolt@tuxbox.org>
 *
 * Copyright (C) 2007 NXP B.V.
 * All Rights Reserved.
 *
 * NXP based DVB adapter driver.
 * Based on the bt8xx driver by Florian Schirmer <jolt@tuxbox.org>
 *
*//*

Rev Date        Author         Comments
--------------------------------------------------------------------------------
001 20071221    Mike Whittaker  Port from Caen code
002 20080211 Lucas Cordeiro  Fixes in the tuner init and calibrateRF functions
003 20080318 Lucas Cordeiro Incorporate updates of Windows driver v.3.4
001 20080514 Christophe Grosse First version for Caen Database + alignement with latest FeComps
--------------------------------------------------------------------------------
    For consistency and standardisation retain the Section Separators.
*/

/***********************************************
* INCLUDE FILES                                *
************************************************/

#include <linux/i2c.h>
#include <linux/delay.h>

// For tuner configuration
#include <prjconfig.h>

#include "tda18211.h"
#include "tda10048.h"


/***********************************************
* LOCAL MACROS                                 *
************************************************/

// For initialisation tables
#define dimof(a) (sizeof(a)/sizeof(a[0]))

#define TDA18211_THERMOMETER_NB_ROWS  (16)   
#define TDA18211_BP_FILTER_NB_ROWS   (2)
#define TDA18211_GAIN_TAPER_NB_ROWS   (48)
#define TDA18211_RF_BAND_NB_ROWS   (3)
#define TDA18211_RF_CAL_KMCO_NB_ROWS  (3)
#define TDA18211_CAL_PLL_NB_ROWS   (18)
#define TDA18211_MAIN_PLL_NB_ROWS   (20)
#define TDA18211_RF_CAL_NB_ROWS    (319)
#define TDA18211_RF_CAL_DC_OVER_DT_NB_ROWS (85)
#define TDA18211_IR_MEAS_NB_ROWS   (3)
#define TDA18211_RF_CAL_CID_TARGET_NB_ROWS (7)

#define dprintk( args... ) \
 do { \
  if (debug) printk(KERN_DEBUG args); \
 } while (0)

// Porting definitions
#define TMBSL_ERR_IIC_ERR -1
#define TM_FALSE 0
#define TM_OK 1
#define TRUE 1
#define True 1
#define False 0

#define RF_CAL_IF_FREQ 1000000

/******************************************************************
* LOCAL TYPEDEFS                                                  *
* recommendation only:                     [p]phStbDbg_<Word>+_t  *
*******************************************************************/

/******************************************************************
* LOCAL TYPEDEFS                                                  *
*******************************************************************/

// Porting definitions
typedef unsigned int UInt32;
typedef int Int32;
typedef unsigned char UInt8;
typedef signed char Int8;
typedef unsigned char Bool;
typedef int tmErrorCode_t;

enum {
 TDA18211_R_ID = 0,
 TDA18211_R_TM,
 TDA18211_R_PL,
 TDA18211_R_EP1,
 TDA18211_R_EP2,
 TDA18211_R_EP3,
 TDA18211_R_EP4,
 TDA18211_R_EP5,
 TDA18211_R_CPD,
 TDA18211_R_CD1,
 TDA18211_R_CD2,
 TDA18211_R_CD3,
 TDA18211_R_MPD,
 TDA18211_R_MD1,
 TDA18211_R_MD2,
 TDA18211_R_MD3,
 TDA18211_R_EB1,
 TDA18211_R_EB2,
 TDA18211_R_EB3,
 TDA18211_R_EB4,
 TDA18211_R_EB5,
 TDA18211_R_EB6,
 TDA18211_R_EB7,
 TDA18211_R_EB8,
 TDA18211_R_EB9,
 TDA18211_R_EB10,
 TDA18211_R_EB11,
 TDA18211_R_EB12,
 TDA18211_R_EB13,
 TDA18211_R_EB14,
 TDA18211_R_EB15,
 TDA18211_R_EB16,
 TDA18211_R_EB17,
 TDA18211_R_EB18,
 TDA18211_R_EB19,
 TDA18211_R_EB20,
 TDA18211_R_EB21,
 TDA18211_R_EB22,
 TDA18211_R_EB23,
 
 NUM_TDA18211_REG
};

// For Caen code's 'static variables'
typedef struct {
 UInt8 Master, StandardMode;
 UInt32        uStandard;
 UInt32        uRF;
 UInt32        uIF;
 UInt32        uBW;
 UInt32        uTMVALUE_RFCAL;
 UInt32        uPLMODE;
 Int32        uRFCAL_TCOMP;
} tmTDA182I1Config_t;

struct tda18211_priv {
 u8 i2c_addr;
 struct i2c_adapter *i2c_adapt;
 unsigned char tda18211_regs[NUM_TDA18211_REG];
 short init;

 u32 frequency;
 u32 bandwidth;

 tmTDA182I1Config_t Config_Instance; // to hold 'static data' for Caen code
};

// For Caen code
typedef struct _tmTDA18211_IR_MEAS_Map_t {
 UInt32 uRF_Max;
    UInt32 uIR_Meas;
} tmTDA18211_IR_MEAS_Map_t, *ptmTDA18211_IR_MEAS_Map_t;

// For Caen code
typedef enum {
 tmDigital_TV_ATSC_6MHz,     // Digital TV ATSC 6MHz
 tmDigital_TV_DVBT_6MHz,     // Digital TV DVB-T 6MHz: not in orig code
 tmDigital_TV_DVBT_7MHz,     // Digital TV DVB-T 7MHz
 tmDigital_TV_DVBT_8MHz,     // Digital TV DVB-T 8MHz
 tmDigital_CAL,       // Digital CAL mode
 tmDigital_TV_QAM_6MHz,     // Digital TV QAM 6MHz
 tmDigital_TV_QAM_8MHz,     // Digital TV QAM 8MHz
 tmDigital_TV_ISDBT_6MHz,    // Digital TV ISDBT 6MHz
 tmStandardNotSupported,     // Not supported standard
} tmTDA182I1StandardMode_t, *ptmTDA182I1StandardMode_t;


/******************************************************************
* STATIC DATA                  g[k|p|kp|pk|kpk]<Module>_<Word>+   *
*******************************************************************/

// @todo Remove default setting to '1'
static int debug;  // module param



static const struct {
 UInt32 uRF_Max, uIR_Meas;
} IR_MEAS_Map[] =
{        // IR_MEAS_Map uRF_Max 
  {174000000, 0x00},
  {200000000, 0x05},		
  {600000000, 0x06},
  {865000000, 0x07},
};

static const struct {
 UInt32 uRF;
 UInt8 uIR_GStep;
} IR_CAL_Map[] =
{       // IR_CAL_Map uRF, uIR_GStep 
 {72000000, 0x03},  
 {408000000, 0x03},
 {808000000, 0x03},
};

static const struct {
 UInt32 uRF_Max;
 UInt8 uBP_Filter;
} BP_FILTER_Map[] =
{       // BP_FILTER_Map uRF_Max, uBP_Filter 
 {180000000, 0x05},
 {865000000, 0x06},
};

typedef struct {
 UInt32 uRF_Max;
 UInt32 uRF_Band;
 UInt32 uRF1;
 UInt32 uRF2;
 UInt32 uRF3;
 Int32 uRF_A1;
 Int32 uRF_B1;
 Int32 uRF_A2;
 Int32 uRF_B2;
 UInt32 uRF1_default;
 UInt32 uRF2_default;
 UInt32 uRF3_default;
} tmTDA182I1_RF_BAND_Map_t, *ptmTDA182I1_RF_BAND_Map_t;

static const tmTDA182I1_RF_BAND_Map_t RF_BAND_Map[] =
{ // RF_BAND_Map uRF_Max, uRF_Band, uRF1, uRF2, uRF3, uRF_A1, uRF_B1, uRF_A2, uRF_B2, uRF1_default, uRF2_default, uRF3_default
 {203500000, 0x04, 0, 0, 0, 0x00, 0x00, 0x00, 0x00, 186250000, 0,   0   }, 
 {457800000, 0x05, 0, 0, 0, 0x00, 0x00, 0x00, 0x00, 230000000, 345000000, 426000000 }, 
 {865000000, 0x06, 0, 0, 0, 0x00, 0x00, 0x00, 0x00, 489500000, 697500000, 842000000 },
};

static const struct {
 UInt32 uRF_Max;
 UInt8 uGain_Taper;
} GAIN_TAPER_Map[] =
{       // GAIN_TAPER_Map uRF_Max, uGain_Taper 
 {175800000, 0x16},   
 {181300000, 0x15},   
 {186900000, 0x14},   
 {192400000, 0x13},   
 {198000000, 0x12},   
 {203500000, 0x11},   
 {216200000, 0x14},   
 {228900000, 0x13},   
 {241600000, 0x12},   
 {254400000, 0x11},   
 {267100000, 0x10},   
 {279800000, 0x0F},   
 {292500000, 0x0E},   
 {305200000, 0x0D},   
 {317900000, 0x0C},   
 {330700000, 0x0B},   
 {343400000, 0x0A},   
 {356100000, 0x09},   
 {368800000, 0x08},   
 {381500000, 0x07},   
 {394200000, 0x06},   
 {406900000, 0x05},   
 {419700000, 0x04},   
	{432400000, 0x03},			
	{445100000, 0x02},			
	{457800000, 0x01},			
	{476300000, 0x19},			
	{494800000, 0x18},			
	{513300000, 0x17},			
	{531800000, 0x16},			
	{550300000, 0x15},			
	{568900000, 0x14},			
	{587400000, 0x13},			
	{605900000, 0x12},			
	{624400000, 0x11},			
	{642900000, 0x10},			
	{661400000, 0x0F},			
	{679900000, 0x0E},			
	{698400000, 0x0D},			
	{716900000, 0x0C},			
	{735400000, 0x0B},			
	{753900000, 0x0A},			
	{772500000, 0x09},			
	{791000000, 0x08},			
	{809500000, 0x07},			
	{828000000, 0x06},			
	{846500000, 0x05},			
	{865000000, 0x04},

};

static const struct {
	UInt32 uRF_Max;
	UInt8 uRFC_Cprog;
} RF_CAL_Map[] =
{							// RF_CAL_Map uRF_Max, uRFC_Cprog
	{174000000, 0x18},
	{175000000, 0x1A},
	{176000000, 0x1B},
	{178000000, 0x1D},
	{179000000, 0x1E},
	{180000000, 0x1F},
	{181000000, 0x20},
	{182000000, 0x21},
	{183000000, 0x22},
	{184000000, 0x24},
	{185000000, 0x25},
	{186000000, 0x26},
	{187000000, 0x27},
	{188000000, 0x29},
	{189000000, 0x2A},
	{190000000, 0x2C},
	{191000000, 0x2D},
	{192000000, 0x2E},
	{193000000, 0x2F},
	{194000000, 0x30},
	{195000000, 0x33},
	{196000000, 0x35},
	{198000000, 0x36},
	{200000000, 0x38},
	{201000000, 0x3C},
	{202000000, 0x3D},
	{203500000, 0x3E},
	{206000000, 0x0E},
	{208000000, 0x0F},
	{212000000, 0x10},
	{216000000, 0x11},
	{217000000, 0x12},
	{218000000, 0x13},
	{220000000, 0x14},
	{222000000, 0x15},
	{225000000, 0x16},
	{228000000, 0x17},
	{231000000, 0x18},
	{234000000, 0x19},
	{235000000, 0x1A},
	{236000000, 0x1B},
	{237000000, 0x1C},
	{240000000, 0x1D},
	{242000000, 0x1E},
	{244000000, 0x1F},
	{247000000, 0x20},
	{249000000, 0x21},
	{252000000, 0x22},
	{253000000, 0x23},
	{254000000, 0x24},
	{256000000, 0x25},
	{259000000, 0x26},
	{262000000, 0x27},
	{264000000, 0x28},
	{267000000, 0x29},
	{269000000, 0x2A},
	{271000000, 0x2B},
	{273000000, 0x2C},
	{275000000, 0x2D},
	{277000000, 0x2E},
	{279000000, 0x2F},
	{282000000, 0x30},
	{284000000, 0x31},
	{286000000, 0x32},
	{287000000, 0x33},
	{290000000, 0x34},
	{293000000, 0x35},
	{295000000, 0x36},
	{297000000, 0x37},
	{300000000, 0x38},
	{303000000, 0x39},
	{305000000, 0x3A},
	{306000000, 0x3B},
	{307000000, 0x3C},
	{310000000, 0x3D},
	{312000000, 0x3E},
	{315000000, 0x3F},
	{318000000, 0x40},
	{320000000, 0x41},
	{323000000, 0x42},
	{324000000, 0x43},
	{325000000, 0x44},
	{327000000, 0x45},
	{331000000, 0x46},
	{334000000, 0x47},
	{337000000, 0x48},
	{339000000, 0x49},
	{340000000, 0x4A},
	{341000000, 0x4B},
	{343000000, 0x4C},
	{345000000, 0x4D},
	{349000000, 0x4E},
	{352000000, 0x4F},
	{353000000, 0x50},
	{355000000, 0x51},
	{357000000, 0x52},
	{359000000, 0x53},
	{361000000, 0x54},
	{362000000, 0x55},
	{364000000, 0x56},
	{368000000, 0x57},
	{370000000, 0x58},
	{372000000, 0x59},
	{375000000, 0x5A},
	{376000000, 0x5B},
	{377000000, 0x5C},
	{379000000, 0x5D},
	{382000000, 0x5E},
	{384000000, 0x5F},
	{385000000, 0x60},
	{386000000, 0x61},
	{388000000, 0x62},
	{390000000, 0x63},
	{393000000, 0x64},
	{394000000, 0x65},
	{396000000, 0x66},
	{397000000, 0x67},
	{398000000, 0x68},
	{400000000, 0x69},
	{402000000, 0x6A},
	{403000000, 0x6B},
	{407000000, 0x6C},
	{408000000, 0x6D},
	{409000000, 0x6E},
	{410000000, 0x6F},
	{411000000, 0x70},
	{412000000, 0x71},
	{413000000, 0x72},
	{414000000, 0x73},
	{417000000, 0x74},
	{418000000, 0x75},
	{420000000, 0x76},
	{422000000, 0x77},
	{423000000, 0x78},
	{424000000, 0x79},
	{427000000, 0x7A},
	{428000000, 0x7B},
	{429000000, 0x7D},
	{432000000, 0x7F},
	{434000000, 0x80},
	{435000000, 0x81},
	{436000000, 0x83},
	{437000000, 0x84},
	{438000000, 0x85},
	{439000000, 0x86},
	{440000000, 0x87},
	{441000000, 0x88},
	{442000000, 0x89},
	{445000000, 0x8A},
	{446000000, 0x8B},
	{447000000, 0x8C},
	{448000000, 0x8E},
 {449000000, 0x8F},
 {450000000, 0x90},
 {452000000, 0x91},
 {453000000, 0x93},
 {454000000, 0x94},
 {456000000, 0x96},
 {457800000, 0x98},
 {461000000, 0x11},
 {468000000, 0x12},
 {472000000, 0x13},
 {473000000, 0x14},
 {474000000, 0x15},
 {481000000, 0x16},
 {486000000, 0x17},
 {491000000, 0x18},
 {498000000, 0x19},
 {499000000, 0x1A},
 {501000000, 0x1B},
 {506000000, 0x1C},
 {511000000, 0x1D},
 {516000000, 0x1E},
 {520000000, 0x1F},
 {521000000, 0x20},
 {525000000, 0x21},
 {529000000, 0x22},
 {533000000, 0x23},
 {539000000, 0x24},
 {541000000, 0x25},
 {547000000, 0x26},
 {549000000, 0x27},
 {551000000, 0x28},
 {556000000, 0x29},
 {561000000, 0x2A},
 {563000000, 0x2B},
 {565000000, 0x2C},
 {569000000, 0x2D},
 {571000000, 0x2E},
 {577000000, 0x2F},
 {580000000, 0x30},
 {582000000, 0x31},
 {584000000, 0x32},
 {588000000, 0x33},
 {591000000, 0x34},
 {596000000, 0x35},
 {598000000, 0x36},
 {603000000, 0x37},
 {604000000, 0x38},
 {606000000, 0x39},
 {612000000, 0x3A},
 {615000000, 0x3B},
 {617000000, 0x3C},
 {621000000, 0x3D},
 {622000000, 0x3E},
 {625000000, 0x3F},
 {632000000, 0x40},
 {633000000, 0x41},
 {634000000, 0x42},
 {642000000, 0x43},
 {643000000, 0x44},
 {647000000, 0x45},
 {650000000, 0x46},
 {652000000, 0x47},
 {657000000, 0x48},
 {661000000, 0x49},
 {662000000, 0x4A},
 {665000000, 0x4B},
 {667000000, 0x4C},
 {670000000, 0x4D},
 {673000000, 0x4E},
 {676000000, 0x4F},
 {677000000, 0x50},
 {681000000, 0x51},
 {683000000, 0x52},
 {686000000, 0x53},
 {688000000, 0x54},
 {689000000, 0x55},
 {691000000, 0x56},
 {695000000, 0x57},
 {698000000, 0x58},
 {703000000, 0x59},
 {704000000, 0x5A},
 {705000000, 0x5B},
 {707000000, 0x5C},
 {710000000, 0x5D},
 {712000000, 0x5E},
 {717000000, 0x5F},
 {718000000, 0x60},
 {721000000, 0x61},
 {722000000, 0x62},
 {723000000, 0x63},
 {725000000, 0x64},
 {727000000, 0x65},
 {730000000, 0x66},
 {732000000, 0x67},
 {735000000, 0x68},
 {740000000, 0x69},
 {741000000, 0x6A},
 {742000000, 0x6B},
 {743000000, 0x6C},
 {745000000, 0x6D},
 {747000000, 0x6E},
 {748000000, 0x6F},
 {750000000, 0x70},
 {752000000, 0x71},
 {754000000, 0x72},
 {757000000, 0x73},
 {758000000, 0x74},
 {760000000, 0x75},
 {763000000, 0x76},
 {764000000, 0x77},
 {766000000, 0x78},
 {767000000, 0x79},
 {768000000, 0x7A},
 {773000000, 0x7B},
 {774000000, 0x7C},
 {776000000, 0x7D},
 {777000000, 0x7E},
 {778000000, 0x7F},
 {779000000, 0x80},
 {781000000, 0x81},
 {783000000, 0x82},
 {784000000, 0x83},
 {785000000, 0x84},
 {786000000, 0x85},
 {793000000, 0x86},
 {794000000, 0x87},
 {795000000, 0x88},
 {797000000, 0x89},
 {799000000, 0x8A},
 {801000000, 0x8B},
 {802000000, 0x8C},
 {803000000, 0x8D},
 {804000000, 0x8E},
 {810000000, 0x90},
 {811000000, 0x91},
 {812000000, 0x92},
 {814000000, 0x93},
 {816000000, 0x94},
 {817000000, 0x96},
 {818000000, 0x97},
 {820000000, 0x98},
 {821000000, 0x99},
 {822000000, 0x9A},
 {828000000, 0x9B},
 {829000000, 0x9D},
 {830000000, 0x9F},
 {831000000, 0xA0},
 {833000000, 0xA1},
 {835000000, 0xA2},
 {836000000, 0xA3},
 {837000000, 0xA4},
 {838000000, 0xA6},
 {840000000, 0xA8},
 {842000000, 0xA9},
 {845000000, 0xAA},
 {846000000, 0xAB},
 {847000000, 0xAD},
 {848000000, 0xAE},
 {852000000, 0xAF},
 {853000000, 0xB0},
 {858000000, 0xB1},
 {860000000, 0xB2},
 {861000000, 0xB3},
 {862000000, 0xB4},
 {863000000, 0xB6},
 {864000000, 0xB8},
 {865000000, 0xB9},
};

static const struct {
 UInt32 uRF_Max;
 UInt8 udC_Over_dT;
} RF_CAL_DC_OVER_DT_Map[] =
{       // RF_CAL_DC_OVER_DT_Map uRF_Max, udC_Over_dT   
 {203500000, 0x32},
 {353000000, 0x19},
 {356000000, 0x1A},
 {359000000, 0x1B},
 {363000000, 0x1C},
 {366000000, 0x1D},
 {369000000, 0x1E},
 {373000000, 0x1F},
 {376000000, 0x20},
 {379000000, 0x21},
 {383000000, 0x22},
 {386000000, 0x23},
 {389000000, 0x24},
 {393000000, 0x25},
 {396000000, 0x26},
 {399000000, 0x27},
 {402000000, 0x28},
 {404000000, 0x29},
 {407000000, 0x2A},
 {409000000, 0x2B},
 {412000000, 0x2C},
 {414000000, 0x2D},
 {417000000, 0x2E},
 {419000000, 0x2F},
 {422000000, 0x30},
 {424000000, 0x31},
 {427000000, 0x32},
 {429000000, 0x33},
 {432000000, 0x34},
 {434000000, 0x35},
 {437000000, 0x36},
 {439000000, 0x37},
 {442000000, 0x38},
 {444000000, 0x39},
 {447000000, 0x3A},
 {449000000, 0x3B},
 {457800000, 0x3C},
 {465000000, 0x0F},
 {477000000, 0x12},
 {483000000, 0x14},
 {502000000, 0x19},
 {508000000, 0x1B},
 {519000000, 0x1C},
 {522000000, 0x1D},
 {524000000, 0x1E},
 {534000000, 0x1F},
 {549000000, 0x20},
 {554000000, 0x22},
 {584000000, 0x24},
 {589000000, 0x26},
 {658000000, 0x27},
 {664000000, 0x2C},
 {669000000, 0x2D},
 {699000000, 0x2E},
 {704000000, 0x30},
 {709000000, 0x31},
 {714000000, 0x32},
 {724000000, 0x33},
 {729000000, 0x36},
 {739000000, 0x38},
 {744000000, 0x39},
 {749000000, 0x3B},
 {754000000, 0x3C},
 {759000000, 0x3D},
 {764000000, 0x3E},
 {769000000, 0x3F},
 {774000000, 0x40},
 {779000000, 0x41},
 {784000000, 0x43},
 {789000000, 0x46},
 {794000000, 0x48},
 {799000000, 0x4B},
 {804000000, 0x4F},
 {809000000, 0x54},
 {814000000, 0x59},
 {819000000, 0x5D},
 {824000000, 0x61},
 {829000000, 0x68},
 {834000000, 0x6E},
 {839000000, 0x75},
 {844000000, 0x7E},
 {849000000, 0x82},
 {854000000, 0x84},
 {859000000, 0x8F},
 {865000000, 0x9A},
};

static const struct {
 UInt32 uRF_Max;
 UInt8 uK;
 UInt8 uM;
 UInt8 uCOAmpl;
} RF_CAL_KMCO_Map[] =
{       // RF_CAL_KMCO_Map uRF_Max, uK, uM, UCOAmp
 {350000000, 3, 0, 3},  
 {720000000, 2, 1, 3},  
 {865000000, 3, 3, 3},
 };

static const struct {
 UInt32 uRF_Max;
 UInt8 uCID_Target;
 UInt32 uCount_Limit;
} RF_CAL_CID_TARGET_Map[] = 
{       // RF_CAL_CID_TARGET_Map uRF_Max, uCID_Target, uCount_Limit
 {186250000, 10, 4000000},
 {230000000, 10, 4000000},
 {345000000, 24, 4000000},
 {426000000, 14, 4000000},
 {489500000, 30, 4000000},
 {697500000, 50, 4000000},
 {842000000, 58, 4000000},
};

static const struct {
 UInt8 uTM_D, uTM_60_92, uTM_92_122;
} THERMOMETER_Map[]=
{
 {0, 40, 92}, // 0
 {1, 62, 94}, // 1
 {2, 66, 98}, // 2
 {3, 64, 96}, // 3
 {4, 74, 106}, // 4
 {5, 72, 104}, // 5
 {6, 68, 100}, // 6
 {7, 70, 102}, // 7
 {8, 90, 122}, // 8
 {9, 88, 120}, // 9
 {10, 84, 116}, //10
 {11, 86, 118}, //11
 {12, 76, 108}, //12
 {13, 78, 110}, //13
 {14, 82, 114}, //14
 {15, 80, 112}, //15
};

static const struct {
 UInt32 uLO_Max;
 UInt8 uPost_Div;
 UInt8 uDiv;
} MAIN_PLL_Map[] =
{       // MAIN_PLL_Map uLO_Max, uPost_Div, uDiv 
       //Updated according to datasheet p.29
 {180500000, 0x3B, 0x2C}, //{180500000, 0x33, 0x2C},
 {198750000, 0x3A, 0x28}, //{198750000, 0x32, 0x28},
 {220750000, 0x39, 0x24}, //{220750000, 0x31, 0x24},
 {248500000, 0x38, 0x20}, //{248500000, 0x30, 0x20},
 {265000000, 0x2F, 0x1E}, //{265000000, 0x27, 0x1E},
 {284000000, 0x2E, 0x1C}, //{284000000, 0x26, 0x1C},
 {305500000, 0x2D, 0x1A}, //{305500000, 0x25, 0x1A},
 {331000000, 0x2C, 0x18}, //{331000000, 0x24, 0x18},
 {361000000, 0x2B, 0x16}, //{361000000, 0x23, 0x16},
 {397500000, 0x2A, 0x14}, //{397500000, 0x22, 0x14},
 {441500000, 0x29, 0x12}, //{441500000, 0x21, 0x12},
 {497000000, 0x28, 0x10}, //{497000000, 0x20, 0x10},
 {530000000, 0x1F, 0x0F}, //{530000000, 0x17, 0x0F},
 {568000000, 0x1E, 0x0E}, //{568000000, 0x16, 0x0E},
 {611000000, 0x1D, 0x0D}, //{611000000, 0x15, 0x0D},
 {662000000, 0x1C, 0x0C}, //{662000000, 0x14, 0x0C},
 {722000000, 0x1B, 0x0B}, //{722000000, 0x13, 0x0B},
 {795000000, 0x1A, 0x0A}, //{795000000, 0x12, 0x0A},
 {883000000, 0x19, 0x09}, //{883000000, 0x11, 0x09},
 {994000000, 0x18, 0x08}, //{994000000, 0x10, 0x08}, 
};

static const struct {
 UInt32 uLO_Max;
 UInt8 uPost_Div;
 UInt8 uDiv;
} CAL_PLL_Map[] =
{       // CAL_PLL_Map uLO_Max, uPost_Div, uDiv
       // Updated according to datasheet p. 29
 {175750000, 0xBA, 0x28},  
 {195250000, 0xB9, 0x24},  
 {219750000, 0xB8, 0x20},  
 {251250000, 0xB3, 0x1C},  
 {270500000, 0xAD, 0x1A},  
 {293000000, 0xAC, 0x18},  
 {319500000, 0xAB, 0x16},  
 {351500000, 0xAA, 0x14},  
 {390500000, 0xA9, 0x12},  
 {439500000, 0xA8, 0x10},  
 {502500000, 0xA3, 0x0E},  
 {541000000, 0x9D, 0x0D},  
 {586000000, 0x9C, 0x0C},  
 {639000000, 0x9B, 0x0B},  
 {703000000, 0x9A, 0x0A},  
 {781000000, 0x99, 0x09},  
 {879000000, 0x98, 0x08},  
// {1005000000,0x93, 0x07},  
};

typedef struct          
{         
 union        
 {        
  UInt8 ID_BYTE;    // address 0x00   
  // Chip identification byte
  struct       
  {       
   UInt8 ID   :7; // Chip identification number  
   UInt8 UNUSED  :1; // Reserved, must be written as 1    
  }bF;       
 }uBx00;

 union        
 {        
  UInt8 THERMO_BYTE;   // address 0x01    
  // Thermometer byte
  struct       
  {       
   UInt8 TM_D   :4; // Data from die temperature measurement   
   UInt8 TM_ON   :1; // Enable Die temperature measurement  
   UInt8 TM_Range  :1; // Range selection bit for the internal die sensor   
   // 0: 60 to 92C
   // 1: 92 to 122C
   UInt8 MAIN_Lock  :1; // Indicate that the MAIN synthesizer is locked to the programmed frequency   
   // 0: Not Locked
   // 1: Locked
   UInt8 POR   :1; // Power on reset bit  
   // This bit is set to 1 each time the power supply falls below a certain level (around 1.4V) and is reset after a read operation ending with a stop condition
  }bF;       
 }uBx01;

 union        
 {        
  UInt8 POWER_LEVEL_BYTE;  // address 0x02     
  // Power level byte
  struct       
  {       
   UInt8 Power_Level_7_to_0:8;// Power level indicator value      
  }bF;       
 }uBx02;

 union        
 {        
  UInt8 EASY_PROG_BYTE_1;  // address 0x03     
  // Easy programming byte 1
  struct       
  {       
   UInt8 BP_Filter  :3; // RF band-pass filter selection (H3/H5)    
   UInt8 IR_CAL_OK  :1; // Indicate that the 3 Image rejection calibration procedure  (Flow, Fmid, Fhigh) have been successful   
   UInt8 RF_CAL_OK  :1; // Indicate that the RF tracking filter calibration procedure has been successful   
   UInt8 UNUSED  :1; // Reserved    
   UInt8 Dis_Power_level:1;// Disable power level measurement      
   // 0: Power measurement valid
   // 1: Power measurement not guaranted
   UInt8 Power_Level_8 :1; // Power level indicator value    
  }bF;       
 }uBx03;

 union        
 {        
  UInt8 EASY_PROG_BYTE_2;  // address 0x04     
  // Easy programming byte 2 
  struct       
  {       
   UInt8 Gain_Taper :5; // Gain taper value    
   // 0  : max atten. (end of Band)
   // 31: min atten. (start of Band)
   UInt8 RF_Band  :3; // RF tracking filter band and sub-band selection   
  }bF;       
 }uBx04;

 union        
 {        
  UInt8 EASY_PROG_BYTE_3;  // address 0x05     
  // Easy programming byte 3 
  struct       
  {       
   UInt8 Std   :5; // Standard selection  
   UInt8 SM_XT   :1; // XTAL output sleep mode  
   UInt8 SM_LT   :1; // Loop through sleep mode  
   UInt8 SM   :1; // General sleep mode  
  }bF;       
 }uBx05;

 union        
 {        
  UInt8 EASY_PROG_BYTE_4;  // address 0x06     
  // Easy programming byte 4 
  struct       
  {       
   UInt8 CAL_Mode  :2; // calibration mode selection   
   UInt8 IF_Level  :3; // IF output level selection   
   UInt8 Xtout_400mV :1; // XTAL output level optional selection
   UInt8 XTout_ON  :1; // Enable 16MHz on XTAL output   

   UInt8 CAL_RFn  :1; // CAL or RF input selection   
  }bF;       
 }uBx06;

 union        
 {        
  UInt8 EASY_PROG_BYTE_5;  // address 0x07     
  // Easy programming byte 5
  struct       
  {       
   UInt8 IR_Meas  :3; // Image rejection measurement mode   
   UInt8 I2C_Xtout_Asym:1; // Reserved
   UInt8 IR_Gstep  :3; // Gain step for image rejection measurement. Depends on frequency   
   UInt8 Extended_Reg :1; // Enable the extended byte addressing    
   // 0: Limited byte (&h00:&h0F)
   // 1: Extended byte (&h00:&h26)
  }bF;       
 }uBx07;

 union         
 {         
  UInt8 CAL_POST_DIV_BYTE; // address 0x08       
  // CAL post divider byte  
  struct       
  {       
   UInt8 CALPostDiv :7; // CAL post divider   
   UInt8 RUF_0   :1; // Reserved
  }bF;
 }uBx08;

 union         
 {         
  UInt8 CAL_DIV_BYTE_1;  // address 0x09      
  // CAL divider byte 1
  struct        
  {        
   UInt8 CAL_Div_22_to_16:7;// CAL divider value 22 to 16       
   UInt8 RUF_1   :1; // Reserved
  }bF;       
 }uBx09;

 union         
 {         
  UInt8 CAL_DIV_BYTE_2;  // address 0x0A      
  // CAL divider byte 2
  struct        
  {        
   UInt8 CAL_Div_15_to_8:8;// CAL divider value 15 to 8       
  }bF;       
 }uBx0A;

 union         
 {         
  UInt8 CAL_DIV_BYTE_3;  // address 0x0B      
  // CAL divider byte 3
  struct        
  {        
   UInt8 CAL_Div_7_to_0:8; // CAL divider value 7 to 0      
  }bF;       
 }uBx0B;

 union         
 {         
  UInt8 MAIN_POST_DIV_BYTE; // address 0x0C       
  // MAIN post divider byte  
  struct        
  {       
   UInt8 MAIN_Post_Div :7; // MAIN post divider value
   UInt8 IF_notch :1; // Reserved
  }bF;       
 }uBx0C;

 union        
 {        
  UInt8 MAIN_DIV_BYTE_1;  // address 0x0D     
  // MAIN divider byte 1
  struct       
  {       
   UInt8 MAIN_Div_22_to_16:7;// MAIN divider value 22 to 16      
   UInt8 RUF_2   :1; // Reserved    
  }bF;       
 }uBx0D;

 union        
 {        
  UInt8 MAIN_DIV_BYTE_2;  // address 0x0E     
  // MAIN divider byte 2
  struct       
  {       
   UInt8 MAIN_Div_15_to_8:8;// MAIN divider value 15 to 8      
  }bF;       
 }uBx0E;

 union        
 {        
  UInt8 MAIN_DIV_BYTE_3;  // address 0x0F     
  // MAIN divider byte 3
  struct       
  {       
   UInt8 MAIN_Div_7_to_0:8;// MAIN divider value 7 to 0      
  }bF;       
 }uBx0F;

 union        
 {        
  UInt8 EXTENDED_BYTE_1;  // address 0x10     
  // extended byte 1
  struct       
  {       
   UInt8 AGC1_firstn :1; // 
   UInt8 AGC1_always_mastern:1;// 
   UInt8 CALVCO_forLOn :1; //
   UInt8 UNUSED  :1; // Reserved  
  }bF;
 }uBx10; 


 union        
 {        
  UInt8 EXTENDED_BYTE_2;  // address 0x11     
 }uBx11;       // extended byte 2


 union        
 {        
  UInt8 EXTENDED_BYTE_3;  // address 0x12     
 }uBx12;       // extended byte 3


 union        
 {        
  UInt8 EXTENDED_BYTE_4;  // address 0x13     
  // extended byte 4
  struct
  {   
   UInt8 UNUSED_1  :5; // Reserved
   UInt8 LO_ForceSrce :1; // 
   UInt8 UNUSED_2  :2; // Reserved 
  }bF;
 }uBx13; 

 union        
 {        
  UInt8 EXTENDED_BYTE_5;  // address 0x14     
 }uBx14;       // extended byte 5

 union        
 {        
  UInt8 EXTENDED_BYTE_6;  // address 0x15     
 }uBx15;       // extended byte 6

 union        
 {        
  UInt8 EXTENDED_BYTE_7;  // address 0x16     
  // extended byte 7
  struct
  {   
   UInt8 CAL_Lock  :1;
   UInt8 UNUSED_1  :4; // Reserved
   UInt8 CAL_ForceSrce :1; // 
   UInt8 UNUSED_2  :2; // Reserved 
  }bF;
 }uBx16; 

 union        
 {        
  UInt8 EXTENDED_BYTE_8;  // address 0x17     
  // extended byte 8
  struct
  {   
   UInt8 UNUSED  :7; // Reserved
   UInt8 CID_Alarm  :1; //   
  }bF;
 }uBx17;

 union        
 {        
  UInt8 EXTENDED_BYTE_9;  // address 0x18     
 }uBx18;       // extended byte 9

 union        
 {        
  UInt8 EXTENDED_BYTE_10;  // address 0x19     
  // extended byte 10
  struct
  {   
   UInt8 CID_Gain  :6; // 
   UInt8 UNUSED  :2; // Reserved
  }bF;
 }uBx19;

 union        
 {        
  UInt8 EXTENDED_BYTE_11;  // address 0x1A     
 }uBx1A;       // extended byte 11

 union        
 {        
  UInt8 EXTENDED_BYTE_12;  // address 0x1B     
  // extended byte 12
  struct
  {   
   UInt8 UNUSED_1  :4; // Reserved
   UInt8 PD_AGC2_Det :1; // 
   UInt8 PD_AGC1_Det :1; // 
   UInt8 UNUSED_2  :2; // Reserved
  }bF;
 }uBx1B;

 union        
 {        
  UInt8 EXTENDED_BYTE_13;  // address 0x1C     
  // extended byte 13
  struct
  {   
   UInt8 UNUSED_1  :2; // Reserved
   UInt8 RFC_M   :2; // 
   UInt8 RFC_K   :3; // 
   UInt8 UNUSED_2  :1; // Reserved
  }bF;
 }uBx1C;

 union        
 {        
  UInt8 EXTENDED_BYTE_14;  // address 0x1D     
  // extended byte 14
  UInt8 RFC_Cprog;
 }uBx1D;

 union        
 {        
  UInt8 EXTENDED_BYTE_15;  // address 0x1E     
 }uBx1E;       // extended byte 15

 union        
 {        
  UInt8 EXTENDED_BYTE_16;  // address 0x1F     
 }uBx1F;       // extended byte 16

 union        
 {        
  UInt8 EXTENDED_BYTE_17;  // address 0x20     
 }uBx20;       // extended byte 17

 union        
 {        
  UInt8 EXTENDED_BYTE_18;  // address 0x21     
  // extended byte 18
  struct       
  {   
   UInt8 AGC1_Gain  :2; // 
   UInt8 UNUSED  :5; // Reserved
   UInt8 AGC1_loop_off :1; //
  }bF;
 }uBx21; 

 union        
 {        
  UInt8 EXTENDED_BYTE_19;  // address 0x22     
 }uBx22;       // extended byte 19

 union        
 {        
  UInt8 EXTENDED_BYTE_20;  // address 0x23     
  // extended byte 20
  struct       
  {   
   UInt8 UNUSED_1  :5; // Reserved 
   UInt8 Force_Lock :1; // 
   UInt8 UNUSED_2  :2; // Reserved
  }bF;
 }uBx23;

	union								
	{								
		UInt8 EXTENDED_BYTE_21;		// address 0x24					
		// extended byte 21
		struct							
		{			
			UInt8 AGC2_Gain		:2;	// 
			UInt8 UNUSED		:5;	// Reserved
			UInt8 AGC2_loop_off	:1;	//
		}bF;
	}uBx24;	

 union        
 {        
  UInt8 EXTENDED_BYTE_22;  // address 0x25     
 }uBx25;       // extended byte 22

 union        
 {        
  UInt8 EXTENDED_BYTE_23;  // address 0x26     
  // extended byte 23
  struct       
  {   
   UInt8 UNUSED_1  :1; // Reserved
   UInt8 LP_Fc   :1; // 
   UInt8 ForceLP_Fc2_En:1; // 
   UInt8 UNUSED_2  :3; // Reserved
   UInt8 CAL_LNAGain  :2; //
  }bF;
 }uBx26; 

} tmTDA182I1I2CMap_t;

// Prototypes for Caen code

static tmErrorCode_t
TDA182I1CalcRFFilterCurve (
  struct dvb_frontend * tuner_card, unsigned char * p_reg_map
  );

static tmErrorCode_t
TDA182I1RFTrackingFiltersInit (
  struct dvb_frontend * tuner_card,
  unsigned char * p_reg_map,
        ptmTDA182I1_RF_BAND_Map_t pRF_BAND_Map // I: address of RF band map
          );
static int 
TDA182I1ThermometerRead (struct dvb_frontend * tuner_card, unsigned char * p_reg_map, UInt8 * puValue);


static int tuner_i2c_xfer(struct dvb_frontend * tuner_card, unsigned char * buf, int len, int is_read)
{
 struct tda18211_priv * priv = tuner_card->tuner_priv;
 int ret;
 struct i2c_msg tuner_i2c_msg =
 {
		.addr  = priv->i2c_addr,	//   tuner_addr,
		.flags = is_read ? I2C_M_RD : 0,
		.buf   = buf,
		.len   = len,
	};
	
	ret = i2c_transfer(priv->i2c_adapt, &tuner_i2c_msg, 1); // returns number of successful transfers
//	dprintk("%s: i2c:%02X, len:%d ret:%d\n", __FUNCTION__, priv->i2c_addr, len, ret);
    return (ret != 1) ? -EIO : 0;
}


static int tuner_i2c_read(struct dvb_frontend * tuner_card, unsigned char * buf, int len)
{
	int ret;
	
    ret = tuner_i2c_xfer(tuner_card, buf, len, 1);
//  dprintk("%s: i2c:%02X, buf: 0x%0X 0x%0X ... len:%d \n", __FUNCTION__, tuner_card->tuner_addr, buf[0], (len > 1) ? buf[1] : 0, len);
    return ret;
}


static int tuner_i2c_write(struct dvb_frontend * tuner_card, unsigned char * buf, int len)
{
 //int i;
 
// dprintk("%s: i2c:%02X, len: %d, buf: ", __FUNCTION__, tuner_card->tuner_addr, len);
// for (i = 0; debug && (i < len); ++i) dprintk("0x%0X%s", buf[i], (i==len-1) ? "\n" : ", ");

 return tuner_i2c_xfer(tuner_card, buf, len, 0);
}

static int tda_update_map_write_chip(struct dvb_frontend * tuner_card, unsigned char * tda18211_reg_map, int reg_num, int reg_value)
{
 unsigned char buf[2] = { (unsigned char)reg_num, (unsigned char)reg_value };
 int ret;
 
 dprintk("%s(%d)\n", __FUNCTION__, __LINE__);

 if (reg_num >= NUM_TDA18211_REG || reg_value > 0xFF)
 {
     dprintk("%s: invalid register setting r%d<-0x%0X\n", __FUNCTION__, reg_num, reg_value);
     return -1;
 }
 
 tda18211_reg_map[(unsigned char)reg_num] = (unsigned char)reg_value;

 ret = tuner_i2c_write(tuner_card, buf, sizeof(buf));
 if (ret < 0) dprintk("error return %d\n", ret);
 
 return ret;
}

static int tda_write_chip(struct dvb_frontend * tuner_card, int reg_num, int reg_value)
{
 unsigned char buf[2] = { (unsigned char)reg_num, (unsigned char)reg_value };
 int ret;
 
 //dprintk("%s(%d): Reg address: %02X, Reg value: %02X\n", __FUNCTION__, __LINE__, buf[0], buf[1]);

 if (reg_num >= NUM_TDA18211_REG || reg_value > 0xFF)
 {
     dprintk("%s: invalid register setting r%d<-0x%0X\n", __FUNCTION__, reg_num, reg_value);
     return -1;
	}
	
	ret = tuner_i2c_write(tuner_card, buf, sizeof(buf));
	if (ret < 0) dprintk("error return %d\n", ret);
	
	return ret;
}

/**
 * Write values from register map to chip, preceded by first register number
 * (Writes: <first_reg> map[first_reg] ... map[last_reg])
 * 
 * @param tuner_card tuner instance reference
 * @param p_reg_map copy of state of 18211 registers
 * @param first_reg first register index to be written (> 0)
 * @param last_reg last register index to be written
 * @return <0: error; 0: OK
 */
static int tda_write_map_to_chip(struct dvb_frontend * tuner_card, unsigned char * p_reg_map, int first_reg, int last_reg)
{
	int ret;
	unsigned char regvalue;

	//dprintk("%s(%d)\n", __FUNCTION__, __LINE__);

 /* Note - chip requires first register number followed by map data bytes.
  * To perform this in a single transfer, we temporarily store the
  * register number in the map byte _before_ the first register to be sent,
  * send register number + map bytes,
  * then restore the map byte value after the transfer.
  */

 if (first_reg <= 0) { dprintk("Warning - writing chip ID register\n"); first_reg = 1; }
 if (last_reg < first_reg) { dprintk("Warning - chip registers in wrong order\n"); regvalue = first_reg; first_reg = last_reg; last_reg = regvalue;}
 
 regvalue = p_reg_map[first_reg - 1]; // preserve map value
 p_reg_map[first_reg - 1] = first_reg; // insert reg addressstatic int tda_write_chip(struct dvb_frontend * tuner_card, int reg_num, int reg_value)

 ret = tuner_i2c_write(tuner_card, &p_reg_map[first_reg - 1], last_reg-first_reg+2);
 p_reg_map[first_reg - 1] = regvalue; // restore value

 if (ret < 0) dprintk("error return %d\n", ret);
 return ret;
}

//-----------------------------------------------------------------------------
// FUNCTION:    TDA182I1Init:
//
// DESCRIPTION: initialization of the Tuner
//
// RETURN:      always True
//
// NOTES:       
//-----------------------------------------------------------------------------
//

static int
TDA182I1Init (struct dvb_frontend * tuner_card, unsigned char * p_reg_map)
{  
 struct tda18211_priv * priv = tuner_card->tuner_priv;
 tmTDA182I1I2CMap_t * I2CMap = (tmTDA182I1I2CMap_t *)p_reg_map;
 tmErrorCode_t ret = TM_FALSE;

 dprintk("%s(%d)\n", __FUNCTION__, __LINE__);

 //----------------------
 // configuration reset
 //----------------------
	// set power level indicator to off
	priv->Config_Instance.uPLMODE = 1;

	//----------------------
	// I2C map initialization
	//----------------------
	// set & write all bytes
	I2CMap->uBx01.THERMO_BYTE = 0x08;
	I2CMap->uBx02.POWER_LEVEL_BYTE = 0x80;
	I2CMap->uBx03.EASY_PROG_BYTE_1 = 0xC6;
	I2CMap->uBx04.EASY_PROG_BYTE_2 = 0xDF;
	I2CMap->uBx05.EASY_PROG_BYTE_3 = 0x16;
	I2CMap->uBx06.EASY_PROG_BYTE_4 = 0x60;
	I2CMap->uBx07.EASY_PROG_BYTE_5 = 0x80;
	I2CMap->uBx08.CAL_POST_DIV_BYTE = 0x80;
	I2CMap->uBx09.CAL_DIV_BYTE_1 = 0x00;
	I2CMap->uBx0A.CAL_DIV_BYTE_2 = 0x00;
	I2CMap->uBx0B.CAL_DIV_BYTE_3 = 0x00;
	I2CMap->uBx0C.MAIN_POST_DIV_BYTE = 0x00;
	I2CMap->uBx0D.MAIN_DIV_BYTE_1 = 0x00;
	I2CMap->uBx0E.MAIN_DIV_BYTE_2 = 0x00;
	I2CMap->uBx0F.MAIN_DIV_BYTE_3 = 0x00;
	I2CMap->uBx10.EXTENDED_BYTE_1 = 0xFC;
	I2CMap->uBx11.EXTENDED_BYTE_2 = 0x01;
	I2CMap->uBx12.EXTENDED_BYTE_3 = 0x84;
	I2CMap->uBx13.EXTENDED_BYTE_4 = 0x41;
	I2CMap->uBx14.EXTENDED_BYTE_5 = 0x01;
	I2CMap->uBx15.EXTENDED_BYTE_6 = 0x84;
	I2CMap->uBx16.EXTENDED_BYTE_7 = 0x40;
	I2CMap->uBx17.EXTENDED_BYTE_8 = 0x07;
 I2CMap->uBx18.EXTENDED_BYTE_9 = 0x00;
 I2CMap->uBx19.EXTENDED_BYTE_10 = 0x00;
 I2CMap->uBx1A.EXTENDED_BYTE_11 = 0x96;
 I2CMap->uBx1B.EXTENDED_BYTE_12 = 0x3F;
 I2CMap->uBx1C.EXTENDED_BYTE_13 = 0xC1;
 I2CMap->uBx1D.EXTENDED_BYTE_14 = 0x00;
 I2CMap->uBx1E.EXTENDED_BYTE_15 = 0x8F;
 I2CMap->uBx1F.EXTENDED_BYTE_16 = 0x00;
 I2CMap->uBx20.EXTENDED_BYTE_17 = 0x00;
 I2CMap->uBx21.EXTENDED_BYTE_18 = 0x8C;
 I2CMap->uBx22.EXTENDED_BYTE_19 = 0x00;
 I2CMap->uBx23.EXTENDED_BYTE_20 = 0x20;
 I2CMap->uBx24.EXTENDED_BYTE_21 = 0xB3;
 I2CMap->uBx25.EXTENDED_BYTE_22 = 0x48;
 I2CMap->uBx26.EXTENDED_BYTE_23 = 0xB0;
 if (tda_write_map_to_chip(tuner_card, p_reg_map, TDA18211_R_TM, TDA18211_R_EB23) < 0) {
  dprintk("%s(%d): error while writing to registers durint init\n", __FUNCTION__, __LINE__);
  return TMBSL_ERR_IIC_ERR;
 }

 //----------------------
 // AGC1 gain setup
 //----------------------
 // AGC1_Gain_do
 // update & write EXTENDED_BYTE_17
 I2CMap->uBx20.EXTENDED_BYTE_17 = 0x00; // set gain_do address
 if (tda_write_map_to_chip(tuner_card, p_reg_map, TDA18211_R_EB17, TDA18211_R_EB17) < 0) {
  dprintk("%s(%d): error while writing to EXTENDED_BYTE_17 register\n", __FUNCTION__, __LINE__);
  return TMBSL_ERR_IIC_ERR;
 }

 I2CMap->uBx20.EXTENDED_BYTE_17 = 0x03; // keep gain_do address, set gain_do 
 if (tda_write_map_to_chip(tuner_card, p_reg_map, TDA18211_R_EB17, TDA18211_R_EB17) < 0) {
  dprintk("%s(%d): error while writing to EXTENDED_BYTE_17 register\n", __FUNCTION__, __LINE__);
  return TMBSL_ERR_IIC_ERR;
 }

 // AGC1_Gain_up
 // update & write EXTENDED_BYTE_17
 I2CMap->uBx20.EXTENDED_BYTE_17 = 0x43; // set gain_up address, keep gain_do 
 if (tda_write_map_to_chip(tuner_card, p_reg_map, TDA18211_R_EB17, TDA18211_R_EB17) < 0) {
  dprintk("%s(%d): error while writing to EXTENDED_BYTE_17 register\n", __FUNCTION__, __LINE__);
  return TMBSL_ERR_IIC_ERR;
 }

	I2CMap->uBx20.EXTENDED_BYTE_17 = 0x4C;	// keep gain_up address, set gain_up 
	if (tda_write_map_to_chip(tuner_card, p_reg_map, TDA18211_R_EB17, TDA18211_R_EB17) < 0) {
		dprintk("%s(%d): error while writing to EXTENDED_BYTE_17 register\n", __FUNCTION__, __LINE__);
		return TMBSL_ERR_IIC_ERR;
	}

	//----------------------
	// image rejection calibration - low band
	//----------------------
	// initialisation
	I2CMap->uBx05.EASY_PROG_BYTE_3 = 0x1F;
	I2CMap->uBx06.EASY_PROG_BYTE_4 = 0x66;
	I2CMap->uBx07.EASY_PROG_BYTE_5 = 0x81;
	I2CMap->uBx08.CAL_POST_DIV_BYTE = 0xCC;
	I2CMap->uBx09.CAL_DIV_BYTE_1 = 0x6C;
	I2CMap->uBx0A.CAL_DIV_BYTE_2 = 0x00;
	I2CMap->uBx0B.CAL_DIV_BYTE_3 = 0x00;
	I2CMap->uBx0C.MAIN_POST_DIV_BYTE = 0xC5;
	I2CMap->uBx0D.MAIN_DIV_BYTE_1 = 0x77;
	I2CMap->uBx0E.MAIN_DIV_BYTE_2 = 0x08;
	I2CMap->uBx0F.MAIN_DIV_BYTE_3 = 0x00;
	if (tda_write_map_to_chip(tuner_card, p_reg_map, TDA18211_R_EP2, TDA18211_R_MD3) < 0) {
		dprintk("%s(%d): error while writing from TDA18211_R_EP3 to TDA18211_R_MD3 registers\n", __FUNCTION__, __LINE__);
		return TMBSL_ERR_IIC_ERR;
	}

//	I2CMap->uBx13.EXTENDED_BYTE_4 = 0x61;
//	if (tda_write_map_to_chip(tuner_card, p_reg_map, TDA18211_R_EB4, TDA18211_R_EB4) < 0) {
//		dprintk("%s(%d): error while writing in TDA18211_R_EB4 register\n", __FUNCTION__, __LINE__);
//  return TMBSL_ERR_IIC_ERR;
// }
//
//
// msleep(1);
//
// I2CMap->uBx13.EXTENDED_BYTE_4 = 0x41;
// if (tda_write_map_to_chip(tuner_card, p_reg_map, TDA18211_R_EB4, TDA18211_R_EB4) < 0) {
//  dprintk("%s(%d): error while writing in TDA18211_R_EB4 register\n", __FUNCTION__, __LINE__);
//  return TMBSL_ERR_IIC_ERR;
// }

 // wait 5 ms for pll locking
 msleep(5);

 // launch detector
 if (tda_write_map_to_chip(tuner_card, p_reg_map, TDA18211_R_EP1, TDA18211_R_EP1) < 0) {
  dprintk("%s(%d): error while writing in TDA18211_R_EP3 register\n", __FUNCTION__, __LINE__);
  return TMBSL_ERR_IIC_ERR;
 }

 // wait 5 ms for wanted measurement
 msleep(5);

 // CAL pll update
 I2CMap->uBx07.EASY_PROG_BYTE_5 = 0x85;
 I2CMap->uBx08.CAL_POST_DIV_BYTE = 0xCB; 
 I2CMap->uBx09.CAL_DIV_BYTE_1 = 0x66;
 I2CMap->uBx0A.CAL_DIV_BYTE_2 = 0x70;

 // write bytes EASY_PROG_BYTE_3 to CAL_DIV_BYTE_3
 if (tda_write_map_to_chip(tuner_card, p_reg_map, TDA18211_R_EP3, TDA18211_R_CD3) < 0) {
  dprintk("%s(%d): error while writing from TDA18211_R_EP3 to TDA18211_R_CD3 registers\n", __FUNCTION__, __LINE__);
  return TMBSL_ERR_IIC_ERR;
 }

 // wait 5 ms for pll locking
 msleep(5);

 // launch optimisation algorithm
 if (tda_write_map_to_chip(tuner_card, p_reg_map, TDA18211_R_EP2, TDA18211_R_EP2) < 0) {
  dprintk("%s(%d): error while writing in TDA18211_R_EP2 register\n", __FUNCTION__, __LINE__);
  return TMBSL_ERR_IIC_ERR;
 }

	// wait 30 ms for image optimization completion
	msleep(30);

	//----------------------
	// image rejection calibration - mid band
	//----------------------
	// initialisation
	I2CMap->uBx07.EASY_PROG_BYTE_5 = 0x82;
	I2CMap->uBx08.CAL_POST_DIV_BYTE = 0xA8;
	I2CMap->uBx0A.CAL_DIV_BYTE_2 = 0x00;
	I2CMap->uBx0C.MAIN_POST_DIV_BYTE = 0xA1;
	I2CMap->uBx0D.MAIN_DIV_BYTE_1 = 0x73;
	I2CMap->uBx0E.MAIN_DIV_BYTE_2 = 0x1A;
	if (tda_write_map_to_chip(tuner_card, p_reg_map, TDA18211_R_EP3, TDA18211_R_MD3) < 0) {
		dprintk("%s(%d): error while writing from TDA18211_R_EP3 to TDA18211_R_MD3 registers\n", __FUNCTION__, __LINE__);
		return TMBSL_ERR_IIC_ERR;
	}

	// wait 5 ms for pll locking
	msleep(5);

	// launch detector
	// write byte EASY_PROG_BYTE_1
	if (tda_write_map_to_chip(tuner_card, p_reg_map, TDA18211_R_EP1, TDA18211_R_EP1) < 0) {
  dprintk("%s(%d): error while writing from TDA18211_R_EP1 to TDA18211_R_EP1 registers\n", __FUNCTION__, __LINE__);
  return TMBSL_ERR_IIC_ERR;
 }

 // wait 5 ms for wanted measurement
 msleep(5);

 // CAL pll update
 I2CMap->uBx07.EASY_PROG_BYTE_5 = 0x86;
 I2CMap->uBx08.CAL_POST_DIV_BYTE = 0xA8;
 I2CMap->uBx09.CAL_DIV_BYTE_1 = 0x66;
 I2CMap->uBx0A.CAL_DIV_BYTE_2 = 0xA0;

 if (tda_write_map_to_chip(tuner_card, p_reg_map, TDA18211_R_EP3, TDA18211_R_CD3) < 0) {
  dprintk("%s(%d): error while writing from TDA18211_R_EP3 to TDA18211_R_CD3 registers\n", __FUNCTION__, __LINE__);
  return TMBSL_ERR_IIC_ERR;
 }

 // wait 5 ms for pll locking
 msleep(5);

 // launch optimisation algorithm
 if (tda_write_map_to_chip(tuner_card, p_reg_map, TDA18211_R_EP2, TDA18211_R_EP2) < 0) {
  dprintk("%s(%d): error while writing in TDA18211_R_EP2 register\n", __FUNCTION__, __LINE__);
  return TMBSL_ERR_IIC_ERR;
 }

 // wait 30 ms for image optimization completion
 msleep(30);

 //----------------------
 // image rejection calibration - high band
 //----------------------
 // initialisation
 I2CMap->uBx07.EASY_PROG_BYTE_5 = 0x83;
 I2CMap->uBx08.CAL_POST_DIV_BYTE = 0x98;
 I2CMap->uBx09.CAL_DIV_BYTE_1 = 0x65;
 I2CMap->uBx0A.CAL_DIV_BYTE_2 = 0x00;
 I2CMap->uBx0C.MAIN_POST_DIV_BYTE = 0x91;
 I2CMap->uBx0D.MAIN_DIV_BYTE_1 = 0x71;
 I2CMap->uBx0E.MAIN_DIV_BYTE_2 = 0xCD;  
 if (tda_write_map_to_chip(tuner_card, p_reg_map, TDA18211_R_EP3, TDA18211_R_MD3) < 0) {
  dprintk("%s(%d): error while writing from TDA18211_R_EP3 to TDA18211_R_MD3 registers\n", __FUNCTION__, __LINE__);
		return TMBSL_ERR_IIC_ERR;
	}


	// wait 5 ms for pll locking
	msleep(5);

	// launch detector
	// write byte EASY_PROG_BYTE_1
	if (tda_write_map_to_chip(tuner_card, p_reg_map, TDA18211_R_EP1, TDA18211_R_EP1) < 0) {
		dprintk("%s(%d): error while writing in TDA18211_R_EP1 register\n", __FUNCTION__, __LINE__);
		return TMBSL_ERR_IIC_ERR;
	}


 // wait 5 ms for wanted measurement
 msleep(5);

 // CAL pll update
 I2CMap->uBx07.EASY_PROG_BYTE_5 = 0x87;
 I2CMap->uBx09.CAL_DIV_BYTE_1 = 0x65;
 I2CMap->uBx0A.CAL_DIV_BYTE_2 = 0x50;

 // write bytes EASY_PROG_BYTE_3 to CAL_DIV_BYTE_3
 if (tda_write_map_to_chip(tuner_card, p_reg_map, TDA18211_R_EP3, TDA18211_R_CD3) < 0) {
  dprintk("%s(%d): error while writing from TDA18211_R_EP3 to TDA18211_R_CD3 registers\n", __FUNCTION__, __LINE__);
  return TMBSL_ERR_IIC_ERR;
 }

 // wait 5 ms for pll locking
 msleep(5);

 // launch optimisation algorithm
 if (tda_write_map_to_chip(tuner_card, p_reg_map, TDA18211_R_EP2, TDA18211_R_EP2) < 0) {
  dprintk("%s(%d): error while writing in TDA18211_R_EP2 register\n", __FUNCTION__, __LINE__);
  return TMBSL_ERR_IIC_ERR;
 }


 // wait 30 ms for image optimization completion
 msleep(30);

 //----------------------
 // back to normal mode
 //----------------------
 // update & write byte EASY_PROG_BYTE_4
 I2CMap->uBx06.EASY_PROG_BYTE_4 = 0x64;
 if (tda_write_map_to_chip(tuner_card, p_reg_map, TDA18211_R_EP4, TDA18211_R_EP4) < 0) {
  dprintk("%s(%d): error while writing in TDA18211_R_EP4 register\n", __FUNCTION__, __LINE__);
  return TMBSL_ERR_IIC_ERR;
 }

 // synchronization
 // write byte EASY_PROG_BYTE_1
 if (tda_write_map_to_chip(tuner_card, p_reg_map, TDA18211_R_EP1, TDA18211_R_EP1) < 0) {
  dprintk("%s(%d): error while writing in TDA18211_R_EP1 register\n", __FUNCTION__, __LINE__);
  return TMBSL_ERR_IIC_ERR;
 }


	//----------------------
	// RF tracking filters calibration
	//----------------------
	ret = TDA182I1CalcRFFilterCurve(tuner_card, p_reg_map);
	if (ret != TM_OK) {
		dprintk("%s(%d): error while calibrating the RF filters\n", __FUNCTION__, __LINE__);
		return ret;
	}

	//----------------------
 // back to POR mode
 //----------------------
 // power up detector 1
 I2CMap->uBx1B.bF.PD_AGC1_Det = 0x00;
 // write byte EXTENDED_BYTE_12
 if (tda_write_map_to_chip(tuner_card, p_reg_map, TDA18211_R_EB12, TDA18211_R_EB12) < 0) {
  dprintk("%s(%d): error while writing in TDA18211_R_EB12 register\n", __FUNCTION__, __LINE__);
  return TMBSL_ERR_IIC_ERR;
 }

 // turn AGC1 loop on
 I2CMap->uBx21.bF.AGC1_loop_off = 0x00;
 // set AGC1Gain = 6dB
 I2CMap->uBx21.bF.AGC1_Gain = 0x00;
 // write byte EXTENDED_BYTE_18
 if (tda_write_map_to_chip(tuner_card, p_reg_map, TDA18211_R_EB18, TDA18211_R_EB18) < 0) {
  dprintk("%s(%d): error while writing in TDA18211_R_EB18 register\n", __FUNCTION__, __LINE__);
  return TMBSL_ERR_IIC_ERR;
 }

 // set AGC2Gain = -6dB
 I2CMap->uBx24.bF.AGC2_Gain = 0x03;

 // swicth to POR mode
 I2CMap->uBx05.bF.SM = 0x01;
 I2CMap->uBx05.bF.SM_LT = 0x00;
 I2CMap->uBx05.bF.SM_XT = 0x00;
 // write byte EASY_PROG_BYTE_3
 if (tda_write_map_to_chip(tuner_card, p_reg_map, TDA18211_R_EP3, TDA18211_R_EP3) < 0) {
  dprintk("%s(%d): error while writing in TDA18211_R_EP3 register\n", __FUNCTION__, __LINE__);
  return TMBSL_ERR_IIC_ERR;
 }

 // disable 1.5MHz low pass filter
 I2CMap->uBx26.bF.ForceLP_Fc2_En = 0x00;
 I2CMap->uBx26.bF.LP_Fc = 0x00;

 // write bytes EXTENDED_BYTE_21 to EXTENDED_BYTE_23
 if (tda_write_map_to_chip(tuner_card, p_reg_map, TDA18211_R_EB21, TDA18211_R_EB23) < 0) {
  dprintk("%s(%d): error while writing from TDA18211_R_EB21 to TDA18211_R_EB23 registers\n", __FUNCTION__, __LINE__);
  return TMBSL_ERR_IIC_ERR;
 }

 return TRUE;
}

//-------------------------------------------------------------------------------------
// FUNCTION:    TDA182I1CalcMAINPLL:
//
// DESCRIPTION: Calculate the MAIN fractionnal PLL settings
//
// RETURN:      True or False
//
// NOTES:       This function doesn't write in the tuner
//-------------------------------------------------------------------------------------
//
static Bool
TDA182I1CalcMAINPLL (
      unsigned char * p_reg_map,
      UInt32     uLO   // I: local oscillator frequency in hertz
      )
{ 
 tmTDA182I1I2CMap_t * I2CMap = (tmTDA182I1I2CMap_t *)p_reg_map;
 UInt8 uCounter = 0;
 UInt32 uDiv;

 dprintk("%s(%d)\n", __FUNCTION__, __LINE__);

 // search for MAIN_Post_Div corresponding to uLO
 do uCounter ++;
 while (uLO > MAIN_PLL_Map[uCounter - 1].uLO_Max && uCounter < TDA18211_MAIN_PLL_NB_ROWS);
 I2CMap->uBx0C.bF.MAIN_Post_Div = ((UInt8)MAIN_PLL_Map[uCounter - 1].uPost_Div) & 0x77;

 // calculate MAIN_Div
 uDiv = (((UInt32)(MAIN_PLL_Map[uCounter - 1].uDiv) * (uLO / 1000)) << 7) / 125;
 I2CMap->uBx0D.bF.MAIN_Div_22_to_16 = (UInt8)(uDiv >> 16) & 0x7F;
 I2CMap->uBx0E.bF.MAIN_Div_15_to_8 = (UInt8)(uDiv >> 8);
 I2CMap->uBx0F.bF.MAIN_Div_7_to_0 = (UInt8)(uDiv);

 return 1;
}


//-------------------------------------------------------------------------------------
// FUNCTION:    TDA182I1CalcCALPLL:
//
// DESCRIPTION: Calculate the CAL fractionnal PLL settings
//
// RETURN:      True or False
//
// NOTES:       This function doesn't write in the tuner
//-------------------------------------------------------------------------------------
//
static Bool
TDA182I1CalcCALPLL (
   unsigned char * p_reg_map,
     UInt32     uLO   // I: local oscillator frequency in hertz
     )
{ 
 tmTDA182I1I2CMap_t * I2CMap = (tmTDA182I1I2CMap_t *)p_reg_map;
 UInt8 uCounter = 0;
 UInt32 uDiv;

 dprintk("%s(%d)\n", __FUNCTION__, __LINE__);

 // search for CAL_Post_Div corresponding to uLO
 do uCounter ++;
 while (uLO > CAL_PLL_Map[uCounter - 1].uLO_Max && uCounter < TDA18211_CAL_PLL_NB_ROWS);
 I2CMap->uBx08.CAL_POST_DIV_BYTE = (UInt8)CAL_PLL_Map[uCounter - 1].uPost_Div;

 // calculate CAL_Div
 uDiv = (((UInt32)(CAL_PLL_Map[uCounter - 1].uDiv) * (uLO / 1000)) << 7) / 125;
 I2CMap->uBx09.bF.CAL_Div_22_to_16 = (UInt8)(uDiv >> 16) & 0x7F;
 I2CMap->uBx0A.bF.CAL_Div_15_to_8 = (UInt8)(uDiv >> 8);
 I2CMap->uBx0B.bF.CAL_Div_7_to_0 = (UInt8)(uDiv);

 return 1;
}


//-------------------------------------------------------------------------------------
// FUNCTION:    TDA182I1CalibrateRF:
//
// DESCRIPTION: RF tracking filter calibration
//
// RETURN:      TMBSL_ERR_IIC_ERR
//              TM_OK
//
// NOTES:       
//-------------------------------------------------------------------------------------
//
tmErrorCode_t
TDA182I1CalibrateRF (
  struct dvb_frontend * tuner_card, unsigned char * p_reg_map,
      UInt32     uRF,  // I: RF frequency in hertz
      UInt8*     puCprog     // I: Address of the variable to output the Cprog value
      )
{
 tmTDA182I1I2CMap_t * I2CMap = (tmTDA182I1I2CMap_t *)p_reg_map;
 UInt32 uCounter = 0;

 dprintk("%s(%d)\n", __FUNCTION__, __LINE__);

 //------------------------------
 // initialization
 //------------------------------

 // set CAL_Mode to normal mode
 I2CMap->uBx06.bF.CAL_Mode = 0x00;
 // write byte EASY_PROG_BYTE_4
 if (tda_write_map_to_chip(tuner_card, p_reg_map, TDA18211_R_EP4, TDA18211_R_EP4) < 0) {
  dprintk("%s(%d): error while writing to CAL_Mode register\n", __FUNCTION__, __LINE__);
  return TMBSL_ERR_IIC_ERR;
 }

 // set AGC1Gain = 15dB
 I2CMap->uBx21.bF.AGC1_Gain = 0x03;
 //I2CMap->uBx21.EXTENDED_BYTE_18 = 0x0E;
 // write byte EXTENDED_BYTE_18
 if (tda_write_map_to_chip(tuner_card, p_reg_map, TDA18211_R_EB18, TDA18211_R_EB18) < 0) {
  dprintk("%s(%d): error while writing to AGC1_Gain register\n", __FUNCTION__, __LINE__);
  return TMBSL_ERR_IIC_ERR;
 }
 // switch off AGC1
 I2CMap->uBx05.bF.SM_LT = 0x01;


 
 //------------------------------
 // frequency dependent parameters update
 //------------------------------

 // search for BP_Filter corresponding to uRF (EASY_PROG_BYTE_1)
 uCounter=0;
 do uCounter ++;
 while (uRF > BP_FILTER_Map[uCounter - 1].uRF_Max && uCounter < TDA18211_BP_FILTER_NB_ROWS);
 I2CMap->uBx03.bF.BP_Filter = (UInt8)BP_FILTER_Map[uCounter - 1].uBP_Filter;
 
 // search for Gain_Taper corresponding to uRF (EASY_PROG_BYTE_2)
 uCounter = 0;
 do uCounter ++;
 while (uRF > GAIN_TAPER_Map[uCounter - 1].uRF_Max && uCounter < TDA18211_GAIN_TAPER_NB_ROWS);
 I2CMap->uBx04.bF.Gain_Taper = (UInt8)GAIN_TAPER_Map[uCounter - 1].uGain_Taper;

 // search for RF_BAND corresponding to uRF (EASY_PROG_BYTE_2)
 uCounter = 0;
 do uCounter ++;
 while (uRF > RF_BAND_Map[uCounter - 1].uRF_Max && uCounter < TDA18211_RF_BAND_NB_ROWS);
 I2CMap->uBx04.bF.RF_Band = (UInt8)RF_BAND_Map[uCounter - 1].uRF_Band;

 // search for K,M corresponding to uRF (EXTENDED_BYTE_13)
 uCounter=0;
 do uCounter ++;
 while (uRF > RF_CAL_KMCO_Map[uCounter - 1].uRF_Max && uCounter < TDA18211_RF_CAL_KMCO_NB_ROWS);    
 I2CMap->uBx1C.bF.RFC_K = (UInt8)RF_CAL_KMCO_Map[uCounter - 1].uK;
 I2CMap->uBx1C.bF.RFC_M = (UInt8)RF_CAL_KMCO_Map[uCounter - 1].uM;

 // write bytes EASY_PROG_BYTE_1 to EASY_PROG_BYTE_3
 if (tda_write_map_to_chip(tuner_card, p_reg_map, TDA18211_R_EP1, TDA18211_R_EP3) < 0) {
  dprintk("%s(%d): error while writing to TDA18211_R_EP1 and TDA18211_R_EP3 addresses\n", __FUNCTION__, __LINE__);
  return TMBSL_ERR_IIC_ERR;
 }

 // write byte EXTENDED_BYTE_13
 if (tda_write_map_to_chip(tuner_card, p_reg_map, TDA18211_R_EB13, TDA18211_R_EB13) < 0) {
  dprintk("%s(%d): error while writing to TDA18211_R_EB13 address\n", __FUNCTION__, __LINE__);
  return TMBSL_ERR_IIC_ERR;
 }

 // MAIN pll charge pump source
 I2CMap->uBx13.bF.LO_ForceSrce = 0x01;
 // write byte EXTENDED_BYTE_4
 if (tda_write_map_to_chip(tuner_card, p_reg_map, TDA18211_R_EB4, TDA18211_R_EB4) < 0) {
  dprintk("%s(%d): error while writing to TDA18211_R_EB4 address\n", __FUNCTION__, __LINE__);
  return TMBSL_ERR_IIC_ERR;
 }

 // CAL pll charge pump source
 I2CMap->uBx16.bF.CAL_ForceSrce = 0x01;
 // write byte EXTENDED_BYTE_7
 if (tda_write_map_to_chip(tuner_card, p_reg_map, TDA18211_R_EB7, TDA18211_R_EB7) < 0) {
  dprintk("%s(%d): error while writing to TDA18211_R_EB7 address\n", __FUNCTION__, __LINE__);
  return TMBSL_ERR_IIC_ERR;
 }

 // force DCDC converter to 0V
 I2CMap->uBx1D.RFC_Cprog = 0x00;
 //I2CMap->uBx1D.EXTENDED_BYTE_14 = 0x17;
 // write byte EXTENDED_BYTE_14
 if (tda_write_map_to_chip(tuner_card, p_reg_map, TDA18211_R_EB14, TDA18211_R_EB14) < 0) {
  dprintk("%s(%d): error while writing to TDA18211_R_EB14 address\n", __FUNCTION__, __LINE__);
  return TMBSL_ERR_IIC_ERR;
 }

 // disable plls lock
 I2CMap->uBx23.bF.Force_Lock = 0x00;
 // write byte EXTENDED_BYTE_20
 if (tda_write_map_to_chip(tuner_card, p_reg_map, TDA18211_R_EB20, TDA18211_R_EB20) < 0) {
  dprintk("%s(%d): error while writing to TDA18211_R_EB20 address\n", __FUNCTION__, __LINE__);
  return TMBSL_ERR_IIC_ERR;
 }

 // RF tracking filters calibration mode
 I2CMap->uBx06.bF.CAL_Mode = 0x03;

 // write bytes EASY_PROG_BYTE_4 & EASY_PROG_BYTE_5
 if (tda_write_map_to_chip(tuner_card, p_reg_map, TDA18211_R_EP4, TDA18211_R_EP5) < 0) {
  dprintk("%s(%d): error while writing to TDA18211_R_EP4 address\n", __FUNCTION__, __LINE__);
  return TMBSL_ERR_IIC_ERR;
 }

 //------------------------------
 // set internal calibration signals
 //------------------------------
 // calculate CAL PLL
 // CAL LO Frequency = channel center frequency
 if (TDA182I1CalcCALPLL(p_reg_map, uRF) == False) {
  dprintk("%s(%d): error while calling TDA182I1CalcCALPLL()\n", __FUNCTION__, __LINE__);
  return TMBSL_ERR_IIC_ERR;
 }

 // calculate MAIN PLL
 // MAIN LO Frequency = channel center frequency + 1MHz
 if (TDA182I1CalcMAINPLL(p_reg_map, uRF + RF_CAL_IF_FREQ) == False) {
  dprintk("%s(%d): error while calling TDA182I1CalcMAINPLL()\n", __FUNCTION__, __LINE__);
  return TMBSL_ERR_IIC_ERR;
 }

 // write bytes EASY_PROG_BYTE_3 to MAIN_DIVIDER_BYTE_3
 if (tda_write_map_to_chip(tuner_card, p_reg_map, TDA18211_R_EP5, TDA18211_R_MD3) < 0) {
  dprintk("%s(%d): error while writing from TDA18211_R_EP5 to TDA18211_R_MD3 address\n", __FUNCTION__, __LINE__);
  return TMBSL_ERR_IIC_ERR;
 }
 msleep(5);

 //------------------------------
 // internal synchronization
 //------------------------------
 // write byte EASY_PROG_BYTE_2
 if (tda_write_map_to_chip(tuner_card, p_reg_map, TDA18211_R_EP2, TDA18211_R_EP2) < 0) {
  dprintk("%s(%d): error while synchronizing\n", __FUNCTION__, __LINE__);
  return TMBSL_ERR_IIC_ERR;
 }

 // write byte EASY_PROG_BYTE_1
 if (tda_write_map_to_chip(tuner_card, p_reg_map, TDA18211_R_EP1, TDA18211_R_EP1) < 0) {
  dprintk("%s(%d): error while synchronizing\n", __FUNCTION__, __LINE__);
  return TMBSL_ERR_IIC_ERR;
 }

 // write byte EASY_PROG_BYTE_2
 if (tda_write_map_to_chip(tuner_card, p_reg_map, TDA18211_R_EP2, TDA18211_R_EP2) < 0) {
  dprintk("%s(%d): error while synchronizing\n", __FUNCTION__, __LINE__);
  return TMBSL_ERR_IIC_ERR;
 }

 // write byte EASY_PROG_BYTE_1
 if (tda_write_map_to_chip(tuner_card, p_reg_map, TDA18211_R_EP1, TDA18211_R_EP1) < 0) {
  dprintk("%s(%d): error while synchronizing\n", __FUNCTION__, __LINE__);
  return TMBSL_ERR_IIC_ERR;
 }

 //------------------------------
 // RF calibration launch
 //------------------------------
 // MAIN pll charge pump source
 I2CMap->uBx13.bF.LO_ForceSrce = 0x00;
 // write byte EXTENDED_BYTE_4
 if (tda_write_map_to_chip(tuner_card, p_reg_map, TDA18211_R_EB4, TDA18211_R_EB4) < 0) {
  dprintk("%s(%d): error while writing to TDA18211_R_EB4 register\n", __FUNCTION__, __LINE__);
  return TMBSL_ERR_IIC_ERR;
 }

 // CAL pll charge pump source
 I2CMap->uBx16.bF.CAL_ForceSrce = 0x00;
 // write byte EXTENDED_BYTE_7
 if (tda_write_map_to_chip(tuner_card, p_reg_map, TDA18211_R_EB7, TDA18211_R_EB7) < 0) {
  dprintk("%s(%d): error while writing to TDA18211_R_EB7 register\n", __FUNCTION__, __LINE__);
  return TMBSL_ERR_IIC_ERR;
 }

 msleep(10);

 // launch the RF tracking filters calibartion
 I2CMap->uBx23.bF.Force_Lock = 0x01;
 // write byte EXTENDED_BYTE_20
 if (tda_write_map_to_chip(tuner_card, p_reg_map, TDA18211_R_EB20, TDA18211_R_EB20) < 0) {
  dprintk("%s(%d): error while writing to TDA18211_R_EB20 register\n", __FUNCTION__, __LINE__);
  return TMBSL_ERR_IIC_ERR;
 }

 // wait 60 ms for calibration
 msleep(60);
 
 // normal mode (EASY_PROG_BYTE_4)
 I2CMap->uBx06.bF.CAL_Mode = 0x00;


 // set AGC1Gain = 6dB (EXTENDED_BYTE_18)
 I2CMap->uBx21.bF.AGC1_Gain = 0x00;
 //I2CMap->uBx21.EXTENDED_BYTE_18 = 0x0E;
 // write byte EXTENDED_BYTE_18
 if (tda_write_map_to_chip(tuner_card, p_reg_map, TDA18211_R_EB18, TDA18211_R_EB18) < 0) {
  dprintk("%s(%d): error while writing to TDA18211_R_EB18 address\n", __FUNCTION__, __LINE__);
  return TMBSL_ERR_IIC_ERR;
 }

 // switch on AGC1 (EASY_PROG_BYTE_3)
 I2CMap->uBx05.bF.SM_LT = 0x00;

 // write bytes EASY_PROG_BYTE_3 & EASY_PROG_BYTE_4
 if (tda_write_map_to_chip(tuner_card, p_reg_map, TDA18211_R_EP3, TDA18211_R_EP4) < 0) {
  dprintk("%s(%d): error while writing from TDA18211_R_EP3 to TDA18211_R_EP4 addresses\n", __FUNCTION__, __LINE__);
  return TMBSL_ERR_IIC_ERR;
 }

 // write byte EASY_PROG_BYTE_1
 if (tda_write_map_to_chip(tuner_card, p_reg_map, TDA18211_R_EP1, TDA18211_R_EP1) < 0) {
  dprintk("%s(%d): error while writing to TDA18211_R_EP1 address\n", __FUNCTION__, __LINE__);
  return TMBSL_ERR_IIC_ERR;
 }

 // read bytes 0x00 to 0x26
 if (tuner_i2c_read(tuner_card, p_reg_map, NUM_TDA18211_REG) < 0)
  return TMBSL_ERR_IIC_ERR;

 // update puCprog
 *puCprog = I2CMap->uBx1D.RFC_Cprog;

 dprintk("%s(%d): TDA18211_R_EP1: %.2X\n", __FUNCTION__, __LINE__, p_reg_map[TDA18211_R_EP1]);

 // return value
 return TM_OK;
}


//-------------------------------------------------------------------------------------
// FUNCTION:    TDA182I1PowerScanInit:
//
// DESCRIPTION: Initializes power scan
//
// RETURN:      TMBSL_ERR_IIC_ERR
//              TM_OK
//
// NOTES:       
//-------------------------------------------------------------------------------------
//
tmErrorCode_t
TDA182I1PowerScanInit (
  struct dvb_frontend * tuner_card, unsigned char * p_reg_map
        )
{
 tmTDA182I1I2CMap_t * I2CMap = (tmTDA182I1I2CMap_t *)p_reg_map;

 dprintk("%s(%d)\n", __FUNCTION__, __LINE__);


 // set standard mode to DVBT 1.5 MHz
 I2CMap->uBx05.bF.Std = 0x12;
 I2CMap->uBx06.bF.IF_Level = 0x00;
 I2CMap->uBx06.bF.CAL_Mode = 0x00;
 // write bytes EASY_PROG_BYTE_3 & EASY_PROG_BYTE_4
 if (tda_write_map_to_chip(tuner_card, p_reg_map, TDA18211_R_EP3, TDA18211_R_EP4) < 0) {
  dprintk("%s(%d): Error while writing in EASY_PROG_BYTE_3 & EASY_PROG_BYTE_4\n", __FUNCTION__, __LINE__);
  return TMBSL_ERR_IIC_ERR;
 }


 // set AGC1Gain = 6dB
 I2CMap->uBx21.bF.AGC1_Gain = 0x00;
 // write byte EXTENDED_BYTE_18
 if (tda_write_chip(tuner_card, TDA18211_R_EB18, p_reg_map[TDA18211_R_EB18]) < 0) {
  dprintk("%s(%d): Error while writing in EXTENDED_BYTE_18\n", __FUNCTION__, __LINE__);
  return TMBSL_ERR_IIC_ERR;
 }

 // set AGC2Gain = -15dB
 I2CMap->uBx24.bF.AGC2_Gain = 0x00;
 // set low pass filter to 1.5MHz
 I2CMap->uBx26.bF.ForceLP_Fc2_En = 0x01;
 I2CMap->uBx26.bF.LP_Fc = 0x01;
 if (tda_write_map_to_chip(tuner_card, p_reg_map, TDA18211_R_EB21, TDA18211_R_EB23) < 0) {
  dprintk("%s(%d): Error while writing in EXTENDED_BYTE_18\n", __FUNCTION__, __LINE__);
  return TMBSL_ERR_IIC_ERR;
 }

 // return value
 return TM_OK;
}

#define POWER_SCAN_FREQ_STEP 200000

//-------------------------------------------------------------------------------------
// FUNCTION:    TDA182I1PowerScan:
//
// DESCRIPTION: Scan power and adjust RF Frequency
//
// RETURN:      TMBSL_ERR_IIC_ERR
//              TM_OK
//
// NOTES:       
//-------------------------------------------------------------------------------------
//
tmErrorCode_t
TDA182I1PowerScan (
  struct dvb_frontend * tuner_card, unsigned char * p_reg_map,
       UInt32*     puRF,  // I/O: RF frequency in hertz
       Bool*     pCal  // O: Calibration allowed if pCal = True
       )
{
 tmTDA182I1I2CMap_t * I2CMap = (tmTDA182I1I2CMap_t *)p_reg_map;

 UInt32 uCounter = 0;
 UInt32 count_limit = 0;
 UInt32 freq_input = 0;
 UInt32 freq_MAINPLL = 0;
 UInt32 step = 0;

 UInt8 CID_Gain = 0;
 UInt8 CID_Target = 0;

 Int8 sgn = 0;

 Bool wait = False;

 dprintk("%s(%d)\n", __FUNCTION__, __LINE__);

 // set freq_input
 freq_input = *puRF;

 // search for count_limit corresponding to uRF
 uCounter = 0;
 do uCounter ++;
 while (freq_input > RF_CAL_CID_TARGET_Map[uCounter - 1].uRF_Max && uCounter < TDA18211_RF_CAL_CID_TARGET_NB_ROWS);
 count_limit = RF_CAL_CID_TARGET_Map[uCounter - 1].uCount_Limit;

 // check if powerscan is requested
 if (count_limit == 0)
 {
  // enable calibration and exit
  *pCal = True;
  dprintk("%s(%d)\n check if powerscan is requested failed", __FUNCTION__, __LINE__);
  return TM_OK;
 }

 // search for CID_Target corresponding to uRF
 uCounter = 0;
 do uCounter ++;
 while (freq_input > RF_CAL_CID_TARGET_Map[uCounter - 1].uRF_Max && uCounter < TDA18211_RF_CAL_CID_TARGET_NB_ROWS);
 CID_Target = (UInt8)RF_CAL_CID_TARGET_Map[uCounter - 1].uCID_Target;

 // search for sub-band corresponding to uRF
 uCounter = 0;
 do uCounter ++;
 while (freq_input > RF_BAND_Map[uCounter - 1].uRF_Max && uCounter < TDA18211_RF_BAND_NB_ROWS);
 I2CMap->uBx04.bF.RF_Band = (UInt8)RF_BAND_Map[uCounter - 1].uRF_Band;

 // search for Cprog corresponding to uRF
 uCounter = 0;
 do uCounter ++;
 while (freq_input > RF_CAL_Map[uCounter - 1].uRF_Max && uCounter < TDA18211_RF_CAL_NB_ROWS);
 I2CMap->uBx1D.RFC_Cprog = (UInt8)RF_CAL_Map[uCounter - 1].uRFC_Cprog;

 // search for Gain_Taper corresponding to uRF
 uCounter = 0;
 do uCounter ++;
 while (freq_input > GAIN_TAPER_Map[uCounter - 1].uRF_Max && uCounter < TDA18211_GAIN_TAPER_NB_ROWS);
 I2CMap->uBx04.bF.Gain_Taper = (UInt8)GAIN_TAPER_Map[uCounter - 1].uGain_Taper;

 // write byte EASY_PROG_BYTE_2
 if (tda_write_chip(tuner_card, TDA18211_R_EP2, p_reg_map[TDA18211_R_EP2]) < 0){
  dprintk("%s(%d)\n error while writing in EASY_PROG_BYTE_2", __FUNCTION__, __LINE__);
  return TMBSL_ERR_IIC_ERR;
 }

 // write byte EXTENDED_BYTE_14
 if (tda_write_chip(tuner_card, TDA18211_R_EB14, p_reg_map[TDA18211_R_EB14]) < 0) {
  dprintk("%s(%d)\n error while writing in EXTENDED_BYTE_14", __FUNCTION__, __LINE__);
  return TMBSL_ERR_IIC_ERR;
 }

 // set freq_MAINPLL
 freq_MAINPLL = freq_input + RF_CAL_IF_FREQ;

 // calculate MAIN PLL
 if (TDA182I1CalcMAINPLL(p_reg_map, freq_MAINPLL) == False) {
  dprintk("%s(%d)\n calculate MAIN PLL failed", __FUNCTION__, __LINE__);
  return TMBSL_ERR_IIC_ERR; 
 }

	// write bytes MAIN_POST_DIVIDER_BYTE(0x0C) to MAIN_DIVIDER_BYTE_3(0x0F)
 if (tda_write_map_to_chip(tuner_card, p_reg_map, TDA18211_R_MPD, TDA18211_R_MD3) < 0) {
  dprintk("%s(%d): error while writing from TDA18211_R_EP3 to TDA18211_R_EP4 addresses\n", __FUNCTION__, __LINE__);
  return TMBSL_ERR_IIC_ERR;
 }

 msleep(5);

 // launch power detection measurement
 I2CMap->uBx06.bF.CAL_Mode = 0x01;

 // write byte EASY_PROG_BYTE_4
 if (tda_write_chip(tuner_card, TDA18211_R_EP4, p_reg_map[TDA18211_R_EP4]) < 0){
  dprintk("%s(%d)\n error while writing byte EASY_PROG_BYTE_4", __FUNCTION__, __LINE__);
  return TMBSL_ERR_IIC_ERR;
 }
 
 // write byte EASY_PROG_BYTE_2
 if (tda_write_chip(tuner_card, TDA18211_R_EP2, p_reg_map[TDA18211_R_EP2]) < 0) {
  dprintk("%s(%d)\n error while writing byte EASY_PROG_BYTE_2", __FUNCTION__, __LINE__);
  return TMBSL_ERR_IIC_ERR;
 }

 // read power detector informations
 if (tuner_i2c_read(tuner_card, p_reg_map, NUM_TDA18211_REG) < 0) {
  dprintk("%s(%d)\n read power detector informations failed", __FUNCTION__, __LINE__);
  return TMBSL_ERR_IIC_ERR;
 }

 //update CID_Gain
 CID_Gain = I2CMap->uBx19.bF.CID_Gain;

 //----------------------
 // power scan algorithm
 //----------------------
 // initialization
 uCounter = 0;
 sgn = 1; 
 *puRF = freq_input;
 *pCal = False;
 step = POWER_SCAN_FREQ_STEP;
 wait = False;

 // main loop
 while (CID_Gain < CID_Target)
 {
  // update freq_MAINPLL
  freq_MAINPLL = freq_input + sgn * uCounter + RF_CAL_IF_FREQ;

  // calculate MAIN PLL
  if (TDA182I1CalcMAINPLL(p_reg_map, freq_MAINPLL) == False) {
   dprintk("%s(%d)\n calculate MAIN PLL failed", __FUNCTION__, __LINE__);
   return TMBSL_ERR_IIC_ERR;
  }

  // write bytes 0x0C to 0x0F
  if (tda_write_map_to_chip(tuner_card, p_reg_map, TDA18211_R_MPD, TDA18211_R_MD3) < 0) {
   dprintk("%s(%d)\n error while writing bytes 0x0C to 0x0F", __FUNCTION__, __LINE__);
   return TMBSL_ERR_IIC_ERR;
  }

  if (wait)
  {
   // wait 5 ms for pll locking
   msleep(5);

   // reset wait flag
   wait = False;
  }
  else
  {
   // wait 100 us for pll locking
   msleep(1); // TODO remove this or not. It's not in FeComps version
  }

  // write byte EASY_PROG_BYTE_2
  if (tda_write_chip(tuner_card, TDA18211_R_EP2, p_reg_map[TDA18211_R_EP2]) < 0) {
   dprintk("%s(%d)\n error while writing in EASY_PROG_BYTE_2", __FUNCTION__, __LINE__);
   return TMBSL_ERR_IIC_ERR;
  }

  // read power detector informations
  if (tuner_i2c_read(tuner_card, p_reg_map, NUM_TDA18211_REG) < 0) {
   dprintk("%s(%d)\n read power detector informations failed", __FUNCTION__, __LINE__);
   return TMBSL_ERR_IIC_ERR;
  }

  // update CID_Gain
  CID_Gain = I2CMap->uBx19.bF.CID_Gain;

  // increase count
  uCounter += step;

  // check uCounter
  if (uCounter >= count_limit)
  {
   if (sgn > 0)
   {
    // update sgn
    sgn = -sgn;

    // update uCounter
    uCounter = step;

    // update wait flag
    wait = True;
   }
   else
   {
    // exit loop
    break;
   }
  }
 }

 // return results
 if (CID_Gain >= CID_Target)
 {
  *pCal = True;
  *puRF = freq_MAINPLL - RF_CAL_IF_FREQ;
 }
 else
 {
  *pCal = False;
  *puRF = freq_input;
 }

 return TM_OK;
}


//-------------------------------------------------------------------------------------
// FUNCTION:    TDA182I1CalcRFFilterCurve:
//
// DESCRIPTION: Calculate RF Filter curve coefficients
//
// RETURN:      TMBSL_ERR_IIC_ERR
//              TM_OK
//
// NOTES:       
//-------------------------------------------------------------------------------------
//
static tmErrorCode_t
TDA182I1CalcRFFilterCurve (
  struct dvb_frontend * tuner_card, unsigned char * p_reg_map
  )
{ 
 struct tda18211_priv * priv = tuner_card->tuner_priv;
 tmErrorCode_t ret = TM_OK;

 UInt32 uCounter = 0;

 dprintk("%s(%d)\n", __FUNCTION__, __LINE__);

 // wait 200 ms for die temperature stabilization
 msleep(200);

 // power scan initialization
 TDA182I1PowerScanInit(tuner_card, p_reg_map);

 // calculate RF filter curve
 for (uCounter = 0; uCounter < TDA18211_RF_BAND_NB_ROWS; uCounter++)
 {
  if (RF_BAND_Map[uCounter].uRF1_default != 0)
  {
   ret = TDA182I1RFTrackingFiltersInit(tuner_card, p_reg_map, &(RF_BAND_Map[uCounter]));
   if (ret != TM_OK) {
    dprintk("%s(%d): calculate RF filter curve failed\n", __FUNCTION__, __LINE__);
    return ret;
   }
  }
 }

 // sense temperature
 ret = TDA182I1ThermometerRead(tuner_card, p_reg_map, (UInt8 *)&priv->Config_Instance.uTMVALUE_RFCAL);
 if (ret != TM_OK) {
  dprintk("%s(%d): sense temperature failed\n", __FUNCTION__, __LINE__);
  return ret;
 }

 // return value
 return TM_OK;
}


//-------------------------------------------------------------------------------------
// FUNCTION:    TDA182I1RFTrackingFiltersInit:
//
// DESCRIPTION: Initialize RF Filter calibration
//
// RETURN:      TMBSL_ERR_IIC_ERR
//              TM_OK
//
// NOTES:       This function needs attention! It differs from the datasheet
//-------------------------------------------------------------------------------------
//
static tmErrorCode_t
TDA182I1RFTrackingFiltersInit (
  struct dvb_frontend * tuner_card,
  unsigned char * p_reg_map,
        const ptmTDA182I1_RF_BAND_Map_t pRF_BAND_Map // I: address of RF band map
          )
{
// struct tda18211_priv * priv = tuner_card->tuner_priv;
 tmErrorCode_t ret = TM_OK;

 UInt32 uCounter = 0;

 UInt8 uCprog_cal_1 = 0;
 UInt8 uCprog_table_1 = 0;
 UInt8 uCprog_cal_2 = 0;
 UInt8 uCprog_table_2 = 0;
 UInt8 uCprog_cal_3 = 0;
 UInt8 uCprog_table_3 = 0;

 Bool bCal = False;

 //tmTDA182I1StandardMode_t StandardMode = priv->Config_Instance.StandardMode;

 // set A1 coefficient
 pRF_BAND_Map->uRF_A1 = 0;
 // set B1 coefficient
 pRF_BAND_Map->uRF_B1 = 0;
 // set A2 coefficient
 pRF_BAND_Map->uRF_A2 = 0;
 // set B2 coefficient
 pRF_BAND_Map->uRF_B2 = 0;

 dprintk("%s(%d)\n", __FUNCTION__, __LINE__);

 //----------------------
 // RF tracking filter calibration at RF1 frequency
 //----------------------
 // test uRF1_default value
 if (pRF_BAND_Map->uRF1_default == 0) {
  dprintk("%s(%d), test uRF1_default value failed\n", __FUNCTION__, __LINE__);
  return ret;
 }

 // look for optimized calibration frequency
 pRF_BAND_Map->uRF1 = pRF_BAND_Map->uRF1_default;
 ret = TDA182I1PowerScan(tuner_card, p_reg_map, &pRF_BAND_Map->uRF1, &bCal);
 if (ret != TM_OK) {
  dprintk("%s(%d), look for optimized calibration frequency failed\n", __FUNCTION__, __LINE__);
  return ret;
 }

 // search for uCprog_table_1 corresponding to RF1
 uCounter = 0;
 do uCounter ++;
 while (pRF_BAND_Map->uRF1 > RF_CAL_Map[uCounter - 1].uRF_Max && uCounter < TDA18211_RF_CAL_NB_ROWS);
 uCprog_table_1 = (UInt8)RF_CAL_Map[uCounter - 1].uRFC_Cprog;

 if(bCal)
 {
  // launch tracking filter calibration
  ret = TDA182I1CalibrateRF(tuner_card, p_reg_map, pRF_BAND_Map->uRF1, &uCprog_cal_1);
  if (ret != TM_OK) {
   dprintk("%s(%d), launch tracking filter calibration failed\n", __FUNCTION__, __LINE__);
   return ret;
  }
 }
 else
 {
  // use tracking filter table value
  uCprog_cal_1 = uCprog_table_1;
 }

 // set A1 coefficient
 pRF_BAND_Map->uRF_A1 = 0;

 // calculate B1 coefficient
 pRF_BAND_Map->uRF_B1 = uCprog_cal_1 - uCprog_table_1;

 //----------------------
 // RF tracking filter calibration at RF2 frequency
 //----------------------
 // test RF2 value
 if (pRF_BAND_Map->uRF2_default == 0) {
  dprintk("%s(%d), uRF2_default is 0\n", __FUNCTION__, __LINE__);
  return ret;
 }

 // look for optimized calibration frequency
 pRF_BAND_Map->uRF2 = pRF_BAND_Map->uRF2_default;
 ret = TDA182I1PowerScan(tuner_card, p_reg_map, &pRF_BAND_Map->uRF2, &bCal);
 if (ret != TM_OK) {
  dprintk("%s(%d), look for optimized calibration frequency failed\n", __FUNCTION__, __LINE__);
  return ret;
 }

 // search for uCprog_table_2 corresponding to RF2
 uCounter = 0;
 do uCounter ++;
 while (pRF_BAND_Map->uRF2 > RF_CAL_Map[uCounter - 1].uRF_Max && uCounter < TDA18211_RF_CAL_NB_ROWS);
 uCprog_table_2 = (UInt8)RF_CAL_Map[uCounter - 1].uRFC_Cprog;

 if(bCal)
 {
  // launch tracking filter calibration
  ret = TDA182I1CalibrateRF(tuner_card, p_reg_map, pRF_BAND_Map->uRF2, &uCprog_cal_2);
  if (ret != TM_OK) {
   dprintk("%s(%d), launch tracking filter calibration failed\n", __FUNCTION__, __LINE__);
   return ret;
  }
 }
 else
 {
  // use tracking filter table value
  uCprog_cal_2 = uCprog_table_2;
 }

 // calculate A1 coefficient
 pRF_BAND_Map->uRF_A1 = ((uCprog_cal_2 - uCprog_table_2 - (uCprog_cal_1 - uCprog_table_1)) * 1000000)
  / (Int32)((pRF_BAND_Map->uRF2 - pRF_BAND_Map->uRF1) / 1000000);

 //----------------------
 // RF tracking filter calibration at RF3 frequency
 //----------------------
 // test RF3 value
 if (pRF_BAND_Map->uRF3_default == 0) {
  dprintk("%s(%d), uRF3_default is 0\n", __FUNCTION__, __LINE__);
  return ret; 
 }

 // look for optimized calibration frequency
 pRF_BAND_Map->uRF3 = pRF_BAND_Map->uRF3_default;
 ret = TDA182I1PowerScan(tuner_card, p_reg_map, &pRF_BAND_Map->uRF3, &bCal);
 if (ret != TM_OK) {
  dprintk("%s(%d), look for optimized calibration frequency failed\n", __FUNCTION__, __LINE__);
  return ret;
 }

 // search for uCprog_table_3 corresponding to RF3
 uCounter = 0;
 do uCounter ++;
 while (pRF_BAND_Map->uRF3 > RF_CAL_Map[uCounter - 1].uRF_Max && uCounter < TDA18211_RF_CAL_NB_ROWS);
 uCprog_table_3 = (UInt8)RF_CAL_Map[uCounter - 1].uRFC_Cprog;

 if(bCal)
 {
  // launch tracking filter calibration
  ret = TDA182I1CalibrateRF(tuner_card, p_reg_map, pRF_BAND_Map->uRF3, &uCprog_cal_3);
  if (ret != TM_OK) {
   dprintk("%s(%d), launch tracking filter calibration failed\n", __FUNCTION__, __LINE__);
   return ret;
  }
 }
 else
 {
  // use tracking filter table value
  uCprog_cal_3 = uCprog_table_3;
 }

 // calculate A2 coefficient
 pRF_BAND_Map->uRF_A2 = ((uCprog_cal_3 - uCprog_table_3 - (uCprog_cal_2 - uCprog_table_2)) * 1000000) 
  / (Int32)((pRF_BAND_Map->uRF3 - pRF_BAND_Map->uRF2) / 1000000);

 // calculate B2 coefficient
 pRF_BAND_Map->uRF_B2 = uCprog_cal_2 - uCprog_table_2;

 // return value
 return TM_OK;
}


//-------------------------------------------------------------------------------------
// FUNCTION:    TDA182I1ThermometerRead:
//
// DESCRIPTION: Read die temperature
//
// RETURN:      TMBSL_ERR_IIC_ERR
//              TM_OK
//
// NOTES:       
//-------------------------------------------------------------------------------------
//
static int 
TDA182I1ThermometerRead (struct dvb_frontend * tuner_card, unsigned char * p_reg_map, UInt8 * puValue)
{

 tmTDA182I1I2CMap_t * I2CMap = (tmTDA182I1I2CMap_t *)p_reg_map;
 UInt8 uCounter = 0;

 dprintk("%s(%d)\n", __FUNCTION__, __LINE__);

 // switch thermometer on
 I2CMap->uBx01.bF.TM_ON = 0x01;

 // write byte THERMO_BYTE
 if (tda_write_chip(tuner_card, TDA18211_R_TM, p_reg_map[TDA18211_R_TM]) < 0){
  dprintk("%s(%d), Error while writing in THERMO_BYTE\n", __FUNCTION__, __LINE__);
  return -1;
 }

 // read byte THERMO_BYTE
 if (tuner_i2c_read(tuner_card, p_reg_map, 16) < 0){
  dprintk("%s(%d), Error while reading in THERMO_BYTE\n", __FUNCTION__, __LINE__);
  return -1;
 }

 // set & write TM_Range
 if (((I2CMap->uBx01.bF.TM_D == 0x00) && (I2CMap->uBx01.bF.TM_Range == 0x01)) || ((I2CMap->uBx01.bF.TM_D == 0x08) && (I2CMap->uBx01.bF.TM_Range == 0x00)))
 {
  I2CMap->uBx01.bF.TM_Range = !(I2CMap->uBx01.bF.TM_Range);

  // write byte THERMO_BYTE
  if (tda_write_chip(tuner_card, TDA18211_R_TM, p_reg_map[TDA18211_R_TM]) < 0) {
   dprintk("%s(%d), Error while writing in THERMO_BYTE\n", __FUNCTION__, __LINE__);
   return -1;
  }

  // wait 10ms
  msleep(10);
  
  // read byte THERMO_BYTE
  if (tuner_i2c_read(tuner_card, p_reg_map, 16) < 0) {
   dprintk("%s(%d), Error while reading in THERMO_BYTE\n", __FUNCTION__, __LINE__);   
   return -1;
  }
 }

 // search for TMVALUE corresponding to TM_D
 uCounter = 0;
 do uCounter ++;
 while (I2CMap->uBx01.bF.TM_D > THERMOMETER_Map[uCounter - 1].uTM_D && uCounter < TDA18211_THERMOMETER_NB_ROWS);

 // get TMVALUE value
 if (I2CMap->uBx01.bF.TM_Range == 0x00)
  *puValue = (UInt8)THERMOMETER_Map[uCounter - 1].uTM_60_92;
 else
  *puValue = (UInt8)THERMOMETER_Map[uCounter - 1].uTM_92_122;

 // switch thermometer off
 I2CMap->uBx01.bF.TM_ON = 0x00;

 // write byte THERMO_BYTE
 if (tda_write_chip(tuner_card, TDA18211_R_TM, p_reg_map[TDA18211_R_TM]) < 0) {
  dprintk("%s(%d), Error while writing in THERMO_BYTE\n", __FUNCTION__, __LINE__);
  return -1;
 }

// // set CAL_Mode to normal mode
// I2CMap->uBx06.bF.CAL_Mode = 0x00;
//
// // write byte EASY_PROG_BYTE_4
// if (tda_write_map_to_chip(tuner_card, p_reg_map, TDA18211_R_EP4, TDA18211_R_EP4) < 0) {
//  dprintk("%s(%d): error while writing to CAL_Mode register\n", __FUNCTION__, __LINE__);
//  return TMBSL_ERR_IIC_ERR;
// }

 return TM_OK;
}


//-------------------------------------------------------------------------------------
// FUNCTION:    TDA182I1SetStandardMode:
//
// DESCRIPTION: Set the standard mode of this device.
//
// RETURN:      TMBSL_ERR_TUNER_BAD_UNIT_NUMBER
//              TMBSL_ERR_TUNER_NOT_INITIALIZED
//              TM_OK
//
// NOTES:       
//-------------------------------------------------------------------------------------
//
static int TDA182I1SetStandardMode (struct dvb_frontend * tuner_card, unsigned char * p_reg_map,
      tmTDA182I1StandardMode_t StandardMode
      )
{

 struct tda18211_priv * priv = tuner_card->tuner_priv;
 tmTDA182I1I2CMap_t * I2CMap = (tmTDA182I1I2CMap_t *)p_reg_map;

 Bool customIF = 0;

 dprintk("%s(%d)\n", __FUNCTION__, __LINE__);

 // set uIF & Std
 switch (StandardMode)
 {
 default: break; // ignore unhandled values

 case tmDigital_TV_ATSC_6MHz:
  // set IF frequency    
  if (!customIF)
   priv->Config_Instance.uIF = 3250000;
  // set bandwidth value 
  priv->Config_Instance.uBW = 6000000;   
  // set Std bit
  I2CMap->uBx05.bF.Std = 0x1C; //!customLPFc ? 0x1C : (I2CMap->uBx05.bF.Std & 0xE3) | (0x1C & 0x1C);

  // set CAL_RFn bit
  I2CMap->uBx06.bF.CAL_RFn = 0x00;
  break;

 case tmDigital_TV_DVBT_6MHz: // new
  // set IF frequency 
  if (!customIF)
   priv->Config_Instance.uIF = 3300000;
  // set bandwidth value 
  priv->Config_Instance.uBW = 6000000;    
  // set Std bit
  I2CMap->uBx05.bF.Std = 0x1C; //!customLPFc ? 0x1D : (I2CMap->uBx05.bF.Std & 0xE3) | (0x1D & 0x1C);

  // set CAL_RFn bit
  I2CMap->uBx06.bF.CAL_RFn = 0x00;
  break;

 case tmDigital_TV_DVBT_7MHz:
  // set IF frequency 
  if (!customIF)
   priv->Config_Instance.uIF = 3500000; //3800000; //!! change in data sheet v1.1.1
  // set bandwidth value 
  priv->Config_Instance.uBW = 7000000;    
  // set Std bit
  I2CMap->uBx05.bF.Std = 0x1C; //!customLPFc ? 0x1D : (I2CMap->uBx05.bF.Std & 0xE3) | (0x1D & 0x1C);

  // set CAL_RFn bit
  I2CMap->uBx06.bF.CAL_RFn = 0x00;
  break;

 case tmDigital_TV_DVBT_8MHz:
  // set IF frequency 
  if (!customIF)
   priv->Config_Instance.uIF = 4000000; //4300000; //!! change in data sheet v1.1.1 p35 
  // set bandwidth value 
  priv->Config_Instance.uBW = 8000000;    
  // set Std bit
  I2CMap->uBx05.bF.Std = 0x1D; //!! d/s v1.1.1 //!customLPFc ? 0x1E : (I2CMap->uBx05.bF.Std & 0xE3) | (0x1E & 0x1C);

  // set CAL_RFn bit
  I2CMap->uBx06.bF.CAL_RFn = 0x00;
  break;

 case tmDigital_CAL:
  // set IF frequency 
  if (!customIF)
   priv->Config_Instance.uIF = 1250000;
  // set bandwidth value 
  priv->Config_Instance.uBW = 250000;    
  // set Std bit
  I2CMap->uBx05.bF.Std = 0x18; //!customLPFc ? 0x18 : (I2CMap->uBx05.bF.Std & 0xE3) | (0x18 & 0x1C);

  // set CAL_RFn bit
  I2CMap->uBx06.bF.CAL_RFn = 0x01;
  break;

 case tmDigital_TV_QAM_6MHz:
  // set IF frequency 
  if (!customIF)
   priv->Config_Instance.uIF = 4000000;
  // set bandwidth value 
  priv->Config_Instance.uBW = 6000000;    
  // set Std bit
  I2CMap->uBx05.bF.Std = 0x1D; //!customLPFc ? 0x1D : (I2CMap->uBx05.bF.Std & 0xE3) | (0x1D & 0x1C);

  // set CAL_RFn bit
  I2CMap->uBx06.bF.CAL_RFn = 0x00;
  break;

 case tmDigital_TV_QAM_8MHz:
  // set IF frequency 
  if (!customIF)
   priv->Config_Instance.uIF = 5000000;
  // set bandwidth value 
  priv->Config_Instance.uBW = 8000000;    
  // set Std bit
  I2CMap->uBx05.bF.Std = 0x1F; //!customLPFc ? 0x1F : (I2CMap->uBx05.bF.Std & 0xE3) | (0x1F & 0x1C);

  // set CAL_RFn bit
  I2CMap->uBx06.bF.CAL_RFn = 0x00;
  break;

 case tmDigital_TV_ISDBT_6MHz:
  // set IF frequency 
  if (!customIF)
   priv->Config_Instance.uIF = 4063000;
  // set bandwidth value 
  priv->Config_Instance.uBW = 6000000;    
  // set Std bit
  I2CMap->uBx05.bF.Std = 0x1D; //!customLPFc ? 0x1D : (I2CMap->uBx05.bF.Std & 0xE3) | (0x1D & 0x1C);

  // set CAL_RFn bit
  I2CMap->uBx06.bF.CAL_RFn = 0x00;
  break;
 }

 // set CAL_Mode to normal mode
 I2CMap->uBx06.bF.CAL_Mode = 0x00;

 // set IF_Level & IF_notch & RFAGC_Top & IFAGC_Top
 switch (StandardMode)
 {
 case tmDigital_TV_ATSC_6MHz:
 case tmDigital_TV_DVBT_6MHz: // new
 case tmDigital_TV_DVBT_7MHz:
 case tmDigital_TV_DVBT_8MHz:
 case tmDigital_TV_QAM_6MHz:
 case tmDigital_TV_QAM_8MHz:
 case tmDigital_TV_ISDBT_6MHz:
  // set IF_Level
  I2CMap->uBx06.bF.IF_Level = 0x01;
  // set IF_notch
  I2CMap->uBx0C.bF.IF_notch = 0x01;
  // set RFAGC_Top & IFAGC_Top
  I2CMap->uBx25.EXTENDED_BYTE_22 = 0x37;
  break;

 case tmDigital_CAL:
  // set IF_Level
  I2CMap->uBx06.bF.IF_Level = 0x00;
  // set IF_notch
  I2CMap->uBx0C.bF.IF_notch = 0x00;
  // set RFAGC_Top & IFAGC_Top
  I2CMap->uBx25.EXTENDED_BYTE_22 = 0x2C;
  break;

 default:
  // standard mode not supported
  return -1;
 }

 // store standard mode 
 priv->Config_Instance.StandardMode = StandardMode;

 return 0;
}


//-------------------------------------------------------------------------------------
// FUNCTION:    tmbslTDA182I1SetRf:
//
// DESCRIPTION: Calculate i2c I2CMap & write in TDA182I1
//
// RETURN:      TMBSL_ERR_TUNER_BAD_UNIT_NUMBER
//              TMBSL_ERR_TUNER_NOT_INITIALIZED
//              TMBSL_ERR_TUNER_BAD_PARAMETER
//              TMBSL_ERR_IIC_ERR
//              TM_OK
//
// NOTES:       
//-------------------------------------------------------------------------------------
//
static int TDA182I1SetRf(struct dvb_frontend * tuner_card, unsigned char * p_reg_map, tmTDA182I1StandardMode_t op_standard,
int uRF)
{ 

 struct tda18211_priv * priv = tuner_card->tuner_priv;
 tmErrorCode_t ret  = TM_OK;

 UInt32 uCounter = 0;
 UInt8 uTMVALUE_CURRENT = 0;
 UInt8 utmpStd = 0;

 UInt8 uIRMeasCounter = 0;
 UInt8 uCprog_table = 0;
 UInt8 uCapprox = 0;
 Int32 uCprog_signed = 0;

 tmTDA182I1I2CMap_t * I2CMap = (tmTDA182I1I2CMap_t *)p_reg_map;

 dprintk("%s(%d): uRF %d\n", __FUNCTION__, __LINE__, uRF);

 priv->Config_Instance.StandardMode = op_standard;

 // Config.uRF update
 priv->Config_Instance.uRF = uRF;

 //----------------------
 // configuration reset
 //----------------------
 // set power level indicator to off
 priv->Config_Instance.uPLMODE = 1;
 //----------------------
 // normal mode restore
 //----------------------
 // power up in calibration standard
 I2CMap->uBx05.bF.SM = 0x00;
 I2CMap->uBx05.bF.SM_LT = 0x00;
 I2CMap->uBx05.bF.SM_XT = 0x00;
 // write byte EASY_PROG_BYTE_3
 if (tda_write_chip(tuner_card, TDA18211_R_EP3, p_reg_map[TDA18211_R_EP3]) < 0) {
  dprintk("%s(%d): Error writing in EASY_PROG_BYTE_3\n", __FUNCTION__, __LINE__);
  return TMBSL_ERR_IIC_ERR;
 }

 //----------------------
 // RF tracking filter correction
 //----------------------
 // sense temperature
 ret = TDA182I1ThermometerRead(tuner_card, p_reg_map, &uTMVALUE_CURRENT);
 if (ret < 0) {
  dprintk("%s(%d): Error calling TDA182I1ThermometerRead\n", __FUNCTION__, __LINE__);
  return ret;
 }

 //----------------------
 // frequency dependent parameters update
 //----------------------
 // search for uCprog_table corresponding to uRF
 uCounter = 0;
 do uCounter ++;
 while (uRF > RF_CAL_Map[uCounter - 1].uRF_Max && uCounter < TDA18211_RF_CAL_NB_ROWS);
 uCprog_table = (UInt8)RF_CAL_Map[uCounter - 1].uRFC_Cprog;

 // search for sub-band corresponding to uRF
 uCounter = 0;
 do uCounter ++;
 while (uRF > RF_BAND_Map[uCounter - 1].uRF_Max && uCounter < TDA18211_RF_BAND_NB_ROWS);

 // calculate Capprox
 if (RF_BAND_Map[uCounter].uRF1 == 0)
 {
  // Capprox = uCprog_table
  uCapprox = (Int32)uCprog_table;
 }
 else if ((RF_BAND_Map[uCounter - 1].uRF3 != 0) && (uRF >= RF_BAND_Map[uCounter - 1].uRF2))
 {
  // Capprox = A2 * (uRF - uRF2) + B2 + uCprog_table
  uCapprox = (Int32)(((RF_BAND_Map[uCounter - 1].uRF_A2 * ((Int32)(uRF - RF_BAND_Map[uCounter - 1].uRF2) / 1000000)) / 1000000)
   + RF_BAND_Map[uCounter - 1].uRF_B2 + uCprog_table);
 }
 else
 {
  // Capprox = A1 * (uRF - uRF1) + B1 + uCprog_table
  uCapprox = (Int32)(((RF_BAND_Map[uCounter - 1].uRF_A1 * ((Int32)(uRF - RF_BAND_Map[uCounter - 1].uRF1) / 1000000)) / 1000000)
   + RF_BAND_Map[uCounter - 1].uRF_B1 + uCprog_table);
 }

 // search for udC_Over_dT corresponding to uRF
 uCounter = 0;
 do uCounter ++;
 while (uRF > RF_CAL_DC_OVER_DT_Map[uCounter - 1].uRF_Max && uCounter < TDA18211_RF_CAL_DC_OVER_DT_NB_ROWS);

 // calculate CTcomp
 priv->Config_Instance.uRFCAL_TCOMP = (Int32)(RF_CAL_DC_OVER_DT_Map[uCounter - 1].udC_Over_dT * (uTMVALUE_CURRENT - priv->Config_Instance.uTMVALUE_RFCAL)) / 1000;

 // calculate Cprog
 uCprog_signed = uCapprox + priv->Config_Instance.uRFCAL_TCOMP;
 if (uCprog_signed < 0) uCprog_signed = 0;
 if (uCprog_signed > 255) uCprog_signed = 255;
 I2CMap->uBx1D.RFC_Cprog = (UInt8)uCprog_signed;

 // write byte RFC_Cprog
 if (tda_write_chip(tuner_card, TDA18211_R_EB14, p_reg_map[TDA18211_R_EB14]) < 0) {
  dprintk("%s(%d): Error writing in TDA18211_R_EB14\n", __FUNCTION__, __LINE__);
  return TMBSL_ERR_IIC_ERR;
 }

 //----------------------
 // standard mode update
 //----------------------
 // update TV broadcast parameters
 ret = TDA182I1SetStandardMode(tuner_card, p_reg_map, op_standard);
 if (ret < 0)
  return ret;

 // switch RFAGC to high speed mode (store current value)
 utmpStd = I2CMap->uBx05.bF.Std;
 I2CMap->uBx05.bF.Std &= 0x1B;

 // write byte EASY_PROG_BYTE_3
 if (tda_write_map_to_chip(tuner_card, p_reg_map, TDA18211_R_EP3, TDA18211_R_EP3) < 0)
  return TMBSL_ERR_IIC_ERR;

 //----------------------
 // update frequency dependent parameters
 //----------------------
 // search for IR_Meas corresponding to wanted frequency
 uIRMeasCounter = 0;
 do uIRMeasCounter ++;
 while (uRF > IR_MEAS_Map[uIRMeasCounter - 1].uRF_Max && uCounter - 1 < TDA18211_IR_MEAS_NB_ROWS);
 I2CMap->uBx07.bF.IR_Meas = (UInt8)IR_MEAS_Map[uCounter - 1].uIR_Meas;
 
 // search for BP_Filter corresponding to uRF
 uCounter = 0;
 do uCounter ++;
 while (uRF > BP_FILTER_Map[uCounter - 1].uRF_Max && uCounter < TDA18211_BP_FILTER_NB_ROWS);
 I2CMap->uBx03.bF.BP_Filter = (UInt8)BP_FILTER_Map[uCounter - 1].uBP_Filter;

 // search for RF_BAND corresponding to uRF
 uCounter = 0;
 do uCounter ++;
 while (uRF > RF_BAND_Map[uCounter - 1].uRF_Max && uCounter < TDA18211_RF_BAND_NB_ROWS);
 I2CMap->uBx04.bF.RF_Band = (UInt8)RF_BAND_Map[uCounter - 1].uRF_Band;

 // search for Gain_Taper corresponding to uRF
 uCounter = 0;
 do uCounter ++;
 while (uRF > GAIN_TAPER_Map[uCounter - 1].uRF_Max && uCounter < TDA18211_GAIN_TAPER_NB_ROWS);
 I2CMap->uBx04.bF.Gain_Taper = GAIN_TAPER_Map[uCounter - 1].uGain_Taper;

 //---------------------
 // dual tuner and AGC1 extra configuration management
 //---------------------
 // use MAIN VCO when master, CAL VCO when slave
 I2CMap->uBx10.bF.CALVCO_forLOn = (priv->Config_Instance.Master != 0) ? 1 : 0;

 // AGC1 & AGC2 management
 I2CMap->uBx10.bF.AGC1_always_mastern = 0x00;
 I2CMap->uBx10.bF.AGC1_firstn = 0x00;

 // write byte EXTENDED_BYTE_1
 if (tda_write_chip(tuner_card, TDA18211_R_EB1, p_reg_map[TDA18211_R_EB1]) < 0)
  return TMBSL_ERR_IIC_ERR;

 //---------------------
 // tune to wanted channel frequency
 //---------------------
 // use MAIN VCO when master, CAL VCO when slave
 if (priv->Config_Instance.Master != 0) // master
 {
  dprintk("%s(%d): Programming master tuner\n", __FUNCTION__, __LINE__);

  // calculate MAIN PLL
  if (!TDA182I1CalcMAINPLL(p_reg_map, uRF + priv->Config_Instance.uIF))
   return TMBSL_ERR_IIC_ERR;

  // write bytes 0x01 to 0x0F
  if (tda_write_map_to_chip(tuner_card, p_reg_map, TDA18211_R_TM, TDA18211_R_MD3) < 0)
   return TMBSL_ERR_IIC_ERR;    

  // MAIN pll charge pump source
  I2CMap->uBx13.bF.LO_ForceSrce = 0x01;
  // write byte EXTENDED_BYTE_4
  if (tda_write_chip(tuner_card, TDA18211_R_EB4, p_reg_map[TDA18211_R_EB4]) < 0)
   return TMBSL_ERR_IIC_ERR;

  // wait 1 ms for charge pump source
  msleep(1);

  // MAIN pll normal operation
  I2CMap->uBx13.bF.LO_ForceSrce = 0x00;
  // write byte EXTENDED_BYTE_4
  if (tda_write_chip(tuner_card, TDA18211_R_EB4, p_reg_map[TDA18211_R_EB4]) < 0)
   return TMBSL_ERR_IIC_ERR;
 }
 else // slave
 {  
  dprintk("%s(%d): Programming slave tuner\n", __FUNCTION__, __LINE__); 
  // calculate CAL PLL
  if (!TDA182I1CalcCALPLL(p_reg_map, uRF + priv->Config_Instance.uIF))
   return TMBSL_ERR_IIC_ERR;

  // copy CAL PLL PostDiv to MAIN PLL Post Div
  I2CMap->uBx0C.bF.MAIN_Post_Div = I2CMap->uBx08.CAL_POST_DIV_BYTE & 0x77;

  // write bytes 0x01 to 0x0F
  if (tda_write_map_to_chip(tuner_card, p_reg_map, TDA18211_R_TM, TDA18211_R_MD3) < 0)
   return TMBSL_ERR_IIC_ERR;    

  // CAL pll charge pump source
  I2CMap->uBx16.bF.CAL_ForceSrce = 0x01;
  // write byte EXTENDED_BYTE_7
  if (tda_write_chip(tuner_card, TDA18211_R_EB7, p_reg_map[TDA18211_R_EB7]) < 0)
   return TMBSL_ERR_IIC_ERR;

  // wait 1 ms for charge pump source
  msleep(1);

  // CAL pll normal operation
  I2CMap->uBx16.bF.CAL_ForceSrce = 0x00;
  // write byte EXTENDED_BYTE_7
  if (tda_write_chip(tuner_card, TDA18211_R_EB7, p_reg_map[TDA18211_R_EB7]) < 0)
   return TMBSL_ERR_IIC_ERR;
 }

 // wait 20 ms for pll locking
 msleep(20);

 // switch RFAGC to normal mode (restore previous value)
 I2CMap->uBx05.bF.Std = utmpStd;

 // write byte EASY_PROG_BYTE_3
 if (tda_write_chip(tuner_card, TDA18211_R_EP3, p_reg_map[TDA18211_R_EP3]) < 0)
  return TMBSL_ERR_IIC_ERR;

 // read bytes 0x00 to 0x26
 if (tuner_i2c_read(tuner_card, p_reg_map, NUM_TDA18211_REG) < 0)
  return TMBSL_ERR_IIC_ERR;

 return TM_OK;
}

/**
 * Set frequency, operating mode, bandwidth
 *  
 * @param fe frontend
 * @param params ptr to structure with settings
 * @return 0:success >0:invalid value or operation
 */
static int tda18211_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
	struct tda18211_priv *priv = fe->tuner_priv;
    tmTDA182I1StandardMode_t op_standard;
    int bw = 0;

	dprintk("%s(%d)\n", __FUNCTION__, __LINE__);

    // First-time initialisation
	if (!priv->init) {
        TDA182I1Init(fe, priv->tda18211_regs);
        priv->init = 1;
    }

    // Check parameters
    if (priv == NULL || params == NULL)
    {
    	dprintk("%s: %s NULL\n", __FUNCTION__, (priv == NULL) ? "fe->priv" : "params");
    	return -EINVAL;
    }
    
    // Set operating mode & bandwidth from fe info
    // @todo determine how to deal with other modes
	switch (fe->ops.info.type)
	{
		case FE_OFDM:
			switch (params->u.ofdm.bandwidth) {
					case BANDWIDTH_6_MHZ:
						op_standard = tmDigital_TV_DVBT_6MHz; // not in original code
						bw = 6000000;
						break;
					case BANDWIDTH_7_MHZ:
						op_standard = tmDigital_TV_DVBT_7MHz;
						bw = 7000000;
						break;
					case BANDWIDTH_8_MHZ:
						op_standard = tmDigital_TV_DVBT_8MHz;
						bw = 8000000;
						break;
					default:
					 	dprintk("%s: invalid OFDM setting\n", __FUNCTION__);
					 	return -EINVAL;
					}			
			break;
		case FE_ATSC:
			op_standard = tmDigital_TV_ATSC_6MHz;
			bw = 6000000;
			break;
			
		case FE_QPSK:
		case FE_QAM:
		default:
		 	dprintk("%s: invalid fe type\n", __FUNCTION__);
			return -EINVAL;
	}

	dprintk("\n%s: freq: '%d', bw: '%d', if: '%d'\n", __FUNCTION__, params->frequency, bw, priv->Config_Instance.uIF);

    // First-time initialisation
	if (!priv->init) {
        TDA182I1Init(fe, priv->tda18211_regs);
        priv->init = 1;
    }

	// tune to frequency
    TDA182I1SetRf(fe, priv->tda18211_regs, op_standard, params->frequency); // freq supplied is in Hz
    // save settings
    priv->frequency = params->frequency;
	priv->bandwidth = bw;

    dprintk("%s(%d): Pll lock:%c RF cal:%c IR cal:%c\n", __FUNCTION__, __LINE__, (priv->tda18211_regs[1] & 0x40) ? 'y' : 'n', (priv->tda18211_regs[3] & 0x10) ? 'y' : 'n', (priv->tda18211_regs[3] & 0x08) ? 'y' : 'n');

    return 0;

}

/**
 * Driver release
 * @param fe frontend
 * @return 0:success
 */
static int tda18211_release(struct dvb_frontend *fe)
{

	dprintk("%s(%d)\n", __FUNCTION__, __LINE__);

	if (fe != NULL)
	{
		kfree(fe->tuner_priv);
		fe->tuner_priv = NULL;
	}

	return 0;
}

/**
 * Report tuned frequency
 * @param fe frontend
 * @param frequency location in which tuned frequency is returned (non-NULL)
 * @return 0:success
 */
int tda18211_get_frequency(struct dvb_frontend *fe, u32 *frequency)
{
	struct tda18211_priv *priv = fe->tuner_priv;

    dprintk("%s(%d): frequency %d\n", __FUNCTION__, __LINE__, priv->frequency);

	*frequency = priv->frequency;
	return 0;
}

/**
 * Report set bandwidth
 * @param fe frontend
 * @param bandwidth location in which configured bandwidth is returned (non-NULL)
 * @return 0:success
 */
static int tda18211_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
{
	struct tda18211_priv *priv = fe->tuner_priv;

	dprintk("%s(%d)\n", __FUNCTION__, __LINE__);

	*bandwidth = priv->bandwidth;
	return 0;
}

/**
 * Standard tuner operations
 */
static struct dvb_tuner_ops tda18211_tuner_ops = {
	.info =
	{
		.name = "NXP TDA18211HD/C2",
		.frequency_min  = 174000000,
		.frequency_max  = 864000000,
		.frequency_step = 8000000
	},
 .set_params        = tda18211_set_params,
 .get_frequency     = tda18211_get_frequency,
 .get_bandwidth     = tda18211_get_bandwidth,
 .release           = tda18211_release,
};

/**
 * Allocate memory for tuner private data and ops, attach to frontend
 * 
 * @param fe frontend to attach to
 * @param addr I2C address 
 * @param i2c I2C bus
 * @param is_master true if 'master' tuner, false if 'slave'
 */
struct dvb_frontend * tda18211_attach(struct dvb_frontend * fe, u8 i2c_addr, struct i2c_adapter * i2c_adap, int is_master)
{
 struct tda18211_priv * priv;

 dprintk("%s(%d): i2c addr: 0x%x\n", __FUNCTION__, __LINE__, i2c_addr);
 
 priv = kzalloc(sizeof(struct tda18211_priv), GFP_KERNEL);
 if (priv == NULL)
 {
  return NULL;
 }
 
 priv->i2c_addr = i2c_addr;
 priv->i2c_adapt = i2c_adap;
 priv->Config_Instance.Master = (is_master != 0);

 memcpy(&fe->ops.tuner_ops, &tda18211_tuner_ops, sizeof(tda18211_tuner_ops));

 fe->tuner_priv = priv;

 return fe;
}

module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, " Turn on (=1) debugging. Default off (=0).");

EXPORT_SYMBOL(tda18211_attach);

MODULE_DESCRIPTION("NXP TDA18211HD/C2");
MODULE_AUTHOR("Mike Whittaker");
MODULE_LICENSE("GPL");
