summaryrefslogtreecommitdiff
path: root/linux/drivers/media/dvb/frontends/stv0299.c
diff options
context:
space:
mode:
authorAndrew de Quincy <devnull@localhost>2004-02-23 23:20:29 +0000
committerAndrew de Quincy <devnull@localhost>2004-02-23 23:20:29 +0000
commita3601efd36d390b7437a57e8f8301d80cffe4c13 (patch)
tree013994aa5e7b6e4c3a323d32b435fc8a6f155689 /linux/drivers/media/dvb/frontends/stv0299.c
parenteac35592452cdc3b7e6d9a0684d17c03fac94aba (diff)
downloadmediapointer-dvb-s2-a3601efd36d390b7437a57e8f8301d80cffe4c13.tar.gz
mediapointer-dvb-s2-a3601efd36d390b7437a57e8f8301d80cffe4c13.tar.bz2
Fixes to sort out tuning at low symbol rates
Diffstat (limited to 'linux/drivers/media/dvb/frontends/stv0299.c')
-rw-r--r--linux/drivers/media/dvb/frontends/stv0299.c119
1 files changed, 84 insertions, 35 deletions
diff --git a/linux/drivers/media/dvb/frontends/stv0299.c b/linux/drivers/media/dvb/frontends/stv0299.c
index 19988e4f4..97036259a 100644
--- a/linux/drivers/media/dvb/frontends/stv0299.c
+++ b/linux/drivers/media/dvb/frontends/stv0299.c
@@ -49,6 +49,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/string.h>
+#include <linux/slab.h>
#include <asm/div64.h>
#include "dvb_frontend.h"
@@ -68,12 +69,12 @@ static int stv0299_status = 0;
/* frontend types */
#define UNKNOWN_FRONTEND -1
-#define PHILIPS_SU1278_TSA 0 // SU1278 with TSA5959 synth and datasheet recommended settings
+#define PHILIPS_SU1278_TSA 0 // SU1278 with TSA5059 synth and datasheet recommended settings
#define ALPS_BSRU6 1
#define LG_TDQF_S001F 2
#define PHILIPS_SU1278_TUA 3 // SU1278 with TUA6100 synth
#define SAMSUNG_TBMU24112IMB 4
-#define PHILIPS_SU1278_TSA_TT 5 // SU1278 with TSA5959 synth and TechnoTrend settings
+#define PHILIPS_SU1278_TSA_TT 5 // SU1278 with TSA5059 synth and TechnoTrend settings
/* Master Clock = 88 MHz */
#define M_CLK (88000000UL)
@@ -95,11 +96,18 @@ static struct dvb_frontend_info uni0299_info = {
.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
FE_CAN_QPSK |
- FE_CAN_FEC_AUTO | FE_CAN_INVERSION_AUTO |
+ FE_CAN_FEC_AUTO |
FE_CAN_CLEAN_SETUP
};
+struct stv0299_state {
+ u8 tuner_type;
+ u8 initialised:1;
+ u32 tuner_frequency;
+};
+
+
static u8 init_tab [] = {
0x04, 0x7d, /* F22FR = 0x7d */
/* F22 = f_VCO / 128 / 0x7d = 22 kHz */
@@ -349,7 +357,7 @@ static int tsa5059_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq, int ftype, in
u8 addr;
u32 div;
u8 buf[4];
- int i, divisor, regcode;
+ int divisor, regcode;
dprintk ("%s: freq %i, ftype %i\n", __FUNCTION__, freq, ftype);
@@ -357,7 +365,7 @@ static int tsa5059_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq, int ftype, in
divisor = 500;
regcode = 2;
-
+
// setup frequency divisor
div = freq / divisor;
buf[0] = (div >> 8) & 0x7f;
@@ -374,10 +382,10 @@ static int tsa5059_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq, int ftype, in
if (srate < 4000000) buf[3] |= 1;
- if (freq <= 1250000) buf[3] |= 0;
- else if (freq <= 1550000) buf[3] |= 0x40;
- else if (freq <= 2050000) buf[3] |= 0x80;
- else if (freq <= 2150000) buf[3] |= 0xC0;
+ if (freq < 1250000) buf[3] |= 0;
+ else if (freq < 1550000) buf[3] |= 0x40;
+ else if (freq < 2050000) buf[3] |= 0x80;
+ else if (freq < 2150000) buf[3] |= 0xC0;
break;
case ALPS_BSRU6:
@@ -579,7 +587,7 @@ static int stv0299_init (struct dvb_i2c_bus *i2c, int ftype)
case PHILIPS_SU1278_TSA_TT:
for (i=0; i<sizeof(init_tab_su1278_tsa_tt); i+=2) {
stv0299_writereg (i2c, init_tab_su1278_tsa_tt[i], init_tab_su1278_tsa_tt[i+1]);
- }
+ }
break;
default:
@@ -895,6 +903,7 @@ static int stv0299_set_symbolrate (struct dvb_i2c_bus *i2c, u32 srate, int tuner
stv0299_writereg (i2c, 0x1c, 0x12);
stv0299_writereg (i2c, 0x2d, 0x05);
}
+
stv0299_writereg (i2c, 0x0e, 0x23);
stv0299_writereg (i2c, 0x0f, 0x94);
stv0299_writereg (i2c, 0x10, 0x39);
@@ -984,9 +993,9 @@ static int stv0299_get_symbolrate (struct dvb_i2c_bus *i2c, int tuner_type)
static int uni0299_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
{
- int tuner_type = (long) fe->data;
struct dvb_i2c_bus *i2c = fe->i2c;
-
+ struct stv0299_state *state = (struct stv0299_state *) fe->data;
+
dprintk ("%s\n", __FUNCTION__);
switch (cmd) {
@@ -995,7 +1004,7 @@ static int uni0299_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
struct dvb_frontend_info* tmp = (struct dvb_frontend_info*) arg;
memcpy (arg, &uni0299_info, sizeof(struct dvb_frontend_info));
- if (tuner_type == PHILIPS_SU1278_TSA_TT) {
+ if (state->tuner_type == PHILIPS_SU1278_TSA_TT) {
tmp->frequency_tolerance = M_CLK_SU1278_TSA_TT / 2000;
}
break;
@@ -1072,25 +1081,46 @@ static int uni0299_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
case FE_SET_FRONTEND:
{
- struct dvb_frontend_parameters *p = arg;
+ struct dvb_frontend_parameters *p = arg;
- dprintk ("%s : FE_SET_FRONTEND\n", __FUNCTION__);
+ dprintk ("%s : FE_SET_FRONTEND\n", __FUNCTION__);
- pll_set_tv_freq (i2c, p->frequency, tuner_type,
- p->u.qpsk.symbol_rate);
+ if (p->inversion == INVERSION_OFF) {
+ stv0299_writereg(i2c, 0x0c, stv0299_readreg(i2c, 0x0c) & 0xfe);
+ } else if (p->inversion == INVERSION_ON) {
+ stv0299_writereg(i2c, 0x0c, stv0299_readreg(i2c, 0x0c) | 1);
+ } else {
+ printk("stv0299 does not support auto-inversion\n");
+ return -EINVAL;
+ }
stv0299_set_FEC (i2c, p->u.qpsk.fec_inner);
- stv0299_set_symbolrate (i2c, p->u.qpsk.symbol_rate, tuner_type);
- stv0299_writereg (i2c, 0x22, 0x00);
- stv0299_writereg (i2c, 0x23, 0x00);
- if (tuner_type != PHILIPS_SU1278_TSA_TT) {
- stv0299_readreg (i2c, 0x23);
- stv0299_writereg (i2c, 0x12, 0xb9);
+ stv0299_set_symbolrate (i2c, p->u.qpsk.symbol_rate, state->tuner_type);
+
+ if (state->tuner_type == PHILIPS_SU1278_TSA_TT) {
+ /* check if we should do a finetune */
+ int frequency_delta = p->frequency - state->tuner_frequency;
+ int minmax = p->u.qpsk.symbol_rate / 1000;
+ if ((frequency_delta > -minmax) && (frequency_delta < minmax)) {
+ int Drot_freq = ((frequency_delta) << 16) / (M_CLK_SU1278_TSA_TT /1000);
+ stv0299_writereg (i2c, 0x22, Drot_freq >> 8);
+ stv0299_writereg (i2c, 0x23, Drot_freq);
+ break;
+ }
}
- stv0299_check_inversion (i2c);
- /* printk ("%s: tsa5059 status: %x\n", __FUNCTION__, tsa5059_read_status(i2c)); */
- break;
+ /* A "normal" tune is requested */
+ pll_set_tv_freq (i2c, p->frequency, state->tuner_type,
+ p->u.qpsk.symbol_rate);
+ stv0299_writereg (i2c, 0x22, 0x00);
+ stv0299_writereg (i2c, 0x23, 0x00);
+ if (state->tuner_type != PHILIPS_SU1278_TSA_TT) {
+ stv0299_readreg (i2c, 0x23);
+ stv0299_writereg (i2c, 0x12, 0xb9);
+ }
+
+ state->tuner_frequency = p->frequency;
+ break;
}
case FE_GET_FRONTEND:
@@ -1099,7 +1129,7 @@ static int uni0299_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
s32 derot_freq;
int Mclk = M_CLK;
- if (tuner_type == PHILIPS_SU1278_TSA_TT) Mclk = M_CLK_SU1278_TSA_TT;
+ if (state->tuner_type == PHILIPS_SU1278_TSA_TT) Mclk = M_CLK_SU1278_TSA_TT;
derot_freq = (s32)(s16) ((stv0299_readreg (i2c, 0x22) << 8)
| stv0299_readreg (i2c, 0x23));
@@ -1112,7 +1142,7 @@ static int uni0299_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
p->inversion = (stv0299_readreg (i2c, 0x0c) & 1) ?
INVERSION_OFF : INVERSION_ON;
p->u.qpsk.fec_inner = stv0299_get_fec (i2c);
- p->u.qpsk.symbol_rate = stv0299_get_symbolrate (i2c, tuner_type);
+ p->u.qpsk.symbol_rate = stv0299_get_symbolrate (i2c, state->tuner_type);
break;
}
@@ -1123,7 +1153,16 @@ static int uni0299_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
break;
case FE_INIT:
- return stv0299_init (i2c, tuner_type);
+ if ((!state->initialised) || (state->tuner_type != PHILIPS_SU1278_TSA_TT)) {
+ state->initialised = 1;
+ return stv0299_init (i2c, state->tuner_type);
+ } else {
+ stv0299_writereg (i2c, 0x0c, 0x01); /* LNB power on! */
+ stv0299_writereg (i2c, 0x08, 0x02); /* LNB power on! */
+ stv0299_writereg (i2c, 0x02, 0x30);
+ return 0;
+ }
+
case FE_DISEQC_SEND_MASTER_CMD:
return stv0299_send_diseqc_msg (i2c, arg);
@@ -1177,11 +1216,11 @@ static long probe_tuner (struct dvb_i2c_bus *i2c)
if ((ret = i2c->xfer(i2c, msg1, 2)) == 2) {
if ( strcmp(adapter->name, "TT-Budget/WinTV-NOVA-CI PCI") == 0 ) {
// technotrend cards require non-datasheet settings
- printk ("%s: setup for tuner SU1278 (TSA5959 synth) on TechnoTrend hardware\n", __FILE__);
+ printk ("%s: setup for tuner SU1278 (TSA5059 synth) on TechnoTrend hardware\n", __FILE__);
return PHILIPS_SU1278_TSA_TT;
} else {
// fall back to datasheet-recommended settings
- printk ("%s: setup for tuner SU1278 (TSA5959 synth)\n", __FILE__);
+ printk ("%s: setup for tuner SU1278 (TSA5059 synth)\n", __FILE__);
return PHILIPS_SU1278_TSA;
}
}
@@ -1218,7 +1257,8 @@ static long probe_tuner (struct dvb_i2c_bus *i2c)
static int uni0299_attach (struct dvb_i2c_bus *i2c, void **data)
{
- long tuner_type;
+ struct stv0299_state* state;
+ int tuner_type;
u8 id;
stv0299_writereg (i2c, 0x02, 0x00); /* standby off */
@@ -1233,8 +1273,16 @@ static int uni0299_attach (struct dvb_i2c_bus *i2c, void **data)
if ((tuner_type = probe_tuner(i2c)) < 0)
return -ENODEV;
-
- return dvb_register_frontend (uni0299_ioctl, i2c, (void*) tuner_type,
+
+ if ((state = kmalloc(sizeof(struct stv0299_state), GFP_KERNEL)) == NULL) {
+ return -ENOMEM;
+ }
+
+ *data = state;
+ state->tuner_type = tuner_type;
+ state->initialised = 0;
+ state->tuner_frequency = 0;
+ return dvb_register_frontend (uni0299_ioctl, i2c, (void *) state,
&uni0299_info);
}
@@ -1242,6 +1290,7 @@ static int uni0299_attach (struct dvb_i2c_bus *i2c, void **data)
static void uni0299_detach (struct dvb_i2c_bus *i2c, void *data)
{
dprintk ("%s\n", __FUNCTION__);
+ kfree(data);
dvb_unregister_frontend (uni0299_ioctl, i2c);
}
@@ -1263,7 +1312,7 @@ module_init (init_uni0299);
module_exit (exit_uni0299);
MODULE_DESCRIPTION("Universal STV0299/TSA5059/SL1935 DVB Frontend driver");
-MODULE_AUTHOR("Ralph Metzler, Holger Waechtler, Peter Schildmann, Felix Domke, Andreas Oberritter");
+MODULE_AUTHOR("Ralph Metzler, Holger Waechtler, Peter Schildmann, Felix Domke, Andreas Oberritter, Andrew de Quincey");
MODULE_LICENSE("GPL");
MODULE_PARM(stv0299_status, "i");