From: "nibble.max" <nibble.max@gmail.com>
To: "Mauro Carvalho Chehab" <mchehab@redhat.com>
Cc: linux-media <linux-media@vger.kernel.org>
Subject: Re: Re: [PATCH 1/6] m88ds3103, montage dvb-s/s2 demodulator driver
Date: Fri, 20 Apr 2012 16:01:36 +0800 [thread overview]
Message-ID: <201204201601331714628@gmail.com> (raw)
In-Reply-To: 4F905425.4030102@redhat.com
2012-04-20 15:48:53 nibble.max@gmail.com
Mauro, thank you.
>
>Hi Max,
>
>Em 15-04-2012 12:53, nibble.max escreveu:
>> Montage m88ds3103 demodulator and ts2022 tuner driver.
>>
>> Signed-off-by: Max nibble <nibble.max@gmail.com>
>
>Please always test any patch you send upstream with ./scripts/checkpatch.pl.
>
>It analyses the code and checks if it is following the Linux Coding Style
>(Documentation/CodingStyle).
>
>From what I've seen, there are several small CodingStyle issues on this patch.
>
>There's also another problem here: this driver is mixing an I2C tuner driver
>with the demod one. Please split. If the tuner is simple enough, you an add
>it to:
> drivers/media/common/tuners/tuner-simple.c
>or at:
> drivers/media/dvb/frontends/dvb-pll.c
>
>But please don't mix tuners with demods. Mixing it causes code duplication and
>more time lost when debugging it (as two different version of the same driver
>can have different bugs).
I check the tuner-simple.c and dvb-pll.c is not fit for m88ts202x tuner.
Should we create a new tuner file like "stv6110x"?
>
>I'll analyze it deeper after you fix those two issues.
>
>Thanks,
>Mauro
>
>
>> ---
>> 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.max@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 */
>
>.
next prev parent reply other threads:[~2012-04-20 8:01 UTC|newest]
Thread overview: 56+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-01-22 10:38 [PATCH 1/3] m88brs2000 DVB-S frontend and tuner module Malcolm Priestley
2012-01-26 16:56 ` Mauro Carvalho Chehab
2012-01-27 22:26 ` Malcolm Priestley
2012-04-15 15:53 ` [PATCH 1/6] m88ds3103, montage dvb-s/s2 demodulator driver nibble.max
2012-04-19 18:06 ` Mauro Carvalho Chehab
2012-04-20 8:01 ` nibble.max [this message]
2012-04-19 20:08 ` Mauro Carvalho Chehab
2012-04-20 8:01 ` nibble.max
2012-04-20 9:47 ` Antti Palosaari
2012-04-20 17:24 ` Mauro Carvalho Chehab
2012-04-21 2:45 ` nibble.max
2012-04-23 16:41 ` Antti Palosaari
2012-04-23 19:51 ` Konstantin Dimitrov
2012-04-23 21:04 ` Antti Palosaari
2012-04-27 18:44 ` Konstantin Dimitrov
2012-04-23 21:49 ` Mauro Carvalho Chehab
2012-04-27 19:01 ` Konstantin Dimitrov
2012-04-27 19:36 ` Mauro Carvalho Chehab
2012-04-27 20:37 ` Konstantin Dimitrov
2012-04-27 20:40 ` Konstantin Dimitrov
2012-04-27 20:54 ` Antti Palosaari
2012-04-27 21:01 ` Konstantin Dimitrov
2012-04-27 19:55 ` Antti Palosaari
2012-04-27 20:21 ` Konstantin Dimitrov
2012-04-27 20:42 ` Antti Palosaari
2012-04-27 21:13 ` Konstantin Dimitrov
2012-04-28 3:54 ` nibble.max
2012-04-28 9:17 ` Demod hardware pid filter implement nibble.max
2012-04-28 10:15 ` Antti Palosaari
2012-04-24 2:45 ` Re: [PATCH 1/6] m88ds3103, montage dvb-s/s2 demodulator driver nibble.max
2012-04-26 13:03 ` nibble.max
2012-04-26 13:24 ` Mauro Carvalho Chehab
2012-04-27 7:06 ` [PATCH 1/6 v2] dvbsky, montage dvb-s/s2 TS202x tuner and M88DS3103 " nibble.max
2012-04-27 11:06 ` Mauro Carvalho Chehab
2012-04-27 14:17 ` Re: [PATCH 1/6 v2] dvbsky, montage dvb-s/s2 TS202x tuner and M88DS3103demodulator driver nibble.max
2012-04-27 14:35 ` Mauro Carvalho Chehab
2012-04-27 18:03 ` Konstantin Dimitrov
2012-04-27 7:06 ` [PATCH 2/6 v2] dvbsky, dvb-s/s2 usb box nibble.max
2013-06-30 3:07 ` Fwd: " P. van Gaans
2014-01-15 19:30 ` Mauro Carvalho Chehab
2012-04-27 7:06 ` [PATCH 3/6 v2] dvbsky, dvb-s/s2 PCIe card nibble.max
2012-04-27 7:07 ` [PATCH 4/6 v2] dvbsky, dvb-s/s2 PCI card nibble.max
2012-04-27 7:07 ` [PATCH 5/6 v2] dvbsky, remote control key map nibble.max
2012-04-27 7:07 ` [PATCH 6/6 v2] dvbsky, remote control include header file nibble.max
2012-04-20 17:10 ` [PATCH 1/6] m88ds3103, montage dvb-s/s2 demodulator driver Mauro Carvalho Chehab
2012-04-15 15:53 ` [PATCH 2/6] m88ds3103, dvbsky dvb-s2 usb box nibble.max
2012-04-19 18:09 ` Mauro Carvalho Chehab
2012-04-20 8:08 ` nibble.max
2012-04-20 17:08 ` Mauro Carvalho Chehab
2012-04-15 15:53 ` [PATCH 3/6] m88ds3103, dvbsky dvb-s2 cx23883 pci card nibble.max
2012-04-15 15:53 ` [PATCH 4/6] m88ds3103, dvbsky dvb-s2 cx23885 pcie card nibble.max
2012-04-19 18:11 ` Mauro Carvalho Chehab
2012-04-15 15:53 ` [PATCH 5/6] m88ds3103, dvbsky remote control key map nibble.max
2012-04-19 18:16 ` Mauro Carvalho Chehab
2012-04-20 8:01 ` nibble.max
2012-04-15 15:53 ` [PATCH 6/6] m88ds3103, dvbsky remote control include header file nibble.max
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=201204201601331714628@gmail.com \
--to=nibble.max@gmail.com \
--cc=linux-media@vger.kernel.org \
--cc=mchehab@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).