Allow /sys/dev/bktr to support Pinnacle PCTV Rave cards

PR:		73669
Submitted by:	arne_woerner at yahoo dot com
MFC after:	1 week
This commit is contained in:
Julian Elischer 2004-12-16 23:37:41 +00:00
parent b7ad4d221a
commit 080bb7c1dd
4 changed files with 440 additions and 17 deletions

View file

@ -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",

View file

@ -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

View file

@ -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);
}

View file

@ -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