diff options
author | julian <julian@FreeBSD.org> | 2004-12-16 23:37:41 +0000 |
---|---|---|
committer | julian <julian@FreeBSD.org> | 2004-12-16 23:37:41 +0000 |
commit | 900b64f296dbe0c12df0a825ca652e316431a623 (patch) | |
tree | ed458e77dc9518199ff904e0256d8754ae0b6bb7 | |
parent | 3b2878da37add43296ace63d9752644b2aad33d3 (diff) | |
download | FreeBSD-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.c | 28 | ||||
-rw-r--r-- | sys/dev/bktr/bktr_card.h | 3 | ||||
-rw-r--r-- | sys/dev/bktr/bktr_tuner.c | 395 | ||||
-rw-r--r-- | sys/dev/bktr/bktr_tuner.h | 31 |
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 |