/*
 * 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
005 20090423 CC Fix driver to comply with last driver development
--------------------------------------------------------------------------------
    For consistency and standardisation retain the Section Separators.
*/

/***********************************************
* INCLUDE FILES                                *
************************************************/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include "tda18211.h"

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

#define TDA18211_NB_BYTES 39
#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)

#ifndef NXPFE_TEST
#define TRACE_LVL KERN_DEBUG /* KERN_INFO */

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

/* Porting definitions */
#define TM_ERR_NOT_SUPPORTED    (-1)
#define TMBSL_ERR_IIC_ERR       (-1)
#define TM_OK                   (0) /* TM_OK = 0. It is an NXP convention */
#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 unsigned short UInt16;
typedef signed char Int8;
typedef unsigned char Bool;
typedef int tmErrorCode_t;

/* For Caen code */
typedef enum _tmTDA18211PowerState_t {
    tmTDA18211_PowerNormalMode = 0,                 /* Device normal mode                         */
    tmTDA18211_PowerSleepMode,                      /* Device sleep mode                          */
    tmTDA18211_PowerStandbyWith16MHz,               /* Device standby with 16Mhz                  */
    tmTDA18211_PowerStandbyWith16MHzAndLoopThrough, /* Device standby with 16Mhz and loop through */
    tmTDA18211_PowerStandbyWithLoopThrough,         /* Device standby with loop through           */
    tmTDA18211_PowerNotSupported                    /* Not supported power mode                   */
} tmTDA18211PowerState_t;

typedef enum _tmTDA18211StandardMode_t {
    tmTDA18211_DVBT_6MHz = 0,                       /* Digital TV DVB-T 6MHz  */
    tmTDA18211_DVBT_7MHz,                           /* Digital TV DVB-T 7MHz  */
    tmTDA18211_DVBT_8MHz,                           /* Digital TV DVB-T 8MHz  */
    tmTDA18211_QAM_6MHz,                            /* Digital TV QAM 6MHz    */
    tmTDA18211_QAM_8MHz,                            /* Digital TV QAM 8MHz    */
    tmTDA18211_ISDBT_6MHz,                          /* Digital TV ISDBT 6MHz  */
    tmTDA18211_ATSC_6MHz,                           /* Digital TV ATSC 6MHz   */
    tmTDA18211_DMBT_8MHz,                           /* Digital TV DMB-T 8MHz  */
    tmTDA18211_StdNotSupported                      /* Not supported standard */
} tmTDA18211StandardMode_t;

typedef enum _tmTDA18211LPFc_t {
    tmTDA18211_LPFc_6MHz = 0,                       /* 6MHz LPFc */
    tmTDA18211_LPFc_7MHz = 1,                       /* 7MHz LPFc */
    tmTDA18211_LPFc_8MHz = 2,                       /* 8MHz LPFc */
    tmTDA18211_LPFc_9MHz = 3                        /* 9MHz LPFc */
} tmTDA18211LPFc_t;

typedef enum _tmTDA18211IF_Level_t {
    tmTDA18211_IF_LVL_0dB = 0,                      /*     0dB IF Level */
    tmTDA18211_IF_LVL_min_4dB = 1,                  /*    -4dB IF Level */
    tmTDA18211_IF_LVL_min_6dB = 2,                  /*    -6dB IF Level */
    tmTDA18211_IF_LVL_min_10_4dB = 6,               /* -10.4dB IF Level */
    tmTDA18211_IF_LVL_min_12dB = 7                  /*   -12dB IF Level */
} tmTDA18211IF_Level_t;

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

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

typedef struct _tmTDA18211StdCoefficients
{
    UInt32 uIF;                                     /* IF in Hz        */
    UInt8 uAGCK_Mode;                               /* AGCK_Mode       */
    UInt8 uLPFc;                                    /* LPFc            */
    UInt8 uIF_Level;                                /* IF Output Level */
    UInt8 uIF_Notch;                                /* IF Notch        */
    UInt8 uRF_IF_AGC_Top;                           /* RF & IF AGC Top */
    UInt8 uCAL_RFn;                                 /* CAL RFn         */
} tmTDA18211StdCoefficients, *ptmTDA18211StdCoefficients;

static tmTDA18211StdCoefficients Std_Array[tmTDA18211_StdNotSupported] =
{
    {    /* DVB-T 6MHz */
        3300000,                        /* uIF */
        0x03,                           /* uAGCK_Mode */
        tmTDA18211_LPFc_6MHz,           /* uLPFc */
        tmTDA18211_IF_LVL_min_4dB,      /* uIF_Level */
        0x01,                           /* uIF_Notch */
        0x57,                           /* uRF_IF_AGC_Top */
        0x00        /* uCAL_RFn */
    },
    {    /* DVB-T 7Hz */
        3500000,                        /* uIF */
        0x03,                           /* uAGCK_Mode */
        tmTDA18211_LPFc_6MHz,           /* uLPFc */
        tmTDA18211_IF_LVL_min_4dB,      /* uIF_Level */
        0x01,                           /* uIF_Notch */
        0x57,                           /* uRF_IF_AGC_Top */
        0x00                            /* uCAL_RFn */
    },
    {    /* DVB-T 8MHz */
        4000000,                        /* uIF */
        0x03,                           /* uAGCK_Mode */
        tmTDA18211_LPFc_7MHz,           /* uLPFc */
        tmTDA18211_IF_LVL_min_4dB,      /* uIF_Level */
        0x01,                           /* uIF_Notch */
        0x57,                           /* uRF_IF_AGC_Top */
        0x00                            /* uCAL_RFn */
    },
    {    /* QAM 6MHz */
        4000000,                        /* uIF */
        0x03,                           /* uAGCK_Mode */
        tmTDA18211_LPFc_7MHz,           /* uLPFc */
        tmTDA18211_IF_LVL_min_4dB,      /* uIF_Level */
        0x01,                           /* uIF_Notch */
        0x37,                           /* uRF_IF_AGC_Top */
        0x00                            /* uCAL_RFn */
    },
    {    /* QAM 8MHz */
        5000000,                        /* uIF */
        0x03,                           /* uAGCK_Mode */
        tmTDA18211_LPFc_9MHz,           /* uLPFc */
        tmTDA18211_IF_LVL_min_4dB,      /* uIF_Level */
        0x01,                           /* uIF_Notch */
        0x37,                           /* uRF_IF_AGC_Top */
        0x00                            /* uCAL_RFn */
    },
    {    /* ISDBT 6MHz */
        3300000,                        /* uIF */
        0x03,                           /* uAGCK_Mode */
        tmTDA18211_LPFc_6MHz,           /* uLPFc */
        tmTDA18211_IF_LVL_min_12dB,     /* uIF_Level */
        0x01,                           /* uIF_Notch */
        0x37,                           /* uRF_IF_AGC_Top */
        0x00                            /* uCAL_RFn */
    },
    {    /* ATSC 6MHz */
        3250000,                        /* uIF */
        0x03,                           /* uAGCK_Mode */
        tmTDA18211_LPFc_6MHz,           /* uLPFc */
        tmTDA18211_IF_LVL_min_10_4dB,   /* uIF_Level */
        0x01,                           /* uIF_Notch */
        0x58,                           /* uRF_IF_AGC_Top */
        0x00                            /* uCAL_RFn */
    },
    {    /* DMB-T 8MHz */
        3250000,                        /* uIF */
        0x03,                           /* uAGCK_Mode */
        tmTDA18211_LPFc_6MHz,           /* uLPFc */
        tmTDA18211_IF_LVL_min_10_4dB,   /* uIF_Level */
        0x01,                           /* uIF_Notch */
        0x58,                           /* uRF_IF_AGC_Top */
        0x00                            /* uCAL_RFn */
    }
};

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

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

