blob: c1846e1e28cdad39e28c4e90db7704fa8f9b77d6 [file] [log] [blame]
/*
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"
#include "m88ds3103_priv.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)
/*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_get_locked_sym_rate(struct m88ds3103_state *state, u32 *sym_rate_KSs)
{
u16 tmp;
u32 sym_rate_tmp;
u8 val_0x6d, val_0x6e;
val_0x6d = m88ds3103_readreg(state, 0x6d);
val_0x6e = m88ds3103_readreg(state, 0x6e);
tmp = (u16)((val_0x6e<<8) | val_0x6d);
sym_rate_tmp = (u32)(tmp * MT_FE_MCLK_KHZ);
sym_rate_tmp = (u32)(sym_rate_tmp / (1<<16));
*sym_rate_KSs = sym_rate_tmp;
return 0;
}
static int m88ds3103_get_channel_info(struct m88ds3103_state *state, u8 *p_mode, u8 *p_coderate)
{
u8 tmp, val_0x7E;
if(state->delivery_system == SYS_DVBS2){
val_0x7E = m88ds3103_readreg(state, 0x7e);
tmp = (u8)((val_0x7E&0xC0) >> 6);
*p_mode = tmp;
tmp = (u8)(val_0x7E & 0x0f);
*p_coderate = tmp;
} else {
*p_mode = 0;
tmp = m88ds3103_readreg(state, 0xe6);
tmp = (u8)(tmp >> 5);
*p_coderate = tmp;
}
return 0;
}
static int m88ds3103_set_clock_ratio(struct m88ds3103_state *state)
{
u8 val, mod_fac, tmp1, tmp2;
u32 input_datarate, locked_sym_rate_KSs;
u32 MClk_KHz = 96000;
u8 mod_mode, code_rate, divid_ratio = 0;
locked_sym_rate_KSs = 0;
m88ds3103_get_locked_sym_rate(state, &locked_sym_rate_KSs);
if(locked_sym_rate_KSs == 0)
return 0;
m88ds3103_get_channel_info(state, &mod_mode, &code_rate);
if (state->delivery_system == SYS_DVBS2)
{
switch(mod_mode) {
case 1: mod_fac = 3; break;
case 2: mod_fac = 4; break;
case 3: mod_fac = 5; break;
default: mod_fac = 2; break;
}
switch(code_rate) {
case 0: input_datarate = locked_sym_rate_KSs*mod_fac/8/4; break;
case 1: input_datarate = locked_sym_rate_KSs*mod_fac/8/3; break;
case 2: input_datarate = locked_sym_rate_KSs*mod_fac*2/8/5; break;
case 3: input_datarate = locked_sym_rate_KSs*mod_fac/8/2; break;
case 4: input_datarate = locked_sym_rate_KSs*mod_fac*3/8/5; break;
case 5: input_datarate = locked_sym_rate_KSs*mod_fac*2/8/3; break;
case 6: input_datarate = locked_sym_rate_KSs*mod_fac*3/8/4; break;
case 7: input_datarate = locked_sym_rate_KSs*mod_fac*4/8/5; break;
case 8: input_datarate = locked_sym_rate_KSs*mod_fac*5/8/6; break;
case 9: input_datarate = locked_sym_rate_KSs*mod_fac*8/8/9; break;
case 10: input_datarate = locked_sym_rate_KSs*mod_fac*9/8/10; break;
default: input_datarate = locked_sym_rate_KSs*mod_fac*2/8/3; break;
}
if(state->demod_id == DS3000_ID)
input_datarate = input_datarate * 115 / 100;
if(input_datarate < 4800) {tmp1 = 15;tmp2 = 15;} //4.8MHz TS clock
else if(input_datarate < 4966) {tmp1 = 14;tmp2 = 15;} //4.966MHz TS clock
else if(input_datarate < 5143) {tmp1 = 14;tmp2 = 14;} //5.143MHz TS clock
else if(input_datarate < 5333) {tmp1 = 13;tmp2 = 14;} //5.333MHz TS clock
else if(input_datarate < 5538) {tmp1 = 13;tmp2 = 13;} //5.538MHz TS clock
else if(input_datarate < 5760) {tmp1 = 12;tmp2 = 13;} //5.76MHz TS clock allan 0809
else if(input_datarate < 6000) {tmp1 = 12;tmp2 = 12;} //6MHz TS clock
else if(input_datarate < 6260) {tmp1 = 11;tmp2 = 12;} //6.26MHz TS clock
else if(input_datarate < 6545) {tmp1 = 11;tmp2 = 11;} //6.545MHz TS clock
else if(input_datarate < 6857) {tmp1 = 10;tmp2 = 11;} //6.857MHz TS clock
else if(input_datarate < 7200) {tmp1 = 10;tmp2 = 10;} //7.2MHz TS clock
else if(input_datarate < 7578) {tmp1 = 9;tmp2 = 10;} //7.578MHz TS clock
else if(input_datarate < 8000) {tmp1 = 9;tmp2 = 9;} //8MHz TS clock
else if(input_datarate < 8470) {tmp1 = 8;tmp2 = 9;} //8.47MHz TS clock
else if(input_datarate < 9000) {tmp1 = 8;tmp2 = 8;} //9MHz TS clock
else if(input_datarate < 9600) {tmp1 = 7;tmp2 = 8;} //9.6MHz TS clock
else if(input_datarate < 10285) {tmp1 = 7;tmp2 = 7;} //10.285MHz TS clock
else if(input_datarate < 12000) {tmp1 = 6;tmp2 = 6;} //12MHz TS clock
else if(input_datarate < 14400) {tmp1 = 5;tmp2 = 5;} //14.4MHz TS clock
else if(input_datarate < 18000) {tmp1 = 4;tmp2 = 4;} //18MHz TS clock
else {tmp1 = 3;tmp2 = 3;} //24MHz TS clock
if(state->demod_id == DS3000_ID) {
val = (u8)((tmp1<<4) + tmp2);
m88ds3103_writereg(state, 0xfe, val);
} else {
tmp1 = m88ds3103_readreg(state, 0x22);
tmp2 = m88ds3103_readreg(state, 0x24);
tmp1 >>= 6;
tmp1 &= 0x03;
tmp2 >>= 6;
tmp2 &= 0x03;
if((tmp1 == 0x00) && (tmp2 == 0x01))
MClk_KHz = 144000;
else if((tmp1 == 0x00) && (tmp2 == 0x03))
MClk_KHz = 72000;
else if((tmp1 == 0x01) && (tmp2 == 0x01))
MClk_KHz = 115200;
else if((tmp1 == 0x02) && (tmp2 == 0x01))
MClk_KHz = 96000;
else if((tmp1 == 0x03) && (tmp2 == 0x00))
MClk_KHz = 192000;
else
return 0;
if(input_datarate < 5200) /*Max. 2011-12-23 11:55*/
input_datarate = 5200;
if(input_datarate != 0)
divid_ratio = (u8)(MClk_KHz / input_datarate);
else
divid_ratio = 0xFF;
if(divid_ratio > 128)
divid_ratio = 128;
if(divid_ratio < 2)
divid_ratio = 2;
tmp1 = (u8)(divid_ratio / 2);
tmp2 = (u8)(divid_ratio / 2);
if((divid_ratio % 2) != 0)
tmp2 += 1;
tmp1 -= 1;
tmp2 -= 1;
tmp1 &= 0x3f;
tmp2 &= 0x3f;
val = m88ds3103_readreg(state, 0xfe);
val &= 0xF0;
val |= (tmp2 >> 2) & 0x0f;
m88ds3103_writereg(state, 0xfe, val);
val = (u8)((tmp2 & 0x03) << 6);
val |= tmp1;
m88ds3103_writereg(state, 0xea, val);
}
} else {
mod_fac = 2;
switch(code_rate) {
case 4: input_datarate = locked_sym_rate_KSs*mod_fac/2/8; break;
case 3: input_datarate = locked_sym_rate_KSs*mod_fac*2/3/8; break;
case 2: input_datarate = locked_sym_rate_KSs*mod_fac*3/4/8; break;
case 1: input_datarate = locked_sym_rate_KSs*mod_fac*5/6/8; break;
case 0: input_datarate = locked_sym_rate_KSs*mod_fac*7/8/8; break;
default: input_datarate = locked_sym_rate_KSs*mod_fac*3/4/8; break;
}
if(state->demod_id == DS3000_ID)
input_datarate = input_datarate * 115 / 100;
if(input_datarate < 6857) {tmp1 = 7;tmp2 = 7;} //6.857MHz TS clock
else if(input_datarate < 7384) {tmp1 = 6;tmp2 = 7;} //7.384MHz TS clock
else if(input_datarate < 8000) {tmp1 = 6;tmp2 = 6;} //8MHz TS clock
else if(input_datarate < 8727) {tmp1 = 5;tmp2 = 6;} //8.727MHz TS clock
else if(input_datarate < 9600) {tmp1 = 5;tmp2 = 5;} //9.6MHz TS clock
else if(input_datarate < 10666) {tmp1 = 4;tmp2 = 5;} //10.666MHz TS clock
else if(input_datarate < 12000) {tmp1 = 4;tmp2 = 4;} //12MHz TS clock
else if(input_datarate < 13714) {tmp1 = 3;tmp2 = 4;} //13.714MHz TS clock
else if(input_datarate < 16000) {tmp1 = 3;tmp2 = 3;} //16MHz TS clock
else if(input_datarate < 19200) {tmp1 = 2;tmp2 = 3;} //19.2MHz TS clock
else {tmp1 = 2;tmp2 = 2;} //24MHz TS clock
if(state->demod_id == DS3000_ID) {
val = m88ds3103_readreg(state, 0xfe);
val &= 0xc0;
val |= ((u8)((tmp1<<3) + tmp2));
m88ds3103_writereg(state, 0xfe, val);
} else {
if(input_datarate < 5200) /*Max. 2011-12-23 11:55*/
input_datarate = 5200;
if(input_datarate != 0)
divid_ratio = (u8)(MClk_KHz / input_datarate);
else
divid_ratio = 0xFF;
if(divid_ratio > 128)
divid_ratio = 128;
if(divid_ratio < 2)
divid_ratio = 2;
tmp1 = (u8)(divid_ratio / 2);
tmp2 = (u8)(divid_ratio / 2);
if((divid_ratio % 2) != 0)
tmp2 += 1;
tmp1 -= 1;
tmp2 -= 1;
tmp1 &= 0x3f;
tmp2 &= 0x3f;
val = m88ds3103_readreg(state, 0xfe);
val &= 0xF0;
val |= (tmp2 >> 2) & 0x0f;
m88ds3103_writereg(state, 0xfe, val);
val = (u8)((tmp2 & 0x03) << 6);
val |= tmp1;
m88ds3103_writereg(state, 0xea, val);
}
}
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->ci_mode == 2){
val1 = 6; val2 = 6;
}else 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->ci_mode == 2){
val1 = 6; val2 = 6;
}else 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->ci_mode == 2) || (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 dvb_frontend_parameters* params)
{
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->ci_mode == 2)
m88ds3103_set_clock_ratio(state);
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,
struct dvb_frontend_parameters* params,
unsigned int mode_flags,
unsigned int *delay,
fe_status_t *status)
{
*delay = HZ / 5;
dprintk("%s() ", __func__);
dprintk("re_tune = %d\n", params ? 1 : 0);
if (params) {
int ret = m88ds3103_set_frontend(fe, params);
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 = {
.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");