/*
    Driver for NXP tda10048h OFDM Demodulator

    (c) 2008 Yacine Falek

    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.

*/

#ifndef TDA10048_H
#define TDA10048_H

#include <linux/dvb/frontend.h>
#include <linux/firmware.h>

#define TDA10048_I2C_ADDR0          0x08
#define TDA10048_I2C_ADDR1          0x09

enum tda10048_agc {
    TDA10048_AGC_DEFAULT,        /* original configuration */
    TDA10048_AGC_IFO_AUTO_NEG,    /* IF AGC only, automatic, negtive */
    TDA10048_AGC_IFO_AUTO_POS,    /* IF AGC only, automatic, positive */
    TDA10048_AGC_TDA827X,        /* IF AGC only, special setup for tda827x */
};

#define TDA10048_NO_OFFSET        0
#define TDA10048_OFFSET_PLUS_166  1
#define TDA10048_OFFSET_MINUS_166 2
#define TDA10048_OFFSET_PLUS_333  3
#define TDA10048_OFFSET_MINUS_333 4
#define TDA10048_OFFSET_PLUS_500  5
#define TDA10048_OFFSET_MINUS_500 6

/*********************************************/
/***** Sampling frequency configuration ******/
/*********************************************/
/* IF frequency */
#define TDA10048_IF_36M             36000000  /* IF = 36.00 MHz for maxim tuner */
#define TDA10048_IF_36M16           36166666  /* IF = 36.16 MHz for CAN tuner */
#define TDA10048_IF_36M13           36133333  /* IF = 36.13 MHz */
#define TDA10048_IF_5M16             5166667  /* IF =  5.16 MHz for tda9889 */
#define TDA10048_IF_4M75             4750000  /* IF =  4.75 MHz */
#define TDA10048_IF_4M               4000000  /* IF =  4.0  MHz for TDA18211 (silicon tuner) */

/* Xtal frequency=16MHz or 4MHz */
#define TDA10048_XTAL_4M             4000000
#define TDA10048_XTAL_16M           16000000
#define TDA10048_XTAL_25M           25000000

/* PLL factors */
#define TDA10048_PLL_M_FACTOR       1  /* configuration for TDA18211 */
#define TDA10048_PLL_N_FACTOR       4 
#define TDA10048_PLL_P_FACTOR       0

/* AGC Polarity */
#define TDA10048_AGC_TUN_UNUSED             0   /* default config */
#define TDA10048_AGC_TUN_USED               1

/* AGC Polarity */
#define TDA10048_AGC_POLA_TUN_INVERTED      1   /* default config */
#define TDA10048_AGC_POLA_TUN_NOT_INVERTED  0 

#define TDA10048_AGC_POLA_IF_INVERTED       1   /* default config */
#define TDA10048_AGC_POLA_IF_NOT_INVERTED   0 

/* AGC Min-Max */
#define TDA10048_AGC_TUN_MIN     0x00
#define TDA10048_AGC_TUN_MAX     0xff

#define TDA10048_AGC_IF_MIN      0x00
#define TDA10048_AGC_IF_MAX      0xff

/*  TS OUTPUT SELECTION */
/* to configure MODE A or B output */
/* MODE A: Value = 0               */
/* MODE B: Value = 1               */
#define TDA10048_CFG_OUT_MODE_A   0
#define TDA10048_CFG_OUT_MODE_B   1

/* to configure Parallel or Serial mode */
/* Parallel: Value = 0                  */
/* Serial:   Value = 1                  */
#define TDA10048_CFG_OUT_PARALLEL 0
#define TDA10048_CFG_OUT_SERIAL   1

/* Parallel mode B clock */
/* default: Value = 7 correspond to a division of the sampling clock by 8 */
/* Value possible [1:16] */


/* to configure the TS with MSB or LSB first */
/* MSB: Value = 0 */
/* LSB: Value = 1 */
#define TDA10048_CFG_OUT_MSB_FIRST 0
#define TDA10048_CFG_OUT_LSB_FIRST 1


/* to configure clock edge in MODE A    */
/* rising edge:  Value = 0              */
/* falling edge: Value = 1              */
#define TDA10048_CFG_OUT_MODE_A_RISING_EDGE  0
#define TDA10048_CFG_OUT_MODE_A_FALLING_EDGE 1

/* to configure clock edge in MODE B    */
/* falling edge: Value = 0              */
/* rising edge:  Value = 1              */
#define TDA10048_CFG_OUT_MODE_B_RISING_EDGE  1
#define TDA10048_CFG_OUT_MODE_B_FALLING_EDGE 0



struct tda10048_config
{
    /* the demodulator's i2c address */
    u8 demod_address;

    /* Xtal frequency, 4 or 16MHz */
    u32 xtal_freq;

    /* IF frequency */
    u32 if_freq;

    /* PLL factors */
    u32 PLL_M_Factor;
    u32 PLL_N_Factor;
    u32 PLL_P_Factor;

    /* AGC Tuner use */
    bool AGC_TunUsed; 

    /* AGC Polarity */
    bool AGC_PolaTun;
    bool AGC_PolaIf;

    u8 AGC_TunMin;
    u8 AGC_TunMax;
    u8 AGC_IfMin;
    u8 AGC_IfMax;
    
    /* Output configuration */
    u32 OUT_ParaSer;
    u32 OUT_ModeAB;
    u32 OUT_ParaDiv;    /* 7: default value */
    u32 OUT_MsbLsb;
    u32 OUT_Poclk;

    /* does the "inversion" need inverted? */
    u8 spectral_inv;

    /* PLL maintenance */
    int (*pll_init)(struct dvb_frontend* fe);
    void (*pll_sleep)(struct dvb_frontend* fe);
    int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);

    /* the linked attenuator demodulator's i2c address */
    u8 attenuator_demod_address;

    /* enable tuning algorithm 0 = disable / 1 = enable*/
    u8 tuning_algo;
};

struct tda10048_sampling_correction
{
    unsigned long       uInvWref6;
    unsigned long       uWref6;
    unsigned long       uInvWref7;
    unsigned long       uWref7;
    unsigned long       uInvWref8;
    unsigned long       uWref8;
};

struct tda10048_state
{
    struct i2c_adapter*                     i2c;
    struct dvb_frontend_ops                 ops;
    const struct tda10048_config            config;
    struct dvb_frontend                     frontend;
    struct tda10048_sampling_correction     sampling;
    /* private demod data */
    u8 initialised:1;
};

#if defined(CONFIG_DVB_TDA10048) || (defined(CONFIG_DVB_TDA10048_MODULE) && defined(MODULE))
extern struct dvb_frontend* tda10048_attach(const struct tda10048_config* config,
                                                 struct i2c_adapter* i2c);

#else
static inline struct dvb_frontend* tda10048_attach(const struct tda10048_config* config,
                                                        struct i2c_adapter* i2c)
{
    printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
    return NULL;
}
#endif // CONFIG_DVB_TDA10048

extern int 
tda10048_request_firmware (
        struct dvb_frontend*    fe,
        const struct firmware** fw,
        char*                   name
        );


#endif // TDA10048_H

