summaryrefslogtreecommitdiff
path: root/linux/drivers/media/dvb/frontends
diff options
context:
space:
mode:
authorAndrew de Quincy <devnull@localhost>2004-02-20 15:29:34 +0000
committerAndrew de Quincy <devnull@localhost>2004-02-20 15:29:34 +0000
commit69c1e46bb544d8694145d82114473ce6ab90b476 (patch)
tree6b152e013e70bda2b550ff0495aaa39a0af605ff /linux/drivers/media/dvb/frontends
parent0f9d4e1d924309be3ab7ce64c88cedefcc61c222 (diff)
downloadmediapointer-dvb-s2-69c1e46bb544d8694145d82114473ce6ab90b476.tar.gz
mediapointer-dvb-s2-69c1e46bb544d8694145d82114473ce6ab90b476.tar.bz2
Added seperate settings for SU1278 on technotrend hardware
Diffstat (limited to 'linux/drivers/media/dvb/frontends')
-rw-r--r--linux/drivers/media/dvb/frontends/stv0299.c260
1 files changed, 189 insertions, 71 deletions
diff --git a/linux/drivers/media/dvb/frontends/stv0299.c b/linux/drivers/media/dvb/frontends/stv0299.c
index 32d858540..19988e4f4 100644
--- a/linux/drivers/media/dvb/frontends/stv0299.c
+++ b/linux/drivers/media/dvb/frontends/stv0299.c
@@ -25,6 +25,9 @@
Copyright (C) 2003 Vadim Catana <skystar@moldova.cc>:
+ Support for Philips SU1278 on Technotrend hardware
+
+ Copyright (C) 2004 Andrew de Quincey <adq_dvb@lidskialf.net>
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
@@ -40,7 +43,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
+*/
#include <linux/init.h>
#include <linux/kernel.h>
@@ -65,14 +68,18 @@ static int stv0299_status = 0;
/* frontend types */
#define UNKNOWN_FRONTEND -1
-#define PHILIPS_SU1278SH 0
+#define PHILIPS_SU1278_TSA 0 // SU1278 with TSA5959 synth and datasheet recommended settings
#define ALPS_BSRU6 1
#define LG_TDQF_S001F 2
-#define PHILIPS_SU1278 3
+#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
/* Master Clock = 88 MHz */
-#define M_CLK (88000000UL)
+#define M_CLK (88000000UL)
+
+/* Master Clock for TT cards = 64 MHz */
+#define M_CLK_SU1278_TSA_TT (64000000UL)
static struct dvb_frontend_info uni0299_info = {
.name = "STV0299/TSA5059/SL1935 based",
@@ -201,6 +208,51 @@ static u8 init_tab_samsung [] = {
};
+static u8 init_tab_su1278_tsa_tt [] = {
+ 0x01, 0x0f,
+ 0x02, 0x30,
+ 0x03, 0x00,
+ 0x04, 0x5b,
+ 0x05, 0x85,
+ 0x06, 0x02,
+ 0x07, 0x00,
+ 0x08, 0x02,
+ 0x09, 0x00,
+ 0x0C, 0x01,
+ 0x0D, 0x81,
+ 0x0E, 0x44,
+ 0x0f, 0x14,
+ 0x10, 0x3c,
+ 0x11, 0x84,
+ 0x12, 0xda,
+ 0x13, 0x97,
+ 0x14, 0x95,
+ 0x15, 0xc9,
+ 0x16, 0x19,
+ 0x17, 0x8c,
+ 0x18, 0x59,
+ 0x19, 0xf8,
+ 0x1a, 0xfe,
+ 0x1c, 0x7f,
+ 0x1d, 0x00,
+ 0x1e, 0x00,
+ 0x1f, 0x50,
+ 0x20, 0x00,
+ 0x21, 0x00,
+ 0x22, 0x00,
+ 0x23, 0x00,
+ 0x28, 0x00,
+ 0x29, 0x28,
+ 0x2a, 0x14,
+ 0x2b, 0x0f,
+ 0x2c, 0x09,
+ 0x2d, 0x09,
+ 0x31, 0x1f,
+ 0x32, 0x19,
+ 0x33, 0xfc,
+ 0x34, 0x13
+};
+
static int stv0299_writereg (struct dvb_i2c_bus *i2c, u8 reg, u8 data)
{
int ret;
@@ -209,7 +261,7 @@ static int stv0299_writereg (struct dvb_i2c_bus *i2c, u8 reg, u8 data)
ret = i2c->xfer (i2c, &msg, 1);
- if (ret != 1)
+ if (ret != 1)
dprintk("%s: writereg error (reg == 0x%02x, val == 0x%02x, "
"ret == %i)\n", __FUNCTION__, reg, data, ret);
@@ -226,8 +278,8 @@ static u8 stv0299_readreg (struct dvb_i2c_bus *i2c, u8 reg)
{ .addr = 0x68, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
ret = i2c->xfer (i2c, msg, 2);
-
- if (ret != 2)
+
+ if (ret != 2)
dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n",
__FUNCTION__, reg, ret);
@@ -289,7 +341,7 @@ static int sl1935_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq, int ftype)
}
/**
- * set up the downconverter frequency divisor for a
+ * set up the downconverter frequency divisor for a
* reference clock comparision frequency of 125 kHz.
*/
static int tsa5059_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq, int ftype, int srate)
@@ -297,26 +349,31 @@ 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;
dprintk ("%s: freq %i, ftype %i\n", __FUNCTION__, freq, ftype);
if ((freq < 950000) || (freq > 2150000)) return -EINVAL;
-
+
+ divisor = 500;
+ regcode = 2;
+
// setup frequency divisor
- div = freq / 1000;
+ div = freq / divisor;
buf[0] = (div >> 8) & 0x7f;
buf[1] = div & 0xff;
- buf[2] = 0x81 | ((div & 0x18000) >> 10);
+ buf[2] = 0x80 | ((div & 0x18000) >> 10) | regcode;
buf[3] = 0;
-
+
// tuner-specific settings
switch(ftype) {
- case PHILIPS_SU1278SH:
+ case PHILIPS_SU1278_TSA:
+ case PHILIPS_SU1278_TSA_TT:
addr = 0x60;
buf[3] |= 0x20;
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;
@@ -332,7 +389,6 @@ static int tsa5059_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq, int ftype, in
return -EINVAL;
}
- // charge pump
return pll_write (i2c, addr, buf, sizeof(buf));
}
@@ -465,14 +521,19 @@ static int tua6100_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq,
static int pll_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq, int ftype, int srate)
{
- if (ftype == SAMSUNG_TBMU24112IMB)
- return sl1935_set_tv_freq(i2c, freq, ftype);
- else if (ftype == LG_TDQF_S001F)
+ switch(ftype) {
+ case SAMSUNG_TBMU24112IMB:
+ return sl1935_set_tv_freq(i2c, freq, ftype);
+
+ case LG_TDQF_S001F:
return sl1935_set_tv_freq(i2c, freq, ftype);
- else if (ftype == PHILIPS_SU1278)
+
+ case PHILIPS_SU1278_TUA:
return tua6100_set_tv_freq(i2c, freq, ftype, srate);
- else
+
+ default:
return tsa5059_set_tv_freq(i2c, freq, ftype, srate);
+ }
}
#if 0
@@ -515,34 +576,40 @@ static int stv0299_init (struct dvb_i2c_bus *i2c, int ftype)
}
break;
+ 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:
stv0299_writereg (i2c, 0x01, 0x15);
- stv0299_writereg (i2c, 0x02, ftype == PHILIPS_SU1278 ? 0x00 : 0x30);
+ stv0299_writereg (i2c, 0x02, ftype == PHILIPS_SU1278_TUA ? 0x00 : 0x30);
stv0299_writereg (i2c, 0x03, 0x00);
for (i=0; i<sizeof(init_tab); i+=2)
stv0299_writereg (i2c, init_tab[i], init_tab[i+1]);
/* AGC1 reference register setup */
- if (ftype == PHILIPS_SU1278SH)
+ if (ftype == PHILIPS_SU1278_TSA)
stv0299_writereg (i2c, 0x0f, 0x92); /* Iagc = Inverse, m1 = 18 */
- else if (ftype == PHILIPS_SU1278)
+ else if (ftype == PHILIPS_SU1278_TUA)
stv0299_writereg (i2c, 0x0f, 0x94); /* Iagc = Inverse, m1 = 20 */
else
stv0299_writereg (i2c, 0x0f, 0x52); /* Iagc = Normal, m1 = 18 */
break;
}
-
+
switch(stv0299_status) {
case STATUS_BER:
stv0299_writereg(i2c, 0x34, 0x93);
break;
-
+
case STATUS_UCBLOCKS:
stv0299_writereg(i2c, 0x34, 0xB3);
break;
}
-
+
return 0;
}
@@ -725,7 +792,7 @@ static int stv0299_set_tone (struct dvb_i2c_bus *i2c, fe_sec_tone_mode_t tone)
u8 val;
dprintk("%s: %s\n", __FUNCTION__,
- tone == SEC_TONE_ON ? "SEC_TONE_ON" :
+ tone == SEC_TONE_ON ? "SEC_TONE_ON" :
tone == SEC_TONE_OFF ? "SEC_TONE_OFF" : "??");
if (stv0299_wait_diseqc_idle (i2c, 100) < 0)
@@ -738,7 +805,7 @@ static int stv0299_set_tone (struct dvb_i2c_bus *i2c, fe_sec_tone_mode_t tone)
{
dprintk("%s: TONE_ON\n", __FUNCTION__);
return stv0299_writereg (i2c, 0x08, val | 0x3);
- }
+ }
case SEC_TONE_OFF:
{
dprintk("%s: TONE_OFF\n", __FUNCTION__);
@@ -759,7 +826,7 @@ static int stv0299_set_voltage (struct dvb_i2c_bus *i2c, fe_sec_voltage_t voltag
u8 reg0x0c;
dprintk("%s: %s\n", __FUNCTION__,
- voltage == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" :
+ voltage == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" :
voltage == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??");
reg0x08 = stv0299_readreg (i2c, 0x08);
@@ -796,10 +863,49 @@ static int stv0299_set_symbolrate (struct dvb_i2c_bus *i2c, u32 srate, int tuner
u8 aclk = 0;
u8 bclk = 0;
u8 m1;
-
+ int Mclk = M_CLK;
+
+ // check rate is within limits
if ((srate < 1000000) || (srate > 45000000)) return -EINVAL;
+
+ // calculate value to program
+ if (tuner_type == PHILIPS_SU1278_TSA_TT) Mclk = M_CLK_SU1278_TSA_TT;
+ big = big << 20;
+ do_div(big, Mclk);
+ ratio = big << 4;
+
+ // program registers
switch(tuner_type) {
- case PHILIPS_SU1278SH:
+ case PHILIPS_SU1278_TSA_TT:
+ stv0299_writereg (i2c, 0x0e, 0x44);
+ if (srate >= 10000000) {
+ stv0299_writereg (i2c, 0x13, 0x97);
+ stv0299_writereg (i2c, 0x14, 0x95);
+ stv0299_writereg (i2c, 0x15, 0xc9);
+ stv0299_writereg (i2c, 0x17, 0x8c);
+ stv0299_writereg (i2c, 0x1a, 0xfe);
+ stv0299_writereg (i2c, 0x1c, 0x7f);
+ stv0299_writereg (i2c, 0x2d, 0x09);
+ } else {
+ stv0299_writereg (i2c, 0x13, 0x99);
+ stv0299_writereg (i2c, 0x14, 0x8d);
+ stv0299_writereg (i2c, 0x15, 0xce);
+ stv0299_writereg (i2c, 0x17, 0x43);
+ stv0299_writereg (i2c, 0x1a, 0x1d);
+ 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);
+ stv0299_writereg (i2c, 0x15, 0xc9);
+
+ stv0299_writereg (i2c, 0x1f, (ratio >> 16) & 0xff);
+ stv0299_writereg (i2c, 0x20, (ratio >> 8) & 0xff);
+ stv0299_writereg (i2c, 0x21, (ratio ) & 0xf0);
+ break;
+
+ case PHILIPS_SU1278_TSA:
aclk = 0xb5;
if (srate < 2000000) bclk = 0x86;
else if (srate < 5000000) bclk = 0x89;
@@ -808,8 +914,15 @@ static int stv0299_set_symbolrate (struct dvb_i2c_bus *i2c, u32 srate, int tuner
m1 = 0x14;
if (srate < 4000000) m1 = 0x10;
+
+ stv0299_writereg (i2c, 0x13, aclk);
+ stv0299_writereg (i2c, 0x14, bclk);
+ stv0299_writereg (i2c, 0x1f, (ratio >> 16) & 0xff);
+ stv0299_writereg (i2c, 0x20, (ratio >> 8) & 0xff);
+ stv0299_writereg (i2c, 0x21, (ratio ) & 0xf0);
+ stv0299_writereg (i2c, 0x0f, (stv0299_readreg(i2c, 0x0f) & 0xc0) | m1);
break;
-
+
case ALPS_BSRU6:
default:
if (srate <= 1500000) { aclk = 0xb7; bclk = 0x87; }
@@ -818,37 +931,23 @@ static int stv0299_set_symbolrate (struct dvb_i2c_bus *i2c, u32 srate, int tuner
else if (srate <= 14000000) { aclk = 0xb7; bclk = 0x93; }
else if (srate <= 30000000) { aclk = 0xb6; bclk = 0x93; }
else if (srate <= 45000000) { aclk = 0xb4; bclk = 0x91; }
-
m1 = 0x12;
- break;
- }
-
- dprintk("%s : big = 0x%08x%08x\n", __FUNCTION__, (int) ((big>>32) & 0xffffffff), (int) (big & 0xffffffff) );
-
- big = big << 20;
-
- dprintk("%s : big = 0x%08x%08x\n", __FUNCTION__, (int) ((big>>32) & 0xffffffff), (int) (big & 0xffffffff) );
-
- do_div(big, M_CLK);
-
- dprintk("%s : big = 0x%08x%08x\n", __FUNCTION__, (int) ((big>>32) & 0xffffffff), (int) (big & 0xffffffff) );
-
- ratio = big << 4;
- dprintk("%s : ratio = %i\n", __FUNCTION__, ratio);
-
- stv0299_writereg (i2c, 0x13, aclk);
- stv0299_writereg (i2c, 0x14, bclk);
- stv0299_writereg (i2c, 0x1f, (ratio >> 16) & 0xff);
- stv0299_writereg (i2c, 0x20, (ratio >> 8) & 0xff);
- stv0299_writereg (i2c, 0x21, (ratio ) & 0xf0);
- stv0299_writereg (i2c, 0x0f, (stv0299_readreg(i2c, 0x0f) & 0xc0) | m1);
+ stv0299_writereg (i2c, 0x13, aclk);
+ stv0299_writereg (i2c, 0x14, bclk);
+ stv0299_writereg (i2c, 0x1f, (ratio >> 16) & 0xff);
+ stv0299_writereg (i2c, 0x20, (ratio >> 8) & 0xff);
+ stv0299_writereg (i2c, 0x21, (ratio ) & 0xf0);
+ stv0299_writereg (i2c, 0x0f, (stv0299_readreg(i2c, 0x0f) & 0xc0) | m1);
+ break;
+ }
+
return 0;
}
-static int stv0299_get_symbolrate (struct dvb_i2c_bus *i2c)
+static int stv0299_get_symbolrate (struct dvb_i2c_bus *i2c, int tuner_type)
{
u32 Mclk = M_CLK / 4096L;
u32 srate;
@@ -858,6 +957,8 @@ static int stv0299_get_symbolrate (struct dvb_i2c_bus *i2c)
dprintk ("%s\n", __FUNCTION__);
+ if (tuner_type == PHILIPS_SU1278_TSA_TT) Mclk = M_CLK_SU1278_TSA_TT / 4096L;
+
stv0299_readregs (i2c, 0x1f, sfr, 3);
stv0299_readregs (i2c, 0x1a, &rtf, 1);
@@ -865,7 +966,6 @@ static int stv0299_get_symbolrate (struct dvb_i2c_bus *i2c)
srate *= Mclk;
srate /= 16;
srate += (sfr[2] >> 4) * Mclk / 256;
-
offset = (s32) rtf * (srate / 4096L);
offset /= 128;
@@ -890,9 +990,16 @@ static int uni0299_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
dprintk ("%s\n", __FUNCTION__);
switch (cmd) {
- case FE_GET_INFO:
+ case FE_GET_INFO:
+ {
+ 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) {
+ tmp->frequency_tolerance = M_CLK_SU1278_TSA_TT / 2000;
+ }
break;
+ }
case FE_READ_STATUS:
{
@@ -954,7 +1061,7 @@ static int uni0299_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
(snr < 0) ? 0 : snr;
break;
}
- case FE_READ_UNCORRECTED_BLOCKS:
+ case FE_READ_UNCORRECTED_BLOCKS:
if (stv0299_status == STATUS_UCBLOCKS) {
*((u32*) arg) = (stv0299_readreg (i2c, 0x1d) << 8)
| stv0299_readreg (i2c, 0x1e);
@@ -976,8 +1083,10 @@ static int uni0299_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
stv0299_set_symbolrate (i2c, p->u.qpsk.symbol_rate, tuner_type);
stv0299_writereg (i2c, 0x22, 0x00);
stv0299_writereg (i2c, 0x23, 0x00);
- stv0299_readreg (i2c, 0x23);
- stv0299_writereg (i2c, 0x12, 0xb9);
+ if (tuner_type != PHILIPS_SU1278_TSA_TT) {
+ stv0299_readreg (i2c, 0x23);
+ stv0299_writereg (i2c, 0x12, 0xb9);
+ }
stv0299_check_inversion (i2c);
/* printk ("%s: tsa5059 status: %x\n", __FUNCTION__, tsa5059_read_status(i2c)); */
@@ -988,11 +1097,14 @@ static int uni0299_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
{
struct dvb_frontend_parameters *p = arg;
s32 derot_freq;
+ int Mclk = M_CLK;
+ if (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));
- derot_freq *= (M_CLK >> 16);
+ derot_freq *= (Mclk >> 16);
derot_freq += 500;
derot_freq /= 1000;
@@ -1000,7 +1112,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);
+ p->u.qpsk.symbol_rate = stv0299_get_symbolrate (i2c, tuner_type);
break;
}
@@ -1062,15 +1174,21 @@ static long probe_tuner (struct dvb_i2c_bus *i2c)
return SAMSUNG_TBMU24112IMB;
}
-
if ((ret = i2c->xfer(i2c, msg1, 2)) == 2) {
- printk ("%s: setup for tuner SU1278/SH\n", __FILE__);
- return PHILIPS_SU1278SH;
+ 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__);
+ return PHILIPS_SU1278_TSA_TT;
+ } else {
+ // fall back to datasheet-recommended settings
+ printk ("%s: setup for tuner SU1278 (TSA5959 synth)\n", __FILE__);
+ return PHILIPS_SU1278_TSA;
+ }
}
if ((ret = i2c->xfer(i2c, msg2, 2)) == 2) {
//if ((stat[0] & 0x3f) == 0) {
- if (0) {
+ if (0) {
printk ("%s: setup for tuner TDQF-S001F\n", __FILE__);
return LG_TDQF_S001F;
} else {
@@ -1086,8 +1204,8 @@ static long probe_tuner (struct dvb_i2c_bus *i2c)
stv0299_writereg (i2c, 0x02, 0x00);
if ((ret = i2c->xfer(i2c, msg3, 2)) == 2) {
- printk ("%s: setup for tuner Philips SU1278\n", __FILE__);
- return PHILIPS_SU1278;
+ printk ("%s: setup for tuner Philips SU1278 (TUA6100 synth)\n", __FILE__);
+ return PHILIPS_SU1278_TUA;
}
printk ("%s: unknown PLL synthesizer (ret == %i), "
@@ -1102,7 +1220,7 @@ static int uni0299_attach (struct dvb_i2c_bus *i2c, void **data)
{
long tuner_type;
u8 id;
-
+
stv0299_writereg (i2c, 0x02, 0x00); /* standby off */
id = stv0299_readreg (i2c, 0x00);
@@ -1116,7 +1234,7 @@ 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,
+ return dvb_register_frontend (uni0299_ioctl, i2c, (void*) tuner_type,
&uni0299_info);
}