summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjulian <julian@FreeBSD.org>2004-12-16 23:37:41 +0000
committerjulian <julian@FreeBSD.org>2004-12-16 23:37:41 +0000
commit900b64f296dbe0c12df0a825ca652e316431a623 (patch)
treeed458e77dc9518199ff904e0256d8754ae0b6bb7
parent3b2878da37add43296ace63d9752644b2aad33d3 (diff)
downloadFreeBSD-src-900b64f296dbe0c12df0a825ca652e316431a623.zip
FreeBSD-src-900b64f296dbe0c12df0a825ca652e316431a623.tar.gz
Allow /sys/dev/bktr to support Pinnacle PCTV Rave cards
PR: 73669 Submitted by: arne_woerner at yahoo dot com MFC after: 1 week
-rw-r--r--sys/dev/bktr/bktr_card.c28
-rw-r--r--sys/dev/bktr/bktr_card.h3
-rw-r--r--sys/dev/bktr/bktr_tuner.c395
-rw-r--r--sys/dev/bktr/bktr_tuner.h31
4 files changed, 440 insertions, 17 deletions
diff --git a/sys/dev/bktr/bktr_card.c b/sys/dev/bktr/bktr_card.c
index 18c01a5..c4577d2 100644
--- a/sys/dev/bktr/bktr_card.c
+++ b/sys/dev/bktr/bktr_card.c
@@ -368,6 +368,18 @@ static const struct CARDTYPE cards[] = {
{ 0x02, 0x00, 0x00, 0x00, 1 }, /* audio MUX values */
0x18e0 }, /* GPIO mask */
+ { CARD_PINNACLE_PCTV_RAVE, /* the card id */
+ "Pinnacle PCTV Rave", /* the 'name' */
+ NULL, /* the tuner */
+ 0, /* the tuner i2c address */
+ 0, /* dbx unknown */
+ 0,
+ 0,
+ 0, /* EEProm unknown */
+ 0, /* size unknown */
+ { 0x02, 0x01, 0x00, 0x0a, 1 }, /* audio MUX values */
+ 0x03000F }, /* GPIO mask */
+
};
struct bt848_card_sig bt848_card_signature[1]= {
@@ -569,6 +581,7 @@ static int locate_eeprom_address( bktr_ptr_t bktr) {
#define PCI_VENDOR_FLYVIDEO_2 0x1852
#define PCI_VENDOR_PINNACLE_ALT 0xBD11
#define PCI_VENDOR_IODATA 0x10fc
+#define PCI_VENDOR_PINNACLE_NEW 0x11BD
#define MODEL_IODATA_GV_BCTV3_PCI 0x4020
@@ -714,6 +727,21 @@ probeCard( bktr_ptr_t bktr, int verbose, int unit )
goto checkTuner;
}
+ if (subsystem_vendor_id == PCI_VENDOR_PINNACLE_NEW) {
+ bktr->card = cards[ (card = CARD_PINNACLE_PCTV_RAVE) ];
+ bktr->card.eepromAddr = eeprom_i2c_address;
+ bktr->card.eepromSize = (u_char)(256 / EEPROMBLOCKSIZE);
+
+ TDA9887_init(bktr, 0);
+
+ /* look for a tuner */
+ tuner_i2c_address = locate_tuner_address( bktr );
+ printf( "%s: tuner @ %#x\n", bktr_name(bktr), tuner_i2c_address );
+ select_tuner( bktr, TUNER_MT2032 );
+
+ goto checkDBX;
+ }
+
/* Vendor is unknown. We will use the standard probe code */
/* which may not give best results */
printf("%s: Warning - card vendor 0x%04x (model 0x%04x) unknown.\n",
diff --git a/sys/dev/bktr/bktr_card.h b/sys/dev/bktr/bktr_card.h
index d805690..91c8def 100644
--- a/sys/dev/bktr/bktr_card.h
+++ b/sys/dev/bktr/bktr_card.h
@@ -78,7 +78,8 @@
#define CARD_TERRATVPLUS 16
#define CARD_IO_BCTV3 17
#define CARD_AOPEN_VA1000 18
-#define Bt848_MAX_CARD 19
+#define CARD_PINNACLE_PCTV_RAVE 19
+#define Bt848_MAX_CARD 20
#define CARD_IO_GV CARD_IO_BCTV2
diff --git a/sys/dev/bktr/bktr_tuner.c b/sys/dev/bktr/bktr_tuner.c
index 7804773..424643f 100644
--- a/sys/dev/bktr/bktr_tuner.c
+++ b/sys/dev/bktr/bktr_tuner.c
@@ -136,6 +136,10 @@ __FBSDID("$FreeBSD$");
#define TSBH1_FCONTROL 0xce
+static void mt2032_set_tv_freq(bktr_ptr_t bktr, unsigned int freq);
+static int mt2032_init(bktr_ptr_t bktr);
+
+
static const struct TUNER tuners[] = {
/* XXX FIXME: fill in the band-switch crosspoints */
/* NO_TUNER */
@@ -276,7 +280,17 @@ static const struct TUNER tuners[] = {
TSBH1_FCONTROL,
0x00 },
{ 0x00, 0x00 }, /* band-switch crosspoints */
- { 0x01, 0x02, 0x08, 0x00 } } /* the band-switch values */
+ { 0x01, 0x02, 0x08, 0x00 } }, /* the band-switch values */
+
+ /* MT2032 Microtune */
+ { "MT2032", /* the 'name' */
+ TTYPE_PAL, /* input type */
+ { TSA552x_SCONTROL, /* control byte for Tuner PLL */
+ TSA552x_SCONTROL,
+ TSA552x_SCONTROL,
+ 0x00 },
+ { 0x00, 0x00 }, /* band-switch crosspoints */
+ { 0xa0, 0x90, 0x30, 0x00 } }, /* the band-switch values */
};
@@ -712,6 +726,9 @@ void select_tuner( bktr_ptr_t bktr, int tuner_type ) {
} else {
bktr->card.tuner = NULL;
}
+ if (tuner_type == TUNER_MT2032) {
+ mt2032_init(bktr);
+ }
}
/*
@@ -789,6 +806,10 @@ tv_freq( bktr_ptr_t bktr, int frequency, int type )
if ( tuner == NULL )
return( -1 );
+ if (tuner == &tuners[TUNER_MT2032]) {
+ mt2032_set_tv_freq(bktr, frequency);
+ return 0;
+ }
if (type == TV_FREQUENCY) {
/*
* select the band based on frequency
@@ -976,6 +997,8 @@ do_afc( bktr_ptr_t bktr, int addr, int frequency )
* Get the Tuner status and signal strength
*/
int get_tuner_status( bktr_ptr_t bktr ) {
+ if (bktr->card.tuner == &tuners[TUNER_MT2032])
+ return 0;
return i2cRead( bktr, bktr->card.tuner_pllAddr + 1 );
}
@@ -1015,3 +1038,373 @@ tuner_getchnlset(struct bktr_chnlset *chnlset)
chnlset->max_channel=freqTable[chnlset->index].ptr[0];
return( 0 );
}
+
+
+
+
+#define TDA9887_ADDR 0x86
+
+int
+TDA9887_init(bktr_ptr_t bktr, int output2_enable)
+{
+ u_char addr = TDA9887_ADDR;
+#if 0
+ char buf[8];
+
+ /* NOTE: these are PAL values */
+ buf[0] = 0; /* sub address */
+ buf[1] = 0x50; /* output port1 inactive */
+ buf[2] = 0x6e; /* tuner takeover point / de-emphasis */
+ buf[3] = 0x09; /* fVIF = 38.9 MHz, fFM = 5.5 MHz */
+
+ if (!output2_enable)
+ buf[1] |= 0x80;
+
+ if (i2cWriteBuf(bktr, addr, 4, buf) == -1) {
+ printf("%s: TDA9887 write failed\n", bktr_name(bktr));
+ return -1;
+ }
+#else
+ i2cWrite(bktr, addr, 0, output2_enable ? 0x50 : 0xd0);
+ i2cWrite(bktr, addr, 1, 0x6e);
+ i2cWrite(bktr, addr, 2, 0x09);
+#endif
+ return 0;
+}
+
+
+
+#define MT2032_OPTIMIZE_VCO 1
+
+/* holds the value of XOGC register after init */
+static int MT2032_XOGC = 4;
+
+/* card.tuner_pllAddr not set during init */
+#define MT2032_ADDR 0xc0
+
+#ifndef MT2032_ADDR
+#define MT2032_ADDR (bktr->card.tuner_pllAddr)
+#endif
+
+static u_char
+_MT2032_GetRegister(bktr_ptr_t bktr, u_char regNum)
+{
+ int ch;
+
+ if (i2cWrite(bktr, MT2032_ADDR, regNum, -1) == -1) {
+ printf("%s: MT2032 write failed (i2c addr %#x)\n",
+ bktr_name(bktr), MT2032_ADDR);
+ }
+ if ((ch = i2cRead(bktr, MT2032_ADDR + 1)) == -1) {
+ printf("%s: MT2032 get register %d failed\n",
+ bktr_name(bktr), regNum);
+ return 0;
+ }
+ return ch;
+}
+
+static void
+_MT2032_SetRegister(bktr_ptr_t bktr, u_char regNum, u_char data)
+{
+ i2cWrite(bktr, MT2032_ADDR, regNum, data);
+}
+
+#define MT2032_GetRegister(r) _MT2032_GetRegister(bktr,r)
+#define MT2032_SetRegister(r,d) _MT2032_SetRegister(bktr,r,d)
+
+
+static int
+mt2032_init(bktr_ptr_t bktr)
+{
+ u_char rdbuf[22];
+ int xogc, xok = 0;
+ int i;
+
+ TDA9887_init(bktr, 0);
+
+ for (i = 0; i < 21; i++)
+ rdbuf[i] = MT2032_GetRegister(i);
+
+ printf("%s: MT2032: Companycode=%02x%02x Part=%02x Revision=%02x\n",
+ bktr_name(bktr),
+ rdbuf[0x11], rdbuf[0x12], rdbuf[0x13], rdbuf[0x14]);
+
+ /* Initialize Registers per spec. */
+ MT2032_SetRegister(2, 0xff);
+ MT2032_SetRegister(3, 0x0f);
+ MT2032_SetRegister(4, 0x1f);
+ MT2032_SetRegister(6, 0xe4);
+ MT2032_SetRegister(7, 0x8f);
+ MT2032_SetRegister(8, 0xc3);
+ MT2032_SetRegister(9, 0x4e);
+ MT2032_SetRegister(10, 0xec);
+ MT2032_SetRegister(13, 0x32);
+
+ /* Adjust XOGC (register 7), wait for XOK */
+ xogc = 7;
+ do {
+ DELAY(10000);
+ xok = MT2032_GetRegister(0x0e) & 0x01;
+ if (xok == 1) {
+ break;
+ }
+ xogc--;
+ if (xogc == 3) {
+ xogc = 4; /* min. 4 per spec */
+ break;
+ }
+ MT2032_SetRegister(7, 0x88 + xogc);
+ } while (xok != 1);
+
+ TDA9887_init(bktr, 1);
+
+ MT2032_XOGC = xogc;
+
+ return 0;
+}
+
+static int
+MT2032_SpurCheck(int f1, int f2, int spectrum_from, int spectrum_to)
+{
+ int n1 = 1, n2, f;
+
+ f1 = f1 / 1000; /* scale to kHz to avoid 32bit overflows */
+ f2 = f2 / 1000;
+ spectrum_from /= 1000;
+ spectrum_to /= 1000;
+
+ do {
+ n2 = -n1;
+ f = n1 * (f1 - f2);
+ do {
+ n2--;
+ f = f - f2;
+ if ((f > spectrum_from) && (f < spectrum_to)) {
+ return 1;
+ }
+ } while ((f > (f2 - spectrum_to)) || (n2 > -5));
+ n1++;
+ } while (n1 < 5);
+
+ return 0;
+}
+
+static int
+MT2032_ComputeFreq(
+ int rfin,
+ int if1,
+ int if2,
+ int spectrum_from,
+ int spectrum_to,
+ unsigned char *buf,
+ int *ret_sel,
+ int xogc
+)
+{ /* all in Hz */
+ int fref, lo1, lo1n, lo1a, s, sel;
+ int lo1freq, desired_lo1, desired_lo2, lo2, lo2n, lo2a,
+ lo2num, lo2freq;
+ int nLO1adjust;
+
+ fref = 5250 * 1000; /* 5.25MHz */
+
+ /* per spec 2.3.1 */
+ desired_lo1 = rfin + if1;
+ lo1 = (2 * (desired_lo1 / 1000) + (fref / 1000)) / (2 * fref / 1000);
+ lo1freq = lo1 * fref;
+ desired_lo2 = lo1freq - rfin - if2;
+
+ /* per spec 2.3.2 */
+ for (nLO1adjust = 1; nLO1adjust < 3; nLO1adjust++) {
+ if (!MT2032_SpurCheck(lo1freq, desired_lo2, spectrum_from, spectrum_to)) {
+ break;
+ }
+ if (lo1freq < desired_lo1) {
+ lo1 += nLO1adjust;
+ } else {
+ lo1 -= nLO1adjust;
+ }
+
+ lo1freq = lo1 * fref;
+ desired_lo2 = lo1freq - rfin - if2;
+ }
+
+ /* per spec 2.3.3 */
+ s = lo1freq / 1000 / 1000;
+
+ if (MT2032_OPTIMIZE_VCO) {
+ if (s > 1890) {
+ sel = 0;
+ } else if (s > 1720) {
+ sel = 1;
+ } else if (s > 1530) {
+ sel = 2;
+ } else if (s > 1370) {
+ sel = 3;
+ } else {
+ sel = 4;/* >1090 */
+ }
+ } else {
+ if (s > 1790) {
+ sel = 0;/* <1958 */
+ } else if (s > 1617) {
+ sel = 1;
+ } else if (s > 1449) {
+ sel = 2;
+ } else if (s > 1291) {
+ sel = 3;
+ } else {
+ sel = 4;/* >1090 */
+ }
+ }
+
+ *ret_sel = sel;
+
+ /* per spec 2.3.4 */
+ lo1n = lo1 / 8;
+ lo1a = lo1 - (lo1n * 8);
+ lo2 = desired_lo2 / fref;
+ lo2n = lo2 / 8;
+ lo2a = lo2 - (lo2n * 8);
+ /* scale to fit in 32bit arith */
+ lo2num = ((desired_lo2 / 1000) % (fref / 1000)) * 3780 / (fref / 1000);
+ lo2freq = (lo2a + 8 * lo2n) * fref + lo2num * (fref / 1000) / 3780 * 1000;
+
+ if (lo1a < 0 || lo1a > 7 || lo1n < 17 || lo1n > 48 || lo2a < 0 ||
+ lo2a > 7 || lo2n < 17 || lo2n > 30) {
+ printf("MT2032: parameter out of range\n");
+ return -1;
+ }
+ /* set up MT2032 register map for transfer over i2c */
+ buf[0] = lo1n - 1;
+ buf[1] = lo1a | (sel << 4);
+ buf[2] = 0x86; /* LOGC */
+ buf[3] = 0x0f; /* reserved */
+ buf[4] = 0x1f;
+ buf[5] = (lo2n - 1) | (lo2a << 5);
+ if (rfin < 400 * 1000 * 1000) {
+ buf[6] = 0xe4;
+ } else {
+ buf[6] = 0xf4; /* set PKEN per rev 1.2 */
+ }
+
+ buf[7] = 8 + xogc;
+ buf[8] = 0xc3; /* reserved */
+ buf[9] = 0x4e; /* reserved */
+ buf[10] = 0xec; /* reserved */
+ buf[11] = (lo2num & 0xff);
+ buf[12] = (lo2num >> 8) | 0x80; /* Lo2RST */
+
+ return 0;
+}
+
+static int
+MT2032_CheckLOLock(bktr_ptr_t bktr)
+{
+ int t, lock = 0;
+ for (t = 0; t < 10; t++) {
+ lock = MT2032_GetRegister(0x0e) & 0x06;
+ if (lock == 6) {
+ break;
+ }
+ DELAY(1000);
+ }
+ return lock;
+}
+
+static int
+MT2032_OptimizeVCO(bktr_ptr_t bktr, int sel, int lock)
+{
+ int tad1, lo1a;
+
+ tad1 = MT2032_GetRegister(0x0f) & 0x07;
+
+ if (tad1 == 0) {
+ return lock;
+ }
+ if (tad1 == 1) {
+ return lock;
+ }
+ if (tad1 == 2) {
+ if (sel == 0) {
+ return lock;
+ } else {
+ sel--;
+ }
+ } else {
+ if (sel < 4) {
+ sel++;
+ } else {
+ return lock;
+ }
+ }
+ lo1a = MT2032_GetRegister(0x01) & 0x07;
+ MT2032_SetRegister(0x01, lo1a | (sel << 4));
+ lock = MT2032_CheckLOLock(bktr);
+ return lock;
+}
+
+static int
+MT2032_SetIFFreq(bktr_ptr_t bktr, int rfin, int if1, int if2, int from, int to)
+{
+ u_char buf[21];
+ int lint_try, sel, lock = 0;
+
+ if (MT2032_ComputeFreq(rfin, if1, if2, from, to, &buf[0], &sel, MT2032_XOGC) == -1)
+ return -1;
+
+ TDA9887_init(bktr, 0);
+
+ printf("%s: MT2032-SetIFFreq: 0x%02X%02X%02X%02X...\n",
+ bktr_name(bktr),
+ buf[0x00], buf[0x01], buf[0x02], buf[0x03]);
+
+ /* send only the relevant registers per Rev. 1.2 */
+ MT2032_SetRegister(0, buf[0x00]);
+ MT2032_SetRegister(1, buf[0x01]);
+ MT2032_SetRegister(2, buf[0x02]);
+
+ MT2032_SetRegister(5, buf[0x05]);
+ MT2032_SetRegister(6, buf[0x06]);
+ MT2032_SetRegister(7, buf[0x07]);
+
+ MT2032_SetRegister(11, buf[0x0B]);
+ MT2032_SetRegister(12, buf[0x0C]);
+
+ /* wait for PLLs to lock (per manual), retry LINT if not. */
+ for (lint_try = 0; lint_try < 2; lint_try++) {
+ lock = MT2032_CheckLOLock(bktr);
+
+ if (MT2032_OPTIMIZE_VCO) {
+ lock = MT2032_OptimizeVCO(bktr, sel, lock);
+ }
+ if (lock == 6) {
+ break;
+ }
+ /* set LINT to re-init PLLs */
+ MT2032_SetRegister(7, 0x80 + 8 + MT2032_XOGC);
+ DELAY(10000);
+ MT2032_SetRegister(7, 8 + MT2032_XOGC);
+ }
+ if (lock != 6)
+ printf("%s: PLL didn't lock\n", bktr_name(bktr));
+
+ MT2032_SetRegister(2, 0x20);
+
+ TDA9887_init(bktr, 1);
+ return 0;
+}
+
+static void
+mt2032_set_tv_freq(bktr_ptr_t bktr, unsigned int freq)
+{
+ int if2,from,to;
+
+ from=32900*1000;
+ to=39900*1000;
+ if2=38900*1000;
+
+ printf("%s: setting frequency to %d\n", bktr_name(bktr), freq*62500);
+ MT2032_SetIFFreq(bktr, freq*62500 /* freq*1000*1000/16 */,
+ 1090*1000*1000, if2, from, to);
+}
diff --git a/sys/dev/bktr/bktr_tuner.h b/sys/dev/bktr/bktr_tuner.h
index d7a67c0..5674e7f 100644
--- a/sys/dev/bktr/bktr_tuner.h
+++ b/sys/dev/bktr/bktr_tuner.h
@@ -45,21 +45,22 @@
/* Definitions for Tuners */
-#define NO_TUNER 0
-#define TEMIC_NTSC 1
-#define TEMIC_PAL 2
-#define TEMIC_SECAM 3
-#define PHILIPS_NTSC 4
-#define PHILIPS_PAL 5
-#define PHILIPS_SECAM 6
-#define TEMIC_PALI 7
-#define PHILIPS_PALI 8
-#define PHILIPS_FR1236_NTSC 9 /* These have FM radio support */
-#define PHILIPS_FR1216_PAL 10 /* These have FM radio support */
-#define PHILIPS_FR1236_SECAM 11 /* These have FM radio support */
-#define ALPS_TSCH5 12
-#define ALPS_TSBH1 13
-#define Bt848_MAX_TUNER 14
+#define NO_TUNER 0
+#define TEMIC_NTSC 1
+#define TEMIC_PAL 2
+#define TEMIC_SECAM 3
+#define PHILIPS_NTSC 4
+#define PHILIPS_PAL 5
+#define PHILIPS_SECAM 6
+#define TEMIC_PALI 7
+#define PHILIPS_PALI 8
+#define PHILIPS_FR1236_NTSC 9 /* These have FM radio support */
+#define PHILIPS_FR1216_PAL 10 /* These have FM radio support */
+#define PHILIPS_FR1236_SECAM 11 /* These have FM radio support */
+#define ALPS_TSCH5 12
+#define ALPS_TSBH1 13
+#define TUNER_MT2032 14
+#define Bt848_MAX_TUNER 15
/* experimental code for Automatic Frequency Control */
#define TUNER_AFC
OpenPOWER on IntegriCloud