static const struct {
    UInt32 uRF_Max;
    UInt32 uBP_Filter;
} BP_FILTER_Map[] =
{
    {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;
} tmTDA18211_RF_BAND_Map_t, *ptmTDA18211_RF_BAND_Map_t;

static  tmTDA18211_RF_BAND_Map_t RF_BAND_Map[] =
{
    {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;
    UInt32 uGain_Taper;
} GAIN_TAPER_Map[] =
{
    {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;
    UInt32 uRFC_Cprog;
} RF_CAL_Map[] =
{
    {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;
    UInt32 udC_Over_dT;
} RF_CAL_DC_OVER_DT_Map[] =
{
    {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;
    UInt32 uK;
    UInt32 uM;
    UInt32 uCOAmpl;
} RF_CAL_KMCO_Map[] =
{
    {350000000, 0x03, 0x00, 0x03},
    {720000000, 0x02, 0x01, 0x03},
    {865000000, 0x03, 0x03, 0x03}
};

static const struct {
    UInt32 uRF_Max;
    UInt32 uCID_Target;
    UInt32 uCount_Limit;
} RF_CAL_CID_TARGET_Map[] =
{
    {186250000,    0x0A,    4000000},
    {230000000,    0x0A,    4000000},
    {345000000,    0x18,    4000000},
    {426000000,    0x0E,    4000000},
    {489500000,    0x1E,    4000000},
    {697500000,    0x32,    4000000},
    {842000000,    0x3A,    4000000}
};

static const struct {
    UInt32 uTM_D;
    UInt32 uTM_60_92;
    UInt32 uTM_92_122;
} THERMOMETER_Map[]=
{
    {0x00, 0x28, 0x5C},
    {0x01, 0x3E, 0x5E},
    {0x02, 0x42, 0x62},
    {0x03, 0x40, 0x60},
    {0x04, 0x4A, 0x6A},
    {0x05, 0x48, 0x68},
    {0x06, 0x44, 0x64},
    {0x07, 0x46, 0x66},
    {0x08, 0x5A, 0x7A},
    {0x09, 0x58, 0x78},
    {0x0A, 0x54, 0x74},
    {0x0B, 0x56, 0x76},
    {0x0C, 0x4C, 0x6C},
    {0x0D, 0x4E, 0x6E},
    {0x0E, 0x52, 0x72},
    {0x0F, 0x50, 0x70}
};

static const struct {
    UInt32 uLO_Max;
    UInt32 uPost_Div;
    UInt32 uDiv;
} CAL_PLL_Map[] =
{
    {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}
};

static const struct {
    UInt32 uLO_Max;
    UInt32 uPost_Div;
    UInt32 uDiv;
} MAIN_PLL_Map[] =
{
    {180500000,    0x3B,    0x2C},
    {198750000,    0x3A,    0x28},
    {220750000,    0x39,    0x24},
    {248500000,    0x38,    0x20},
    {265000000,    0x2F,    0x1E},
    {284000000,    0x2E,    0x1C},
    {305500000,    0x2D,    0x1A},
    {331000000,    0x2C,    0x18},
    {361000000,    0x2B,    0x16},
    {397500000,    0x2A,    0x14},
    {441500000,    0x29,    0x12},
    {497000000,    0x28,    0x10},
    {530000000,    0x1F,    0x0F},
    {568000000,    0x1E,    0x0E},
    {611000000,    0x1D,    0x0D},
    {662000000,    0x1C,    0x0C},
    {722000000,    0x1B,    0x0B},
    {795000000,    0x1A,    0x0A},
    {883000000,    0x19,    0x09},
    {994000000,    0x18,    0x08}
};

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

    union
    {
        UInt8 THERMO_BYTE;              /* address 0x01 */
        /* Thermometer byte */
        struct
        {
#ifdef _BIG_ENDIAN
            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 */
            UInt8 MAIN_Lock         :1; /* Indicate that the MAIN synthesizer is locked to the programmed frequency */
            /*  0: Not Locked */
            /*  1: Locked */
            UInt8 TM_Range          :1; /* Range selection bit for the internal die sensor */
            /*  0: 60 to 92°C */
            /*  1: 92 to 122°C */
            UInt8 TM_ON             :1; /* Enable Die temperature measurement */
            UInt8 TM_D              :4; /* Data from die temperature measurement */
#else
            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 92°C */
            /*  1: 92 to 122°C */
            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 */
#endif
        }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
        {
#ifdef _BIG_ENDIAN
            UInt8 Power_Level_8     :1; /* Power level indicator value */
            UInt8 Dis_Power_level   :1; /* Disable power level measurement */
            /*  0: Power measurement valid */
            /*  1: Power measurement not guaranteed */
            UInt8 UNUSED            :1; /* Reserved */
            UInt8 RF_CAL_OK         :1; /* Indicate that the RF tracking filter calibration procedure has been successful */
            UInt8 IR_CAL_OK         :1; /* Indicate that the 3 Image rejection calibration procedure  (Flow, Fmid, Fhigh) have been successful */
            UInt8 BP_Filter         :3; /* RF band-pass filter selection (H3/H5) */
#else
            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 guaranteed */
            UInt8 Power_Level_8     :1; /* Power level indicator value */
#endif
        }bF;
    }uBx03;

    union
    {
        UInt8 EASY_PROG_BYTE_2;         /* address 0x04 */
        /* Easy programming byte 2 */
        struct
        {
#ifdef _BIG_ENDIAN
            UInt8 RF_Band           :3; /* RF tracking filter band and sub-band selection */
            UInt8 Gain_Taper        :5; /* Gain taper value */
            /*  0: max atten. (end of Band) */
            /* 31: min atten. (start of Band) */
#else
            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 */
#endif
        }bF;
    }uBx04;

    union
    {
        UInt8 EASY_PROG_BYTE_3;         /* address 0x05 */
        /* Easy programming byte 3 */
        struct
        {
#ifdef _BIG_ENDIAN
            UInt8 SM                :1; /* General sleep mode */
            UInt8 SM_LT             :1; /* Loop through sleep mode */
            UInt8 SM_XT             :1; /* XTAL output sleep mode */
            UInt8 AGCK_Mode         :2; /* Standard selection */
            UInt8 AGC_Low_BW        :1; /* Standard selection */
            UInt8 LP_Fc             :2; /* Standard selection */
#else
            UInt8 LP_Fc             :2; /* Standard selection */
            UInt8 AGC_Low_BW        :1; /* Standard selection */
            UInt8 AGCK_Mode         :2; /* Standard selection */
            UInt8 SM_XT             :1; /* XTAL output sleep mode */
            UInt8 SM_LT             :1; /* Loop through sleep mode */
            UInt8 SM                :1; /* General sleep mode */
#endif
        }bF;
    }uBx05;

    union
    {
        UInt8 EASY_PROG_BYTE_4;         /* address 0x06 */
        /* Easy programming byte 4 */
        struct
        {
#ifdef _BIG_ENDIAN
            UInt8 CAL_RFn           :1; /* CAL or RF input selection */
            UInt8 XTout_ON          :1; /* Enable 16MHz on XTAL output */
            UInt8 Xtout_400mV       :1; /* XTAL output level optional selection */
            UInt8 IF_Level          :3; /* IF output level selection */
            UInt8 CAL_Mode          :2; /* calibration mode selection */
#else
            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 */
#endif

        }bF;
    }uBx06;

    union
    {
        UInt8 EASY_PROG_BYTE_5;         /* address 0x07 */
        /* Easy programming byte 5 */
        struct
        {
#ifdef _BIG_ENDIAN
            UInt8 Extended_Reg      :1; /* Enable the extended byte addressing */
            /*  0: Limited byte (&h00:&h0F) */
            /*  1: Extended byte (&h00:&h26) */
            UInt8 IR_Gstep          :3; /* Gain step for image rejection measurement. Depends on frequency */
            UInt8 I2C_Xtout_Asym    :1; /* Reserved */
            UInt8 IR_Meas           :3; /* Image rejection measurement mode */
#else
            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) */
#endif
        }bF;
    }uBx07;

    union
    {
        UInt8 CAL_POST_DIV_BYTE;        /* address 0x08 */
        /* CAL post divider byte */
        struct
        {
#ifdef _BIG_ENDIAN
            UInt8 RUF_0             :1; /* Reserved */
            UInt8 CALPostDiv        :7; /* CAL post divider */
#else
            UInt8 CALPostDiv        :7; /* CAL post divider */
            UInt8 RUF_0             :1; /* Reserved */
#endif
        }bF;
    }uBx08;

    union
    {
        UInt8 CAL_DIV_BYTE_1;           /* address 0x09 */
        /* CAL divider byte    1 */
        struct
        {
#ifdef _BIG_ENDIAN
            UInt8 RUF_1             :1; /* Reserved */
            UInt8 CAL_Div_22_to_16  :7; /* CAL divider value 22 to 16 */
#else
            UInt8 CAL_Div_22_to_16  :7; /* CAL divider value 22 to 16 */
            UInt8 RUF_1             :1; /* Reserved */
#endif
        }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
        {
#ifdef _BIG_ENDIAN
            UInt8 IF_notch          :1; /* Reserved */
            UInt8 MAIN_Post_Div     :7; /* MAIN post divider value */
#else
            UInt8 MAIN_Post_Div     :7; /* MAIN post divider value */
            UInt8 IF_notch          :1; /* Reserved */
#endif
        }bF;
    }uBx0C;

    union
    {
        UInt8 MAIN_DIV_BYTE_1;          /* address 0x0D */
        /* MAIN divider byte 1 */
        struct
        {
#ifdef _BIG_ENDIAN
            UInt8 RUF_2             :1; /* Reserved */
            UInt8 MAIN_Div_22_to_16 :7; /* MAIN divider value 22 to 16 */
#else
            UInt8 MAIN_Div_22_to_16 :7; /* MAIN divider value 22 to 16 */
            UInt8 RUF_2             :1; /* Reserved */
#endif
        }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
        {
#ifdef _BIG_ENDIAN
            UInt8 UNUSED            :1; /* Reserved */
            UInt8 CALVCO_forLOn     :1;
            UInt8 AGC1_always_mastern:1;
            UInt8 AGC1_firstn       :1;
#else
            UInt8 AGC1_firstn    :  1;
            UInt8 AGC1_always_mastern:1;
            UInt8 CALVCO_forLOn     :1;
            UInt8 UNUSED            :1; /* Reserved */
#endif
        }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
        {
#ifdef _BIG_ENDIAN
            UInt8 UNUSED_2          :2; /* Reserved */
            UInt8 LO_ForceSrce      :1;
            UInt8 UNUSED_1          :5; /* Reserved */
#else
            UInt8 UNUSED_1          :5; /* Reserved */
            UInt8 LO_ForceSrce      :1;
            UInt8 UNUSED_2          :2; /* Reserved */
#endif
        }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
        {
#ifdef _BIG_ENDIAN
            UInt8 UNUSED_2          :2; /* Reserved */
            UInt8 CAL_ForceSrce     :1;
            UInt8 UNUSED_1          :4; /* Reserved */
            UInt8 CAL_Lock          :1;
#else
            UInt8 CAL_Lock          :1;
            UInt8 UNUSED_1          :4; /* Reserved */
            UInt8 CAL_ForceSrce     :1;
            UInt8 UNUSED_2          :2; /* Reserved */
#endif
        }bF;
    }uBx16;

    union
    {
        UInt8 EXTENDED_BYTE_8;          /* address 0x17 */
        /* Extended byte 8 */
        struct
        {
#ifdef _BIG_ENDIAN
            UInt8 CID_Alarm         :1;
            UInt8 UNUSED            :7; /* Reserved */
#else
            UInt8 UNUSED            :7; /* Reserved */
            UInt8 CID_Alarm         :1;
#endif
        }bF;
    }uBx17;

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

    union
    {
        UInt8 EXTENDED_BYTE_10;         /* address 0x19 */
        /* Extended byte 10 */
        struct
        {
#ifdef _BIG_ENDIAN
            UInt8 UNUSED            :2; /* Reserved */
            UInt8 CID_Gain          :6;
#else
            UInt8 CID_Gain          :6;
            UInt8 UNUSED            :2; /* Reserved */
#endif
        }bF;
    }uBx19;

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

    union
    {
        UInt8 EXTENDED_BYTE_12;         /* address 0x1B */
        /* Extended byte 12 */
        struct
        {
#ifdef _BIG_ENDIAN
            UInt8 UNUSED_2          :2; /* Reserved */
            UInt8 PD_AGC1_Det       :1;
            UInt8 PD_AGC2_Det       :1;
            UInt8 UNUSED_1          :4; /* Reserved */
#else
            UInt8 UNUSED_1          :4; /* Reserved */
            UInt8 PD_AGC2_Det       :1;
            UInt8 PD_AGC1_Det       :1;
            UInt8 UNUSED_2          :2; /* Reserved */
#endif
        }bF;
    }uBx1B;

    union
    {
        UInt8 EXTENDED_BYTE_13;         /* address 0x1C */
        /* Extended byte 13 */
        struct
        {
#ifdef _BIG_ENDIAN
            UInt8 UNUSED_2          :1; /* Reserved */
            UInt8 RFC_K             :3;
            UInt8 RFC_M             :2;
            UInt8 UNUSED_1          :2; /* Reserved */
#else
            UInt8 UNUSED_1          :2; /* Reserved */
            UInt8 RFC_M             :2;
            UInt8 RFC_K             :3;
            UInt8 UNUSED_2          :1; /* Reserved */
#endif
        }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
        {
#ifdef _BIG_ENDIAN
            UInt8 AGC1_loop_off     :1;
            UInt8 UNUSED            :5; /* Reserved */
            UInt8 AGC1_Gain         :2;
#else
            UInt8 AGC1_Gain         :2;
            UInt8 UNUSED            :5; /* Reserved */
            UInt8 AGC1_loop_off     :1;
#endif
        }bF;
    }uBx21;

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

    union
    {
        UInt8 EXTENDED_BYTE_20;         /* address 0x23 */
        /* Extended byte 20 */
        struct
        {
#ifdef _BIG_ENDIAN
            UInt8 UNUSED_2          :2; /* Reserved */
            UInt8 Force_Lock        :1;
            UInt8 UNUSED_1          :5; /* Reserved */
#else
            UInt8 UNUSED_1          :5; /* Reserved */
            UInt8 Force_Lock        :1;
            UInt8 UNUSED_2          :2; /* Reserved */
#endif
        }bF;
    }uBx23;

    union
    {
        UInt8 EXTENDED_BYTE_21;         /* address 0x24 */
        /* Extended byte 21 */
        struct
        {
#ifdef _BIG_ENDIAN
            UInt8 AGC2_loop_off     :1;
            UInt8 UNUSED            :5; /* Reserved */
            UInt8 AGC2_Gain         :2;
#else
            UInt8 AGC2_Gain         :2;
            UInt8 UNUSED            :5; /* Reserved */
            UInt8 AGC2_loop_off     :1;
#endif
        }bF;
    }uBx24;

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

    union
    {
        UInt8 EXTENDED_BYTE_23;         /* address 0x26 */
        /* Extended byte 23 */
        struct
        {
#ifdef _BIG_ENDIAN
            UInt8 CAL_LNAGain       :2;
            UInt8 UNUSED_2          :3; /* Reserved */
            UInt8 ForceLP_Fc2_En    :1;
            UInt8 LP_Fc             :1;
            UInt8 UNUSED_1          :1; /* Reserved */
#else
            UInt8 UNUSED_1          :1; /* Reserved */
            UInt8 LP_Fc             :1;
            UInt8 ForceLP_Fc2_En    :1;
            UInt8 UNUSED_2          :3; /* Reserved */
            UInt8 CAL_LNAGain       :2;
#endif
        }bF;
    }uBx26;

} tmTDA18211I2CMap_t, *ptmTDA18211I2CMap_t;


typedef struct {
    Bool                        Master;
    UInt32                      StandardMode;
    UInt32                      lastStandardMode;
    UInt32                      uRF;
    UInt32                      uIF;
    UInt8                       uTMVALUE_RFCAL;
    tmTDA18211_RF_BAND_Map_t    RF_BAND_Map[TDA18211_RF_BAND_NB_ROWS];
    UInt32                      uPLMODE;
    Int32                       uRFCAL_TCOMP;
} tmTDA18211Config_t;

struct tda18211_priv {
    u8                      i2c_addr;
    struct i2c_adapter *    i2c_adapt;
    u32                     frequency;
    u32                     bandwidth;

    /* Caen Code Specific */
    tmTDA18211PowerState_t  curPowerState;
    tmTDA18211I2CMap_t      I2CMap;
    tmTDA18211Config_t      Config_Instance;
};

/* Prototypes for Caen code */

static tmErrorCode_t
TDA18211Write(struct dvb_frontend * tuner_card, UInt8 uSubAddress, UInt8 uNbData);

static tmErrorCode_t
TDA18211Read(struct dvb_frontend * tuner_card, UInt8 uSubAddress, UInt8 uNbData);

static tmErrorCode_t
TDA18211Wait(struct dvb_frontend * tuner_card, UInt16 wTime);

static tmErrorCode_t
TDA18211SetPowerState (struct dvb_frontend * tuner_card, tmTDA18211PowerState_t  powerState);

static tmErrorCode_t
TDA18211Init (struct dvb_frontend * tuner_card);

static tmErrorCode_t
TDA18211CalcMAINPLL (struct dvb_frontend * tuner_card, UInt32 uLO);

static tmErrorCode_t
TDA18211CalcCALPLL (struct dvb_frontend * tuner_card, UInt32 uLO);

tmErrorCode_t
TDA18211PowerScanInit (struct dvb_frontend * tuner_card);

tmErrorCode_t
TDA18211PowerScan (struct dvb_frontend * tuner_card, UInt32* puRF, Bool* pCal);

static tmErrorCode_t
TDA18211CalibrateRF (struct dvb_frontend * tuner_card, UInt32 uRF, UInt8* puCprog);

static tmErrorCode_t
TDA18211RFTrackingFiltersInit (struct dvb_frontend * tuner_card, ptmTDA18211_RF_BAND_Map_t pRF_BAND_Map);

static tmErrorCode_t
TDA18211CalcRFFilterCurve (struct dvb_frontend * tuner_card);

static tmErrorCode_t
TDA18211ThermometerRead (struct dvb_frontend * tuner_card, UInt8 * puValue);

static tmErrorCode_t
TDA18211SetStandardMode (struct dvb_frontend * tuner_card, tmTDA18211StandardMode_t StandardMode);

static tmErrorCode_t
TDA18211SetRf(struct dvb_frontend * tuner_card, UInt32 uRF);


/*============================================================================*/
/* FUNCTION:    tuner_i2c_xfer:                                               */
/*                                                                            */
/* DESCRIPTION: i2c transfer                                                  */
/*                                                                            */
/* RETURN:      0 if no error, -EIO otherwise                                 */
/*                                                                            */
/* NOTES:                                                                     */
/*============================================================================*/
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;

    tuner_i2c_msg.addr = priv->i2c_addr;
    tuner_i2c_msg.flags = is_read?I2C_M_RD:0;
    tuner_i2c_msg.len = (__u16)len;
    tuner_i2c_msg.buf = buf;

    ret = i2c_transfer(priv->i2c_adapt, &tuner_i2c_msg, 1); /* returns number of successful transfers */

    return (ret != 1) ? -EIO : TM_OK;
}

/*============================================================================*/
/* FUNCTION:    TDA18211Write:                                                */
/*                                                                            */
/* DESCRIPTION: Calculate i2c I2CMap & write in TDA18211.                     */
/*                                                                            */
/* RETURN:      TM_OK if no error                                             */
/*                                                                            */
/* NOTES:                                                                     */
/*============================================================================*/
static tmErrorCode_t
TDA18211Write(struct dvb_frontend * tuner_card, UInt8 uSubAddress, UInt8 uNbData)
{
    tmErrorCode_t   err = TM_OK;
    struct tda18211_priv * priv = tuner_card->tuner_priv;
    UInt8*          pI2CMap;
    UInt8           WriteBuffer[TDA18211_NB_BYTES+1];

    /* force I2CMap */
    priv->I2CMap.uBx03.bF.Dis_Power_level = (UInt8)priv->Config_Instance.uPLMODE;

    /* pI2CMap & pWriteBuffer initialization */
    pI2CMap = &(priv->I2CMap.uBx00.ID_BYTE);

    WriteBuffer[0] = uSubAddress;

    memcpy(&WriteBuffer[1], &pI2CMap[uSubAddress], uNbData);

    err = tuner_i2c_xfer(tuner_card, WriteBuffer, uNbData + 1, False);

    return err;
}

/*============================================================================*/
/* FUNCTION:    TDA18211Read:                                                 */
/*                                                                            */
/* DESCRIPTION: Calculate i2c I2CMap & write in TDA18211.                     */
/*                                                                            */
/* RETURN:      TM_OK if no error                                             */
/*                                                                            */
/* NOTES:                                                                     */
/*============================================================================*/
static tmErrorCode_t
TDA18211Read(struct dvb_frontend * tuner_card, UInt8 uSubAddress, UInt8 uNbData)
{
    tmErrorCode_t   err = TM_OK;
    struct tda18211_priv * priv = tuner_card->tuner_priv;
    UInt8*          pI2CMap;
    UInt8           ReadBuffer[TDA18211_NB_BYTES];

    /* force I2CMap */
    priv->I2CMap.uBx03.bF.Dis_Power_level = (UInt8)priv->Config_Instance.uPLMODE;

    /* pI2CMap & pWriteBuffer initialization */
    pI2CMap = &(priv->I2CMap.uBx00.ID_BYTE);

    err = tuner_i2c_xfer(tuner_card, ReadBuffer, uNbData, True);

    if(err == TM_OK)
    {
        memcpy(&pI2CMap[uSubAddress], &(ReadBuffer[uSubAddress]), uNbData);
    }

    return err;
}

/*============================================================================*/
/* FUNCTION:    TDA18211Wait:                                                 */
/*                                                                            */
/* DESCRIPTION: This function waits for requested time.                       */
/*                                                                            */
/* RETURN:      TM_OK if no error                                             */
/*                                                                            */
/* NOTES:                                                                     */
/*============================================================================*/
static tmErrorCode_t
TDA18211Wait(struct dvb_frontend * tuner_card, UInt16 wTime)
{
    tuner_card = tuner_card;

    msleep(wTime);

    return TM_OK;
}

/*============================================================================*/
/* FUNCTION:    TDA18211SetPowerState:                                        */
/*                                                                            */
/* DESCRIPTION: Set the power state of this device.                           */
/*                                                                            */
/* RETURN:      TM_OK if no error                                             */
/*                                                                            */
/* NOTES:                                                                     */
/*============================================================================*/
static tmErrorCode_t
TDA18211SetPowerState (struct dvb_frontend * tuner_card, tmTDA18211PowerState_t  powerState)
{
    struct tda18211_priv * priv = tuner_card->tuner_priv;
    tmErrorCode_t   err  = TM_OK;

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

    switch (powerState)
    {
    case tmTDA18211_PowerNormalMode:
        /* set SM bits */
        priv->I2CMap.uBx05.bF.SM = 0x00;
        priv->I2CMap.uBx05.bF.SM_LT = 0x00;
        priv->I2CMap.uBx05.bF.SM_XT = 0x00;
        break;

    case tmTDA18211_PowerSleepMode:
        /* set SM bits */
        priv->I2CMap.uBx05.bF.SM = 0x01;
        priv->I2CMap.uBx05.bF.SM_LT = 0x01;
        priv->I2CMap.uBx05.bF.SM_XT = 0x01;
        break;

    case tmTDA18211_PowerStandbyWith16MHz:
        /* set SM bits */
        priv->I2CMap.uBx05.bF.SM = 0x01;
        priv->I2CMap.uBx05.bF.SM_LT = 0x01;
        priv->I2CMap.uBx05.bF.SM_XT = 0x00;
        break;

    case tmTDA18211_PowerStandbyWith16MHzAndLoopThrough:
        /* set SM bits */
        priv->I2CMap.uBx05.bF.SM = 0x01;
        priv->I2CMap.uBx05.bF.SM_LT = 0x00;
        priv->I2CMap.uBx05.bF.SM_XT = 0x00;
        break;

    case tmTDA18211_PowerStandbyWithLoopThrough:
        /* set SM bits */
        priv->I2CMap.uBx05.bF.SM = 0x01;
        priv->I2CMap.uBx05.bF.SM_LT = 0x00;
        priv->I2CMap.uBx05.bF.SM_XT = 0x01;
        break;

    default:
        /* power state not supported */
        return TM_ERR_NOT_SUPPORTED;
    }

    /* store power state */
    priv->curPowerState = powerState;

    /* set CAL_Mode to normal mode */
    priv->I2CMap.uBx06.bF.CAL_Mode = 0x00;
    err = TDA18211Write(tuner_card, 0x05, 2);
    if(err < 0) {
        dprintk("tda18211: TDA18211Write(0x05, 2) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    return err;
}

/*============================================================================*/
/* FUNCTION:    TDA18211Init:                                                 */
/*                                                                            */
/* DESCRIPTION: initialize TDA18211 Tuner                                     */
/*                                                                            */
/* RETURN:      TM_OK if no error                                             */
/*                                                                            */
/* NOTES:                                                                     */
/*============================================================================*/
static tmErrorCode_t
TDA18211Init (struct dvb_frontend * tuner_card)
{
    struct tda18211_priv * priv = tuner_card->tuner_priv;
    tmErrorCode_t err = TM_OK;

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

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

    /* Read ID Byte */
    err = TDA18211Read(tuner_card, 0x00, 16);
    if(err < 0) {
        dprintk("tda18211: TDA18211Read(0x00, 16) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    dprintk("tda18211: TDA18211Init\n");

    if(priv->I2CMap.uBx03.bF.IR_CAL_OK != 0)
    {
        dprintk("tda18211:  --> Already Initialized. Exit\n");
        return TM_OK;
    }
    else
    {
        // Reset parameters before initializing
        priv->curPowerState = tmTDA18211_PowerNotSupported;
        priv->Config_Instance.StandardMode = tmTDA18211_DVBT_8MHz;
        priv->Config_Instance.lastStandardMode = tmTDA18211_StdNotSupported;

        memcpy(&priv->Config_Instance.RF_BAND_Map, &RF_BAND_Map, sizeof(tmTDA18211_RF_BAND_Map_t)*TDA18211_RF_BAND_NB_ROWS);
    }

    dprintk("tda18211:  --> I2C Map Initialization\n");

    /*------------------------*/
    /* I2C map initialization */
    /*------------------------*/
    /* set & write all bytes */
    priv->I2CMap.uBx01.THERMO_BYTE = 0x08;
    priv->I2CMap.uBx02.POWER_LEVEL_BYTE = 0x80;
    priv->I2CMap.uBx03.EASY_PROG_BYTE_1 = 0xC6;
    priv->I2CMap.uBx04.EASY_PROG_BYTE_2 = 0xDF;
    priv->I2CMap.uBx05.EASY_PROG_BYTE_3 = 0x16;
    priv->I2CMap.uBx06.EASY_PROG_BYTE_4 = 0x60;
    priv->I2CMap.uBx07.EASY_PROG_BYTE_5 = 0x80;
    priv->I2CMap.uBx08.CAL_POST_DIV_BYTE = 0x80;
    priv->I2CMap.uBx09.CAL_DIV_BYTE_1 = 0x00;
    priv->I2CMap.uBx0A.CAL_DIV_BYTE_2 = 0x00;
    priv->I2CMap.uBx0B.CAL_DIV_BYTE_3 = 0x00;
    priv->I2CMap.uBx0C.MAIN_POST_DIV_BYTE = 0x00;
    priv->I2CMap.uBx0D.MAIN_DIV_BYTE_1 = 0x00;
    priv->I2CMap.uBx0E.MAIN_DIV_BYTE_2 = 0x00;
    priv->I2CMap.uBx0F.MAIN_DIV_BYTE_3 = 0x00;
    priv->I2CMap.uBx10.EXTENDED_BYTE_1 = 0xFC;
    priv->I2CMap.uBx11.EXTENDED_BYTE_2 = 0x01;
    priv->I2CMap.uBx12.EXTENDED_BYTE_3 = 0x84;
    priv->I2CMap.uBx13.EXTENDED_BYTE_4 = 0x41;
    priv->I2CMap.uBx14.EXTENDED_BYTE_5 = 0x01;
    priv->I2CMap.uBx15.EXTENDED_BYTE_6 = 0x84;
    priv->I2CMap.uBx16.EXTENDED_BYTE_7 = 0x40;
    priv->I2CMap.uBx17.EXTENDED_BYTE_8 = 0x07;
    priv->I2CMap.uBx18.EXTENDED_BYTE_9 = 0x00;
    priv->I2CMap.uBx19.EXTENDED_BYTE_10 = 0x00;
    priv->I2CMap.uBx1A.EXTENDED_BYTE_11 = 0x96;
    priv->I2CMap.uBx1B.EXTENDED_BYTE_12 = 0x3F;
    priv->I2CMap.uBx1C.EXTENDED_BYTE_13 = 0xC1;
    priv->I2CMap.uBx1D.EXTENDED_BYTE_14 = 0x00;
    priv->I2CMap.uBx1E.EXTENDED_BYTE_15 = 0x8F;
    priv->I2CMap.uBx1F.EXTENDED_BYTE_16 = 0x00;
    priv->I2CMap.uBx20.EXTENDED_BYTE_17 = 0x00;
    priv->I2CMap.uBx21.EXTENDED_BYTE_18 = 0x8C;
    priv->I2CMap.uBx22.EXTENDED_BYTE_19 = 0x00;
    priv->I2CMap.uBx23.EXTENDED_BYTE_20 = 0x20;
    priv->I2CMap.uBx24.EXTENDED_BYTE_21 = 0xB3;
    priv->I2CMap.uBx25.EXTENDED_BYTE_22 = 0x48;
    priv->I2CMap.uBx26.EXTENDED_BYTE_23 = 0xB0;

    err = TDA18211Write(tuner_card, 0x01, 38);
    if(err < 0) {
        dprintk("tda18211: TDA18211Write(0x01, 38) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /*-----------------*/
    /* AGC1 gain setup */
    /*-----------------*/
    /* AGC1_Gain_do */
    priv->I2CMap.uBx20.EXTENDED_BYTE_17 = 0x00;    /* set gain_do address */
    err = TDA18211Write(tuner_card, 0x20, 1);
    if(err < 0) {
        dprintk("tda18211: TDA18211Write(0x20, 1) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    priv->I2CMap.uBx20.EXTENDED_BYTE_17 = 0x03;    /* keep gain_do address, set gain_do */
    err = TDA18211Write(tuner_card, 0x20, 1);
    if(err < 0) {
        dprintk("tda18211: TDA18211Write(0x20, 1) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* AGC1_Gain_up */
    priv->I2CMap.uBx20.EXTENDED_BYTE_17 = 0x43;    /* set gain_up address, keep gain_do */
    err = TDA18211Write(tuner_card, 0x20, 1);
    if(err < 0) {
        dprintk("tda18211: TDA18211Write(0x20, 1) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    priv->I2CMap.uBx20.EXTENDED_BYTE_17 = 0x4C;    /* keep gain_up address, set gain_up */
    err = TDA18211Write(tuner_card, 0x20, 1);
    if(err < 0) {
        dprintk("tda18211: TDA18211Write(0x20, 1) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    dprintk("tda18211:  --> IR Calibration\n");
    dprintk("tda18211:      - IR Cal Low Band\n");

    /*----------------------------------------*/
    /* image rejection calibration - low band */
    /*----------------------------------------*/
    /* initialization */
    priv->I2CMap.uBx05.EASY_PROG_BYTE_3 = 0x1F;
    priv->I2CMap.uBx06.EASY_PROG_BYTE_4 = 0x66;
    priv->I2CMap.uBx07.EASY_PROG_BYTE_5 = 0x81;
    priv->I2CMap.uBx08.CAL_POST_DIV_BYTE = 0xCC;
    priv->I2CMap.uBx09.CAL_DIV_BYTE_1 = 0x6C;
    priv->I2CMap.uBx0A.CAL_DIV_BYTE_2 = 0x00;
    priv->I2CMap.uBx0B.CAL_DIV_BYTE_3 = 0x00;
    priv->I2CMap.uBx0C.MAIN_POST_DIV_BYTE = 0xC5;
    priv->I2CMap.uBx0D.MAIN_DIV_BYTE_1 = 0x77;
    priv->I2CMap.uBx0E.MAIN_DIV_BYTE_2 = 0x08;
    priv->I2CMap.uBx0F.MAIN_DIV_BYTE_3 = 0x00;
    err = TDA18211Write(tuner_card, 0x04, 12);
    if(err < 0) {
        dprintk("tda18211: TDA18211Write(0x04, 12) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* wait 5 ms for PLL locking */
    err = TDA18211Wait(tuner_card, 5);
    if(err < 0) {
        dprintk("tda18211: TDA18211Wait(5) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* launch detector */
    /* write byte EASY_PROG_BYTE_1*/
    err = TDA18211Write(tuner_card, 0x03, 1);
    if(err < 0) {
        dprintk("tda18211: TDA18211Write(0x03, 1) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* wait 5 ms for wanted measurement */
    err = TDA18211Wait(tuner_card, 5);
    if(err < 0) {
        dprintk("tda18211: TDA18211Wait(5) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

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

    /* write bytes EASY_PROG_BYTE_3 to CAL_DIV_BYTE_3 */
    err = TDA18211Write(tuner_card, 0x05, 7);
    if(err < 0) {
        dprintk("tda18211: TDA18211Write(0x05, 7) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* wait 5 ms for PLL locking */
    err = TDA18211Wait(tuner_card, 5);
    if(err < 0) {
        dprintk("tda18211: TDA18211Wait(5) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* launch optimization algorithm */
    /* write byte EASY_PROG_BYTE_2 */
    err = TDA18211Write(tuner_card, 0x04, 1);
    if(err < 0) {
        dprintk("tda18211: TDA18211Write(0x04, 1) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* wait 30 ms for image optimization completion */
    err = TDA18211Wait(tuner_card, 30);
    if(err < 0) {
        dprintk("tda18211: TDA18211Wait(30) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    dprintk("tda18211:      - IR Cal Mid Band\n");
    /*----------------------------------------*/
    /* image rejection calibration - mid band */
    /*----------------------------------------*/
    /* initialization */
    priv->I2CMap.uBx07.EASY_PROG_BYTE_5 = 0x82;
    priv->I2CMap.uBx08.CAL_POST_DIV_BYTE = 0xA8;
    priv->I2CMap.uBx0A.CAL_DIV_BYTE_2 = 0x00;
    priv->I2CMap.uBx0C.MAIN_POST_DIV_BYTE = 0xA1;
    priv->I2CMap.uBx0D.MAIN_DIV_BYTE_1 = 0x73;
    priv->I2CMap.uBx0E.MAIN_DIV_BYTE_2 = 0x1A;
    /* write bytes EASY_PROG_BYTE_3 to MAIN_DIV_BYTE_3 */
    err = TDA18211Write(tuner_card, 0x05, 11);
    if(err < 0) {
        dprintk("tda18211: TDA18211Write(0x05, 11) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* wait 5 ms for PLL locking */
    err = TDA18211Wait(tuner_card, 5);
    if(err < 0) {
        dprintk("tda18211: TDA18211Wait(5) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* launch detector */
    /* write byte EASY_PROG_BYTE_1 */
    err = TDA18211Write(tuner_card, 0x03, 1);
    if(err < 0) {
        dprintk("tda18211: TDA18211Write(0x03, 1) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* wait 5 ms for wanted measurement */
    err = TDA18211Wait(tuner_card, 5);
    if(err < 0) {
        dprintk("tda18211: TDA18211Wait(5) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

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

    /* write bytes EASY_PROG_BYTE_3 to CAL_DIV_BYTE_3 */
    err = TDA18211Write(tuner_card, 0x05, 7);
    if(err < 0) {
        dprintk("tda18211: TDA18211Write(0x05, 7) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* wait 5 ms for PLL locking */
    err = TDA18211Wait(tuner_card, 5);
    if(err < 0) {
        dprintk("tda18211: TDA18211Wait(5) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* launch optimization algorithm */
    /* write byte EASY_PROG_BYTE_2 */
    err = TDA18211Write(tuner_card, 0x04, 1);
    if(err < 0) {
        dprintk("tda18211: TDA18211Write(0x04, 1) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* wait 30 ms for image optimization completion */
    err = TDA18211Wait(tuner_card, 30);
    if(err < 0) {
        dprintk("tda18211: TDA18211Wait(30) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    dprintk("tda18211:      - IR Cal High Band.\n");
    /*-----------------------------------------*/
    /* image rejection calibration - high band */
    /*-----------------------------------------*/
    /* initialization */
    priv->I2CMap.uBx07.EASY_PROG_BYTE_5 = 0x83;
    priv->I2CMap.uBx08.CAL_POST_DIV_BYTE = 0x98;
    priv->I2CMap.uBx09.CAL_DIV_BYTE_1 = 0x65;
    priv->I2CMap.uBx0A.CAL_DIV_BYTE_2 = 0x00;
    priv->I2CMap.uBx0C.MAIN_POST_DIV_BYTE = 0x91;
    priv->I2CMap.uBx0D.MAIN_DIV_BYTE_1 = 0x71;
    priv->I2CMap.uBx0E.MAIN_DIV_BYTE_2 = 0xCD;
    /* write bytes EASY_PROG_BYTE_3 to CAL_DIV_BYTE_3 */
    err = TDA18211Write(tuner_card, 0x05, 11);
    if(err < 0) {
        dprintk("tda18211: TDA18211Write(0x05, 11) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* wait 5 ms for PLL locking */
    err = TDA18211Wait(tuner_card, 5);
    if(err < 0) {
        dprintk("tda18211: TDA18211Wait(5) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* launch detector */
    /* write byte EASY_PROG_BYTE_1 */
    err = TDA18211Write(tuner_card, 0x03, 1);
    if(err < 0) {
        dprintk("tda18211: TDA18211Write(0x03, 1) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* wait 5 ms for wanted measurement */
    err = TDA18211Wait(tuner_card, 5);
    if(err < 0) {
        dprintk("tda18211: TDA18211Wait(5) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

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

    /* write bytes EASY_PROG_BYTE_3 to CAL_DIV_BYTE_3 */
    err = TDA18211Write(tuner_card, 0x05, 7);
    if(err < 0) {
        dprintk("tda18211: TDA18211Write(0x05, 7) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* wait 5 ms for PLL locking */
    err = TDA18211Wait(tuner_card, 5);
    if(err < 0) {
        dprintk("tda18211: TDA18211Wait(5) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* launch optimization algorithm */
    /* write byte EASY_PROG_BYTE_2 */
    err = TDA18211Write(tuner_card, 0x04, 1);
    if(err < 0) {
        dprintk("tda18211: TDA18211Write(0x04, 1) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* wait 30 ms for image optimization completion */
    err = TDA18211Wait(tuner_card, 30);
    if(err < 0) {
        dprintk("tda18211: TDA18211Wait(30) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /*---------------------*/
    /* back to normal mode */
    /*---------------------*/
    priv->I2CMap.uBx06.EASY_PROG_BYTE_4 = 0x64;
    err = TDA18211Write(tuner_card, 0x06, 1);
    if(err < 0) {
        dprintk("tda18211: TDA18211Write(0x06, 1) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* synchronization */
    /* write byte EASY_PROG_BYTE_1 */
    err = TDA18211Write(tuner_card, 0x03, 1);
    if(err < 0) {
        dprintk("tda18211: TDA18211Write(0x03, 1) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    dprintk("tda18211:      - IR Calibration OK\n");

    /*---------------------------------*/
    /* RF tracking filters calibration */
    /*---------------------------------*/
    dprintk("tda18211:  --> RF Tracking Filters Calibration\n");

    err = TDA18211CalcRFFilterCurve(tuner_card);
    if(err < 0) {
        dprintk("tda18211: TDA18211CalcRFFilterCurve() failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    dprintk("tda18211:      - RF Tracking Filters Calibration OK\n");

    /*------------------*/
    /* back to POR mode */
    /*------------------*/
    /* power up detector 1 */
    priv->I2CMap.uBx1B.bF.PD_AGC1_Det = 0x00;
    /* write byte EXTENDED_BYTE_12 */
    err = TDA18211Write(tuner_card, 0x1B, 1);
    if(err < 0) {
        dprintk("tda18211: TDA18211Write(0x1B, 1) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* turn AGC1 loop on */
    priv->I2CMap.uBx21.bF.AGC1_loop_off = 0x00;
    /* set AGC1Gain = 6dB */
    priv->I2CMap.uBx21.bF.AGC1_Gain = 0x00;
    /* write byte EXTENDED_BYTE_18 */
    err = TDA18211Write(tuner_card, 0x21, 1);
    if(err < 0) {
        dprintk("tda18211: TDA18211Write(0x21, 1) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

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

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

    /* write bytes EXTENDED_BYTE_21 to EXTENDED_BYTE_23 */
    err = TDA18211Write(tuner_card, 0x24, 3);
    if(err < 0) {
        dprintk("tda18211: TDA18211Write(0x24, 3) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

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

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

    /* write byte EXTENDED_BYTE_1 */
    err = TDA18211Write(tuner_card, 0x10, 1);
    if(err < 0) {
        dprintk("tda18211: TDA18211Write(0x10, 1) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* switch to POR mode */
    err = TDA18211SetPowerState(tuner_card, tmTDA18211_PowerStandbyWith16MHzAndLoopThrough);
    if(err < 0) {
        dprintk("tda18211: TDA18211SetPowerState(tmTDA18211_PowerStandbyWith16MHzAndLoopThrough) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    return err;
}

/*============================================================================*/
/* FUNCTION:    TDA18211CalcMAINPLL:                                          */
/*                                                                            */
/* DESCRIPTION: Calculate the MAIN fractional PLL settings.                   */
/*                                                                            */
/* RETURN:      TM_OK                                                         */
/*                                                                            */
/* NOTES:       This function doesn't write in the tuner                      */
/*============================================================================*/
static tmErrorCode_t
TDA18211CalcMAINPLL (struct dvb_frontend * tuner_card, UInt32 uLO)
{
    struct tda18211_priv * priv = tuner_card->tuner_priv;
    UInt8   uCounter = 0;
    UInt32  uDiv = 0;

    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);
    priv->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;
    priv->I2CMap.uBx0D.bF.MAIN_Div_22_to_16 = (UInt8)(uDiv >> 16) & 0x7F;
    priv->I2CMap.uBx0E.bF.MAIN_Div_15_to_8 = (UInt8)(uDiv >> 8);
    priv->I2CMap.uBx0F.bF.MAIN_Div_7_to_0 = (UInt8)(uDiv);

    return TM_OK;
}


/*============================================================================*/
/* FUNCTION:    TDA18211CalcCALPLL:                                           */
/*                                                                            */
/* DESCRIPTION: Calculate the CAL fractional PLL settings.                    */
/*                                                                            */
/* RETURN:      TM_OK                                                         */
/*                                                                            */
/* NOTES:       This function doesn't write in the tuner                      */
/*============================================================================*/
static tmErrorCode_t
TDA18211CalcCALPLL (struct dvb_frontend * tuner_card, UInt32 uLO)
{
    struct tda18211_priv * priv = tuner_card->tuner_priv;
    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);
    priv->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;
    priv->I2CMap.uBx09.bF.CAL_Div_22_to_16 = (UInt8)(uDiv >> 16) & 0x7F;
    priv->I2CMap.uBx0A.bF.CAL_Div_15_to_8 = (UInt8)(uDiv >> 8);
    priv->I2CMap.uBx0B.bF.CAL_Div_7_to_0 = (UInt8)(uDiv);

    return TM_OK;
}

/*============================================================================*/
/* FUNCTION:    TDA18211PowerScanInit:                                        */
/*                                                                            */
/* DESCRIPTION: Initializes power scan.                                       */
/*                                                                            */
/* RETURN:      TM_OK if no error                                             */
/*                                                                            */
/* NOTES:       This function doesn't write in the tuner                      */
/*============================================================================*/
tmErrorCode_t
TDA18211PowerScanInit (struct dvb_frontend * tuner_card)
{
    struct tda18211_priv * priv = tuner_card->tuner_priv;
    tmErrorCode_t err = TM_OK;

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

    /* set standard mode to DVBT 1.5 MHz */
    priv->I2CMap.uBx05.bF.AGCK_Mode = 0x02;
    priv->I2CMap.uBx05.bF.AGC_Low_BW = 0x00;
    priv->I2CMap.uBx05.bF.LP_Fc = 0x02;

    priv->I2CMap.uBx06.bF.IF_Level = 0x00;
    priv->I2CMap.uBx06.bF.CAL_Mode = 0x00;

    err = TDA18211Write(tuner_card, 0x05, 2);
    if(err < 0) {
        dprintk("tda18211: TDA18211Write(0x05, 2) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* set AGC1Gain = 6dB */
    priv->I2CMap.uBx21.bF.AGC1_Gain = 0x00;
    err = TDA18211Write(tuner_card, 0x21, 1);
    if(err < 0) {
        dprintk("tda18211: TDA18211Write(0x21, 1) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* set AGC2Gain = -15dB */
    priv->I2CMap.uBx24.bF.AGC2_Gain = 0x00;
    /* set low pass filter to 1.5MHz */
    priv->I2CMap.uBx26.bF.ForceLP_Fc2_En = 0x01;
    priv->I2CMap.uBx26.bF.LP_Fc = 0x01;

    err = TDA18211Write(tuner_card, 0x24, 3);
    if(err < 0) {
        dprintk("tda18211: TDA18211Write(0x24, 3) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* return value */
    return err;
}

#define POWER_SCAN_FREQ_STEP 200000

/*============================================================================*/
/* FUNCTION:    TDA18211PowerScan:                                            */
/*                                                                            */
/* DESCRIPTION: Scan power and adjust RF Frequency.                           */
/*                                                                            */
/* RETURN:      TM_OK if no error                                             */
/*                                                                            */
/* NOTES:                                                                     */
/*============================================================================*/
tmErrorCode_t
TDA18211PowerScan (struct dvb_frontend * tuner_card, UInt32* puRF, Bool* pCal)
{
    struct tda18211_priv * priv = tuner_card->tuner_priv;
    tmErrorCode_t err = TM_OK;

    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 a power scan is requested */
    if (count_limit == 0)
    {
        /* enable calibration and exit */
        *pCal = True;
        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 > priv->Config_Instance.RF_BAND_Map[uCounter - 1].uRF_Max && uCounter < TDA18211_RF_BAND_NB_ROWS);
    priv->I2CMap.uBx04.bF.RF_Band = (UInt8)priv->Config_Instance.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);
    priv->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);
    priv->I2CMap.uBx04.bF.Gain_Taper = (UInt8)GAIN_TAPER_Map[uCounter - 1].uGain_Taper;

    /* write byte EASY_PROG_BYTE_2 */
    err = TDA18211Write(tuner_card, 0x04, 1);
    if(err < 0) {
        dprintk("tda18211: TDA18211Write(0x04, 1) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* write byte EXTENDED_BYTE_14 */
    err = TDA18211Write(tuner_card, 0x1D, 1);
    if(err < 0) {
        dprintk("tda18211: TDA18211Write(0x1D, 1) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* set freq_MAINPLL */
    freq_MAINPLL = freq_input + RF_CAL_IF_FREQ;

    /* calculate MAIN PLL */
    TDA18211CalcMAINPLL(tuner_card, freq_MAINPLL);
    if(err < 0) {
        dprintk("tda18211: TDA18211CalcMAINPLL() failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* write bytes 0x0C to 0x0F */
    err = TDA18211Write(tuner_card, 0x0C, 4);
    if(err < 0) {
        dprintk("tda18211: TDA18211Write(0x0C, 4) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* wait 5 ms for PLL locking */
    err = TDA18211Wait(tuner_card, 5);
    if(err < 0) {
        dprintk("tda18211: TDA18211Wait(5) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

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

    /* write byte EASY_PROG_BYTE_4 */
    err = TDA18211Write(tuner_card, 0x06, 1);
    if(err < 0) {
        dprintk("tda18211: TDA18211Write(0x06, 1) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* write byte EASY_PROG_BYTE_2 */
    err = TDA18211Write(tuner_card, 0x04, 1);
    if(err < 0) {
        dprintk("tda18211: TDA18211Write(0x04, 1) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* read power detector informations */
    err = TDA18211Read(tuner_card, 0x00, 39);
    if(err < 0) {
        dprintk("tda18211: TDA18211Read(0x00, 39) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* update CID_Gain */
    CID_Gain = priv->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 */
        err = TDA18211CalcMAINPLL(tuner_card, freq_MAINPLL);
        if(err < 0) {
            dprintk("tda18211: TDA18211CalcMAINPLL() failed.\n");
            return TMBSL_ERR_IIC_ERR;
        }

        /* write bytes 0x0C to 0x0F */
        err = TDA18211Write(tuner_card, 0x0C, 4);
        if(err < 0) {
            dprintk("tda18211: TDA18211Write(0x0C, 4) failed.\n");
            return TMBSL_ERR_IIC_ERR;
        }

        if (wait)
        {
            /* wait 5 ms for PLL locking */
            err = TDA18211Wait(tuner_card, 5);
            if(err < 0) {
                dprintk("tda18211: TDA18211Wait(5) failed.\n");
                return TMBSL_ERR_IIC_ERR;
            }

            /* reset wait flag */
            wait = False;
        }
        else
        {
            /* wait 100 µs for PLL locking */
        }

        /* write byte EASY_PROG_BYTE_2 */
        err = TDA18211Write(tuner_card, 0x04, 1);
        if(err < 0) {
            dprintk("tda18211: TDA18211Write(0x04, 1) failed.\n");
            return TMBSL_ERR_IIC_ERR;
        }

        /* read power detector informations */
        err = TDA18211Read(tuner_card, 0x00, 39);
        if(err < 0) {
            dprintk("tda18211: TDA18211Read(0x00, 39) failed.\n");
            return TMBSL_ERR_IIC_ERR;
        }

        /* update CID_Gain */
        CID_Gain = priv->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 err;
}

/*============================================================================*/
/* FUNCTION:    TDA18211CalibrateRF:                                          */
/*                                                                            */
/* DESCRIPTION: RF tracking filter calibration.                               */
/*                                                                            */
/* RETURN:      TM_OK if no error                                             */
/*                                                                            */
/* NOTES:                                                                     */
/*============================================================================*/
static tmErrorCode_t
TDA18211CalibrateRF (struct dvb_frontend * tuner_card, UInt32 uRF, UInt8* puCprog)
{
    struct tda18211_priv * priv = tuner_card->tuner_priv;
    tmErrorCode_t err = TM_OK;
    UInt32 uCounter = 0;

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

    /*----------------*/
    /* initialization */
    /*----------------*/
    /* set CAL_Mode to normal mode */
    priv->I2CMap.uBx06.bF.CAL_Mode = 0x00;
    err = TDA18211Write(tuner_card, 0x06, 1);
    if(err < 0) {
        dprintk("tda18211: TDA18211Write(0x06, 1) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* set AGC1Gain = 15dB */
    priv->I2CMap.uBx21.bF.AGC1_Gain = 0x03;
    err = TDA18211Write(tuner_card, 0x21, 1);
    if(err < 0) {
        dprintk("tda18211: TDA18211Write(0x21, 1) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* switch off AGC1 */
    priv->I2CMap.uBx05.bF.SM_LT = 0x01;

    /*---------------------------------------*/
    /* frequency dependent parameters update */
    /*---------------------------------------*/
    /* 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);
    priv->I2CMap.uBx03.bF.BP_Filter = (UInt8)BP_FILTER_Map[uCounter - 1].uBP_Filter;

    /* 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);
    priv->I2CMap.uBx04.bF.Gain_Taper = (UInt8)GAIN_TAPER_Map[uCounter - 1].uGain_Taper;

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

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

    /* write bytes EASY_PROG_BYTE_1 to EASY_PROG_BYTE_3 */
    err = TDA18211Write(tuner_card, 0x03, 3);
    if(err < 0) {
        dprintk("tda18211: TDA18211Write(0x03, 3) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* write byte EXTENDED_BYTE_13 */
    err = TDA18211Write(tuner_card, 0x1C, 1);
    if(err < 0) {
        dprintk("tda18211: TDA18211Write(0x1C, 1) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* MAIN PLL charge pump source */
    priv->I2CMap.uBx13.bF.LO_ForceSrce = 0x01;
    err = TDA18211Write(tuner_card, 0x13, 1);
    if(err < 0) {
        dprintk("tda18211: TDA18211Write(0x13, 1) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* CAL PLL charge pump source */
    priv->I2CMap.uBx16.bF.CAL_ForceSrce = 0x01;
    err = TDA18211Write(tuner_card, 0x16, 1);
    if(err < 0) {
        dprintk("tda18211: TDA18211Write(0x16, 1) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* force DCDC converter to 0V */
    priv->I2CMap.uBx1D.RFC_Cprog = 0x00;
    err = TDA18211Write(tuner_card, 0x1D, 1);
    if(err < 0) {
        dprintk("tda18211: TDA18211Write(0x1D, 1) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* disable PLLs lock */
    priv->I2CMap.uBx23.bF.Force_Lock = 0x00;
    err = TDA18211Write(tuner_card, 0x23, 1);
    if(err < 0) {
        dprintk("tda18211: TDA18211Write(0x23, 1) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

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

    /* write bytes EASY_PROG_BYTE_4 & EASY_PROG_BYTE_5 */
    err = TDA18211Write(tuner_card, 0x06, 2);
    if(err < 0) {
        dprintk("tda18211: TDA18211Write(0x06, 2) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /*----------------------------------*/
    /* set internal calibration signals */
    /*----------------------------------*/
    /* calculate CAL PLL */
    /* CAL LO Frequency = channel center frequency */
    err = TDA18211CalcCALPLL(tuner_card, uRF);
    if(err < 0) {
        dprintk("tda18211: TDA18211CalcCALPLL() failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* calculate MAIN PLL */
    /* MAIN LO Frequency = channel center frequency + 1MHz */
    err = TDA18211CalcMAINPLL(tuner_card, uRF + RF_CAL_IF_FREQ);
    if(err < 0) {
        dprintk("tda18211: TDA18211CalcMAINPLL() failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* write bytes 0x05 to 0x0F */
    err = TDA18211Write(tuner_card, 0x05, 11);
    if(err < 0) {
        dprintk("tda18211: TDA18211Write(0x05, 2) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* wait 5 ms for RF tracking filter calibration initialization */
    err = TDA18211Wait(tuner_card, 5);
    if(err < 0) {
        dprintk("tda18211: TDA18211Wait(5) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /*--------------------------*/
    /* internal synchronization */
    /*--------------------------*/
    /* write byte EASY_PROG_BYTE_2 */
    err = TDA18211Write(tuner_card, 0x04, 1);
    if(err < 0) {
        dprintk("tda18211: TDA18211Write(0x04, 1) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* write byte EASY_PROG_BYTE_1 */
    err = TDA18211Write(tuner_card, 0x03, 1);
    if(err < 0) {
        dprintk("tda18211: TDA18211Write(0x03, 1) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* write byte EASY_PROG_BYTE_2 */
    err = TDA18211Write(tuner_card, 0x04, 1);
    if(err < 0) {
        dprintk("tda18211: TDA18211Write(0x04, 1) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* write byte EASY_PROG_BYTE_1 */
    err = TDA18211Write(tuner_card, 0x03, 1);
    if(err < 0) {
        dprintk("tda18211: TDA18211Write(0x03, 1) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /*-----------------------*/
    /* RF calibration launch */
    /*-----------------------*/
    /* MAIN PLL charge pump source */
    priv->I2CMap.uBx13.bF.LO_ForceSrce = 0x00;
    /* write byte EXTENDED_BYTE_4 */
    err = TDA18211Write(tuner_card, 0x13, 1);
    if(err < 0) {
        dprintk("tda18211: TDA18211Write(0x13, 1) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* CAL PLL charge pump source */
    priv->I2CMap.uBx16.bF.CAL_ForceSrce = 0x00;
    /* write byte EXTENDED_BYTE_7 */
    err = TDA18211Write(tuner_card, 0x16, 1);
    if(err < 0) {
        dprintk("tda18211: TDA18211Write(0x16, 1) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* wait 10 ms for PLL locking */
    err = TDA18211Wait(tuner_card, 10);
    if(err < 0) {
        dprintk("tda18211: TDA18211Wait(10) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* launch the RF tracking filters calibration */
    priv->I2CMap.uBx23.bF.Force_Lock = 0x01;
    /* write byte EXTENDED_BYTE_20 */
    err = TDA18211Write(tuner_card, 0x23, 1);
    if(err < 0) {
        dprintk("tda18211: TDA18211Write(0x23, 1) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* wait 60 ms for calibration */
    err = TDA18211Wait(tuner_card, 60);
    if(err < 0) {
        dprintk("tda18211: TDA18211Wait(60) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* normal mode */
    priv->I2CMap.uBx06.bF.CAL_Mode = 0x00;

    /* set AGC1Gain = 6dB */
    priv->I2CMap.uBx21.bF.AGC1_Gain = 0x00;
    err = TDA18211Write(tuner_card ,0x21, 1);
    if(err < 0) {
        dprintk("tda18211: TDA18211Write(0x21, 1) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* switch on AGC1 */
    priv->I2CMap.uBx05.bF.SM_LT = 0x00;

    /* write bytes EASY_PROG_BYTE_3 & EASY_PROG_BYTE_4 */
    err = TDA18211Write(tuner_card, 0x05, 2);
    if(err < 0) {
        dprintk("tda18211: TDA18211Write(0x05, 2) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* write byte EASY_PROG_BYTE_1 */
    err = TDA18211Write(tuner_card, 0x03, 1);
    if(err < 0) {
        dprintk("tda18211: TDA18211Write(0x03, 1) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* read bytes 0x00 to 0x26 */
    err = TDA18211Read(tuner_card, 0x00, 39);
    if(err < 0) {
        dprintk("tda18211: TDA18211Read(0x00, 39) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

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

    return err;
}

/*============================================================================*/
/* FUNCTION:    TDA18211RFTrackingFiltersInit:                                */
/*                                                                            */
/* DESCRIPTION: Initialize RF Filter calibration.                             */
/*                                                                            */
/* RETURN:      TMBSL_ERR_IIC_ERR                                             */
/*              TM_OK                                                         */
/*                                                                            */
/* NOTES:                                                                     */
/*============================================================================*/
static tmErrorCode_t
TDA18211RFTrackingFiltersInit (struct dvb_frontend * tuner_card, ptmTDA18211_RF_BAND_Map_t pRF_BAND_Map)
{
    tmErrorCode_t               err = 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;

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

    /*-------------------------------------------------*/
    /* RF tracking filter calibration at RF1 frequency */
    /*-------------------------------------------------*/
    /* test uRF1_default value */
    if (pRF_BAND_Map->uRF1_default == 0)
        return err;

    /* look for optimized calibration frequency */
    pRF_BAND_Map->uRF1 = pRF_BAND_Map->uRF1_default;
    err = TDA18211PowerScan(tuner_card, &pRF_BAND_Map->uRF1, &bCal);
    if(err < 0) {
        dprintk("tda18211: TDA18211PowerScan(uRF1) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* 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 */
        err = TDA18211CalibrateRF(tuner_card, pRF_BAND_Map->uRF1, &uCprog_cal_1);
        if(err < 0) {
            dprintk("tda18211: TDA18211CalibrateRF(uRF1) failed.\n");
            return TMBSL_ERR_IIC_ERR;
        }
    }
    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)
        return err;

    /* look for optimized calibration frequency */
    pRF_BAND_Map->uRF2 = pRF_BAND_Map->uRF2_default;
    err = TDA18211PowerScan(tuner_card, &pRF_BAND_Map->uRF2, &bCal);
    if(err < 0) {
        dprintk("tda18211: TDA18211PowerScan(uRF2) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* 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 */
        err = TDA18211CalibrateRF(tuner_card, pRF_BAND_Map->uRF2, &uCprog_cal_2);
        if(err < 0) {
            dprintk("tda18211: TDA18211CalibrateRF(uRF2) failed.\n");
            return TMBSL_ERR_IIC_ERR;
        }
    }
    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)
        return err;

    /* look for optimized calibration frequency */
    pRF_BAND_Map->uRF3 = pRF_BAND_Map->uRF3_default;
    err = TDA18211PowerScan(tuner_card, &pRF_BAND_Map->uRF3, &bCal);
    if(err < 0) {
        dprintk("tda18211: TDA18211PowerScan(uRF3) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* 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 */
        err = TDA18211CalibrateRF(tuner_card, pRF_BAND_Map->uRF3, &uCprog_cal_3);
        if(err < 0) {
            dprintk("tda18211: TDA18211CalibrateRF(uRF3) failed.\n");
            return TMBSL_ERR_IIC_ERR;
        }
    }
    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 err;
}


/*============================================================================*/
/* FUNCTION:    TDA18211CalcRFFilterCurve:                                    */
/*                                                                            */
/* DESCRIPTION: Calculate RF Filter curve coefficients.                       */
/*                                                                            */
/* RETURN:      TMBSL_ERR_IIC_ERR                                             */
/*              TM_OK                                                         */
/*                                                                            */
/* NOTES:                                                                     */
/*============================================================================*/
static tmErrorCode_t
TDA18211CalcRFFilterCurve (struct dvb_frontend * tuner_card)
{
    struct tda18211_priv *  priv = tuner_card->tuner_priv;
    tmErrorCode_t           err = TM_OK;

    UInt32 uCounter = 0;

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

    /* wait 200 ms for die temperature stabilization */
    err = TDA18211Wait(tuner_card, 200);
    if(err < 0) {
        dprintk("tda18211: TDA18211Wait(200) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* power scan initialization */
    err = TDA18211PowerScanInit(tuner_card);
    if(err < 0) {
        dprintk("tda18211: TDA18211PowerScanInit() failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* calculate RF filter curve */
    for (uCounter = 0; uCounter < TDA18211_RF_BAND_NB_ROWS; uCounter++)
    {
       dprintk("tda18211:      - RF Tracking Filters Band %d\n", uCounter);

        if (priv->Config_Instance.RF_BAND_Map[uCounter].uRF1_default != 0)
        {
            err = TDA18211RFTrackingFiltersInit(tuner_card, &(priv->Config_Instance.RF_BAND_Map[uCounter]));
            if(err < 0) {
                dprintk("tda18211: TDA18211RFTrackingFiltersInit(%d) failed.\n", uCounter);
                return TMBSL_ERR_IIC_ERR;
            }
        }
    }

    /* sense temperature */
    err = TDA18211ThermometerRead(tuner_card, &(priv->Config_Instance.uTMVALUE_RFCAL));
    if(err < 0) {
        dprintk("tda18211: TDA18211ThermometerRead() failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    return err;
}

/*============================================================================*/
/* FUNCTION:    TDA18211ThermometerRead:                                      */
/*                                                                            */
/* DESCRIPTION: Read die temperature.                                         */
/*                                                                            */
/* RETURN:      TMBSL_ERR_IIC_ERR                                             */
/*              TM_OK                                                         */
/*                                                                            */
/* NOTES:                                                                     */
/*============================================================================*/
static tmErrorCode_t
TDA18211ThermometerRead (struct dvb_frontend * tuner_card, UInt8 * puValue)
{
    struct tda18211_priv * priv = tuner_card->tuner_priv;
    tmErrorCode_t err = TM_OK;
    UInt8 uCounter = 0;

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

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

    /* write byte THERMO_BYTE */
    err = TDA18211Write(tuner_card, 0x01, 1);
    if(err < 0) {
        dprintk("tda18211: TDA18211Write(0x01, 1) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    /* read byte THERMO_BYTE */
    err = TDA18211Read(tuner_card, 0x00, 16);
    if(err < 0) {
        dprintk("tda18211: TDA18211Read(0x00, 16) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

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

     /* write byte THERMO_BYTE */
     err = TDA18211Write(tuner_card,0x01, 1);
     if(err < 0) {
         dprintk("tda18211: TDA18211Write(0x01, 1) failed.\n");
         return TMBSL_ERR_IIC_ERR;
     }

     /* read byte THERMO_BYTE */
     err = TDA18211Read(tuner_card, 0x00, 16);
     if(err < 0) {
         dprintk("tda18211: TDA18211Read(0x00, 16) failed.\n");
         return TMBSL_ERR_IIC_ERR;
     }
    }

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

    /* get TMVALUE value */
    if (priv->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 */
    priv->I2CMap.uBx01.bF.TM_ON = 0x00;

    /* write byte THERMO_BYTE */
    err = TDA18211Write(tuner_card, 0x01, 1);
    if(err < 0) {
        dprintk("tda18211: TDA18211Write(0x01, 1) failed.\n");
        return TMBSL_ERR_IIC_ERR;
    }

    return TM_OK;
}

/*============================================================================*/
/* FUNCTION:    TDA18211SetStandardMode:                                      */
/*                                                                            */
/* DESCRIPTION: Set the standard mode of this device.                         */
/*                                                                            */
/* RETURN:      TM_OK if no error                                            */
/*                                                                            */
/* NOTES:                                                                     */
/*============================================================================*/
static tmErrorCode_t
TDA18211SetStandardMode (struct dvb_frontend * tuner_card, tmTDA18211StandardMode_t StandardMode)
{
    struct tda18211_priv * priv = tuner_card->tuner_priv;

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

    if(StandardMode>=tmTDA18211_StdNotSupported)
    {
        /* standard mode not supported */
        dprintk("tda18211: Standard not supported.\n");
       return TM_ERR_NOT_SUPPORTED;
    }

    priv->Config_Instance.uIF = Std_Array[StandardMode].uIF;

    /* set AGCK_Mode */
    priv->I2CMap.uBx05.bF.AGCK_Mode = Std_Array[StandardMode].uAGCK_Mode;
    priv->I2CMap.uBx05.bF.AGC_Low_BW = 0x01;

    /* Set LPFc */
    priv->I2CMap.uBx05.bF.LP_Fc = Std_Array[StandardMode].uLPFc;

    /* set CAL_RFn bit */
    priv->I2CMap.uBx06.bF.CAL_RFn = Std_Array[StandardMode].uCAL_RFn;

    /* set IF_Level */
    priv->I2CMap.uBx06.bF.IF_Level = Std_Array[StandardMode].uIF_Level;

    /* set IF_notch */
    priv->I2CMap.uBx0C.bF.IF_notch = Std_Array[StandardMode].uIF_Notch;

    /* set RFAGC_Top & IFAGC_Top */
    priv->I2CMap.uBx25.EXTENDED_BYTE_22 = Std_Array[StandardMode].uRF_IF_AGC_Top;

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

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

    return TM_OK;
}

/*============================================================================*/
/* FUNCTION:    TDA18211SetRf:                                                */
/*                                                                            */
/* DESCRIPTION: Calculate i2c I2CMap & write in TDA18211.                     */
/*                                                                            */
/* RETURN:      TM_OK if no error                                             */
/*                                                                            */
/* NOTES:                                                                     */
/*============================================================================*/
static tmErrorCode_t
TDA18211SetRf(struct dvb_frontend * tuner_card, UInt32 uRF)
{
    struct tda18211_priv * priv = tuner_card->tuner_priv;
    tmErrorCode_t       err  = TM_OK;

    UInt32              uCounter = 0;
    UInt8               uTMVALUE_CURRENT = 0;
    UInt8               utmpRFAGC = 0;
    UInt8               uCprog_table = 0;
    Int32               uCapprox = 0;
    Int32               uCprog_signed = 0;

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

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

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

    if (err == TM_OK)
    {
        /* Power up if required */
        if (priv->curPowerState != tmTDA18211_PowerNormalMode)
        {
            err = TDA18211SetPowerState(tuner_card, tmTDA18211_PowerNormalMode);

            if(err < 0) {
                dprintk("tda18211: TDA18211SetPowerState(tmTDA18211_PowerNormalMode) failed.\n");
                return TMBSL_ERR_IIC_ERR;
            }
        }
    }

    if (err == TM_OK)
    {
        /*-------------------------------*/
        /* RF tracking filter correction */
        /*-------------------------------*/
        /* sense temperature */
        err = TDA18211ThermometerRead(tuner_card, &uTMVALUE_CURRENT);
        if(err < 0) {
            dprintk("tda18211: TDA18211ThermometerRead() failed.\n");
            return TMBSL_ERR_IIC_ERR;
        }
    }

    if (err == TM_OK)
    {
        /*---------------------------------------*/
        /* 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 > priv->Config_Instance.RF_BAND_Map[uCounter - 1].uRF_Max && uCounter < TDA18211_RF_BAND_NB_ROWS);

        /* calculate Capprox */
        if (priv->Config_Instance.RF_BAND_Map[uCounter - 1].uRF1 == 0)
        {
            /* Capprox = uCprog_table */
            uCapprox = (Int32)uCprog_table;
        }
        else if ((priv->Config_Instance.RF_BAND_Map[uCounter - 1].uRF3 != 0) && (uRF >= priv->Config_Instance.RF_BAND_Map[uCounter - 1].uRF2))
        {
            /* Capprox = A2 * (uRF - uRF2) + B2 + uCprog_table */
            uCapprox = (Int32)(((priv->Config_Instance.RF_BAND_Map[uCounter - 1].uRF_A2 * ((Int32)(uRF - priv->Config_Instance.RF_BAND_Map[uCounter - 1].uRF2) / 1000000)) / 1000000)
                + priv->Config_Instance.RF_BAND_Map[uCounter - 1].uRF_B2 + uCprog_table);
        }
        else
        {
            /* Capprox = A1 * (uRF - uRF1) + B1 + uCprog_table */
            uCapprox = (Int32)(((priv->Config_Instance.RF_BAND_Map[uCounter - 1].uRF_A1 * ((Int32)(uRF - priv->Config_Instance.RF_BAND_Map[uCounter - 1].uRF1) / 1000000)) / 1000000)
                + priv->Config_Instance.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;
        priv->I2CMap.uBx1D.RFC_Cprog = (UInt8)uCprog_signed;
        err = TDA18211Write(tuner_card, 0x1D, 1);
        if(err < 0) {
            dprintk("tda18211: TDA18211Write(0x1D, 1) failed.\n");
            return TMBSL_ERR_IIC_ERR;
        }
    }

    /*----------------------*/
    /* standard mode update */
    /*----------------------*/
    /* update TV broadcast parameters */

    if(priv->Config_Instance.lastStandardMode != priv->Config_Instance.StandardMode)
    {
        if (err == TM_OK)
        {
            err = TDA18211SetStandardMode(tuner_card, priv->Config_Instance.StandardMode);
            if(err < 0) {
                dprintk("tda18211: TDA18211SetStandardMode(%d) failed.\n", priv->Config_Instance.StandardMode);
                return TMBSL_ERR_IIC_ERR;
            }
        }

        if (err == TM_OK)
        {
            /* write bytes EXTENDED_BYTE_22 */
            err = TDA18211Write(tuner_card, 0x22, 1);
            if(err < 0) {
                dprintk("tda18211: TDA18211Write(0x22, 1) failed.\n");
                return TMBSL_ERR_IIC_ERR;
            }

            priv->Config_Instance.lastStandardMode = priv->Config_Instance.StandardMode;
        }
    }

    if (err == TM_OK)
    {
        /* switch RFAGC to high speed mode (store current value) */
        utmpRFAGC = priv->I2CMap.uBx05.bF.AGC_Low_BW;
        priv->I2CMap.uBx05.bF.AGC_Low_BW = 0x00;
        err = TDA18211Write(tuner_card, 0x05, 1);
        if(err < 0) {
            dprintk("tda18211: TDA18211Write(0x05, 1) failed.\n");
            return TMBSL_ERR_IIC_ERR;
        }
    }

    if (err == TM_OK)
    {
        /* write bytes EXTENDED_BYTE_21 to EXTENDED_BYTE_23 */
        err = TDA18211Write(tuner_card, 0x24, 3);
        if(err < 0) {
            dprintk("tda18211: TDA18211Write(0x24, 3) failed.\n");
            return TMBSL_ERR_IIC_ERR;
        }
    }

    if (err == TM_OK)
    {
        /*---------------------------------------*/
        /* update frequency dependent parameters */
        /*---------------------------------------*/
        /* search for IR_Meas corresponding to wanted frequency */
        uCounter = 0;
        do uCounter ++;
        while (uRF > IR_MEAS_Map[uCounter - 1].uRF_Max && uCounter < TDA18211_IR_MEAS_NB_ROWS);
        priv->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);
        priv->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);
        priv->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);
        priv->I2CMap.uBx04.bF.Gain_Taper = (UInt8)GAIN_TAPER_Map[uCounter - 1].uGain_Taper;
    }

    if (err == TM_OK)
    {
        /*----------------------------------*/
        /* tune to wanted channel frequency */
        /*----------------------------------*/
        /* use MAIN VCO when master, CAL VCO when slave */
        if (priv->Config_Instance.Master) /* master */
        {
            /* calculate MAIN PLL */
            err = TDA18211CalcMAINPLL(tuner_card, uRF + priv->Config_Instance.uIF);
            if(err < 0) {
                dprintk("tda18211: TDA18211CalcMAINPLL() failed.\n");
                return TMBSL_ERR_IIC_ERR;
            }

            /* write bytes 0x01 to 0x0F */
            err = TDA18211Write(tuner_card, 0x01, 15);
            if(err < 0) {
                dprintk("tda18211: TDA18211Write(0x01, 15) failed.\n");
                return TMBSL_ERR_IIC_ERR;
            }

            /* MAIN PLL charge pump source */
            priv->I2CMap.uBx13.bF.LO_ForceSrce = 0x01;
            err = TDA18211Write(tuner_card, 0x13, 1);
            if(err < 0) {
                dprintk("tda18211: TDA18211Write(0x13, 1) failed.\n");
                return TMBSL_ERR_IIC_ERR;
            }

            /* wait 1 ms for charge pump source */
            err = TDA18211Wait(tuner_card, 1);
            if(err < 0) {
                dprintk("tda18211: TDA18211Wait(1) failed.\n");
                return TMBSL_ERR_IIC_ERR;
            }

            /* MAIN PLL normal operation */
            priv->I2CMap.uBx13.bF.LO_ForceSrce = 0x00;
            err = TDA18211Write(tuner_card, 0x13, 1);
            if(err < 0) {
                dprintk("tda18211: TDA18211Write(0x13, 1) failed.\n");
                return TMBSL_ERR_IIC_ERR;
            }
        }
        else /* slave */
        {
            /* calculate CAL PLL */
            err = TDA18211CalcCALPLL(tuner_card, uRF + priv->Config_Instance.uIF);
            if(err < 0) {
                dprintk("tda18211: TDA18211CalcCALPLL() failed.\n");
                return TMBSL_ERR_IIC_ERR;
            }

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

            /* write bytes 0x01 to 0x0F */
            err = TDA18211Write(tuner_card, 0x01, 15);
            if(err < 0) {
                dprintk("tda18211: TDA18211Write(0x1, 15) failed.\n");
                return TMBSL_ERR_IIC_ERR;
            }

            /* CAL PLL charge pump source */
            priv->I2CMap.uBx16.bF.CAL_ForceSrce = 0x01;
            err = TDA18211Write(tuner_card, 0x16, 1);
            if(err < 0) {
                dprintk("tda18211: TDA18211Write(0x16, 1) failed.\n");
                return TMBSL_ERR_IIC_ERR;
            }

            /* wait 1 ms for charge pump source */
            err = TDA18211Wait(tuner_card, 1);
            if(err < 0) {
                dprintk("tda18211: TDA18211Wait(1) failed.\n");
                return TMBSL_ERR_IIC_ERR;
            }

            /* CAL PLL normal operation */
            priv->I2CMap.uBx16.bF.CAL_ForceSrce = 0x00;
            err = TDA18211Write(tuner_card, 0x16, 1);
            if(err < 0) {
                dprintk("tda18211: TDA18211Write(0x16, 1) failed.\n");
                return TMBSL_ERR_IIC_ERR;
            }
        }
    }

    if (err == TM_OK)
    {
        /* wait 20 ms for PLL locking */
        err = TDA18211Wait(tuner_card, 20);
        if(err < 0) {
            dprintk("tda18211: TDA18211Wait(20) failed.\n");
            return TMBSL_ERR_IIC_ERR;
        }

        /* switch RFAGC to normal mode (restore previous value) */
        priv->I2CMap.uBx05.bF.AGC_Low_BW = utmpRFAGC;

        /* write byte EASY_PROG_BYTE_3 */
        err = TDA18211Write(tuner_card, 0x05, 1);
        if(err < 0) {
            dprintk("tda18211: TDA18211Write(0x05, 1) failed.\n");
            return TMBSL_ERR_IIC_ERR;
        }
    }

    if (err == TM_OK)
    {
        /* read bytes 0x00 to 0x26 */
        err = TDA18211Read(tuner_card, 0x00, 39);
        if(err < 0) {
            dprintk("tda18211: TDA18211Read(0x00, 39) failed.\n");
            return TMBSL_ERR_IIC_ERR;
        }
    }

    return err;
}

/**
* Driver init
* @param fe frontend
* @return 0:success
*/
int
tda18211_init(struct dvb_frontend* fe)
{
    tmErrorCode_t err = TM_OK;

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

    if (fe->ops.i2c_gate_ctrl)
        fe->ops.i2c_gate_ctrl(fe, 1);

    err = TDA18211Init(fe);

    if (fe->ops.i2c_gate_ctrl)
        fe->ops.i2c_gate_ctrl(fe, 0);

    return err;
}

/**
* Driver sleep
* @param fe frontend
* @return 0:success
*/
int
tda18211_sleep(struct dvb_frontend* fe)
{
    struct tda18211_priv *priv = fe->tuner_priv;
    tmErrorCode_t err = TM_OK;

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

    if (fe->ops.i2c_gate_ctrl)
        fe->ops.i2c_gate_ctrl(fe, 1);

    err = TDA18211SetPowerState(fe, (priv->Config_Instance.Master != 0)?tmTDA18211_PowerStandbyWith16MHzAndLoopThrough : tmTDA18211_PowerStandbyWith16MHz);

    if (fe->ops.i2c_gate_ctrl)
        fe->ops.i2c_gate_ctrl(fe, 0);

    return err;
}
/**
 * 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;
    tmTDA18211StandardMode_t op_standard;
    tmErrorCode_t err = TM_OK;
    int bw = 0;

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

    /* 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 = tmTDA18211_DVBT_6MHz;
                        bw = 6000000;
                        break;
                    case BANDWIDTH_7_MHZ:
                        op_standard = tmTDA18211_DVBT_7MHz;
                        bw = 7000000;
                        break;
                    case BANDWIDTH_8_MHZ:
                        op_standard = tmTDA18211_DVBT_8MHz;
                        bw = 8000000;
                        break;
                    default:
                         dprintk("%s: invalid OFDM setting\n", __FUNCTION__);
                         return -EINVAL;
                    }
            break;
        case FE_ATSC:
            op_standard = tmTDA18211_ATSC_6MHz;
            bw = 6000000;
            break;

        case FE_QPSK:
        case FE_QAM:
        default:
             dprintk("%s: invalid fe type\n", __FUNCTION__);
            return -EINVAL;
    }

    if (fe->ops.i2c_gate_ctrl)
        fe->ops.i2c_gate_ctrl(fe, 1);

    /* Initialize */
    err = TDA18211Init(fe);

    if(err == TM_OK)
    {
        /* Set standard */
        err = TDA18211SetStandardMode(fe, op_standard);

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

    if(err == TM_OK)
    {
        /* Tune to frequency */
        err = TDA18211SetRf(fe, params->frequency); /* freq supplied is in Hz */
    }

    if (fe->ops.i2c_gate_ctrl)
        fe->ops.i2c_gate_ctrl(fe, 0);

    /* Save settings */
    priv->frequency = params->frequency;
    priv->bandwidth = bw;

    dprintk("%s(%d): Pll lock:%c IR cal:%c\n", __FUNCTION__, __LINE__, (priv->I2CMap.uBx01.bF.MAIN_Lock) ? 'y' : 'n', (priv->I2CMap.uBx03.bF.IR_CAL_OK )? 'y' : 'n');

    return err;
}

/**
 * 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;

    /* Check parameters */
    if (priv == NULL)
    {
        dprintk("%s: fe->priv NULL\n", __FUNCTION__);
        return -EINVAL;
    }

    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;

    /* Check parameters */
    if (priv == NULL)
    {
        dprintk("%s: fe->priv NULL\n", __FUNCTION__);
        return -EINVAL;
    }

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

    *bandwidth = priv->bandwidth;

    return 0;
}

/**
 * Standard tuner operations
 */

static struct dvb_tuner_ops tda18211_tuner_ops = {
    {
        "NXP TDA18211HD/C2", /* name */
        174000000,   /* frequency_min */
        864000000,   /* frequency_max */
        8000000,     /* frequency_step */
        0,  /* bandwidth_min */
        0,  /* bandwidth_max */
        0,  /* bandwidth_step */
    },
    tda18211_release, /* int (*release)(struct dvb_frontend *fe); */
    tda18211_init, /* int (*init)(struct dvb_frontend *fe); */
    tda18211_sleep, /* int (*sleep)(struct dvb_frontend *fe); */
    tda18211_set_params, /* int (*set_params)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p); */
    NULL, /* int (*set_analog_params)(struct dvb_frontend *fe, struct analog_parameters *p); */
    NULL, /* int (*calc_regs)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p, u8 *buf, int buf_len); */
    NULL, /* int (*set_config)(struct dvb_frontend *fe, void *priv_cfg); */
    tda18211_get_frequency, /* int (*get_frequency)(struct dvb_frontend *fe, u32 *frequency); */
    tda18211_get_bandwidth, /* int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth); */
    NULL, /* int (*get_status)(struct dvb_frontend *fe, u32 *status); */
    NULL, /* int (*get_rf_strength)(struct dvb_frontend *fe, u16 *strength); */
    NULL, /* int (*set_frequency)(struct dvb_frontend *fe, u32 frequency); */
    NULL, /* int (*set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth); */

};

/**
 * 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 = NULL;

    dprintk("%s(%d): i2c addr: 0x%x\n", __FUNCTION__, __LINE__, i2c_addr);

    priv = kmalloc(sizeof(struct tda18211_priv), GFP_KERNEL);
    if (priv == NULL)
    {
        return NULL;
    }

    memset(priv, 0, sizeof(struct tda18211_priv));
    priv->i2c_addr = i2c_addr;
    priv->i2c_adapt = i2c_adap;

    priv->Config_Instance.Master = (Bool)(is_master != 0);

    priv->curPowerState = tmTDA18211_PowerNotSupported;
    priv->Config_Instance.uPLMODE = 1;
    priv->Config_Instance.StandardMode = tmTDA18211_DVBT_8MHz;
    priv->Config_Instance.lastStandardMode = tmTDA18211_StdNotSupported;

    memcpy(&priv->Config_Instance.RF_BAND_Map, &RF_BAND_Map, sizeof(tmTDA18211_RF_BAND_Map_t)*TDA18211_RF_BAND_NB_ROWS);

    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");
