Hi Max,

Em 15-04-2012 12:53, nibble.max escreveu:
> Montage m88ds3103 demodulator and ts2022 tuner driver.

It was pointed to me that this device were already discussed on:

   http://www.mail-archive.com/linux-media@vger.kernel.org/msg43109.html

If m88ds3103 demod is similar enough to ds3000, it should just add the needed
bits at the existing driver, and not creating a new driver. 

Thanks,
Mauro

> 
> Signed-off-by: Max nibble <nibble....@gmail.com>
> ---
>  drivers/media/dvb/frontends/Kconfig     |    7 +
>  drivers/media/dvb/frontends/Makefile    |    2 +
>  drivers/media/dvb/frontends/m88ds3103.c | 1851 
> +++++++++++++++++++++++++++++++
>  drivers/media/dvb/frontends/m88ds3103.h |   53 +
>  4 files changed, 1913 insertions(+)
>  create mode 100644 drivers/media/dvb/frontends/m88ds3103.c
>  create mode 100644 drivers/media/dvb/frontends/m88ds3103.h
> 
> diff --git a/drivers/media/dvb/frontends/Kconfig 
> b/drivers/media/dvb/frontends/Kconfig
> index e11adb6..d2bb312 100644
> --- a/drivers/media/dvb/frontends/Kconfig
> +++ b/drivers/media/dvb/frontends/Kconfig
> @@ -214,6 +214,13 @@ config DVB_CX24116
>       help
>         A DVB-S/S2 tuner module. Say Y when you want to support this frontend.
>  
> +config DVB_M88DS3103
> +     tristate "Montage DS3103 based"
> +     depends on DVB_CORE && I2C
> +     default m if DVB_FE_CUSTOMISE
> +     help
> +       A DVB-S/S2 tuner module. Say Y when you want to support this frontend.
> +       
>  config DVB_SI21XX
>       tristate "Silicon Labs SI21XX based"
>       depends on DVB_CORE && I2C
> diff --git a/drivers/media/dvb/frontends/Makefile 
> b/drivers/media/dvb/frontends/Makefile
> index 6ca7557..84ddf41 100644
> --- a/drivers/media/dvb/frontends/Makefile
> +++ b/drivers/media/dvb/frontends/Makefile
> @@ -98,5 +98,7 @@ obj-$(CONFIG_DVB_A8293) += a8293.o
>  obj-$(CONFIG_DVB_TDA10071) += tda10071.o
>  obj-$(CONFIG_DVB_RTL2830) += rtl2830.o
>  obj-$(CONFIG_DVB_M88RS2000) += m88rs2000.o
> +obj-$(CONFIG_DVB_M88DS3103) += m88ds3103.o
>  obj-$(CONFIG_DVB_AF9033) += af9033.o
>  
> +
> diff --git a/drivers/media/dvb/frontends/m88ds3103.c 
> b/drivers/media/dvb/frontends/m88ds3103.c
> new file mode 100644
> index 0000000..a186ba0
> --- /dev/null
> +++ b/drivers/media/dvb/frontends/m88ds3103.c
> @@ -0,0 +1,1851 @@
> +/*
> +    Montage Technology M88DS3103/M88TS2022 - DVBS/S2 Satellite demod/tuner 
> driver
> +
> +    Copyright (C) 2011 Max nibble<nibble....@gmail.com>
> +    Copyright (C) 2010 Montage Technology<www.montage-tech.com>
> +    Copyright (C) 2009 Konstantin Dimitrov.
> +
> +    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.
> + */
> +
> +#include <linux/slab.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/moduleparam.h>
> +#include <linux/init.h>
> +#include <linux/firmware.h>
> +
> +#include "dvb_frontend.h"
> +#include "m88ds3103.h"
> +
> +static int debug;
> +module_param(debug, int, 0644);
> +MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
> +
> +#define dprintk(args...) \
> +     do { \
> +             if (debug) \
> +                     printk(KERN_INFO "m88ds3103: " args); \
> +     } while (0)
> +
> +#define FW_DOWN_SIZE 32
> +#define FW_DOWN_LOOP (8192/FW_DOWN_SIZE)
> +#define DS3103_DEFAULT_FIRMWARE "dvb-fe-ds3103.fw"
> +#define DS3000_DEFAULT_FIRMWARE "dvb-fe-ds300x.fw"
> +#define MT_FE_MCLK_KHZ 96000 /* in kHz */
> +#define MT_FE_CRYSTAL_KHZ   27000 /* in kHz */
> +#define FREQ_OFFSET_AT_SMALL_SYM_RATE_KHz 3000
> +#define DS3000_ID    0x3000
> +#define DS3103_ID    0x3103
> +#define TS2020_ID    0x2020
> +#define TS2022_ID    0x2022
> +#define UNKNOW_ID    0x0000
> +
> +/* For M88DS3103 demod dvbs mode.*/
> +static u8 ds3103_dvbs_init_tab[] = {
> +     0x23, 0x07,
> +     0x08, 0x03,
> +     0x0c, 0x02,
> +     0x21, 0x54,
> +     0x25, 0x82,
> +     0x27, 0x31,
> +     0x30, 0x08,
> +     0x31, 0x40,
> +     0x32, 0x32,
> +     0x33, 0x35,
> +     0x35, 0xff,
> +     0x3a, 0x00,
> +     0x37, 0x10,
> +     0x38, 0x10,
> +     0x39, 0x02,
> +     0x42, 0x60,
> +     0x4a, 0x80,
> +     0x4b, 0x04,
> +     0x4d, 0x91,
> +     0x5d, 0xc8,
> +     0x50, 0x36,
> +     0x51, 0x36,
> +     0x52, 0x36,
> +     0x53, 0x36,
> +     0x63, 0x0f,
> +     0x64, 0x30,
> +     0x65, 0x40,
> +     0x68, 0x26,
> +     0x69, 0x4c,
> +     0x70, 0x20,
> +     0x71, 0x70,
> +     0x72, 0x04,
> +     0x73, 0x00,
> +     0x70, 0x40,
> +     0x71, 0x70,
> +     0x72, 0x04,
> +     0x73, 0x00,
> +     0x70, 0x60,
> +     0x71, 0x70,
> +     0x72, 0x04,
> +     0x73, 0x00,
> +     0x70, 0x80,
> +     0x71, 0x70,
> +     0x72, 0x04,
> +     0x73, 0x00,
> +     0x70, 0xa0,
> +     0x71, 0x70,
> +     0x72, 0x04,
> +     0x73, 0x00,
> +     0x70, 0x1f,
> +     0x76, 0x38,
> +     0x77, 0xa6,
> +     0x78, 0x0c,
> +     0x79, 0x80,
> +     0x7f, 0x14,
> +     0x7c, 0x00,
> +     0xae, 0x82,
> +     0x80, 0x64,
> +     0x81, 0x66,
> +     0x82, 0x44,
> +     0x85, 0x04,
> +     0xcd, 0xf4,
> +     0x90, 0x33,
> +     0xa0, 0x44,
> +     0xc0, 0x08,
> +     0xc3, 0x10,
> +     0xc4, 0x08,
> +     0xc5, 0xf0,
> +     0xc6, 0xff,
> +     0xc7, 0x00,
> +     0xc8, 0x1a,
> +     0xc9, 0x80,
> +     0xe0, 0xf8,
> +     0xe6, 0x8b,
> +     0xd0, 0x40,
> +     0xf8, 0x20,
> +     0xfa, 0x0f,
> +     0x00, 0x00,
> +     0xbd, 0x01,
> +     0xb8, 0x00,
> +};
> +/* For M88DS3103 demod dvbs2 mode.*/
> +static u8 ds3103_dvbs2_init_tab[] = {
> +     0x23, 0x07,
> +     0x08, 0x07,
> +     0x0c, 0x02,
> +     0x21, 0x54,
> +     0x25, 0x82,
> +     0x27, 0x31,
> +     0x30, 0x08,
> +     0x32, 0x32,
> +     0x33, 0x35,
> +     0x35, 0xff,
> +     0x3a, 0x00,
> +     0x37, 0x10,
> +     0x38, 0x10,
> +     0x39, 0x02,
> +     0x42, 0x60,
> +     0x4a, 0x80,
> +     0x4b, 0x04,
> +     0x4d, 0x91,
> +     0x5d, 0xc8,
> +     0x50, 0x36,
> +     0x51, 0x36,
> +     0x52, 0x36,
> +     0x53, 0x36,
> +     0x63, 0x0f,
> +     0x64, 0x10,
> +     0x65, 0x20,
> +     0x68, 0x46,
> +     0x69, 0xcd,
> +     0x70, 0x20,
> +     0x71, 0x70,
> +     0x72, 0x04,
> +     0x73, 0x00,
> +     0x70, 0x40,
> +     0x71, 0x70,
> +     0x72, 0x04,
> +     0x73, 0x00,
> +     0x70, 0x60,
> +     0x71, 0x70,
> +     0x72, 0x04,
> +     0x73, 0x00,
> +     0x70, 0x80,
> +     0x71, 0x70,
> +     0x72, 0x04,
> +     0x73, 0x00,
> +     0x70, 0xa0,
> +     0x71, 0x70,
> +     0x72, 0x04,
> +     0x73, 0x00,
> +     0x70, 0x1f,
> +     0x76, 0x38,
> +     0x77, 0xa6,
> +     0x78, 0x0c,
> +     0x79, 0x80,
> +     0x7f, 0x14,
> +     0x85, 0x08,
> +     0xcd, 0xf4,
> +     0x90, 0x33,
> +     0x86, 0x00,
> +     0x87, 0x0f,
> +     0x89, 0x00,
> +     0x8b, 0x44,
> +     0x8c, 0x66,
> +     0x9d, 0xc1,
> +     0x8a, 0x10,
> +     0xad, 0x40,
> +     0xa0, 0x44,
> +     0xc0, 0x08,
> +     0xc1, 0x10,
> +     0xc2, 0x08,
> +     0xc3, 0x10,
> +     0xc4, 0x08,
> +     0xc5, 0xf0,
> +     0xc6, 0xff,
> +     0xc7, 0x00,
> +     0xc8, 0x1a,
> +     0xc9, 0x80,
> +     0xca, 0x23,
> +     0xcb, 0x24,
> +     0xcc, 0xf4,
> +     0xce, 0x74,
> +     0x00, 0x00,
> +     0xbd, 0x01,
> +     0xb8, 0x00,
> +};
> +
> +/* For M88DS3000 demod dvbs mode.*/
> +static u8 ds3000_dvbs_init_tab[] = {
> +     0x23, 0x05,
> +     0x08, 0x03,
> +     0x0c, 0x02,
> +     0x21, 0x54,
> +     0x25, 0x82,
> +     0x27, 0x31,
> +     0x30, 0x08,
> +     0x31, 0x40,
> +     0x32, 0x32,
> +     0x33, 0x35,
> +     0x35, 0xff,
> +     0x3a, 0x00,
> +     0x37, 0x10,
> +     0x38, 0x10,
> +     0x39, 0x02,
> +     0x42, 0x60,
> +     0x4a, 0x40,
> +     0x4b, 0x04,
> +     0x4d, 0x91,
> +     0x5d, 0xc8,
> +     0x50, 0x77,
> +     0x51, 0x77,
> +     0x52, 0x36,
> +     0x53, 0x36,
> +     0x56, 0x01,
> +     0x63, 0x47,
> +     0x64, 0x30,
> +     0x65, 0x40,
> +     0x68, 0x26,
> +     0x69, 0x4c,
> +     0x70, 0x20,
> +     0x71, 0x70,
> +     0x72, 0x04,
> +     0x73, 0x00,
> +     0x70, 0x40,
> +     0x71, 0x70,
> +     0x72, 0x04,
> +     0x73, 0x00,
> +     0x70, 0x60,
> +     0x71, 0x70,
> +     0x72, 0x04,
> +     0x73, 0x00,
> +     0x70, 0x80,
> +     0x71, 0x70,
> +     0x72, 0x04,
> +     0x73, 0x00,
> +     0x70, 0xa0,
> +     0x71, 0x70,
> +     0x72, 0x04,
> +     0x73, 0x00,
> +     0x70, 0x1f,
> +     0x76, 0x00,
> +     0x77, 0xd1,
> +     0x78, 0x0c,
> +     0x79, 0x80,
> +     0x7f, 0x04,
> +     0x7c, 0x00,
> +     0x80, 0x86,
> +     0x81, 0xa6,
> +     0x85, 0x04,
> +     0xcd, 0xf4,
> +     0x90, 0x33,
> +     0xa0, 0x44,
> +     0xc0, 0x18,
> +     0xc3, 0x10,
> +     0xc4, 0x08,
> +     0xc5, 0x80,
> +     0xc6, 0x80,
> +     0xc7, 0x0a,
> +     0xc8, 0x1a,
> +     0xc9, 0x80,
> +     0xfe, 0xb6,
> +     0xe0, 0xf8,
> +     0xe6, 0x8b,
> +     0xd0, 0x40,
> +     0xf8, 0x20,
> +     0xfa, 0x0f,
> +     0xad, 0x20,
> +     0xae, 0x07,
> +     0xb8, 0x00,
> +};
> +
> +/* For M88DS3000 demod dvbs2 mode.*/
> +static u8 ds3000_dvbs2_init_tab[] = {
> +     0x23, 0x0f,
> +     0x08, 0x07,
> +     0x0c, 0x02,
> +     0x21, 0x54,
> +     0x25, 0x82,
> +     0x27, 0x31,
> +     0x30, 0x08,
> +     0x31, 0x32,
> +     0x32, 0x32,
> +     0x33, 0x35,
> +     0x35, 0xff,
> +     0x3a, 0x00,
> +     0x37, 0x10,
> +     0x38, 0x10,
> +     0x39, 0x02,
> +     0x42, 0x60,
> +     0x4a, 0x80,
> +     0x4b, 0x04,
> +     0x4d, 0x91,
> +     0x5d, 0x88,
> +     0x50, 0x36,
> +     0x51, 0x36,
> +     0x52, 0x36,
> +     0x53, 0x36,
> +     0x63, 0x60,
> +     0x64, 0x10,
> +     0x65, 0x10,
> +     0x68, 0x04,
> +     0x69, 0x29,
> +     0x70, 0x20,
> +     0x71, 0x70,
> +     0x72, 0x04,
> +     0x73, 0x00,
> +     0x70, 0x40,
> +     0x71, 0x70,
> +     0x72, 0x04,
> +     0x73, 0x00,
> +     0x70, 0x60,
> +     0x71, 0x70,
> +     0x72, 0x04,
> +     0x73, 0x00,
> +     0x70, 0x80,
> +     0x71, 0x70,
> +     0x72, 0x04,
> +     0x73, 0x00,
> +     0x70, 0xa0,
> +     0x71, 0x70,
> +     0x72, 0x04,
> +     0x73, 0x00,
> +     0x70, 0x1f,
> +     0xa0, 0x44,
> +     0xc0, 0x08,
> +     0xc1, 0x10,
> +     0xc2, 0x08,
> +     0xc3, 0x10,
> +     0xc4, 0x08,
> +     0xc5, 0xf0,
> +     0xc6, 0xf0,
> +     0xc7, 0x0a,
> +     0xc8, 0x1a,
> +     0xc9, 0x80,
> +     0xca, 0x23,
> +     0xcb, 0x24,
> +     0xce, 0x74,
> +     0x56, 0x01,
> +     0x90, 0x03,
> +     0x76, 0x80,
> +     0x77, 0x42,
> +     0x78, 0x0a,
> +     0x79, 0x80,
> +     0xad, 0x40,
> +     0xae, 0x07,
> +     0x7f, 0xd4,
> +     0x7c, 0x00,
> +     0x80, 0xa8,
> +     0x81, 0xda,
> +     0x7c, 0x01,
> +     0x80, 0xda,
> +     0x81, 0xec,
> +     0x7c, 0x02,
> +     0x80, 0xca,
> +     0x81, 0xeb,
> +     0x7c, 0x03,
> +     0x80, 0xba,
> +     0x81, 0xdb,
> +     0x85, 0x08,
> +     0x86, 0x00,
> +     0x87, 0x02,
> +     0x89, 0x80,
> +     0x8b, 0x44,
> +     0x8c, 0xaa,
> +     0x8a, 0x10,
> +     0xba, 0x00,
> +     0xf5, 0x04,
> +     0xd2, 0x32,
> +     0xb8, 0x00,
> +};
> +
> +struct m88ds3103_state {
> +     struct i2c_adapter *i2c;
> +     const struct m88ds3103_config *config;
> +     
> +     struct dvb_frontend frontend;
> +     
> +     u32 preBer;
> +     u8 skip_fw_load;        
> +     u8 first_lock; /* The first time of signal lock */
> +     u16 demod_id; /* demod chip type */
> +     u16 tuner_id; /* tuner chip type */
> +     fe_delivery_system_t delivery_system;
> +};
> +
> +/*demod register operations.*/
> +static int m88ds3103_writereg(struct m88ds3103_state *state, int reg, int 
> data)
> +{
> +     u8 buf[] = { reg, data };
> +     struct i2c_msg msg = { .addr = state->config->demod_address,
> +             .flags = 0, .buf = buf, .len = 2 };
> +     int err;
> +
> +     if (debug > 1)
> +             printk("m88ds3103: %s: write reg 0x%02x, value 0x%02x\n",
> +                     __func__, reg, data);
> +
> +     err = i2c_transfer(state->i2c, &msg, 1);
> +     if (err != 1) {
> +             printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x,"
> +                      " value == 0x%02x)\n", __func__, err, reg, data);
> +             return -EREMOTEIO;
> +     }
> +     return 0;
> +}
> +
> +static int m88ds3103_readreg(struct m88ds3103_state *state, u8 reg)
> +{
> +     int ret;
> +     u8 b0[] = { reg };
> +     u8 b1[] = { 0 };
> +     struct i2c_msg msg[] = {
> +             { .addr = state->config->demod_address, .flags = 0,
> +                     .buf = b0, .len = 1 },
> +             { .addr = state->config->demod_address, .flags = I2C_M_RD,
> +                     .buf = b1, .len = 1 }
> +     };
> +     ret = i2c_transfer(state->i2c, msg, 2);
> +
> +     if (ret != 2) {
> +             printk(KERN_ERR "%s: reg=0x%x (error=%d)\n",
> +                     __func__, reg, ret);
> +             return ret;
> +     }
> +
> +     if (debug > 1)
> +             printk(KERN_INFO "m88ds3103: read reg 0x%02x, value 0x%02x\n",
> +                     reg, b1[0]);
> +
> +     return b1[0];
> +}
> +
> +/*tuner register operations.*/
> +static int m88ds3103_tuner_writereg(struct m88ds3103_state *state, int reg, 
> int data)
> +{
> +     u8 buf[] = { reg, data };
> +     struct i2c_msg msg = { .addr = 0x60,
> +             .flags = 0, .buf = buf, .len = 2 };
> +     int err;
> +
> +     m88ds3103_writereg(state, 0x03, 0x11);
> +     err = i2c_transfer(state->i2c, &msg, 1);
> +     
> +     if (err != 1) {
> +             printk("%s: writereg error(err == %i, reg == 0x%02x,"
> +                      " value == 0x%02x)\n", __func__, err, reg, data);
> +             return -EREMOTEIO;
> +     }
> +
> +     return 0;
> +}
> +
> +static int m88ds3103_tuner_readreg(struct m88ds3103_state *state, u8 reg)
> +{
> +     int ret;
> +     u8 b0[] = { reg };
> +     u8 b1[] = { 0 };
> +     struct i2c_msg msg[] = {
> +             { .addr = 0x60, .flags = 0,
> +                     .buf = b0, .len = 1 },
> +             { .addr = 0x60, .flags = I2C_M_RD,
> +                     .buf = b1, .len = 1 }
> +     };
> +
> +     m88ds3103_writereg(state, 0x03, 0x11);  
> +     ret = i2c_transfer(state->i2c, msg, 2);
> +
> +     if (ret != 2) {
> +             printk(KERN_ERR "%s: reg=0x%x(error=%d)\n", __func__, reg, ret);
> +             return ret;
> +     }
> +
> +     return b1[0];
> +}
> +
> +/* Bulk demod I2C write, for firmware download. */
> +static int m88ds3103_writeregN(struct m88ds3103_state *state, int reg,
> +                             const u8 *data, u16 len)
> +{
> +     int ret = -EREMOTEIO;
> +     struct i2c_msg msg;
> +     u8 *buf;
> +
> +     buf = kmalloc(len + 1, GFP_KERNEL);
> +     if (buf == NULL) {
> +             printk("Unable to kmalloc\n");
> +             ret = -ENOMEM;
> +             goto error;
> +     }
> +
> +     *(buf) = reg;
> +     memcpy(buf + 1, data, len);
> +
> +     msg.addr = state->config->demod_address;
> +     msg.flags = 0;
> +     msg.buf = buf;
> +     msg.len = len + 1;
> +
> +     if (debug > 1)
> +             printk(KERN_INFO "m88ds3103: %s:  write regN 0x%02x, len = 
> %d\n",
> +                     __func__, reg, len);
> +
> +     ret = i2c_transfer(state->i2c, &msg, 1);
> +     if (ret != 1) {
> +             printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x\n",
> +                      __func__, ret, reg);
> +             ret = -EREMOTEIO;
> +     }
> +     
> +error:
> +     kfree(buf);
> +
> +     return ret;
> +}
> +
> +static int m88ds3103_load_firmware(struct dvb_frontend *fe)
> +{
> +     struct m88ds3103_state *state = fe->demodulator_priv;
> +     const struct firmware *fw;
> +     int i, ret = 0;
> +
> +     dprintk("%s()\n", __func__);
> +             
> +     if (state->skip_fw_load)
> +             return 0;
> +     /* Load firmware */
> +     /* request the firmware, this will block until someone uploads it */    
> +     if(state->demod_id == DS3000_ID){
> +             printk(KERN_INFO "%s: Waiting for firmware upload (%s)...\n", 
> __func__,
> +                             DS3000_DEFAULT_FIRMWARE);               
> +             ret = request_firmware(&fw, DS3000_DEFAULT_FIRMWARE,
> +                                     state->i2c->dev.parent);
> +     }else if(state->demod_id == DS3103_ID){
> +             printk(KERN_INFO "%s: Waiting for firmware upload (%s)...\n", 
> __func__,
> +                             DS3103_DEFAULT_FIRMWARE);
> +             ret = request_firmware(&fw, DS3103_DEFAULT_FIRMWARE,
> +                                     state->i2c->dev.parent);
> +     }
> +     
> +     printk(KERN_INFO "%s: Waiting for firmware upload(2)...\n", __func__);
> +     if (ret) {
> +             printk(KERN_ERR "%s: No firmware uploaded (timeout or file not "
> +                             "found?)\n", __func__);
> +             return ret;
> +     }
> +
> +     /* Make sure we don't recurse back through here during loading */
> +     state->skip_fw_load = 1;
> +
> +     dprintk("Firmware is %zu bytes (%02x %02x .. %02x %02x)\n",
> +                     fw->size,
> +                     fw->data[0],
> +                     fw->data[1],
> +                     fw->data[fw->size - 2],
> +                     fw->data[fw->size - 1]);
> +                     
> +     /* stop internal mcu. */
> +     m88ds3103_writereg(state, 0xb2, 0x01);
> +     /* split firmware to download.*/
> +     for(i = 0; i < FW_DOWN_LOOP; i++){
> +             ret = m88ds3103_writeregN(state, 0xb0, 
> &(fw->data[FW_DOWN_SIZE*i]), FW_DOWN_SIZE);
> +             if(ret != 1) break;             
> +     }
> +     /* start internal mcu. */
> +     if(ret == 1)
> +             m88ds3103_writereg(state, 0xb2, 0x00);
> +             
> +     release_firmware(fw);
> +
> +     dprintk("%s: Firmware upload %s\n", __func__,
> +                     ret == 1 ? "complete" : "failed");
> +
> +     if(ret == 1) ret = 0;
> +     
> +     /* Ensure firmware is always loaded if required */
> +     state->skip_fw_load = 0;
> +
> +     return ret;
> +}
> +
> +
> +static int m88ds3103_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t 
> voltage)
> +{
> +     struct m88ds3103_state *state = fe->demodulator_priv;
> +     u8 data;
> +
> +     dprintk("%s(%d)\n", __func__, voltage);
> +
> +     dprintk("m88ds3103:pin_ctrl = (%02x)\n", state->config->pin_ctrl);
> +     
> +     if(state->config->set_voltage)
> +             state->config->set_voltage(fe, voltage);
> +     
> +     data = m88ds3103_readreg(state, 0xa2);
> +     
> +        if(state->config->pin_ctrl & 0x80){ /*If control pin is assigned.*/
> +             data &= ~0x03; /* bit0 V/H, bit1 off/on */
> +             if(state->config->pin_ctrl & 0x02)
> +                  data |= 0x02;
> +
> +             switch (voltage) {
> +             case SEC_VOLTAGE_18:
> +                  if((state->config->pin_ctrl & 0x01) == 0)
> +                       data |= 0x01;
> +                  break;
> +             case SEC_VOLTAGE_13:
> +                  if(state->config->pin_ctrl & 0x01)
> +                       data |= 0x01;
> +                  break;
> +             case SEC_VOLTAGE_OFF:
> +                  if(state->config->pin_ctrl & 0x02)
> +                        data &= ~0x02;                       
> +                  else
> +                        data |= 0x02;
> +                  break;
> +              }
> +        }
> +
> +     m88ds3103_writereg(state, 0xa2, data);
> +
> +     return 0;
> +}
> +
> +static int m88ds3103_read_status(struct dvb_frontend *fe, fe_status_t* 
> status)
> +{
> +     struct m88ds3103_state *state = fe->demodulator_priv;
> +     int lock = 0;
> +     
> +     *status = 0;
> +     
> +     switch (state->delivery_system){
> +     case SYS_DVBS:
> +             lock = m88ds3103_readreg(state, 0xd1);
> +             dprintk("%s: SYS_DVBS status=%x.\n", __func__, lock);
> +             
> +             if ((lock & 0x07) == 0x07){
> +                     /*if((m88ds3103_readreg(state, 0x0d) & 0x07) == 0x07)*/
> +                             *status = FE_HAS_SIGNAL | FE_HAS_CARRIER 
> +                                     | FE_HAS_VITERBI | FE_HAS_SYNC | 
> FE_HAS_LOCK;
> +                     
> +             }
> +             break;
> +     case SYS_DVBS2:
> +             lock = m88ds3103_readreg(state, 0x0d);
> +             dprintk("%s: SYS_DVBS2 status=%x.\n", __func__, lock);
> +
> +             if ((lock & 0x8f) == 0x8f)
> +                     *status = FE_HAS_SIGNAL | FE_HAS_CARRIER 
> +                             | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
> +                     
> +             break;
> +     default:
> +             break;
> +     }
> +
> +     return 0;
> +}
> +
> +static int m88ds3103_read_ber(struct dvb_frontend *fe, u32* ber)
> +{
> +     struct m88ds3103_state *state = fe->demodulator_priv;
> +     u8 tmp1, tmp2, tmp3;
> +     u32 ldpc_frame_cnt, pre_err_packags, code_rate_fac = 0;
> +
> +     dprintk("%s()\n", __func__);
> +
> +     switch (state->delivery_system) {
> +     case SYS_DVBS:
> +             m88ds3103_writereg(state, 0xf9, 0x04);
> +             tmp3 = m88ds3103_readreg(state, 0xf8);
> +             if ((tmp3&0x10) == 0){
> +                     tmp1 = m88ds3103_readreg(state, 0xf7);
> +                     tmp2 = m88ds3103_readreg(state, 0xf6);
> +                     tmp3 |= 0x10;
> +                     m88ds3103_writereg(state, 0xf8, tmp3);
> +                     state->preBer = (tmp1<<8) | tmp2;
> +             }
> +             break;
> +     case SYS_DVBS2:
> +             tmp1 = m88ds3103_readreg(state, 0x7e) & 0x0f;
> +             switch(tmp1){
> +             case 0: code_rate_fac = 16008 - 80; break;
> +             case 1: code_rate_fac = 21408 - 80; break;
> +             case 2: code_rate_fac = 25728 - 80; break;
> +             case 3: code_rate_fac = 32208 - 80; break;
> +             case 4: code_rate_fac = 38688 - 80; break;
> +             case 5: code_rate_fac = 43040 - 80; break;
> +             case 6: code_rate_fac = 48408 - 80; break;
> +             case 7: code_rate_fac = 51648 - 80; break;
> +             case 8: code_rate_fac = 53840 - 80; break;
> +             case 9: code_rate_fac = 57472 - 80; break;
> +             case 10: code_rate_fac = 58192 - 80; break;
> +             }
> +             
> +             tmp1 = m88ds3103_readreg(state, 0xd7) & 0xff;
> +             tmp2 = m88ds3103_readreg(state, 0xd6) & 0xff;
> +             tmp3 = m88ds3103_readreg(state, 0xd5) & 0xff;           
> +             ldpc_frame_cnt = (tmp1 << 16) | (tmp2 << 8) | tmp3;
> +
> +             tmp1 = m88ds3103_readreg(state, 0xf8) & 0xff;
> +             tmp2 = m88ds3103_readreg(state, 0xf7) & 0xff;
> +             pre_err_packags = tmp1<<8 | tmp2;
> +             
> +             if (ldpc_frame_cnt > 1000){
> +                     m88ds3103_writereg(state, 0xd1, 0x01);
> +                     m88ds3103_writereg(state, 0xf9, 0x01);
> +                     m88ds3103_writereg(state, 0xf9, 0x00);
> +                     m88ds3103_writereg(state, 0xd1, 0x00);
> +                     state->preBer = pre_err_packags;
> +             }                               
> +             break;
> +     default:
> +             break;
> +     }
> +     *ber = state->preBer;
> +     
> +     return 0;
> +}
> +
> +static int m88ds3103_read_signal_strength(struct dvb_frontend *fe,
> +                                             u16 *signal_strength)
> +{
> +     struct m88ds3103_state *state = fe->demodulator_priv;
> +     u16 gain;
> +     u8 gain1, gain2, gain3 = 0;
> +
> +     dprintk("%s()\n", __func__);
> +
> +     gain1 = m88ds3103_tuner_readreg(state, 0x3d) & 0x1f;
> +     dprintk("%s: gain1 = 0x%02x \n", __func__, gain1);
> +     
> +     if (gain1 > 15) gain1 = 15;
> +     gain2 = m88ds3103_tuner_readreg(state, 0x21) & 0x1f;
> +     dprintk("%s: gain2 = 0x%02x \n", __func__, gain2);
> +     
> +     if(state->tuner_id == TS2022_ID){
> +             gain3 = (m88ds3103_tuner_readreg(state, 0x66)>>3) & 0x07;
> +             dprintk("%s: gain3 = 0x%02x \n", __func__, gain3);
> +             
> +             if (gain2 > 16) gain2 = 16;
> +             if (gain2 < 2) gain2 = 2;                       
> +             if (gain3 > 6) gain3 = 6;
> +     }else{
> +             if (gain2 > 13) gain2 = 13;
> +             gain3 = 0;
> +     }
> +
> +     gain = gain1*23 + gain2*35 + gain3*29;
> +     *signal_strength = 60000 - gain*55;
> +
> +     return 0;
> +}
> +
> +
> +static int m88ds3103_read_snr(struct dvb_frontend *fe, u16 *p_snr)
> +{
> +     struct m88ds3103_state *state = fe->demodulator_priv;
> +     u8 val, npow1, npow2, spow1, cnt;
> +     u16 tmp, snr;
> +     u32 npow, spow, snr_total;      
> +     static const u16 mes_log10[] ={
> +             0,      3010,   4771,   6021,   6990,   7781,   8451,   9031,   
> 9542,   10000,
> +             10414,  10792,  11139,  11461,  11761,  12041,  12304,  12553,  
> 12788,  13010,
> +             13222,  13424,  13617,  13802,  13979,  14150,  14314,  14472,  
> 14624,  14771,
> +             14914,  15052,  15185,  15315,  15441,  15563,  15682,  15798,  
> 15911,  16021,
> +             16128,  16232,  16335,  16435,  16532,  16628,  16721,  16812,  
> 16902,  16990,
> +             17076,  17160,  17243,  17324,  17404,  17482,  17559,  17634,  
> 17709,  17782,
> +             17853,  17924,  17993,  18062,  18129,  18195,  18261,  18325,  
> 18388,  18451,
> +             18513,  18573,  18633,  18692,  18751,  18808,  18865,  18921,  
> 18976,  19031
> +     };
> +     static const u16 mes_loge[] ={
> +             0,      6931,   10986,  13863,  16094,  17918,  19459,  20794,  
> 21972,  23026,
> +             23979,  24849,  25649,  26391,  27081,  27726,  28332,  28904,  
> 29444,  29957,
> +             30445,  30910,  31355,  31781,  32189,  32581,  32958,  33322,  
> 33673,  34012,
> +             34340,  34657,
> +     };
> +
> +     dprintk("%s()\n", __func__);
> +
> +     snr = 0;
> +     
> +     switch (state->delivery_system){
> +     case SYS_DVBS:
> +             cnt = 10; snr_total = 0;
> +             while(cnt > 0){
> +                     val = m88ds3103_readreg(state, 0xff);
> +                     snr_total += val;
> +                     cnt--;
> +             }
> +             tmp = (u16)(snr_total/80);
> +             if(tmp > 0){
> +                     if (tmp > 32) tmp = 32;
> +                     snr = (mes_loge[tmp - 1] * 100) / 45;
> +             }else{
> +                     snr = 0;
> +             }
> +             break;
> +     case SYS_DVBS2:
> +             cnt  = 10; npow = 0; spow = 0;
> +             while(cnt >0){
> +                     npow1 = m88ds3103_readreg(state, 0x8c) & 0xff;
> +                     npow2 = m88ds3103_readreg(state, 0x8d) & 0xff;
> +                     npow += (((npow1 & 0x3f) + (u16)(npow2 << 6)) >> 2);
> +
> +                     spow1 = m88ds3103_readreg(state, 0x8e) & 0xff;
> +                     spow += ((spow1 * spow1) >> 1);
> +                     cnt--;
> +             }
> +             npow /= 10; spow /= 10;
> +             if(spow == 0){
> +                     snr = 0;
> +             }else if(npow == 0){
> +                     snr = 19;
> +             }else{
> +                     if(spow > npow){
> +                             tmp = (u16)(spow / npow);
> +                             if (tmp > 80) tmp = 80;
> +                             snr = mes_log10[tmp - 1]*3;
> +                     }else{
> +                             tmp = (u16)(npow / spow);
> +                             if (tmp > 80) tmp = 80;
> +                             snr = -(mes_log10[tmp - 1] / 1000);
> +                     }
> +             }                       
> +             break;
> +     default:
> +             break;
> +     }
> +     *p_snr = snr;
> +
> +     return 0;
> +}
> +
> +
> +static int m88ds3103_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
> +{
> +     struct m88ds3103_state *state = fe->demodulator_priv;
> +     u8 tmp1, tmp2, tmp3, data;
> +
> +     dprintk("%s()\n", __func__);
> +
> +     switch (state->delivery_system) {
> +     case SYS_DVBS:
> +             data = m88ds3103_readreg(state, 0xf8);
> +             data |= 0x40;
> +             m88ds3103_writereg(state, 0xf8, data);          
> +             tmp1 = m88ds3103_readreg(state, 0xf5);
> +             tmp2 = m88ds3103_readreg(state, 0xf4);
> +             *ucblocks = (tmp1 <<8) | tmp2;          
> +             data &= ~0x20;
> +             m88ds3103_writereg(state, 0xf8, data);
> +             data |= 0x20;
> +             m88ds3103_writereg(state, 0xf8, data);
> +             data &= ~0x40;
> +             m88ds3103_writereg(state, 0xf8, data);
> +             break;
> +     case SYS_DVBS2:
> +             tmp1 = m88ds3103_readreg(state, 0xda);
> +             tmp2 = m88ds3103_readreg(state, 0xd9);
> +             tmp3 = m88ds3103_readreg(state, 0xd8);
> +             *ucblocks = (tmp1 <<16)|(tmp2 <<8)|tmp3;
> +             data = m88ds3103_readreg(state, 0xd1);
> +             data |= 0x01;
> +             m88ds3103_writereg(state, 0xd1, data);
> +             data &= ~0x01;
> +             m88ds3103_writereg(state, 0xd1, data);
> +             break;
> +     default:
> +             break;
> +     }
> +     return 0;
> +}
> +
> +static int m88ds3103_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t 
> tone)
> +{
> +     struct m88ds3103_state *state = fe->demodulator_priv;
> +     u8 data_a1, data_a2;
> +
> +     dprintk("%s(%d)\n", __func__, tone);
> +     if ((tone != SEC_TONE_ON) && (tone != SEC_TONE_OFF)) {
> +             printk(KERN_ERR "%s: Invalid, tone=%d\n", __func__, tone);
> +             return -EINVAL;
> +     }
> +
> +     data_a1 = m88ds3103_readreg(state, 0xa1);
> +     data_a2 = m88ds3103_readreg(state, 0xa2);
> +     if(state->demod_id == DS3103_ID)
> +             data_a2 &= 0xdf; /* Normal mode */
> +     switch (tone) {
> +     case SEC_TONE_ON:
> +             dprintk("%s: SEC_TONE_ON\n", __func__);
> +             data_a1 |= 0x04;
> +             data_a1 &= ~0x03;
> +             data_a1 &= ~0x40;
> +             data_a2 &= ~0xc0;
> +             break;
> +     case SEC_TONE_OFF:
> +             dprintk("%s: SEC_TONE_OFF\n", __func__);
> +             data_a2 &= ~0xc0;
> +             data_a2 |= 0x80;
> +             break;
> +     }
> +     m88ds3103_writereg(state, 0xa2, data_a2);
> +     m88ds3103_writereg(state, 0xa1, data_a1);
> +     return 0;
> +}
> +
> +static int m88ds3103_send_diseqc_msg(struct dvb_frontend *fe,
> +                             struct dvb_diseqc_master_cmd *d)
> +{
> +     struct m88ds3103_state *state = fe->demodulator_priv;
> +     int i, ret = 0;
> +     u8 tmp, time_out;
> +
> +     /* Dump DiSEqC message */
> +     if (debug) {
> +             printk(KERN_INFO "m88ds3103: %s(", __func__);
> +             for (i = 0 ; i < d->msg_len ;) {
> +                     printk(KERN_INFO "0x%02x", d->msg[i]);
> +                     if (++i < d->msg_len)
> +                             printk(KERN_INFO ", ");
> +             }
> +     }
> +
> +     tmp = m88ds3103_readreg(state, 0xa2);
> +     tmp &= ~0xc0;
> +     if(state->demod_id == DS3103_ID)
> +             tmp &= ~0x20;
> +     m88ds3103_writereg(state, 0xa2, tmp);
> +     
> +     for (i = 0; i < d->msg_len; i ++)
> +             m88ds3103_writereg(state, (0xa3+i), d->msg[i]);
> +
> +     tmp = m88ds3103_readreg(state, 0xa1);   
> +     tmp &= ~0x38;
> +     tmp &= ~0x40;
> +     tmp |= ((d->msg_len-1) << 3) | 0x07;
> +     tmp &= ~0x80;
> +     m88ds3103_writereg(state, 0xa1, tmp);
> +     /*      1.5 * 9 * 8     = 108ms */
> +     time_out = 150;
> +     while (time_out > 0){
> +             msleep(10);
> +             time_out -= 10;
> +             tmp = m88ds3103_readreg(state, 0xa1);           
> +             if ((tmp & 0x40) == 0)
> +                     break;
> +     }
> +     if (time_out == 0){
> +             tmp = m88ds3103_readreg(state, 0xa1);
> +             tmp &= ~0x80;
> +             tmp |= 0x40;
> +             m88ds3103_writereg(state, 0xa1, tmp);
> +             ret = 1;
> +     }
> +     tmp = m88ds3103_readreg(state, 0xa2);
> +     tmp &= ~0xc0;
> +     tmp |= 0x80;
> +     m88ds3103_writereg(state, 0xa2, tmp);   
> +     return ret;
> +}
> +
> +
> +static int m88ds3103_diseqc_send_burst(struct dvb_frontend *fe,
> +                                     fe_sec_mini_cmd_t burst)
> +{
> +     struct m88ds3103_state *state = fe->demodulator_priv;
> +     u8      val, time_out;
> +     
> +     dprintk("%s()\n", __func__);
> +
> +     val = m88ds3103_readreg(state, 0xa2);
> +     val &= ~0xc0;
> +     if(state->demod_id == DS3103_ID)
> +             val &= 0xdf; /* Normal mode */
> +     m88ds3103_writereg(state, 0xa2, val);
> +     /* DiSEqC burst */
> +     if (burst == SEC_MINI_B)
> +             m88ds3103_writereg(state, 0xa1, 0x01);
> +     else
> +             m88ds3103_writereg(state, 0xa1, 0x02);
> +
> +     msleep(13);
> +
> +     time_out = 5;
> +     do{
> +             val = m88ds3103_readreg(state, 0xa1);
> +             if ((val & 0x40) == 0)
> +                     break;
> +             msleep(1);
> +             time_out --;
> +     } while (time_out > 0);
> +
> +     val = m88ds3103_readreg(state, 0xa2);
> +     val &= ~0xc0;
> +     val |= 0x80;
> +     m88ds3103_writereg(state, 0xa2, val);
> +     
> +     return 0;
> +}
> +
> +static void m88ds3103_release(struct dvb_frontend *fe)
> +{
> +     struct m88ds3103_state *state = fe->demodulator_priv;
> +
> +     dprintk("%s\n", __func__);
> +     kfree(state);
> +}
> +
> +static int m88ds3103_check_id(struct m88ds3103_state *state)
> +{
> +     int val_00, val_01;
> +     
> +     /*check demod id*/
> +     val_01 = m88ds3103_readreg(state, 0x01);
> +     printk(KERN_INFO "DS3000 chip version: %x attached.\n", val_01);
> +                     
> +     if(val_01 == 0xD0)
> +             state->demod_id = DS3103_ID;
> +     else if(val_01 == 0xC0)
> +             state->demod_id = DS3000_ID;
> +     else
> +             state->demod_id = UNKNOW_ID;
> +             
> +     /*check tuner id*/
> +     val_00 = m88ds3103_tuner_readreg(state, 0x00);
> +     printk(KERN_INFO "TS202x chip version[1]: %x attached.\n", val_00);
> +     val_00 &= 0x03;
> +     if(val_00 == 0)
> +     {
> +             m88ds3103_tuner_writereg(state, 0x00, 0x01);
> +             msleep(3);              
> +     }
> +     m88ds3103_tuner_writereg(state, 0x00, 0x03);
> +     msleep(5);
> +     
> +     val_00 = m88ds3103_tuner_readreg(state, 0x00);
> +     printk(KERN_INFO "TS202x chip version[2]: %x attached.\n", val_00);
> +     val_00 &= 0xff;
> +     if((val_00 == 0x01) || (val_00 == 0x41) || (val_00 == 0x81))
> +             state->tuner_id = TS2020_ID;
> +     else if(((val_00 & 0xc0)== 0xc0) || (val_00 == 0x83))
> +             state->tuner_id = TS2022_ID;
> +     else
> +             state->tuner_id = UNKNOW_ID;
> +                     
> +     return state->demod_id; 
> +}
> +
> +static struct dvb_frontend_ops m88ds3103_ops;
> +static int m88ds3103_initilaze(struct dvb_frontend *fe);
> +
> +struct dvb_frontend *m88ds3103_attach(const struct m88ds3103_config *config,
> +                                 struct i2c_adapter *i2c)
> +{
> +     struct m88ds3103_state *state = NULL;
> +
> +     dprintk("%s\n", __func__);
> +
> +     /* allocate memory for the internal state */
> +     state = kzalloc(sizeof(struct m88ds3103_state), GFP_KERNEL);
> +     if (state == NULL) {
> +             printk(KERN_ERR "Unable to kmalloc\n");
> +             goto error2;
> +     }
> +
> +     state->config = config;
> +     state->i2c = i2c;
> +     state->preBer = 0xffff;
> +     state->delivery_system = SYS_DVBS; /*Default to DVB-S.*/
> +     
> +     /* check demod id */
> +     if(m88ds3103_check_id(state) == UNKNOW_ID){
> +             printk(KERN_ERR "Unable to find Montage chip\n");
> +             goto error3;
> +     }
> +
> +     memcpy(&state->frontend.ops, &m88ds3103_ops,
> +                     sizeof(struct dvb_frontend_ops));
> +     state->frontend.demodulator_priv = state;
> +     
> +     m88ds3103_initilaze(&state->frontend);
> +     
> +     return &state->frontend;
> +
> +error3:
> +     kfree(state);
> +error2:
> +     return NULL;
> +}
> +EXPORT_SYMBOL(m88ds3103_attach);
> +
> +static int m88ds3103_set_carrier_offset(struct dvb_frontend *fe,
> +                                     s32 carrier_offset_khz)
> +{
> +     struct m88ds3103_state *state = fe->demodulator_priv;
> +     s32 tmp;
> +
> +     tmp = carrier_offset_khz;
> +     tmp *= 65536;
> +     
> +     tmp = (2*tmp + MT_FE_MCLK_KHZ) / (2*MT_FE_MCLK_KHZ);
> +
> +     if (tmp < 0)
> +             tmp += 65536;
> +
> +     m88ds3103_writereg(state, 0x5f, tmp >> 8);
> +     m88ds3103_writereg(state, 0x5e, tmp & 0xff);
> +
> +     return 0;
> +}
> +
> +static int m88ds3103_set_symrate(struct dvb_frontend *fe)
> +{
> +     struct m88ds3103_state *state = fe->demodulator_priv;
> +     struct dtv_frontend_properties *c = &fe->dtv_property_cache;
> +     u16 value;
> +     
> +     value = (((c->symbol_rate / 1000) << 15) + (MT_FE_MCLK_KHZ / 4)) / 
> (MT_FE_MCLK_KHZ / 2);
> +     m88ds3103_writereg(state, 0x61, value & 0x00ff);
> +     m88ds3103_writereg(state, 0x62, (value & 0xff00) >> 8);
> +
> +     return 0;
> +}
> +
> +static int m88ds3103_set_CCI(struct dvb_frontend *fe)
> +{
> +     struct m88ds3103_state *state = fe->demodulator_priv;
> +     u8 tmp;
> +
> +     tmp = m88ds3103_readreg(state, 0x56);
> +     tmp &= ~0x01;
> +     m88ds3103_writereg(state, 0x56, tmp);
> +
> +     tmp = m88ds3103_readreg(state, 0x76);
> +     tmp &= ~0x80;
> +     m88ds3103_writereg(state, 0x76, tmp);
> +
> +     return 0;
> +}
> +
> +static int m88ds3103_init_reg(struct m88ds3103_state *state, const u8 
> *p_reg_tab, u32 size)
> +{
> +     u32 i;
> +     
> +     for(i = 0; i < size; i+=2)
> +             m88ds3103_writereg(state, p_reg_tab[i], p_reg_tab[i+1]);
> +             
> +     return 0;
> +}
> +
> +static int m88ds3103_demod_connect(struct dvb_frontend *fe, s32 
> carrier_offset_khz) 
> +{
> +     struct m88ds3103_state *state = fe->demodulator_priv;
> +     struct dtv_frontend_properties *c = &fe->dtv_property_cache;
> +     u16 value;
> +     u8 val1,val2,data;
> +     
> +     dprintk("connect delivery system = %d\n", state->delivery_system);
> +     
> +     /* ds3000 global reset */
> +     m88ds3103_writereg(state, 0x07, 0x80);
> +     m88ds3103_writereg(state, 0x07, 0x00);
> +     /* ds3000 build-in uC reset */
> +     m88ds3103_writereg(state, 0xb2, 0x01);
> +     /* ds3000 software reset */
> +     m88ds3103_writereg(state, 0x00, 0x01);
> +
> +     switch (state->delivery_system) {
> +     case SYS_DVBS:
> +             /* initialise the demod in DVB-S mode */
> +             if(state->demod_id == DS3000_ID){
> +                     m88ds3103_init_reg(state, ds3000_dvbs_init_tab, 
> sizeof(ds3000_dvbs_init_tab));
> +                     
> +                     value = m88ds3103_readreg(state, 0xfe);
> +                     value &= 0xc0;
> +                     value |= 0x1b;
> +                     m88ds3103_writereg(state, 0xfe, value);
> +                     
> +                     if(state->config->ci_mode)
> +                             val1 = 0x80;
> +                     else if(state->config->ts_mode)
> +                             val1 = 0x60;
> +                     else
> +                             val1 = 0x20;
> +                     m88ds3103_writereg(state, 0xfd, val1);
> +                     
> +             }else if(state->demod_id == DS3103_ID){
> +                     m88ds3103_init_reg(state, ds3103_dvbs_init_tab, 
> sizeof(ds3103_dvbs_init_tab));
> +                     
> +                     /* set ts clock */
> +                     if(state->config->ts_mode == 0) {
> +                             val1 = 3; val2 = 3;
> +                     }else{
> +                             val1 = 0; val2 = 0;
> +                     }
> +                     val1 -= 1; val2 -= 1;
> +                     val1 &= 0x3f; val2 &= 0x3f;
> +                     data = m88ds3103_readreg(state, 0xfe);
> +                     data &= 0xf0;
> +                     data |= (val2 >> 2) & 0x0f;
> +                     m88ds3103_writereg(state, 0xfe, data);
> +                     data = (val2 & 0x03) << 6;
> +                     data |= val1;
> +                     m88ds3103_writereg(state, 0xea, data);
> +                     
> +                     m88ds3103_writereg(state, 0x4d, 0xfd & 
> m88ds3103_readreg(state, 0x4d));
> +                     m88ds3103_writereg(state, 0x30, 0xef & 
> m88ds3103_readreg(state, 0x30));
> +                     
> +                     /* set master clock */
> +                     val1 = m88ds3103_readreg(state, 0x22);
> +                     val2 = m88ds3103_readreg(state, 0x24);
> +                     
> +                     val1 &= 0x3f;
> +                     val2 &= 0x3f;
> +                     val1 |= 0x80;
> +                     val2 |= 0x40;
> +
> +                     m88ds3103_writereg(state, 0x22, val1);
> +                     m88ds3103_writereg(state, 0x24, val2);  
> +                     
> +                     if(state->config->ci_mode)
> +                             val1 = 0x03;
> +                     else if(state->config->ts_mode)
> +                             val1 = 0x06;
> +                     else
> +                             val1 = 0x42;
> +                     m88ds3103_writereg(state, 0xfd, val1);          
> +             }
> +             break;
> +     case SYS_DVBS2:
> +             /* initialise the demod in DVB-S2 mode */
> +             if(state->demod_id == DS3000_ID){
> +                     m88ds3103_init_reg(state, ds3000_dvbs2_init_tab, 
> sizeof(ds3000_dvbs2_init_tab));
> +             
> +                     if (c->symbol_rate >= 30000000)
> +                             m88ds3103_writereg(state, 0xfe, 0x54);
> +                     else
> +                             m88ds3103_writereg(state, 0xfe, 0x98);
> +                                                             
> +             }else if(state->demod_id == DS3103_ID){
> +                     m88ds3103_init_reg(state, ds3103_dvbs2_init_tab, 
> sizeof(ds3103_dvbs2_init_tab));
> +
> +                     /* set ts clock */
> +                     if(state->config->ts_mode == 0){
> +                             val1 = 5; val2 = 4;
> +                     }else{
> +                             val1 = 0; val2 = 0;
> +                     }
> +                     val1 -= 1; val2 -= 1;
> +                     val1 &= 0x3f; val2 &= 0x3f;
> +                     data = m88ds3103_readreg(state, 0xfe);
> +                     data &= 0xf0;
> +                     data |= (val2 >> 2) & 0x0f;
> +                     m88ds3103_writereg(state, 0xfe, data);
> +                     data = (val2 & 0x03) << 6;
> +                     data |= val1;
> +                     m88ds3103_writereg(state, 0xea, data);
> +                     
> +                     m88ds3103_writereg(state, 0x4d, 0xfd & 
> m88ds3103_readreg(state, 0x4d));
> +                     m88ds3103_writereg(state, 0x30, 0xef & 
> m88ds3103_readreg(state, 0x30));
> +                     
> +                     /* set master clock */
> +                     val1 = m88ds3103_readreg(state, 0x22);
> +                     val2 = m88ds3103_readreg(state, 0x24);
> +                     
> +                     val1 &= 0x3f;
> +                     val2 &= 0x3f;
> +                     if(state->config->ts_mode == 1){
> +                             val1 |= 0x80;
> +                             val2 |= 0x40;
> +                     }else{
> +                             if (c->symbol_rate >= 28000000){
> +                                     val1 |= 0xc0;
> +                             }else if (c->symbol_rate >= 18000000){
> +                                     val2 |= 0x40;
> +                             }else{
> +                                     val1 |= 0x80;
> +                                     val2 |= 0x40;
> +                             }                               
> +                     }
> +                     m88ds3103_writereg(state, 0x22, val1);
> +                     m88ds3103_writereg(state, 0x24, val2);                  
>                 
> +             }
> +             
> +             if(state->config->ci_mode)
> +                     val1 = 0x03;
> +             else if(state->config->ts_mode)
> +                     val1 = 0x06;
> +             else
> +                     val1 = 0x42;
> +             m88ds3103_writereg(state, 0xfd, val1);
> +             
> +             break;
> +     default:
> +             return 1;
> +     }
> +     /* disable 27MHz clock output */
> +     m88ds3103_writereg(state, 0x29, 0x80);
> +     /* enable ac coupling */
> +     m88ds3103_writereg(state, 0x25, 0x8a);
> +
> +     if ((c->symbol_rate / 1000) <= 3000){
> +             m88ds3103_writereg(state, 0xc3, 0x08); /* 8 * 32 * 100 / 64 = 
> 400*/
> +             m88ds3103_writereg(state, 0xc8, 0x20);
> +             m88ds3103_writereg(state, 0xc4, 0x08); /* 8 * 0 * 100 / 128 = 
> 0*/
> +             m88ds3103_writereg(state, 0xc7, 0x00);
> +     }else if((c->symbol_rate / 1000) <= 10000){
> +             m88ds3103_writereg(state, 0xc3, 0x08); /* 8 * 16 * 100 / 64 = 
> 200*/
> +             m88ds3103_writereg(state, 0xc8, 0x10);
> +             m88ds3103_writereg(state, 0xc4, 0x08); /* 8 * 0 * 100 / 128 = 
> 0*/
> +             m88ds3103_writereg(state, 0xc7, 0x00);
> +     }else{
> +             m88ds3103_writereg(state, 0xc3, 0x08); /* 8 * 6 * 100 / 64 = 
> 75*/
> +             m88ds3103_writereg(state, 0xc8, 0x06);
> +             m88ds3103_writereg(state, 0xc4, 0x08); /* 8 * 0 * 100 / 128 = 
> 0*/
> +             m88ds3103_writereg(state, 0xc7, 0x00);
> +     }
> +
> +     m88ds3103_set_symrate(fe);
> +     
> +     m88ds3103_set_CCI(fe);
> +
> +     m88ds3103_set_carrier_offset(fe, carrier_offset_khz);
> +             
> +     /* ds3000 out of software reset */
> +     m88ds3103_writereg(state, 0x00, 0x00);
> +     /* start ds3000 build-in uC */
> +     m88ds3103_writereg(state, 0xb2, 0x00);  
> +     
> +     return 0;
> +}
> +
> +static int m88ds3103_set_frontend(struct dvb_frontend *fe)
> +{
> +     struct m88ds3103_state *state = fe->demodulator_priv;
> +     struct dtv_frontend_properties *c = &fe->dtv_property_cache;
> +
> +     int i;
> +     fe_status_t status;
> +     u8 lpf_mxdiv, mlpf_max, mlpf_min, nlpf, div4, capCode, changePLL;
> +     s32 offset_khz, lpf_offset_KHz;
> +     u16 value, ndiv, lpf_coeff;
> +     u32 f3db, gdiv28, realFreq;
> +     u8 RFgain;
> +
> +     dprintk("%s() ", __func__);
> +     dprintk("c frequency = %d\n", c->frequency);
> +     dprintk("symbol rate = %d\n", c->symbol_rate);
> +     dprintk("delivery system = %d\n", c->delivery_system);
> +     
> +     realFreq = c->frequency;
> +     lpf_offset_KHz = 0;
> +     if(c->symbol_rate < 5000000){
> +             lpf_offset_KHz = FREQ_OFFSET_AT_SMALL_SYM_RATE_KHz;
> +             realFreq += FREQ_OFFSET_AT_SMALL_SYM_RATE_KHz;
> +     }
> +     
> +     if (state->config->set_ts_params)
> +             state->config->set_ts_params(fe, 0);
> +
> +     div4 = 0;
> +     RFgain = 0;
> +     if(state->tuner_id == TS2022_ID){
> +             m88ds3103_tuner_writereg(state, 0x10, 0x0a);
> +             m88ds3103_tuner_writereg(state, 0x11, 0x40);
> +             if (realFreq < 1103000) {
> +                     m88ds3103_tuner_writereg(state, 0x10, 0x1b);
> +                     div4 = 1;
> +                     ndiv = (realFreq * (6 + 8) * 4)/MT_FE_CRYSTAL_KHZ;      
>                         
> +             }else {
> +                     ndiv = (realFreq * (6 + 8) * 2)/MT_FE_CRYSTAL_KHZ;
> +             }
> +             ndiv = ndiv + ndiv%2;
> +             if(ndiv < 4095)
> +                     ndiv = ndiv - 1024;
> +             else if (ndiv < 6143)
> +                     ndiv = ndiv + 1024;
> +             else
> +                     ndiv = ndiv + 3072;     
> +             
> +             m88ds3103_tuner_writereg(state, 0x01, (ndiv & 0x3f00) >> 8);    
>                                                                               
>   
> +     }else{
> +             m88ds3103_tuner_writereg(state, 0x10, 0x00);                    
> +             if (realFreq < 1146000){
> +                     m88ds3103_tuner_writereg(state, 0x10, 0x11);
> +                     div4 = 1;
> +                     ndiv = (realFreq * (6 + 8) * 4) / MT_FE_CRYSTAL_KHZ;
> +             }else{
> +                     m88ds3103_tuner_writereg(state, 0x10, 0x01);
> +                     ndiv = (realFreq * (6 + 8) * 2) / MT_FE_CRYSTAL_KHZ;
> +             }
> +             ndiv = ndiv + ndiv%2;
> +             ndiv = ndiv - 1024;
> +             m88ds3103_tuner_writereg(state, 0x01, (ndiv>>8)&0x0f);
> +     }
> +     /* set pll */
> +     m88ds3103_tuner_writereg(state, 0x02, ndiv & 0x00ff);
> +     m88ds3103_tuner_writereg(state, 0x03, 0x06);
> +     m88ds3103_tuner_writereg(state, 0x51, 0x0f);
> +     m88ds3103_tuner_writereg(state, 0x51, 0x1f);
> +     m88ds3103_tuner_writereg(state, 0x50, 0x10);
> +     m88ds3103_tuner_writereg(state, 0x50, 0x00);    
> +
> +     if(state->tuner_id == TS2022_ID){
> +             if(( realFreq >= 1650000 ) && (realFreq <= 1850000)){
> +                     msleep(5);
> +                     value = m88ds3103_tuner_readreg(state, 0x14);
> +                     value &= 0x7f;
> +                     if(value < 64){
> +                             m88ds3103_tuner_writereg(state, 0x10, 0x82);
> +                             m88ds3103_tuner_writereg(state, 0x11, 0x6f);
> +
> +                             m88ds3103_tuner_writereg(state, 0x51, 0x0f);
> +                             m88ds3103_tuner_writereg(state, 0x51, 0x1f);
> +                             m88ds3103_tuner_writereg(state, 0x50, 0x10);
> +                             m88ds3103_tuner_writereg(state, 0x50, 0x00);
> +                     }
> +             }
> +             msleep(5);
> +             value = m88ds3103_tuner_readreg(state, 0x14);
> +             value &= 0x1f;
> +
> +             if(value > 19){
> +                     value = m88ds3103_tuner_readreg(state, 0x10);
> +                     value &= 0x1d;
> +                     m88ds3103_tuner_writereg(state, 0x10, value);
> +             }                               
> +     }else{
> +             msleep(5);
> +             value = m88ds3103_tuner_readreg(state, 0x66);
> +             changePLL = (((value & 0x80) >> 7) != div4);
> +
> +             if(changePLL){
> +                     m88ds3103_tuner_writereg(state, 0x10, 0x11);
> +                     div4 = 1;
> +                     ndiv = (realFreq * (6 + 8) * 4)/MT_FE_CRYSTAL_KHZ;
> +                     ndiv = ndiv + ndiv%2;
> +                     ndiv = ndiv - 1024;
> +                                     
> +                     m88ds3103_tuner_writereg(state, 0x01, (ndiv>>8) & 0x0f);
> +                     m88ds3103_tuner_writereg(state, 0x02, ndiv & 0xff);
> +                     
> +                     m88ds3103_tuner_writereg(state, 0x51, 0x0f);
> +                     m88ds3103_tuner_writereg(state, 0x51, 0x1f);
> +                     m88ds3103_tuner_writereg(state, 0x50, 0x10);
> +                     m88ds3103_tuner_writereg(state, 0x50, 0x00);
> +             }               
> +     }
> +     /*set the RF gain*/
> +     if(state->tuner_id == TS2020_ID)
> +             m88ds3103_tuner_writereg(state, 0x60, 0x79);
> +                     
> +     m88ds3103_tuner_writereg(state, 0x51, 0x17);
> +     m88ds3103_tuner_writereg(state, 0x51, 0x1f);
> +     m88ds3103_tuner_writereg(state, 0x50, 0x08);
> +     m88ds3103_tuner_writereg(state, 0x50, 0x00);
> +     msleep(5);
> +
> +     if(state->tuner_id == TS2020_ID){
> +             RFgain = m88ds3103_tuner_readreg(state, 0x3d);
> +             RFgain &= 0x0f;
> +             if(RFgain < 15){
> +                     if(RFgain < 4) 
> +                             RFgain = 0;
> +                     else
> +                             RFgain = RFgain -3;
> +                     value = ((RFgain << 3) | 0x01) & 0x79;
> +                     m88ds3103_tuner_writereg(state, 0x60, value);
> +                     m88ds3103_tuner_writereg(state, 0x51, 0x17);
> +                     m88ds3103_tuner_writereg(state, 0x51, 0x1f);
> +                     m88ds3103_tuner_writereg(state, 0x50, 0x08);
> +                     m88ds3103_tuner_writereg(state, 0x50, 0x00);
> +             }
> +     }
> +     
> +     /* set the LPF */
> +     if(state->tuner_id == TS2022_ID){
> +             m88ds3103_tuner_writereg(state, 0x25, 0x00);
> +             m88ds3103_tuner_writereg(state, 0x27, 0x70);
> +             m88ds3103_tuner_writereg(state, 0x41, 0x09);
> +             m88ds3103_tuner_writereg(state, 0x08, 0x0b);
> +     }
> +
> +     f3db = ((c->symbol_rate / 1000) *135) / 200 + 2000;
> +     f3db += lpf_offset_KHz;
> +     if (f3db < 7000)
> +             f3db = 7000;
> +     if (f3db > 40000)
> +             f3db = 40000;
> +                     
> +     gdiv28 = (MT_FE_CRYSTAL_KHZ / 1000 * 1694 + 500) / 1000;
> +     m88ds3103_tuner_writereg(state, 0x04, gdiv28 & 0xff);
> +     m88ds3103_tuner_writereg(state, 0x51, 0x1b);
> +     m88ds3103_tuner_writereg(state, 0x51, 0x1f);
> +     m88ds3103_tuner_writereg(state, 0x50, 0x04);
> +     m88ds3103_tuner_writereg(state, 0x50, 0x00);
> +     msleep(5);
> +
> +     value = m88ds3103_tuner_readreg(state, 0x26);
> +     capCode = value & 0x3f;
> +     if(state->tuner_id == TS2022_ID){
> +             m88ds3103_tuner_writereg(state, 0x41, 0x0d);
> +
> +             m88ds3103_tuner_writereg(state, 0x51, 0x1b);
> +             m88ds3103_tuner_writereg(state, 0x51, 0x1f);
> +             m88ds3103_tuner_writereg(state, 0x50, 0x04);
> +             m88ds3103_tuner_writereg(state, 0x50, 0x00);
> +
> +             msleep(2);
> +
> +             value = m88ds3103_tuner_readreg(state, 0x26);
> +             value &= 0x3f;
> +             value = (capCode + value) / 2;          
> +     }
> +     else
> +             value = capCode;
> +             
> +     gdiv28 = gdiv28 * 207 / (value * 2 + 151);      
> +     mlpf_max = gdiv28 * 135 / 100;
> +     mlpf_min = gdiv28 * 78 / 100;
> +     if (mlpf_max > 63)
> +             mlpf_max = 63;
> +
> +     if(state->tuner_id == TS2022_ID)
> +             lpf_coeff = 3200;
> +     else
> +             lpf_coeff = 2766;
> +             
> +     nlpf = (f3db * gdiv28 * 2 / lpf_coeff / (MT_FE_CRYSTAL_KHZ / 1000)  + 
> 1) / 2 ;  
> +     if (nlpf > 23) nlpf = 23;
> +     if (nlpf < 1) nlpf = 1;
> +
> +     lpf_mxdiv = (nlpf * (MT_FE_CRYSTAL_KHZ / 1000) * lpf_coeff * 2 / f3db + 
> 1) / 2;
> +
> +     if (lpf_mxdiv < mlpf_min){
> +             nlpf++;
> +             lpf_mxdiv = (nlpf * (MT_FE_CRYSTAL_KHZ / 1000) * lpf_coeff * 2  
> / f3db + 1) / 2;
> +     }
> +
> +     if (lpf_mxdiv > mlpf_max)
> +             lpf_mxdiv = mlpf_max;
> +
> +     m88ds3103_tuner_writereg(state, 0x04, lpf_mxdiv);
> +     m88ds3103_tuner_writereg(state, 0x06, nlpf);
> +     m88ds3103_tuner_writereg(state, 0x51, 0x1b);
> +     m88ds3103_tuner_writereg(state, 0x51, 0x1f);
> +     m88ds3103_tuner_writereg(state, 0x50, 0x04);
> +     m88ds3103_tuner_writereg(state, 0x50, 0x00);
> +     msleep(5);
> +     
> +     if(state->tuner_id == TS2022_ID){
> +             msleep(2);
> +             value = m88ds3103_tuner_readreg(state, 0x26);
> +             capCode = value & 0x3f;
> +
> +             m88ds3103_tuner_writereg(state, 0x41, 0x09);
> +
> +             m88ds3103_tuner_writereg(state, 0x51, 0x1b);
> +             m88ds3103_tuner_writereg(state, 0x51, 0x1f);
> +             m88ds3103_tuner_writereg(state, 0x50, 0x04);
> +             m88ds3103_tuner_writereg(state, 0x50, 0x00);
> +
> +             msleep(2);
> +             value = m88ds3103_tuner_readreg(state, 0x26);
> +             value &= 0x3f;
> +             value = (capCode + value) / 2;
> +
> +             value = value | 0x80;
> +             m88ds3103_tuner_writereg(state, 0x25, value);
> +             m88ds3103_tuner_writereg(state, 0x27, 0x30);
> +
> +             m88ds3103_tuner_writereg(state, 0x08, 0x09);            
> +     }
> +
> +     /* Set the BB gain */
> +     m88ds3103_tuner_writereg(state, 0x51, 0x1e);
> +     m88ds3103_tuner_writereg(state, 0x51, 0x1f);
> +     m88ds3103_tuner_writereg(state, 0x50, 0x01);
> +     m88ds3103_tuner_writereg(state, 0x50, 0x00);
> +     if(state->tuner_id == TS2020_ID){
> +             if(RFgain == 15){
> +                     msleep(40);
> +                     value = m88ds3103_tuner_readreg(state, 0x21);
> +                     value &= 0x0f;
> +                     if(value < 3){
> +                             m88ds3103_tuner_writereg(state, 0x60, 0x61);
> +                             m88ds3103_tuner_writereg(state, 0x51, 0x17);
> +                             m88ds3103_tuner_writereg(state, 0x51, 0x1f);
> +                             m88ds3103_tuner_writereg(state, 0x50, 0x08);
> +                             m88ds3103_tuner_writereg(state, 0x50, 0x00);
> +                     }                       
> +             }
> +     }
> +     msleep(60);
> +     
> +     offset_khz = (ndiv - ndiv % 2 + 1024) * MT_FE_CRYSTAL_KHZ
> +             / (6 + 8) / (div4 + 1) / 2 - realFreq;
> +
> +     m88ds3103_demod_connect(fe, offset_khz+lpf_offset_KHz);
> +
> +     for (i = 0; i < 30 ; i++) {
> +             m88ds3103_read_status(fe, &status);
> +             if (status & FE_HAS_LOCK){
> +                     break;
> +                }
> +             msleep(20);
> +     }
> +     
> +     if((status & FE_HAS_LOCK) == 0){
> +             state->delivery_system = (state->delivery_system == SYS_DVBS) ? 
> SYS_DVBS2 : SYS_DVBS;
> +             m88ds3103_demod_connect(fe, offset_khz);
> +     
> +             for (i = 0; i < 30 ; i++) {
> +                     m88ds3103_read_status(fe, &status);
> +                     if (status & FE_HAS_LOCK){
> +                             break;
> +                     }
> +                     msleep(20);
> +             }
> +     }
> +     
> +     if (status & FE_HAS_LOCK){
> +             if(state->config->start_ctrl){
> +                     if(state->first_lock == 0){
> +                             state->config->start_ctrl(fe);
> +                             state->first_lock = 1;  
> +                     }
> +             }               
> +     }
> +             
> +     return 0;
> +}
> +
> +static int m88ds3103_tune(struct dvb_frontend *fe,
> +                     bool re_tune,
> +                     unsigned int mode_flags,
> +                     unsigned int *delay,
> +                     fe_status_t *status)
> +{    
> +     *delay = HZ / 5;
> +     
> +     dprintk("%s() ", __func__);
> +     dprintk("re_tune = %d\n", re_tune);
> +     
> +     if (re_tune) {
> +             int ret = m88ds3103_set_frontend(fe);
> +             if (ret)
> +                     return ret;
> +     }
> +     
> +     return m88ds3103_read_status(fe, status);
> +}
> +
> +static enum dvbfe_algo m88ds3103_get_algo(struct dvb_frontend *fe)
> +{
> +     return DVBFE_ALGO_HW;
> +}
> + 
> + /*
> + * Power config will reset and load initial firmware if required
> + */
> +static int m88ds3103_initilaze(struct dvb_frontend *fe)
> +{
> +     struct m88ds3103_state *state = fe->demodulator_priv;
> +     int ret;
> +
> +     dprintk("%s()\n", __func__);
> +     /* hard reset */
> +     m88ds3103_writereg(state, 0x07, 0x80);
> +     m88ds3103_writereg(state, 0x07, 0x00);
> +     msleep(1);
> +     
> +     m88ds3103_writereg(state, 0x08, 0x01 | m88ds3103_readreg(state, 0x08));
> +     msleep(1);
> +
> +     if(state->tuner_id == TS2020_ID){
> +             /* TS2020 init */
> +             m88ds3103_tuner_writereg(state, 0x42, 0x73);
> +             msleep(2);
> +             m88ds3103_tuner_writereg(state, 0x05, 0x01);
> +             m88ds3103_tuner_writereg(state, 0x62, 0xb5);
> +             m88ds3103_tuner_writereg(state, 0x07, 0x02);
> +             m88ds3103_tuner_writereg(state, 0x08, 0x01);
> +     }
> +     else if(state->tuner_id == TS2022_ID){
> +             /* TS2022 init */
> +             m88ds3103_tuner_writereg(state, 0x62, 0x6c);
> +             msleep(2);
> +             m88ds3103_tuner_writereg(state, 0x42, 0x6c);
> +             msleep(2);
> +             m88ds3103_tuner_writereg(state, 0x7d, 0x9d);
> +             m88ds3103_tuner_writereg(state, 0x7c, 0x9a);
> +             m88ds3103_tuner_writereg(state, 0x7a, 0x76);
> +
> +             m88ds3103_tuner_writereg(state, 0x3b, 0x01);
> +             m88ds3103_tuner_writereg(state, 0x63, 0x88);
> +
> +             m88ds3103_tuner_writereg(state, 0x61, 0x85);
> +             m88ds3103_tuner_writereg(state, 0x22, 0x30);
> +             m88ds3103_tuner_writereg(state, 0x30, 0x40);
> +             m88ds3103_tuner_writereg(state, 0x20, 0x23);
> +             m88ds3103_tuner_writereg(state, 0x24, 0x02);
> +             m88ds3103_tuner_writereg(state, 0x12, 0xa0);    
> +     }
> +             
> +     if(state->demod_id == DS3103_ID){
> +             m88ds3103_writereg(state, 0x07, 0xe0);
> +             m88ds3103_writereg(state, 0x07, 0x00);
> +             msleep(1);              
> +     }
> +     m88ds3103_writereg(state, 0xb2, 0x01);
> +     
> +     /* Load the firmware if required */
> +     ret = m88ds3103_load_firmware(fe);
> +     if (ret != 0){
> +             printk(KERN_ERR "%s: Unable initialize firmware\n", __func__);
> +             return ret;
> +     }
> +     if(state->demod_id == DS3103_ID){
> +             m88ds3103_writereg(state, 0x4d, 0xfd & m88ds3103_readreg(state, 
> 0x4d));
> +             m88ds3103_writereg(state, 0x30, 0xef & m88ds3103_readreg(state, 
> 0x30));         
> +     }
> +
> +     return 0;
> +}
> +
> +/*
> + * Initialise or wake up device
> + */
> +static int m88ds3103_initfe(struct dvb_frontend *fe)
> +{
> +     struct m88ds3103_state *state = fe->demodulator_priv;
> +     u8 val;
> +
> +     dprintk("%s()\n", __func__);
> +
> +     /* 1st step to wake up demod */
> +     m88ds3103_writereg(state, 0x08, 0x01 | m88ds3103_readreg(state, 0x08));
> +     m88ds3103_writereg(state, 0x04, 0xfe & m88ds3103_readreg(state, 0x04));
> +     m88ds3103_writereg(state, 0x23, 0xef & m88ds3103_readreg(state, 0x23));
> +     
> +     /* 2nd step to wake up tuner */
> +     val = m88ds3103_tuner_readreg(state, 0x00) & 0xff;
> +     if((val & 0x01) == 0){
> +             m88ds3103_tuner_writereg(state, 0x00, 0x01);
> +             msleep(50);
> +     }
> +     m88ds3103_tuner_writereg(state, 0x00, 0x03);
> +     msleep(50);
> +     
> +     return 0;       
> +}
> +
> +/* Put device to sleep */
> +static int m88ds3103_sleep(struct dvb_frontend *fe)
> +{
> +     struct m88ds3103_state *state = fe->demodulator_priv;
> +
> +     dprintk("%s()\n", __func__);
> +     
> +     /* 1st step to sleep tuner */
> +     m88ds3103_tuner_writereg(state, 0x00, 0x00);
> +     
> +     /* 2nd step to sleep demod */
> +     m88ds3103_writereg(state, 0x08, 0xfe & m88ds3103_readreg(state, 0x08));
> +     m88ds3103_writereg(state, 0x04, 0x01 | m88ds3103_readreg(state, 0x04));
> +     m88ds3103_writereg(state, 0x23, 0x10 | m88ds3103_readreg(state, 0x23));
> +     
> +
> +     return 0;
> +}
> +
> +static struct dvb_frontend_ops m88ds3103_ops = {
> +     .delsys = { SYS_DVBS, SYS_DVBS2},
> +     .info = {
> +             .name = "Montage DS3103/TS2022",
> +             .type = FE_QPSK,
> +             .frequency_min = 950000,
> +             .frequency_max = 2150000,
> +             .frequency_stepsize = 1011, /* kHz for QPSK frontends */
> +             .frequency_tolerance = 5000,
> +             .symbol_rate_min = 1000000,
> +             .symbol_rate_max = 45000000,
> +             .caps = FE_CAN_INVERSION_AUTO |
> +                     FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
> +                     FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
> +                     FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
> +                     FE_CAN_2G_MODULATION |
> +                     FE_CAN_QPSK | FE_CAN_RECOVER
> +     },
> +
> +     .release = m88ds3103_release,
> +
> +     .init = m88ds3103_initfe,
> +     .sleep = m88ds3103_sleep,
> +     .read_status = m88ds3103_read_status,
> +     .read_ber = m88ds3103_read_ber,
> +     .read_signal_strength = m88ds3103_read_signal_strength,
> +     .read_snr = m88ds3103_read_snr,
> +     .read_ucblocks = m88ds3103_read_ucblocks,
> +     .set_tone = m88ds3103_set_tone,
> +     .set_voltage = m88ds3103_set_voltage,
> +     .diseqc_send_master_cmd = m88ds3103_send_diseqc_msg,
> +     .diseqc_send_burst = m88ds3103_diseqc_send_burst,
> +     .get_frontend_algo = m88ds3103_get_algo,
> +     .tune = m88ds3103_tune,
> +     .set_frontend = m88ds3103_set_frontend,
> +};
> +
> +MODULE_DESCRIPTION("DVB Frontend module for Montage DS3103/TS2022 hardware");
> +MODULE_AUTHOR("Max nibble");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/media/dvb/frontends/m88ds3103.h 
> b/drivers/media/dvb/frontends/m88ds3103.h
> new file mode 100644
> index 0000000..c7b690e
> --- /dev/null
> +++ b/drivers/media/dvb/frontends/m88ds3103.h
> @@ -0,0 +1,53 @@
> +/*
> +    Montage Technology M88DS3103/M88TS2022 - DVBS/S2 Satellite demod/tuner 
> driver
> +
> +    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 M88DS3103_H
> +#define M88DS3103_H
> +
> +#include <linux/dvb/frontend.h>
> +
> +struct m88ds3103_config {
> +     /* the demodulator's i2c address */
> +     u8 demod_address;
> +     u8 ci_mode;
> +     u8 pin_ctrl;
> +     u8 ts_mode; /* 0: Parallel, 1: Serial */
> +
> +     /* Set device param to start dma */
> +     int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured);
> +    /* Start to transfer data */
> +    int (*start_ctrl)(struct dvb_frontend *fe);
> +    /* Set LNB voltage */
> +    int (*set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
> +};
> +
> +#if defined(CONFIG_DVB_M88DS3103) || \
> +     (defined(CONFIG_DVB_M88DS3103_MODULE) && defined(MODULE))
> +extern struct dvb_frontend *m88ds3103_attach(
> +       const struct m88ds3103_config *config,
> +       struct i2c_adapter *i2c);
> +#else
> +static inline struct dvb_frontend *m88ds3103_attach(
> +       const struct m88ds3103_config *config,
> +       struct i2c_adapter *i2c)
> +{
> +     printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
> +     return NULL;
> +}
> +#endif /* CONFIG_DVB_M88DS3103 */
> +#endif /* M88DS3103_H */

--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to