Initial code from GATOS. This needs to be cleaned up, for example the bt829
code is practically untouched since xatitv (which was a standalone test program). However, it all worked and was debugged over long period of time, so I prefer to to mess with these for now. New drivers: fi12xx (including MT2032 - this would be be split off later). tdaXXX msp34xx bt8xx
This commit is contained in:
parent
1dfafe2aee
commit
0d474149f1
737
hw/xfree86/i2c/bt829.c
Normal file
737
hw/xfree86/i2c/bt829.c
Normal file
@ -0,0 +1,737 @@
|
||||
/* TODO: clean up/fix CC code */
|
||||
|
||||
#include "xf86.h"
|
||||
#include "xf86i2c.h"
|
||||
#include "bt829.h"
|
||||
#include "i2c_def.h"
|
||||
|
||||
/* Changing the following settings (especially VCROP) may */
|
||||
/* require modifying code that calls this driver. */
|
||||
#define HCROP 0 /* amount to crop from the left and right edges */
|
||||
#define VCROP 0 /* amount to crop from the top and bottom edges */
|
||||
|
||||
#define BTVERSION (bt->id>>4)
|
||||
|
||||
#define H(X) ( ((X)>>8) & 0xFF )
|
||||
#define L(X) ( (X) & 0xFF )
|
||||
|
||||
#define LIMIT(X,A,B) (((X)<(A)) ? (A) : ((X)>(B)) ? (B) : (X) )
|
||||
|
||||
/* Bt829 family chip ID's */
|
||||
#define BT815 0x02
|
||||
#define BT817 0x06
|
||||
#define BT819 0x07
|
||||
#define BT827 0x0C
|
||||
#define BT829 0x0E
|
||||
|
||||
/* Bt829 registers */
|
||||
#define STATUS 0x00 /* Device Status */
|
||||
#define IFORM 0x01 /* Input Format */
|
||||
#define TDEC 0x02 /* Temporal Decimation */
|
||||
#define CROP 0x03 /* MSB Cropping */
|
||||
#define VDELAY_LO 0x04 /* Vertical Delay */
|
||||
#define VACTIVE_LO 0x05 /* Vertical Active */
|
||||
#define HDELAY_LO 0x06 /* Horizontal Delay */
|
||||
#define HACTIVE_LO 0x07 /* Horizontal Active */
|
||||
#define HSCALE_HI 0x08 /* Horizontal Scaling */
|
||||
#define HSCALE_LO 0x09 /* Horizontal Scaling */
|
||||
#define BRIGHT 0x0A /* Brightness Control */
|
||||
#define CONTROL 0x0B /* Miscellaneous Control */
|
||||
#define CONTRAST_LO 0x0C /* Luma Gain (Contrast) */
|
||||
#define SAT_U_LO 0x0D /* Chroma (U) Gain (Saturation) */
|
||||
#define SAT_V_LO 0x0E /* Chroma (V) Gain (Saturation) */
|
||||
#define HUE 0x0F /* Hue Control */
|
||||
#define SCLOOP 0x10 /* SC Loop Control */
|
||||
#define WC_UP 0x11 /* White Crush Up Count */
|
||||
#define OFORM 0x12 /* Output Format */
|
||||
#define VSCALE_HI 0x13 /* Vertical Scaling */
|
||||
#define VSCALE_LO 0x14 /* Vertical Scaling */
|
||||
#define TEST 0x15 /* Test Control */
|
||||
#define VPOLE 0x16 /* Video Timing Polarity */
|
||||
#define IDCODE 0x17 /* ID Code */
|
||||
#define ADELAY 0x18 /* AGC Delay */
|
||||
#define BDELAY 0x19 /* Burst Gate Delay */
|
||||
#define ADC 0x1A /* ADC Interface */
|
||||
#define VTC 0x1B /* Video Timing Control */
|
||||
#define CC_STATUS 0x1C /* Extended Data Services/Closed Capt Status */
|
||||
#define CC_DATA 0x1D /* Extended Data Services/Closed Capt Data */
|
||||
#define WC_DN 0x1E /* White Crush Down Count */
|
||||
#define SRESET 0x1F /* Software Reset */
|
||||
#define P_IO 0x3F /* Programmable I/O */
|
||||
|
||||
static CARD8 btread(BT829Ptr bt, CARD8 reg)
|
||||
{
|
||||
CARD8 v;
|
||||
|
||||
I2C_WriteRead(&(bt->d), ®, 1, &v, 1);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
static void btwrite(BT829Ptr bt, CARD8 reg, CARD8 val)
|
||||
{
|
||||
CARD8 data[2];
|
||||
|
||||
data[0] = reg;
|
||||
data[1] = val;
|
||||
I2C_WriteRead(&(bt->d), data, 2, NULL, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Register access
|
||||
*/
|
||||
static void btwrite_status(BT829Ptr bt) /* STATUS */
|
||||
{
|
||||
btwrite(bt, STATUS, 0x00); /* clear */
|
||||
}
|
||||
|
||||
static void btwrite_iform(BT829Ptr bt) /* IFORM */
|
||||
{
|
||||
int xtsel;
|
||||
|
||||
switch (bt->format) {
|
||||
case BT829_NTSC:
|
||||
case BT829_NTSC_JAPAN:
|
||||
case BT829_PAL_M:
|
||||
case BT829_PAL_N_COMB: /* gatos says xtsel = 2 */
|
||||
xtsel = 1;
|
||||
break;
|
||||
case BT829_PAL:
|
||||
case BT829_PAL_N:
|
||||
case BT829_SECAM:
|
||||
xtsel = 2;
|
||||
break;
|
||||
default: /* shouldn't get here */
|
||||
xtsel = 3; /* hardware default */
|
||||
break;
|
||||
}
|
||||
|
||||
btwrite(bt, IFORM, (bt->mux<<5) | (xtsel<<3) | bt->format);
|
||||
}
|
||||
|
||||
static void btwrite_tdec(BT829Ptr bt) /* TDEC */
|
||||
{
|
||||
/* use default */
|
||||
}
|
||||
|
||||
static void btwrite_crop(BT829Ptr bt) /* CROP */
|
||||
{
|
||||
btwrite(bt, CROP, (H(bt->vdelay)<<6) | (H(bt->vactive)<<4) |
|
||||
(H(bt->hdelay)<<2) | H(bt->width));
|
||||
}
|
||||
|
||||
static void btwrite_vdelay_lo(BT829Ptr bt) /* VDELAY_LO */
|
||||
{
|
||||
btwrite(bt, VDELAY_LO, L(bt->vdelay));
|
||||
}
|
||||
|
||||
static void btwrite_vactive_lo(BT829Ptr bt) /* VACTIVE_LO */
|
||||
{
|
||||
btwrite(bt, VACTIVE_LO, L(bt->vactive));
|
||||
}
|
||||
|
||||
static void btwrite_hdelay_lo(BT829Ptr bt) /* HDELAY_LO */
|
||||
{
|
||||
btwrite(bt, HDELAY_LO, L(bt->hdelay));
|
||||
}
|
||||
|
||||
static void btwrite_hactive_lo(BT829Ptr bt) /* HACTIVE_LO */
|
||||
{
|
||||
btwrite(bt, HACTIVE_LO, L(bt->width));
|
||||
}
|
||||
|
||||
static void btwrite_hscale_hi(BT829Ptr bt) /* HSCALE_HI */
|
||||
{
|
||||
btwrite(bt, HSCALE_HI, H(bt->hscale));
|
||||
}
|
||||
|
||||
static void btwrite_hscale_lo(BT829Ptr bt) /* HSCALE_LO */
|
||||
{
|
||||
btwrite(bt, HSCALE_LO, L(bt->hscale));
|
||||
}
|
||||
|
||||
static void btwrite_bright(BT829Ptr bt) /* BRIGHT */
|
||||
{
|
||||
btwrite(bt, BRIGHT, bt->brightness);
|
||||
}
|
||||
|
||||
static void btwrite_control(BT829Ptr bt) /* CONTROL */
|
||||
{
|
||||
int ldec;
|
||||
|
||||
/* The data sheet says ldec should always be 0 for SECAM */
|
||||
/* but the picture quality is better with ldec = 1 */
|
||||
ldec = (bt->width > 360); /* gatos says 384 */
|
||||
|
||||
btwrite(bt, CONTROL,
|
||||
((bt->mux==bt->svideo_mux) ? 0xC0:0x00) | /* LNOTCH and COMP */
|
||||
(ldec<<5) | (H(bt->contrast)<<2) | (H(bt->sat_u)<<1) | H(bt->sat_v));
|
||||
}
|
||||
|
||||
static void btwrite_contrast_lo(BT829Ptr bt) /* CONTRAST_LO */
|
||||
{
|
||||
btwrite(bt, CONTRAST_LO, L(bt->contrast));
|
||||
}
|
||||
|
||||
static void btwrite_sat_u_lo(BT829Ptr bt) /* SAT_U_LO */
|
||||
{
|
||||
btwrite(bt, SAT_U_LO, L(bt->sat_u));
|
||||
}
|
||||
|
||||
static void btwrite_sat_v_lo(BT829Ptr bt) /* SAT_V_LO */
|
||||
{
|
||||
btwrite(bt, SAT_V_LO, L(bt->sat_v));
|
||||
}
|
||||
|
||||
static void btwrite_hue(BT829Ptr bt) /* HUE */
|
||||
{
|
||||
btwrite(bt, HUE, bt->hue);
|
||||
}
|
||||
|
||||
static void btwrite_scloop(BT829Ptr bt) /* SCLOOP */
|
||||
{
|
||||
if (BTVERSION >= BT827) {
|
||||
btwrite(bt, SCLOOP,
|
||||
(bt->format==BT829_SECAM) ? 0x10:0x00 /* QCIF or AUTO */
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static void btwrite_wc_up(BT829Ptr bt) /* WC_UP */
|
||||
{
|
||||
if (BTVERSION >= BT827) {
|
||||
/* use default */
|
||||
}
|
||||
}
|
||||
|
||||
static void btwrite_oform(BT829Ptr bt) /* OFORM */
|
||||
{
|
||||
btwrite(bt, OFORM, (bt->code<<3) | (bt->len<<2) |
|
||||
0x02 /* RANGE = 0, CORE = 0, VBI_FRAME = 0, OES = 2 (default) */
|
||||
);
|
||||
}
|
||||
|
||||
static void btwrite_vscale_hi(BT829Ptr bt) /* VSCALE_HI */
|
||||
{
|
||||
btwrite(bt, VSCALE_HI, H(bt->vscale) |
|
||||
0x60 /* YCOMB = 0, COMB = 1, INT = 1 (default) */
|
||||
);
|
||||
}
|
||||
|
||||
static void btwrite_vscale_lo(BT829Ptr bt) /* VSCALE_LO */
|
||||
{
|
||||
btwrite(bt, VSCALE_LO, L(bt->vscale));
|
||||
}
|
||||
|
||||
/* TEST should not be written to */
|
||||
|
||||
static void btwrite_vpole(BT829Ptr bt) /* VPOLE */
|
||||
{
|
||||
btwrite(bt, VPOLE, (bt->out_en<<7));
|
||||
}
|
||||
|
||||
/* IDCODE is read only */
|
||||
|
||||
static void btwrite_adelay(BT829Ptr bt) /* ADELAY */
|
||||
{
|
||||
switch (bt->format) {
|
||||
case BT829_NTSC:
|
||||
case BT829_NTSC_JAPAN:
|
||||
case BT829_PAL_M:
|
||||
btwrite(bt, ADELAY, 104);
|
||||
break;
|
||||
case BT829_PAL:
|
||||
case BT829_PAL_N:
|
||||
case BT829_SECAM:
|
||||
case BT829_PAL_N_COMB:
|
||||
btwrite(bt, ADELAY, 127);
|
||||
break;
|
||||
default: /* shouldn't get here */
|
||||
btwrite(bt, ADELAY, 104); /* hardware default */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void btwrite_bdelay(BT829Ptr bt) /* BDELAY */
|
||||
{
|
||||
switch (bt->format) {
|
||||
case BT829_NTSC:
|
||||
case BT829_NTSC_JAPAN:
|
||||
case BT829_PAL_M:
|
||||
btwrite(bt, BDELAY, 93);
|
||||
break;
|
||||
case BT829_PAL:
|
||||
case BT829_PAL_N:
|
||||
case BT829_PAL_N_COMB:
|
||||
btwrite(bt, BDELAY, 114);
|
||||
break;
|
||||
case BT829_SECAM:
|
||||
btwrite(bt, BDELAY, 160);
|
||||
break;
|
||||
default: /* shouldn't get here */
|
||||
btwrite(bt, BDELAY, 93); /* hardware default */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void btwrite_adc(BT829Ptr bt) /* ADC */
|
||||
{
|
||||
btwrite(bt, ADC, bt->mux==bt->svideo_mux ? 0x80:0x82); /* CSLEEP = 0 or 1 */
|
||||
}
|
||||
|
||||
static void btwrite_vtc(BT829Ptr bt) /* VTC */
|
||||
{
|
||||
int vfilt = 0; /* hardware default */
|
||||
|
||||
if (BTVERSION > BT827) { /* gatos says >= BT827 */
|
||||
switch (bt->format) {
|
||||
case BT829_NTSC:
|
||||
case BT829_NTSC_JAPAN:
|
||||
case BT829_PAL_M:
|
||||
case BT829_PAL_N_COMB: /* gatos groups with BT829_PAL */
|
||||
if (bt->width <= 360) vfilt = 1; /* gatos says <= 240 */
|
||||
if (bt->width <= 180) vfilt = 2; /* gatos says <= 120 */
|
||||
if (bt->width <= 90) vfilt = 3; /* gatos says <= 60 */
|
||||
break;
|
||||
case BT829_PAL:
|
||||
case BT829_PAL_N:
|
||||
case BT829_SECAM:
|
||||
if (bt->width <= 384) vfilt = 1;
|
||||
if (bt->width <= 192) vfilt = 2;
|
||||
if (bt->width<= 96) vfilt = 3;
|
||||
break;
|
||||
default: /* shouldn't get here */
|
||||
break; /* use hardware default */
|
||||
}
|
||||
btwrite(bt, VTC, (bt->vbien<<4) | (bt->vbifmt<<3) | vfilt);
|
||||
}
|
||||
}
|
||||
|
||||
static void btwrite_cc_status(BT829Ptr bt) /* CC_STATUS */
|
||||
{ /* FIXME: ATI specific */
|
||||
if (BTVERSION >= BT827) {
|
||||
if (bt->ccmode == 0) btwrite(bt, CC_STATUS, 0x00);
|
||||
/* 0x40 is activate to set the CCVALID line. Not required yet */
|
||||
else btwrite(bt, CC_STATUS, (bt->ccmode<<4) | 0x40);
|
||||
}
|
||||
}
|
||||
|
||||
/* CC_DATA is read only */
|
||||
|
||||
static void btwrite_wc_dn(BT829Ptr bt) /* WC_DN */
|
||||
{
|
||||
if (BTVERSION >= BT827) {
|
||||
/* use default */
|
||||
}
|
||||
}
|
||||
|
||||
static void bt_reset(BT829Ptr bt) { /* SRESET */
|
||||
btwrite(bt, SRESET, 0x0); /* Reset all registers */
|
||||
}
|
||||
|
||||
static void btwrite_p_io(BT829Ptr bt) /* P_IO */
|
||||
{
|
||||
if (BTVERSION >= BT827) {
|
||||
btwrite(bt, P_IO, bt->p_io);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Deal with dependencies
|
||||
*/
|
||||
static void propagate_changes(BT829Ptr bt)
|
||||
{
|
||||
CARD16 hdelay, unscaled_hdelay, vdelay, hscale, vscale;
|
||||
int htotal, vactive;
|
||||
|
||||
switch (bt->format) {
|
||||
case BT829_NTSC:
|
||||
case BT829_NTSC_JAPAN:
|
||||
case BT829_PAL_M:
|
||||
vdelay = 22;
|
||||
htotal = 754;
|
||||
vactive = 480;
|
||||
unscaled_hdelay = 135;
|
||||
break;
|
||||
case BT829_PAL:
|
||||
case BT829_PAL_N:
|
||||
vdelay = (bt->tunertype==5) ? 34 : 22;
|
||||
htotal = 922;
|
||||
vactive = 576;
|
||||
unscaled_hdelay = 186;
|
||||
break;
|
||||
case BT829_SECAM:
|
||||
vdelay = 34;
|
||||
htotal = 922;
|
||||
vactive = 576;
|
||||
unscaled_hdelay = 186;
|
||||
break;
|
||||
case BT829_PAL_N_COMB:
|
||||
vdelay = (bt->tunertype==5) ? 34 : 22; /* windows says 22 */
|
||||
htotal = 754; /* gatos and windows say 922 */
|
||||
vactive = 576;
|
||||
unscaled_hdelay = 135; /* gatos and windows say 186 */
|
||||
break;
|
||||
default: /* shouldn't get here */
|
||||
vdelay = 22; /* hardware default */
|
||||
htotal = 754;
|
||||
vactive = 480; /* hardware default */
|
||||
unscaled_hdelay = 135;
|
||||
break;
|
||||
}
|
||||
|
||||
bt->htotal = htotal; /* Used for error checking in bt829_SetCaptSize */
|
||||
|
||||
hscale = 4096 * htotal / (bt->width + 2 * HCROP)-4096;
|
||||
hdelay = (
|
||||
HCROP + (bt->width + 2 * HCROP) * unscaled_hdelay / htotal
|
||||
) & 0x3FE;
|
||||
|
||||
vactive = vactive - 2 * VCROP;
|
||||
vdelay = vdelay + VCROP;
|
||||
vscale = (0x10000 - (512*vactive/bt->height-512)) & 0x1FFF;
|
||||
|
||||
if ((hdelay != bt->hdelay) || (vdelay != bt->vdelay) ||
|
||||
(vactive != bt->vactive) || (hscale != bt->hscale) ||
|
||||
(vscale != bt->vscale)) {
|
||||
bt->hdelay = hdelay;
|
||||
bt->vdelay = vdelay;
|
||||
bt->vactive = vactive;
|
||||
bt->hscale = hscale;
|
||||
bt->vscale = vscale;
|
||||
btwrite_crop(bt);
|
||||
btwrite_vdelay_lo(bt);
|
||||
btwrite_vactive_lo(bt);
|
||||
btwrite_hdelay_lo(bt);
|
||||
btwrite_hscale_hi(bt);
|
||||
btwrite_hscale_lo(bt);
|
||||
btwrite_control(bt);
|
||||
btwrite_vscale_hi(bt);
|
||||
btwrite_vscale_lo(bt);
|
||||
}
|
||||
}
|
||||
|
||||
static void write_all(BT829Ptr bt)
|
||||
{
|
||||
bt_reset(bt);
|
||||
propagate_changes(bt); /* ensure consistency */
|
||||
btwrite_iform(bt);
|
||||
btwrite_tdec(bt);
|
||||
btwrite_crop(bt);
|
||||
btwrite_vdelay_lo(bt);
|
||||
btwrite_vactive_lo(bt);
|
||||
btwrite_hdelay_lo(bt);
|
||||
btwrite_hactive_lo(bt);
|
||||
btwrite_hscale_hi(bt);
|
||||
btwrite_hscale_lo(bt);
|
||||
btwrite_bright(bt);
|
||||
btwrite_control(bt);
|
||||
btwrite_contrast_lo(bt);
|
||||
btwrite_sat_u_lo(bt);
|
||||
btwrite_sat_v_lo(bt);
|
||||
btwrite_hue(bt);
|
||||
btwrite_scloop(bt);
|
||||
btwrite_wc_up(bt);
|
||||
btwrite_oform(bt);
|
||||
btwrite_vscale_hi(bt);
|
||||
btwrite_vscale_lo(bt);
|
||||
btwrite_vpole(bt);
|
||||
btwrite_adelay(bt);
|
||||
btwrite_bdelay(bt);
|
||||
btwrite_adc(bt);
|
||||
btwrite_vtc(bt);
|
||||
/* btwrite_cc_status(bt); */ /* FIXME: CC code needs cleaning */
|
||||
btwrite_wc_dn(bt);
|
||||
btwrite_p_io(bt);
|
||||
}
|
||||
|
||||
/*
|
||||
* Public functions
|
||||
*/
|
||||
BT829Ptr bt829_Detect(I2CBusPtr b, I2CSlaveAddr addr)
|
||||
{
|
||||
BT829Ptr bt;
|
||||
I2CByte a;
|
||||
|
||||
bt = xcalloc(1, sizeof(BT829Rec));
|
||||
if(bt == NULL) return NULL;
|
||||
bt->d.DevName = strdup("BT829 video decoder");
|
||||
bt->d.SlaveAddr = addr;
|
||||
bt->d.pI2CBus = b;
|
||||
bt->d.NextDev = NULL;
|
||||
bt->d.StartTimeout = b->StartTimeout;
|
||||
bt->d.BitTimeout = b->BitTimeout;
|
||||
bt->d.AcknTimeout = b->AcknTimeout;
|
||||
bt->d.ByteTimeout = b->ByteTimeout;
|
||||
|
||||
|
||||
if(!I2C_WriteRead(&(bt->d), NULL, 0, &a, 1))
|
||||
{
|
||||
free(bt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bt->id = btread(bt,IDCODE);
|
||||
|
||||
free(bt->d.DevName);
|
||||
bt->d.DevName = xcalloc(200, sizeof(char));
|
||||
switch(BTVERSION){
|
||||
case BT815:
|
||||
sprintf(bt->d.DevName, "bt815a video decoder, revision %d",bt->id & 0xf);
|
||||
break;
|
||||
case BT817:
|
||||
sprintf(bt->d.DevName, "bt817a video decoder, revision %d",bt->id & 0xf);
|
||||
break;
|
||||
case BT819:
|
||||
sprintf(bt->d.DevName, "bt819a video decoder, revision %d",bt->id & 0xf);
|
||||
break;
|
||||
case BT827:
|
||||
sprintf(bt->d.DevName, "bt827a/b video decoder, revision %d",bt->id & 0xf);
|
||||
break;
|
||||
case BT829:
|
||||
sprintf(bt->d.DevName, "bt829a/b video decoder, revision %d",bt->id & 0xf);
|
||||
break;
|
||||
default:
|
||||
sprintf(bt->d.DevName, "bt8xx/unknown video decoder version %d, revision %d",bt->id >> 4,bt->id & 0xf);
|
||||
break;
|
||||
}
|
||||
|
||||
/* set default parameters */
|
||||
if(!I2CDevInit(&(bt->d)))
|
||||
{
|
||||
free(bt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bt->tunertype = 1;
|
||||
|
||||
bt->brightness = 0; /* hardware default */
|
||||
bt->ccmode = 0;
|
||||
bt->code = 0; /* hardware default */
|
||||
bt->contrast = 216; /* hardware default */
|
||||
bt->format = BT829_NTSC;
|
||||
bt->height = 480; /* hardware default for vactive */
|
||||
bt->hue = 0; /* hardware default */
|
||||
bt->len = 1; /* hardware default */
|
||||
bt->mux = BT829_MUX0; /* hardware default */
|
||||
bt->out_en = 0; /* hardware default */
|
||||
bt->p_io = 0; /* hardware default */
|
||||
bt->sat_u = 254; /* hardware default */
|
||||
bt->sat_v = 180; /* hardware default */
|
||||
bt->vbien = 0; /* hardware default */
|
||||
bt->vbifmt = 0; /* hardware default */
|
||||
bt->width = 640; /* hardware default for hactive */
|
||||
|
||||
bt->hdelay = 120; /* hardware default */
|
||||
bt->hscale = 684; /* hardware default */
|
||||
bt->vactive = 480; /* hardware default */
|
||||
bt->vdelay = 22; /* hardware default */
|
||||
bt->vscale = 0; /* hardware default */
|
||||
|
||||
bt->htotal = 754; /* NTSC */
|
||||
bt->svideo_mux = 0; /* no s-video */
|
||||
|
||||
return bt;
|
||||
}
|
||||
|
||||
int bt829_ATIInit(BT829Ptr bt)
|
||||
{
|
||||
bt->code = 1;
|
||||
bt->len = 0;
|
||||
bt->vbien = 1;
|
||||
bt->vbifmt = 1;
|
||||
bt->svideo_mux = BT829_MUX1;
|
||||
|
||||
write_all (bt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bt829_SetFormat(BT829Ptr bt, CARD8 format)
|
||||
{
|
||||
if ((format < 1) || (format > 7)) return -1;
|
||||
if ((BTVERSION <= BT819) &&
|
||||
(format != BT829_NTSC) && (format != BT829_PAL)) return -1;
|
||||
if (format == bt->format) return 0;
|
||||
bt->format = format;
|
||||
propagate_changes(bt);
|
||||
btwrite_iform(bt);
|
||||
btwrite_scloop(bt);
|
||||
btwrite_adelay(bt);
|
||||
btwrite_bdelay(bt);
|
||||
btwrite_vtc(bt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bt829_SetMux(BT829Ptr bt, CARD8 mux)
|
||||
{
|
||||
if ((mux < 1) || (mux > 3)) return -1;
|
||||
if (mux == bt->mux) return 0;
|
||||
bt->mux = mux;
|
||||
/* propagate_changes(bt); */ /* no dependencies */
|
||||
btwrite_iform(bt);
|
||||
btwrite_control(bt);
|
||||
btwrite_adc(bt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bt829_SetBrightness(BT829Ptr bt, int brightness)
|
||||
{
|
||||
brightness = LIMIT(brightness,-1000,999); /* ensure -128 <= brightness <= 127 below */
|
||||
brightness = (128*brightness)/1000;
|
||||
if (brightness == bt->brightness) return;
|
||||
bt->brightness = brightness;
|
||||
/* propagate_changes(bt); */ /* no dependencies */
|
||||
btwrite_bright(bt);
|
||||
}
|
||||
|
||||
void bt829_SetContrast(BT829Ptr bt, int contrast)
|
||||
{
|
||||
contrast = LIMIT(contrast,-1000,1000);
|
||||
contrast = (216*(contrast+1000))/1000;
|
||||
if (contrast == bt->contrast) return;
|
||||
bt->contrast = contrast;
|
||||
/* propagate_changes(bt); */ /* no dependencies */
|
||||
btwrite_control(bt);
|
||||
btwrite_contrast_lo(bt);
|
||||
}
|
||||
|
||||
void bt829_SetSaturation(BT829Ptr bt, int saturation)
|
||||
{
|
||||
CARD16 sat_u, sat_v;
|
||||
|
||||
saturation = LIMIT(saturation,-1000,1000);
|
||||
sat_u = (254*(saturation+1000))/1000;
|
||||
sat_v = (180*(saturation+1000))/1000;
|
||||
if ((sat_u == bt->sat_u) && (sat_v == bt->sat_v)) return;
|
||||
bt->sat_u = sat_u;
|
||||
bt->sat_v = sat_v;
|
||||
/* propagate_changes(bt); */ /* no dependencies */
|
||||
btwrite_control(bt);
|
||||
btwrite_sat_u_lo(bt);
|
||||
btwrite_sat_v_lo(bt);
|
||||
}
|
||||
|
||||
void bt829_SetTint(BT829Ptr bt, int hue)
|
||||
{
|
||||
hue = LIMIT(hue,-1000,999); /* ensure -128 <= hue <= 127 below */
|
||||
hue = (128*hue)/1000;
|
||||
if (hue == bt->hue) return;
|
||||
bt->hue = hue;
|
||||
/* propagate_changes(bt); */ /* no dependencies */
|
||||
btwrite_hue(bt);
|
||||
}
|
||||
|
||||
int bt829_SetCaptSize(BT829Ptr bt, int width, int height)
|
||||
{
|
||||
if ((width > bt->htotal - 2 * HCROP) ||
|
||||
(16 * width < bt->htotal - 32 * HCROP)) return -1;
|
||||
if ((height > bt->vactive) || (16 * height < bt->vactive)) return -1;
|
||||
if ((width == bt->width) && (height == bt->height)) return 0;
|
||||
bt->width = width;
|
||||
bt->height = height;
|
||||
propagate_changes(bt);
|
||||
btwrite_crop(bt);
|
||||
btwrite_hactive_lo(bt);
|
||||
btwrite_control(bt);
|
||||
btwrite_vtc(bt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bt829_SetCC(BT829Ptr bt) /* FIXME: should take ccmode as a parameter */
|
||||
{
|
||||
if (BTVERSION < BT827) return -1; /* can't do it */
|
||||
/* propagate_changes(bt); */ /* no dependencies */
|
||||
btwrite_cc_status(bt);
|
||||
/* we write to STATUS to reset the CCVALID flag */
|
||||
if (bt->ccmode != 0) btwrite_status(bt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bt829_SetOUT_EN(BT829Ptr bt, BOOL out_en)
|
||||
{
|
||||
out_en = (out_en != 0);
|
||||
if (out_en == bt->out_en) return;
|
||||
bt->out_en = out_en;
|
||||
/* propagate_changes(bt); */ /* no dependencies */
|
||||
btwrite_vpole(bt);
|
||||
}
|
||||
|
||||
void bt829_SetP_IO(BT829Ptr bt, CARD8 p_io)
|
||||
{
|
||||
if (p_io == bt->p_io) return;
|
||||
bt->p_io = p_io;
|
||||
/* propagate_changes(bt); */ /* no dependencies */
|
||||
btwrite_p_io(bt);
|
||||
}
|
||||
|
||||
#define BTREAD(R) btread(bt,(R))
|
||||
|
||||
#if 0
|
||||
|
||||
void bt829_getCCdata(BT829Ptr bt,struct CCdata *data)
|
||||
{
|
||||
CARD8 status;
|
||||
data->num_valid=0;
|
||||
/* wait for buffer to be half full (means 8/16 bytes)
|
||||
* either 4 (one of CC/EDS) or 2 (both CC/EDS) frames */
|
||||
if(!(BTREAD(STATUS)&0x04)) return; /* could comment this line */
|
||||
for(;data->num_valid<CC_FIFO_SIZE;data->num_valid++) {
|
||||
status=BTREAD(CC_STATUS);
|
||||
if(!(status&0x04)) break;
|
||||
data->data[data->num_valid]= BTREAD(CC_DATA)&0x7f;
|
||||
/* stripped high bit (parity) */
|
||||
data->status[data->num_valid]= (CCS_EDS*((status&0x02)>>1)) |
|
||||
(CCS_HIGH*(status&0x01)) |
|
||||
(CCS_OVER*((status&0x08)>>3)) |
|
||||
(CCS_PAR*((status&0x80)>>7)) ; }
|
||||
btwrite(bt,STATUS,0x00); /* Reset CCVALID status bit */
|
||||
return;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* Debug and report routines */
|
||||
|
||||
#define DUMPREG(REG) \
|
||||
xf86DrvMsg(bt->d.pI2CBus->scrnIndex,X_INFO," %-12s (0x%02X) = 0x%02X\n", \
|
||||
#REG,REG,BTREAD(REG))
|
||||
|
||||
/*static void bt829_dumpregs(BT829Ptr bt)
|
||||
{
|
||||
DUMPREG(STATUS);
|
||||
DUMPREG(IFORM);
|
||||
DUMPREG(TDEC);
|
||||
DUMPREG(CROP);
|
||||
DUMPREG(VDELAY_LO);
|
||||
DUMPREG(VACTIVE_LO);
|
||||
DUMPREG(HDELAY_LO);
|
||||
DUMPREG(HACTIVE_LO);
|
||||
DUMPREG(HSCALE_HI);
|
||||
DUMPREG(HSCALE_LO);
|
||||
DUMPREG(BRIGHT);
|
||||
DUMPREG(CONTROL);
|
||||
DUMPREG(CONTRAST_LO);
|
||||
DUMPREG(SAT_U_LO);
|
||||
DUMPREG(SAT_V_LO);
|
||||
DUMPREG(HUE);
|
||||
if (BTVERSION >= BT827) {
|
||||
DUMPREG(SCLOOP);
|
||||
DUMPREG(WC_UP) ; }
|
||||
DUMPREG(OFORM);
|
||||
DUMPREG(VSCALE_HI);
|
||||
DUMPREG(VSCALE_LO);
|
||||
DUMPREG(TEST);
|
||||
DUMPREG(VPOLE);
|
||||
DUMPREG(IDCODE);
|
||||
DUMPREG(ADELAY);
|
||||
DUMPREG(BDELAY);
|
||||
DUMPREG(ADC);
|
||||
if (BTVERSION >= BT827) {
|
||||
DUMPREG(VTC);
|
||||
DUMPREG(CC_STATUS);
|
||||
DUMPREG(CC_DATA);
|
||||
DUMPREG(WC_DN);
|
||||
DUMPREG(P_IO) ; }
|
||||
}*/
|
115
hw/xfree86/i2c/bt829.h
Normal file
115
hw/xfree86/i2c/bt829.h
Normal file
@ -0,0 +1,115 @@
|
||||
#ifndef __BT829_H__
|
||||
#define __BT829_H__
|
||||
|
||||
#include "xf86i2c.h"
|
||||
|
||||
typedef struct {
|
||||
int tunertype; /* Must be set before init */
|
||||
/* Private variables */
|
||||
I2CDevRec d;
|
||||
|
||||
CARD8 brightness;
|
||||
CARD8 ccmode;
|
||||
CARD8 code;
|
||||
CARD16 contrast;
|
||||
CARD8 format;
|
||||
int height;
|
||||
CARD8 hue;
|
||||
CARD8 len;
|
||||
CARD8 mux;
|
||||
CARD8 out_en;
|
||||
CARD8 p_io;
|
||||
CARD16 sat_u;
|
||||
CARD16 sat_v;
|
||||
CARD8 vbien;
|
||||
CARD8 vbifmt;
|
||||
int width;
|
||||
|
||||
CARD16 hdelay;
|
||||
CARD16 hscale;
|
||||
CARD16 vactive;
|
||||
CARD16 vdelay;
|
||||
CARD16 vscale;
|
||||
|
||||
CARD16 htotal;
|
||||
CARD8 id;
|
||||
CARD8 svideo_mux;
|
||||
} BT829Rec, *BT829Ptr;
|
||||
|
||||
BT829Ptr bt829_Detect(I2CBusPtr b, I2CSlaveAddr addr);
|
||||
|
||||
/* ATI card specific initialization */
|
||||
#define BT829_ATI_ADDR_1 0x8A
|
||||
#define BT829_ATI_ADDR_2 0x88
|
||||
int bt829_ATIInit(BT829Ptr bt);
|
||||
|
||||
#define BT829_NTSC 1 /* NTSC-M */
|
||||
#define BT829_NTSC_JAPAN 2 /* NTSC-Japan */
|
||||
#define BT829_PAL 3 /* PAL-B,D,G,H,I */
|
||||
#define BT829_PAL_M 4 /* PAL-M */
|
||||
#define BT829_PAL_N 5 /* PAL-N */
|
||||
#define BT829_SECAM 6 /* SECAM */
|
||||
#define BT829_PAL_N_COMB 7 /* PAL-N combination */
|
||||
int bt829_SetFormat(BT829Ptr bt, CARD8 format);
|
||||
|
||||
#define BT829_MUX2 1 /* ATI -> composite video */
|
||||
#define BT829_MUX0 2 /* ATI -> tv tuner */
|
||||
#define BT829_MUX1 3 /* ATI -> s-video */
|
||||
int bt829_SetMux(BT829Ptr bt, CARD8 mux);
|
||||
|
||||
int bt829_SetCaptSize(BT829Ptr bt, int width, int height);
|
||||
|
||||
void bt829_SetBrightness(BT829Ptr bt, int brightness);
|
||||
void bt829_SetContrast(BT829Ptr bt, int contrast);
|
||||
void bt829_SetSaturation(BT829Ptr bt, int saturation);
|
||||
void bt829_SetTint(BT829Ptr bt, int hue); /* Hue */
|
||||
|
||||
void bt829_SetOUT_EN(BT829Ptr bt, BOOL out_en); /* VPOLE register */
|
||||
void bt829_SetP_IO(BT829Ptr bt, CARD8 p_io); /* P_IO register */
|
||||
|
||||
int bt829_SetCC(BT829Ptr bt);
|
||||
|
||||
#define BT829SymbolsList \
|
||||
"bt829_Detect", \
|
||||
"bt829_ATIInit", \
|
||||
"bt829_SetFormat", \
|
||||
"bt829_SetMux", \
|
||||
"bt829_SetBrightness", \
|
||||
"bt829_SetContrast", \
|
||||
"bt829_SetSaturation", \
|
||||
"bt829_SetTint", \
|
||||
"bt829_SetCaptSize", \
|
||||
"bt829_SetOUT_EN", \
|
||||
"bt829_SetP_IO"
|
||||
|
||||
#ifdef XFree86LOADER
|
||||
|
||||
#define xf86_bt829_Detect ((BT829Ptr (*)(I2CBusPtr, I2CSlaveAddr))LoaderSymbol("bt829_Detect"))
|
||||
#define xf86_bt829_ATIInit ((int (*)(BT829Ptr))LoaderSymbol("bt829_ATIInit"))
|
||||
#define xf86_bt829_SetFormat ((int (*)(BT829Ptr, CARD8))LoaderSymbol("bt829_SetFormat"))
|
||||
#define xf86_bt829_SetMux ((int (*)(BT829Ptr, CARD8))LoaderSymbol("bt829_SetMux"))
|
||||
#define xf86_bt829_SetCaptSize ((int (*)(BT829Ptr, int, int))LoaderSymbol("bt829_SetCaptSize"))
|
||||
#define xf86_bt829_SetBrightness ((void (*)(BT829Ptr, int))LoaderSymbol("bt829_SetBrightness"))
|
||||
#define xf86_bt829_SetContrast ((void (*)(BT829Ptr, int))LoaderSymbol("bt829_SetContrast"))
|
||||
#define xf86_bt829_SetSaturation ((void (*)(BT829Ptr, int))LoaderSymbol("bt829_SetSaturation"))
|
||||
#define xf86_bt829_SetTint ((void (*)(BT829Ptr, int))LoaderSymbol("bt829_SetTint"))
|
||||
#define xf86_bt829_SetOUT_EN ((void (*)(BT829Ptr, Bool))LoaderSymbol("bt829_SetOUT_EN"))
|
||||
#define xf86_bt829_SetP_IO ((void (*)(BT829Ptr, CARD8))LoaderSymbol("bt829_SetP_IO"))
|
||||
|
||||
#else
|
||||
|
||||
#define xf86_bt829_Detect bt829_Detect
|
||||
#define xf86_bt829_ATIInit bt829_ATIInit
|
||||
#define xf86_bt829_SetFormat bt829_SetFormat
|
||||
#define xf86_bt829_SetMux bt829_SetMux
|
||||
#define xf86_bt829_SetCaptSize bt829_SetCaptSize
|
||||
#define xf86_bt829_SetBrightness bt829_SetBrightness
|
||||
#define xf86_bt829_SetContrast bt829_SetContrast
|
||||
#define xf86_bt829_SetSaturation bt829_SetSaturation
|
||||
#define xf86_bt829_SetTint bt829_SetTint
|
||||
#define xf86_bt829_SetOUT_EN bt829_SetOUT_EN
|
||||
#define xf86_bt829_SetP_IO bt829_SetP_IO
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
26
hw/xfree86/i2c/bt829_module.c
Normal file
26
hw/xfree86/i2c/bt829_module.c
Normal file
@ -0,0 +1,26 @@
|
||||
|
||||
#include "xf86Module.h"
|
||||
|
||||
static MODULESETUPPROTO(bt829Setup);
|
||||
|
||||
|
||||
static XF86ModuleVersionInfo bt829VersRec =
|
||||
{
|
||||
"bt829",
|
||||
MODULEVENDORSTRING,
|
||||
MODINFOSTRING1,
|
||||
MODINFOSTRING2,
|
||||
XF86_VERSION_CURRENT,
|
||||
1, 0, 0,
|
||||
ABI_CLASS_VIDEODRV, /* This needs the video driver ABI */
|
||||
ABI_VIDEODRV_VERSION,
|
||||
MOD_CLASS_NONE,
|
||||
{0,0,0,0}
|
||||
};
|
||||
|
||||
XF86ModuleData bt829ModuleData = { &bt829VersRec, bt829Setup, NULL };
|
||||
|
||||
static pointer
|
||||
bt829Setup(pointer module, pointer opts, int *errmaj, int *errmin) {
|
||||
return (pointer)1;
|
||||
}
|
550
hw/xfree86/i2c/fi1236.c
Normal file
550
hw/xfree86/i2c/fi1236.c
Normal file
@ -0,0 +1,550 @@
|
||||
#include "xf86.h"
|
||||
#include "xf86i2c.h"
|
||||
#include "fi1236.h"
|
||||
#include "i2c_def.h"
|
||||
|
||||
#define NUM_TUNERS 7
|
||||
|
||||
const FI1236_parameters tuner_parms[NUM_TUNERS] =
|
||||
{
|
||||
/* 0 - FI1236 */
|
||||
{ 733 ,884 ,12820 ,2516 ,7220 ,0xA2 ,0x94, 0x34, 0x8e },
|
||||
/* !!!based on documentation - it should be:
|
||||
{733 ,16*55.25 ,16*801.25 ,16*160 ,16*454 ,0xA0 ,0x90, 0x30, 0x8e},*/
|
||||
|
||||
/* 1 - FI1216 */
|
||||
{ 623 ,16*48.75 ,16*855.25 ,16*170 ,16*450 ,0xA0 ,0x90, 0x30, 0x8e },
|
||||
/* 2 - TEMIC FN5AL */
|
||||
{ 623 ,16*45.75 ,16*855.25 ,16*169 ,16*454 ,0xA0 ,0x90, 0x30, 0x8e },
|
||||
/* 3 - MT2032.. */
|
||||
{ 733 ,768 ,13760 , 0 , 0 , 0 , 0, 0, 0 },
|
||||
/* 4 - FI1246 */
|
||||
{ 623 ,16*45.75 ,16*855.25 ,16*170 ,16*450 ,0xA0 ,0x90, 0x30, 0x8e },
|
||||
/* 5 - FI1256 */
|
||||
{ 623 ,16*49.75 ,16*863.25 ,16*170 ,16*450 ,0xA0 ,0x90, 0x30, 0x8e },
|
||||
/* 6 - FI1236W */
|
||||
{ 733 ,884 ,12820 ,2516 ,7220 ,0x1 ,0x2, 0x4, 0x8e }
|
||||
};
|
||||
|
||||
|
||||
FI1236Ptr Detect_FI1236(I2CBusPtr b, I2CSlaveAddr addr)
|
||||
{
|
||||
FI1236Ptr f;
|
||||
I2CByte a;
|
||||
|
||||
f = xcalloc(1,sizeof(FI1236Rec));
|
||||
if(f == NULL) return NULL;
|
||||
f->d.DevName = strdup("FI12xx Tuner");
|
||||
f->d.SlaveAddr = addr;
|
||||
f->d.pI2CBus = b;
|
||||
f->d.NextDev = NULL;
|
||||
f->d.StartTimeout = b->StartTimeout;
|
||||
f->d.BitTimeout = b->BitTimeout;
|
||||
f->d.AcknTimeout = b->AcknTimeout;
|
||||
f->d.ByteTimeout = b->ByteTimeout;
|
||||
f->type=TUNER_TYPE_FI1236;
|
||||
f->afc_timer_installed=FALSE;
|
||||
f->last_afc_hint=TUNER_OFF;
|
||||
f->video_if=45.7812;
|
||||
|
||||
if(!I2C_WriteRead(&(f->d), NULL, 0, &a, 1))
|
||||
{
|
||||
free(f);
|
||||
return NULL;
|
||||
}
|
||||
FI1236_set_tuner_type(f, TUNER_TYPE_FI1236);
|
||||
if(!I2CDevInit(&(f->d)))
|
||||
{
|
||||
free(f);
|
||||
return NULL;
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
static void MT2032_dump_parameters(FI1236Ptr f, MT2032_parameters *m)
|
||||
{
|
||||
xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "MT2032: input f_rf=%g f_if1=%g f_if2=%g f_ref=%g f_ifbw=%g f_step=%g\n",
|
||||
m->f_rf, m->f_if1, m->f_if2, m->f_ref, m->f_ifbw, m->f_step);
|
||||
|
||||
xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "MT2032: computed f_lo1=%g f_lo2=%g LO1I=%d LO2I=%d SEL=%d STEP=%d NUM=%d\n",
|
||||
m->f_lo1, m->f_lo2, m->LO1I, m->LO2I, m->SEL, m->STEP, m->NUM);
|
||||
}
|
||||
|
||||
|
||||
static void MT2032_getid(FI1236Ptr f)
|
||||
{
|
||||
CARD8 out[4];
|
||||
CARD8 in;
|
||||
|
||||
in=0x11;
|
||||
I2C_WriteRead(&(f->d), (I2CByte *)&in, 1, out, 4);
|
||||
xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "MT2032: Company code 0x%02x%02x, part code 0x%02x, revision code 0x%02x\n",
|
||||
out[0], out[1], out[2], out[3]);
|
||||
|
||||
}
|
||||
|
||||
/* might be buggy */
|
||||
static void MT2032_shutdown(FI1236Ptr f)
|
||||
{
|
||||
CARD8 data[10];
|
||||
CARD8 value;
|
||||
|
||||
data[0]=0x00; /* start with register 0x00 */
|
||||
data[1]=0x1A;
|
||||
data[2]=0x44;
|
||||
data[3]=0x20;
|
||||
|
||||
I2C_WriteRead(&(f->d), (I2CByte *)data, 4, NULL, 0);
|
||||
|
||||
data[0]=0x05; /* now start with register 0x05 */
|
||||
data[1]=0xD7;
|
||||
data[2]=0x14;
|
||||
data[3]=0x05;
|
||||
I2C_WriteRead(&(f->d), (I2CByte *)data, 4, NULL, 0);
|
||||
|
||||
data[0]=0x0B; /* now start with register 0x05 */
|
||||
data[1]=0x8F;
|
||||
data[2]=0x07;
|
||||
data[3]=0x43;
|
||||
I2C_WriteRead(&(f->d), (I2CByte *)data, 4, NULL, 0);
|
||||
|
||||
usleep(15000);
|
||||
}
|
||||
|
||||
|
||||
static void MT2032_init(FI1236Ptr f)
|
||||
{
|
||||
CARD8 data[10];
|
||||
CARD8 value;
|
||||
CARD8 xogc;
|
||||
|
||||
MT2032_getid(f);
|
||||
|
||||
data[0]=0x02; /* start with register 0x02 */
|
||||
data[1]=0xFF;
|
||||
data[2]=0x0F;
|
||||
data[3]=0x1F;
|
||||
|
||||
I2C_WriteRead(&(f->d), (I2CByte *)data, 4, NULL, 0);
|
||||
|
||||
data[0]=0x06; /* now start with register 0x06 */
|
||||
data[1]=0xE4;
|
||||
data[2]=0x8F;
|
||||
data[3]=0xC3;
|
||||
data[4]=0x4E;
|
||||
data[5]=0xEC;
|
||||
I2C_WriteRead(&(f->d), (I2CByte *)data, 6, NULL, 0);
|
||||
|
||||
data[0]=0x0d; /* now start with register 0x0d */
|
||||
data[1]=0x32;
|
||||
I2C_WriteRead(&(f->d), (I2CByte *)data, 2, NULL, 0);
|
||||
|
||||
while(1) {
|
||||
usleep(15000); /* wait 15 milliseconds */
|
||||
|
||||
data[0]=0x0e; /* register number 7, status */
|
||||
value=0xFF;
|
||||
if(!I2C_WriteRead(&(f->d), (I2CByte *)data, 1, &value, 1))
|
||||
xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "MT2032: failed to read XOK\n");
|
||||
xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "MT2032: XOK=%d\n", value & 0x01);
|
||||
if(value & 1) break;
|
||||
|
||||
data[0]=0x07;
|
||||
if(!I2C_WriteRead(&(f->d), (I2CByte *)data, 1, &value, 1))
|
||||
xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "MT2032: failed to read XOGC\n");
|
||||
|
||||
xogc=value & 0x7;
|
||||
if(xogc==4){
|
||||
break; /* XOGC has reached 4.. stop */
|
||||
}
|
||||
xogc--;
|
||||
xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "MT2032: try XOGC=%d\n", xogc);
|
||||
usleep(15000);
|
||||
data[0]=0x07; /* register number 7, control byte 2 */
|
||||
data[1]=0x08 | xogc;
|
||||
I2C_WriteRead(&(f->d), (I2CByte *)data, 2, NULL, 0);
|
||||
}
|
||||
f->xogc=xogc;
|
||||
/* wait before continuing */
|
||||
usleep(15000); /* wait 50 milliseconds */
|
||||
MT2032_dump_status(f);
|
||||
}
|
||||
|
||||
static int MT2032_no_spur_in_band(MT2032_parameters *m)
|
||||
{
|
||||
int n_max, n1, n2;
|
||||
double f_test;
|
||||
n_max=5;
|
||||
n1=1;
|
||||
while(1){
|
||||
n2=-n1;
|
||||
f_test=n1*(m->f_lo1-m->f_lo2);
|
||||
while(1){
|
||||
n2--;
|
||||
f_test=f_test-m->f_lo2;
|
||||
xf86DrvMsg(0, X_INFO, "testing f_test=%g n1=%d n2=%d f_lo1=%g f_lo2=%g f_if2=%g\n", f_test, n1, n2, m->f_lo1, m->f_lo2, m->f_if2);
|
||||
xf86DrvMsg(0, X_INFO, "d_f=%g f_ifbw=%g\n",fabs(fabs(f_test)-m->f_if2), m->f_ifbw);
|
||||
if((fabs(fabs(f_test)-m->f_if2)*2.0)<=m->f_ifbw)return 0;
|
||||
if(n2<=-n_max)break;
|
||||
/* this line in the manual is bogus. I say it is faster
|
||||
and more correct to go over all harmonics.. */
|
||||
#if 0
|
||||
if(f_test<(m->f_lo2-m->f_if2-m->f_ifbw))break;
|
||||
#endif
|
||||
}
|
||||
n1++;
|
||||
if(n1>=n_max)return 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void MT2032_calculate_register_settings(MT2032_parameters *m, double f_rf, double f_if1, double f_if2, double f_ref, double f_ifbw, double f_step)
|
||||
{
|
||||
int n;
|
||||
m->f_rf=f_rf;
|
||||
m->f_if1=f_if1;
|
||||
m->f_if2=f_if2;
|
||||
m->f_ref=f_ref;
|
||||
m->f_ifbw=f_ifbw;
|
||||
m->f_step=f_step;
|
||||
|
||||
m->f_lo1=f_rf+f_if1;
|
||||
m->LO1I=(int)floor((m->f_lo1/f_ref)+0.5);
|
||||
m->f_lo1=f_ref*m->LO1I;
|
||||
|
||||
m->f_lo2=m->f_lo1-f_rf-f_if2;
|
||||
|
||||
/* check for spurs */
|
||||
n=1;
|
||||
while(n<3){
|
||||
if(MT2032_no_spur_in_band(m))break;
|
||||
if(m->f_lo1<(f_rf+f_if1)){
|
||||
m->LO1I+=n;
|
||||
} else {
|
||||
m->LO1I-=n;
|
||||
}
|
||||
m->f_lo1=m->LO1I*f_ref;
|
||||
m->f_lo2=m->f_lo1-f_rf-f_if2;
|
||||
n++;
|
||||
}
|
||||
/* xf86DrvMsg(0, X_INFO, "MT2032: n=%d\n", n); */
|
||||
/* select VCO */
|
||||
|
||||
/* m->f_lo1>1100.0 */
|
||||
if(m->f_lo1<1370.0)m->SEL=4;
|
||||
else
|
||||
if(m->f_lo1<1530.0)m->SEL=3;
|
||||
else
|
||||
if(m->f_lo1<1720.0)m->SEL=2;
|
||||
else
|
||||
if(m->f_lo1<1890.0)m->SEL=1;
|
||||
else /* m->f_lo1 < 1958.0 */
|
||||
m->SEL=0;
|
||||
|
||||
/* calculate the rest of the registers */
|
||||
m->LO2I=(int)floor(m->f_lo2/f_ref);
|
||||
m->STEP=(int)floor(3780.0*f_step/f_ref);
|
||||
m->NUM=(int)floor(3780.0*(m->f_lo2/f_ref-m->LO2I));
|
||||
m->NUM=m->STEP*(int)floor((1.0*m->NUM)/(1.0*m->STEP)+0.5);
|
||||
}
|
||||
|
||||
static int MT2032_wait_for_lock(FI1236Ptr f)
|
||||
{
|
||||
int n;
|
||||
CARD8 data[10];
|
||||
CARD8 value;
|
||||
|
||||
n=12;
|
||||
while(1){
|
||||
data[0]=0x0e; /* register number 7, status */
|
||||
I2C_WriteRead(&(f->d), (I2CByte *)data, 1, &value, 1);
|
||||
/* xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "MT2032: LO1LK=%d LO2LK=%d\n", (value & 0x04)>>2, (value & 0x02)>>1); */
|
||||
if((value & 6)==6) break;
|
||||
usleep(1500);
|
||||
n--;
|
||||
if(n<0)break;
|
||||
}
|
||||
if(n<0){
|
||||
xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "MT2032: failed to set frequency\n");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void MT2032_implement_settings(FI1236Ptr f, MT2032_parameters *m)
|
||||
{
|
||||
CARD8 data[10];
|
||||
CARD8 value;
|
||||
|
||||
data[0]=0x00; /* start with register 0x00 */
|
||||
data[1]=(m->LO1I>>3)-1;
|
||||
data[2]=(m->SEL<<4)|(m->LO1I & 0x7);
|
||||
data[3]=0x86;
|
||||
I2C_WriteRead(&(f->d), (I2CByte *)data, 4, NULL, 0);
|
||||
|
||||
data[0]=0x05; /* start with register 0x05 */
|
||||
data[1]=((m->LO2I & 0x7)<<5)|((m->LO2I>>3)-1);
|
||||
if(m->f_rf<400.0)data[2]=0xe4;
|
||||
else data[2]=0xf4;
|
||||
I2C_WriteRead(&(f->d), (I2CByte *)data, 3, NULL, 0);
|
||||
|
||||
data[0]=0x07; /* register number 7, control byte 2 */
|
||||
I2C_WriteRead(&(f->d), (I2CByte *)data, 1, &value, 1);
|
||||
xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "MT2032: using XOGC=%d\n", (value & 0x07));
|
||||
data[1]=8 | (value & 0x7);
|
||||
I2C_WriteRead(&(f->d), (I2CByte *)data, 2, NULL, 0);
|
||||
|
||||
data[0]=0x0b; /* start with register 0x0b */
|
||||
data[1]=m->NUM & 0xff;
|
||||
data[2]=(1<<7)|((m->NUM >> 8) & 0x0f);
|
||||
I2C_WriteRead(&(f->d), (I2CByte *)data, 3, NULL, 0);
|
||||
|
||||
MT2032_wait_for_lock(f);
|
||||
}
|
||||
|
||||
static void MT2032_optimize_VCO(FI1236Ptr f, MT2032_parameters *m)
|
||||
{
|
||||
CARD8 data[10];
|
||||
CARD8 value;
|
||||
CARD8 TAD1;
|
||||
|
||||
data[0]=0x0f; /* register number 7, status */
|
||||
I2C_WriteRead(&(f->d), (I2CByte *)data, 1, &value, 1);
|
||||
TAD1=value & 0x07;
|
||||
xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "MT2032: TAD1=%d SEL=%d\n", TAD1, m->SEL);
|
||||
if(TAD1 < 2)return;
|
||||
if(TAD1==2){
|
||||
if(m->SEL==0)return;
|
||||
m->SEL--;
|
||||
} else {
|
||||
if(m->SEL>=4)return;
|
||||
m->SEL++;
|
||||
}
|
||||
data[0]=0x01; /* start with register 1 */
|
||||
data[1]=(m->SEL<<4)|(m->LO1I & 0x7);
|
||||
I2C_WriteRead(&(f->d), (I2CByte *)data, 2, NULL, 0);
|
||||
|
||||
}
|
||||
|
||||
static int FI1236_get_afc_hint(FI1236Ptr f)
|
||||
{
|
||||
CARD8 out;
|
||||
CARD8 AFC;
|
||||
I2C_WriteRead(&(f->d), NULL, 0, &out, 1);
|
||||
AFC=out & 0x7;
|
||||
if(AFC==2)return TUNER_TUNED;
|
||||
if(AFC==3)return TUNER_JUST_BELOW;
|
||||
if(AFC==1)return TUNER_JUST_ABOVE;
|
||||
return TUNER_OFF;
|
||||
}
|
||||
|
||||
|
||||
static int MT2032_get_afc_hint(FI1236Ptr f)
|
||||
{
|
||||
CARD8 in;
|
||||
CARD8 out[2];
|
||||
CARD8 AFC;
|
||||
in=0x0e;
|
||||
I2C_WriteRead(&(f->d), (I2CByte *)&in, 1, out, 2);
|
||||
AFC=(out[0]>>4) & 0x7;
|
||||
#if 0
|
||||
xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "AFC=%d TAD1=%d TAD2=%d\n", AFC, out[1] & 0x7, (out[1]>>4)& 0x07);
|
||||
#endif
|
||||
if(AFC==2)return TUNER_TUNED;
|
||||
if(AFC==3)return TUNER_JUST_BELOW;
|
||||
if(AFC==1)return TUNER_JUST_ABOVE;
|
||||
return TUNER_OFF;
|
||||
}
|
||||
|
||||
/* this function is for external use only */
|
||||
int TUNER_get_afc_hint(FI1236Ptr f)
|
||||
{
|
||||
if(f->afc_timer_installed)return TUNER_STILL_TUNING;
|
||||
return f->last_afc_hint;
|
||||
if(f->type==TUNER_TYPE_MT2032)
|
||||
return MT2032_get_afc_hint(f);
|
||||
else
|
||||
return FI1236_get_afc_hint(f);
|
||||
}
|
||||
|
||||
static void MT2032_dump_status(FI1236Ptr f)
|
||||
{
|
||||
CARD8 in;
|
||||
CARD8 out[2];
|
||||
CARD8 AFC;
|
||||
CARD8 LDONrb;
|
||||
CARD8 LO1LK, LO2LK, XOK;
|
||||
CARD8 TAD2, TAD1;
|
||||
|
||||
in=0x0e;
|
||||
I2C_WriteRead(&(f->d), (I2CByte *)&in, 1, out, 2);
|
||||
XOK=out[0] & 1;
|
||||
LO1LK=(out[0]>>2) &1;
|
||||
LO2LK=(out[0]>>1) &1;
|
||||
LDONrb=(out[0]>>3) &1;
|
||||
|
||||
AFC=(out[0]>>4) & 0x7;
|
||||
|
||||
TAD1=(out[1] & 0x7);
|
||||
TAD2=(out[1]>>4) & 0x7;
|
||||
|
||||
xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "MT2032: status: XOK=%d LO1LK=%d LO2LK=%d LDONrb=%d AFC=%d TAD1=%d TAD2=%d\n",
|
||||
XOK, LO1LK, LO2LK, LDONrb, AFC, TAD1, TAD2);
|
||||
xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "MT2032: status: OSCILLATOR:%s PLL1:%s PLL2:%s\n",
|
||||
XOK ? "ok":"off", LO1LK ? "locked" : "off" , LO2LK ? "locked" : "off");
|
||||
|
||||
}
|
||||
|
||||
static void MT2032_tune(FI1236Ptr f, double freq, double step)
|
||||
{
|
||||
MT2032_parameters m;
|
||||
CARD8 data[10];
|
||||
int i;
|
||||
/* NTSC IF is 44mhz.. but 733/16=45.8125 and all TDAXXXX docs mention
|
||||
45.75, 39, 58.75 and 30. */
|
||||
#if 0
|
||||
MT2032_calculate_register_settings(&m, freq, 1090.0, 45.125, 5.25, 6.0, step);
|
||||
MT2032_calculate_register_settings(&m, freq, 1090.0, 45.74, 5.25, 6.0, step);
|
||||
#endif
|
||||
MT2032_calculate_register_settings(&m, freq, 1090.0, f->video_if, 5.25, 3.0, step);
|
||||
MT2032_dump_parameters(f, &m);
|
||||
MT2032_implement_settings(f, &m);
|
||||
/* MT2032_dump_parameters(f, &m); */
|
||||
for(i=0;i<3;i++){
|
||||
MT2032_optimize_VCO(f, &m);
|
||||
if(MT2032_wait_for_lock(f)){
|
||||
data[0]=0x02; /* LO Gain control register 0x02 */
|
||||
data[1]=0x20;
|
||||
I2C_WriteRead(&(f->d), (I2CByte *)data, 2, NULL, 0);
|
||||
return;
|
||||
}
|
||||
data[0]=0x07;
|
||||
data[1]=0x88|f->xogc;
|
||||
I2C_WriteRead(&(f->d), (I2CByte *)data, 2, NULL, 0);
|
||||
usleep(15000);
|
||||
data[1]=0x08|f->xogc;
|
||||
I2C_WriteRead(&(f->d), (I2CByte *)data, 2, NULL, 0);
|
||||
}
|
||||
xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "MT2032: failed to set frequency\n");
|
||||
}
|
||||
|
||||
void FI1236_set_tuner_type(FI1236Ptr f, int type)
|
||||
{
|
||||
f->type=type;
|
||||
if(type>=NUM_TUNERS)type = NUM_TUNERS-1;
|
||||
if(type<0)type = 0;
|
||||
memcpy(&(f->parm), &(tuner_parms[type]), sizeof(FI1236_parameters));
|
||||
f->original_frequency=f->parm.min_freq;
|
||||
f->afc_delta=0;
|
||||
if(type==TUNER_TYPE_MT2032){
|
||||
MT2032_init(f);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CARD32 AFC_TimerCallback(OsTimerPtr timer, CARD32 time, pointer data){
|
||||
FI1236Ptr f=(FI1236Ptr)data;
|
||||
if(FI1236_AFC(f))return 150;
|
||||
else {
|
||||
f->afc_timer_installed=FALSE;
|
||||
f->afc_count=0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void FI1236_tune(FI1236Ptr f, CARD32 frequency)
|
||||
{
|
||||
CARD16 divider;
|
||||
|
||||
if(frequency < f->parm.min_freq) frequency = f->parm.min_freq;
|
||||
if(frequency > f->parm.max_freq) frequency = f->parm.max_freq;
|
||||
|
||||
divider = (f->parm.fcar+(CARD16)frequency) & 0x7fff;
|
||||
f->tuner_data.div1 = (CARD8)((divider>>8)&0x7f);
|
||||
f->tuner_data.div2 = (CARD8)(divider & 0xff);
|
||||
f->tuner_data.control = f->parm.control;
|
||||
|
||||
if(frequency < f->parm.threshold1)
|
||||
{
|
||||
f->tuner_data.band = f->parm.band_low;
|
||||
}
|
||||
else if (frequency < f->parm.threshold2)
|
||||
{
|
||||
f->tuner_data.band = f->parm.band_mid;
|
||||
}
|
||||
else
|
||||
{
|
||||
f->tuner_data.band = f->parm.band_high;
|
||||
}
|
||||
|
||||
#if 0
|
||||
xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "Setting tuner frequency to %d\n", frequency);
|
||||
#endif
|
||||
I2C_WriteRead(&(f->d), (I2CByte *)&(f->tuner_data), 4, NULL, 0);
|
||||
}
|
||||
|
||||
void TUNER_set_frequency(FI1236Ptr f, CARD32 frequency)
|
||||
{
|
||||
CARD16 divider;
|
||||
|
||||
if(frequency < f->parm.min_freq) frequency = f->parm.min_freq;
|
||||
if(frequency > f->parm.max_freq) frequency = f->parm.max_freq;
|
||||
|
||||
f->afc_delta=0;
|
||||
f->original_frequency=frequency;
|
||||
|
||||
if(f->type==TUNER_TYPE_MT2032){
|
||||
MT2032_tune(f, (1.0*frequency)/16.0, 0.0625);
|
||||
} else {
|
||||
FI1236_tune(f, frequency);
|
||||
}
|
||||
|
||||
if(!f->afc_timer_installed){
|
||||
f->afc_timer_installed=TRUE;
|
||||
/* RegisterBlockAndWakeupHandlers(FI1236_BlockHandler, AFCWakeup, f); */
|
||||
TimerSet(NULL, 0, 300, AFC_TimerCallback, f);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
int FI1236_AFC(FI1236Ptr f)
|
||||
{
|
||||
xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "AFC: f=%p f->count=%d f->original_frequency=%d f->afc_delta=%d\n", f, f->afc_count, f->original_frequency, f->afc_delta);
|
||||
f->afc_count++;
|
||||
if(f->type==TUNER_TYPE_MT2032){
|
||||
f->last_afc_hint=MT2032_get_afc_hint(f);
|
||||
xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "AFC: afc_hint=%d\n", f->last_afc_hint);
|
||||
if(f->last_afc_hint==TUNER_TUNED)return 0;
|
||||
if(f->afc_count>3)f->last_afc_hint=TUNER_OFF;
|
||||
if(f->last_afc_hint==TUNER_OFF){
|
||||
f->afc_delta=0;
|
||||
} else
|
||||
f->afc_delta+=f->last_afc_hint;
|
||||
xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "AFC: Setting tuner frequency to %g\n", (0.5*(2*f->original_frequency+f->afc_delta))/16.0);
|
||||
MT2032_tune(f, (1.0*f->original_frequency+0.5*f->afc_delta)/16.0, 0.03125);
|
||||
if(f->last_afc_hint==TUNER_OFF)return 0;
|
||||
return 1; /* call me again */
|
||||
} else {
|
||||
f->last_afc_hint=FI1236_get_afc_hint(f);
|
||||
if(f->last_afc_hint==TUNER_TUNED)return 0;
|
||||
if(f->afc_count>3)f->last_afc_hint=TUNER_OFF;
|
||||
if(f->last_afc_hint==TUNER_OFF){
|
||||
f->afc_delta=0;
|
||||
} else
|
||||
f->afc_delta+=f->last_afc_hint;
|
||||
xf86DrvMsg(f->d.pI2CBus->scrnIndex, X_INFO, "AFC: Setting tuner frequency to %g\n", (0.5*(2*f->original_frequency+f->afc_delta))/16.0);
|
||||
FI1236_tune(f, f->original_frequency+f->afc_delta);
|
||||
if(f->last_afc_hint==TUNER_OFF)return 0;
|
||||
return 1; /* call me again */
|
||||
}
|
||||
return 0; /* done */
|
||||
}
|
||||
|
||||
void fi1236_dump_status(FI1236Ptr f)
|
||||
{
|
||||
if(f->type==TUNER_TYPE_MT2032){
|
||||
MT2032_dump_status(f);
|
||||
}
|
||||
}
|
116
hw/xfree86/i2c/fi1236.h
Normal file
116
hw/xfree86/i2c/fi1236.h
Normal file
@ -0,0 +1,116 @@
|
||||
#ifndef __FI1236_H__
|
||||
#define __FI1236_H__
|
||||
|
||||
#include "xf86i2c.h"
|
||||
|
||||
/* why someone has defined NUM someplace else is beyoung me.. */
|
||||
#undef NUM
|
||||
|
||||
typedef struct {
|
||||
CARD32 fcar; /* 16 * fcar_Mhz */
|
||||
CARD32 min_freq; /* 16 * min_freq_Mhz */
|
||||
CARD32 max_freq; /* 16 * max_freq_Mhz */
|
||||
|
||||
CARD32 threshold1; /* 16 * Value_Mhz */
|
||||
CARD32 threshold2; /* 16 * Value_Mhz */
|
||||
|
||||
CARD8 band_low;
|
||||
CARD8 band_mid;
|
||||
CARD8 band_high;
|
||||
CARD8 control;
|
||||
} FI1236_parameters;
|
||||
|
||||
|
||||
typedef struct {
|
||||
/* what we want */
|
||||
/* all frequencies are in Mhz */
|
||||
double f_rf; /* frequency to tune to */
|
||||
double f_if1; /* first intermediate frequency */
|
||||
double f_if2; /* second intermediate frequency */
|
||||
double f_ref; /* reference frequency */
|
||||
double f_ifbw; /* bandwidth */
|
||||
double f_step; /* step */
|
||||
|
||||
/* what we compute */
|
||||
double f_lo1;
|
||||
double f_lo2;
|
||||
int LO1I;
|
||||
int LO2I;
|
||||
int SEL;
|
||||
int STEP;
|
||||
int NUM;
|
||||
} MT2032_parameters;
|
||||
|
||||
typedef struct {
|
||||
I2CDevRec d;
|
||||
int type;
|
||||
|
||||
int afc_delta;
|
||||
CARD32 original_frequency;
|
||||
Bool afc_timer_installed;
|
||||
int afc_count;
|
||||
int last_afc_hint;
|
||||
|
||||
double video_if;
|
||||
FI1236_parameters parm;
|
||||
int xogc; /* for MT2032 */
|
||||
|
||||
struct {
|
||||
CARD8 div1;
|
||||
CARD8 div2;
|
||||
CARD8 control;
|
||||
CARD8 band;
|
||||
} tuner_data;
|
||||
} FI1236Rec, *FI1236Ptr;
|
||||
|
||||
#define TUNER_TYPE_FI1236 0
|
||||
#define TUNER_TYPE_FI1216 1
|
||||
#define TUNER_TYPE_TEMIC_FN5AL 2
|
||||
#define TUNER_TYPE_MT2032 3
|
||||
#define TUNER_TYPE_FI1246 4
|
||||
#define TUNER_TYPE_FI1256 5
|
||||
#define TUNER_TYPE_FI1236W 6
|
||||
|
||||
#define FI1236_ADDR(a) ((a)->d.SlaveAddr)
|
||||
|
||||
#define FI1236_ADDR_1 0xC6
|
||||
#define FI1236_ADDR_2 0xC0
|
||||
|
||||
#define TUNER_TUNED 0
|
||||
#define TUNER_JUST_BELOW 1
|
||||
#define TUNER_JUST_ABOVE -1
|
||||
#define TUNER_OFF 4
|
||||
#define TUNER_STILL_TUNING 5
|
||||
|
||||
|
||||
FI1236Ptr Detect_FI1236(I2CBusPtr b, I2CSlaveAddr addr);
|
||||
void FI1236_set_tuner_type(FI1236Ptr f, int type);
|
||||
void TUNER_set_frequency(FI1236Ptr f, CARD32 frequency);
|
||||
int FI1236_AFC(FI1236Ptr f);
|
||||
int TUNER_get_afc_hint(FI1236Ptr f);
|
||||
void fi1236_dump_status(FI1236Ptr f);
|
||||
|
||||
#define FI1236SymbolsList \
|
||||
"Detect_FI1236", \
|
||||
"FI1236_set_tuner_type", \
|
||||
"TUNER_set_frequency"
|
||||
|
||||
#ifdef XFree86LOADER
|
||||
|
||||
#define xf86_Detect_FI1236 ((FI1236Ptr (*)(I2CBusPtr, I2CSlaveAddr))LoaderSymbol("Detect_FI1236"))
|
||||
#define xf86_FI1236_set_tuner_type ((void (*)(FI1236Ptr, int))LoaderSymbol("FI1236_set_tuner_type"))
|
||||
#define xf86_TUNER_set_frequency ((void (*)(FI1236Ptr, CARD32))LoaderSymbol("TUNER_set_frequency"))
|
||||
#define xf86_FI1236_AFC ((int (*)(FI1236Ptr))LoaderSymbol("FI1236_AFC"))
|
||||
#define xf86_TUNER_get_afc_hint ((int (*)(FI1236Ptr))LoaderSymbol("TUNER_get_afc_hint"))
|
||||
|
||||
#else
|
||||
|
||||
#define xf86_Detect_FI1236 Detect_FI1236
|
||||
#define xf86_FI1236_set_tuner_type FI1236_set_tuner_type
|
||||
#define xf86_TUNER_set_frequency TUNER_set_frequency
|
||||
#define xf86_FI1236_AFC FI1236_AFC
|
||||
#define xf86_TUNER_get_afc_hint TUNER_get_afc_hint
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
26
hw/xfree86/i2c/fi1236_module.c
Normal file
26
hw/xfree86/i2c/fi1236_module.c
Normal file
@ -0,0 +1,26 @@
|
||||
|
||||
#include "xf86Module.h"
|
||||
|
||||
static MODULESETUPPROTO(fi1236Setup);
|
||||
|
||||
|
||||
static XF86ModuleVersionInfo fi1236VersRec =
|
||||
{
|
||||
"fi1236",
|
||||
MODULEVENDORSTRING,
|
||||
MODINFOSTRING1,
|
||||
MODINFOSTRING2,
|
||||
XF86_VERSION_CURRENT,
|
||||
1, 0, 0,
|
||||
ABI_CLASS_VIDEODRV, /* This needs the video driver ABI */
|
||||
ABI_VIDEODRV_VERSION,
|
||||
MOD_CLASS_NONE,
|
||||
{0,0,0,0}
|
||||
};
|
||||
|
||||
XF86ModuleData fi1236ModuleData = { &fi1236VersRec, fi1236Setup, NULL };
|
||||
|
||||
static pointer
|
||||
fi1236Setup(pointer module, pointer opts, int *errmaj, int *errmin) {
|
||||
return (pointer)1;
|
||||
}
|
29
hw/xfree86/i2c/i2c_def.h
Normal file
29
hw/xfree86/i2c/i2c_def.h
Normal file
@ -0,0 +1,29 @@
|
||||
#ifndef __I2C_DEF_H__
|
||||
#define __I2C_DEF_H__
|
||||
|
||||
/* the following are a workaround for possible loader bug..
|
||||
WATCH function types ! */
|
||||
#if XFree86LOADER
|
||||
|
||||
#define CreateI2CBusRec ((pointer (*)(void))LoaderSymbol("xf86CreateI2CBusRec"))
|
||||
#define DestroyI2CBusRec ((pointer (*)(I2CBusPtr, Bool, Bool))LoaderSymbol("xf86DestroyI2CBusRec"))
|
||||
#define I2CBusInit ((Bool (*)(pointer))LoaderSymbol("xf86I2CBusInit"))
|
||||
#define I2C_WriteRead ((Bool (*)(I2CDevPtr, I2CByte *, int, I2CByte *, int))LoaderSymbol("xf86I2CWriteRead"))
|
||||
#define CreateI2CDevRec ((pointer (*)(void))LoaderSymbol("xf86CreateI2CDevRec"))
|
||||
#define I2CDevInit ((Bool (*)(I2CDevPtr))LoaderSymbol("xf86I2CDevInit"))
|
||||
#define I2CProbeAddress ((Bool (*)(I2CBusPtr,I2CSlaveAddr))LoaderSymbol("xf86I2CProbeAddress"))
|
||||
|
||||
#else
|
||||
|
||||
#define CreateI2CBusRec xf86CreateI2CBusRec
|
||||
#define DestroyI2CBusRec xf86DestroyI2CBusRec
|
||||
#define I2CBusInit xf86I2CBusInit
|
||||
#define I2C_WriteRead xf86I2CWriteRead
|
||||
#define CreateI2CDevRec xf86CreateI2CDevRec
|
||||
#define I2CDevInit xf86I2CDevInit
|
||||
#define I2CProbeAddress xf86I2CProbeAddress
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
718
hw/xfree86/i2c/msp3430.c
Normal file
718
hw/xfree86/i2c/msp3430.c
Normal file
@ -0,0 +1,718 @@
|
||||
#include "xf86.h"
|
||||
#include "xf86i2c.h"
|
||||
#include "msp3430.h"
|
||||
#include "i2c_def.h"
|
||||
|
||||
#define CONTROL 0x00
|
||||
#define WR_DEM 0x10
|
||||
#define RD_DEM 0x11
|
||||
#define WR_DSP 0x12
|
||||
#define RD_DSP 0x13
|
||||
|
||||
|
||||
void InitMSP34xxG(MSP3430Ptr m);
|
||||
void InitMSP34x5D(MSP3430Ptr m);
|
||||
void CheckModeMSP34x5D(MSP3430Ptr m);
|
||||
char *MSP_getProductName (CARD16 product_id);
|
||||
void mpause(int milliseconds);
|
||||
|
||||
#define __MSPDEBUG__ 0
|
||||
|
||||
#if __MSPDEBUG__ > 3
|
||||
|
||||
void MSPBeep(MSP3430Ptr m, CARD8 freq);
|
||||
#define __MSPBEEP MSPBeep(m,0x14);
|
||||
|
||||
#else
|
||||
|
||||
#define __MSPBEEP
|
||||
#endif
|
||||
|
||||
static void SetMSP3430Control(MSP3430Ptr m, CARD8 RegAddress, CARD8 RegValueHigh, CARD8 RegValueLow)
|
||||
{
|
||||
I2CByte data[3];
|
||||
|
||||
data[0]=RegAddress;
|
||||
data[1]=RegValueHigh;
|
||||
data[2]=RegValueLow;
|
||||
|
||||
I2C_WriteRead(&(m->d),data,3,NULL,0);
|
||||
}
|
||||
|
||||
static void SetMSP3430Data(MSP3430Ptr m, CARD8 RegAddress, CARD8 RegSubAddressHigh, CARD8 RegSubAddressLow,
|
||||
CARD8 RegValueHigh, CARD8 RegValueLow)
|
||||
{
|
||||
I2CByte data[5];
|
||||
#ifdef MSP_DEBUG
|
||||
if(!m->registers_present[RegSubAddressLow]){
|
||||
xf86DrvMsg(m->d.pI2CBus->scrnIndex,X_ERROR, "Attempt to access non-existent register in MSP34xxX: 0x%02x 0x%02x 0x%02x <- 0x%02x 0x%02x\n",
|
||||
RegAddress, RegSubAddressHigh, RegSubAddressLow, RegValueHigh, RegValueLow);
|
||||
}
|
||||
#endif
|
||||
|
||||
data[0] = RegAddress;
|
||||
data[1] = RegSubAddressHigh;
|
||||
data[2] = RegSubAddressLow;
|
||||
data[3] = RegValueHigh;
|
||||
data[4] = RegValueLow;
|
||||
|
||||
I2C_WriteRead(&(m->d),data,5,NULL,0);
|
||||
}
|
||||
|
||||
static void GetMSP3430Data(MSP3430Ptr m, CARD8 RegAddress, CARD8 RegSubAddressHigh, CARD8 RegSubAddressLow,
|
||||
CARD8 *RegValueHigh, CARD8 *RegValueLow)
|
||||
{
|
||||
I2CByte send[3];
|
||||
I2CByte receive[2];
|
||||
|
||||
send[0] = RegAddress;
|
||||
send[1] = RegSubAddressHigh;
|
||||
send[2] = RegSubAddressLow;
|
||||
|
||||
I2C_WriteRead(&(m->d), send, 3, receive, 2);
|
||||
|
||||
*RegValueHigh = receive[0];
|
||||
*RegValueLow = receive[1];
|
||||
}
|
||||
|
||||
static void MSP3430DumpStatus(MSP3430Ptr m)
|
||||
{
|
||||
CARD8 status_hi, status_lo;
|
||||
CARD8 subaddr, data[2];
|
||||
|
||||
GetMSP3430Data(m, RD_DEM, 0x02, 0x00, &status_hi, &status_lo);
|
||||
xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO, "MSP34xx: SAP(8)=%d mono/NICAM(7)=%d stereo=%d %s O_1=%d O_0=%d 2nd car=%d 1st car=%d\n",
|
||||
status_hi & 1, (status_lo>>7) & 1, (status_lo>>6)&1,
|
||||
(status_lo>>5)? ( (status_hi>>1)&1? "bad NICAM reception" : "NICAM" ) :
|
||||
((status_hi>>1)&1 ? "bogus" : "ANALOG FM/AM") ,
|
||||
(status_lo>>4)&1, (status_lo>>3)&1,!( (status_lo>>2)&1), !((status_lo>>1)&1));
|
||||
|
||||
GetMSP3430Data(m, RD_DEM, 0x00, 0x7E, &status_hi, &status_lo);
|
||||
xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO, "MSP34xx: standard result=0x%02x%02x\n",
|
||||
status_hi, status_lo);
|
||||
subaddr=0x0;
|
||||
I2C_WriteRead(&(m->d), &subaddr, 1, data, 2);
|
||||
xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO, "MSP34xx: control=0x%02x%02x\n",
|
||||
data[1], data[0]);
|
||||
}
|
||||
|
||||
/* wrapper */
|
||||
void InitMSP3430(MSP3430Ptr m)
|
||||
{
|
||||
#if __MSPDEBUG__ > 1
|
||||
xf86DrvMsg(m->d.pI2CBus->scrnIndex,X_INFO,"InitMSP3430(m->connector=%d, m->standard=%d, m->chip_family=%d)\n",
|
||||
m->connector, m->standard, m->chip_family);
|
||||
#endif
|
||||
switch (m->chip_family) {
|
||||
case MSPFAMILY_34x0G:
|
||||
InitMSP34xxG(m);
|
||||
break;
|
||||
case MSPFAMILY_34x5G:
|
||||
InitMSP34xxG(m);
|
||||
break;
|
||||
case MSPFAMILY_34x5D:
|
||||
InitMSP34x5D(m);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------
|
||||
| common functions for all MSP34xx chips
|
||||
|----------------------------------------------------------------*/
|
||||
|
||||
MSP3430Ptr DetectMSP3430(I2CBusPtr b, I2CSlaveAddr addr)
|
||||
{
|
||||
MSP3430Ptr m;
|
||||
I2CByte a;
|
||||
CARD8 hardware_version, major_revision, product_code, rom_version;
|
||||
Bool supported;
|
||||
|
||||
m = xcalloc(1,sizeof(MSP3430Rec));
|
||||
if(m == NULL)return NULL;
|
||||
m->d.DevName = strdup("MSP34xx");
|
||||
m->d.SlaveAddr = addr;
|
||||
m->d.pI2CBus = b;
|
||||
m->d.NextDev = NULL;
|
||||
m->d.StartTimeout = b->StartTimeout;
|
||||
m->d.BitTimeout = b->BitTimeout;
|
||||
m->d.AcknTimeout = b->AcknTimeout;
|
||||
m->d.ByteTimeout = b->ByteTimeout;
|
||||
|
||||
if(!I2C_WriteRead(&(m->d), NULL, 0, &a, 1))
|
||||
{
|
||||
xfree(m->d.DevName);
|
||||
xfree(m);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
m->standard=MSP3430_NTSC;
|
||||
m->connector=MSP3430_CONNECTOR_1;
|
||||
m->mode=MSPMODE_STEREO_A; /*stereo or chanel A if avail. */
|
||||
m->c_format=MSPFORMAT_UNKNOWN;
|
||||
m->c_standard=MSPSTANDARD_UNKNOWN;
|
||||
m->c_matrix=m->c_fmmatrix=m->c_source=0;
|
||||
m->volume=0;
|
||||
m->recheck=FALSE;
|
||||
|
||||
GetMSP3430Data(m, RD_DSP, 0x00, 0x1E, &hardware_version, &major_revision);
|
||||
GetMSP3430Data(m, RD_DSP, 0x00, 0x1F, &product_code, &rom_version);
|
||||
m->hardware_version=hardware_version;
|
||||
m->major_revision=major_revision;
|
||||
m->product_code=product_code;
|
||||
m->rom_version=rom_version;
|
||||
|
||||
m->chip_id=((major_revision << 8) | product_code);
|
||||
|
||||
supported=FALSE;
|
||||
switch (major_revision) {
|
||||
case 4: /* 34xxD */
|
||||
switch (product_code) {
|
||||
case 0x05: /* 3405D */
|
||||
case 0x0A: /* 3410D */
|
||||
case 0x0F: /* 3415D */
|
||||
m->chip_family=MSPFAMILY_34x5D;
|
||||
m->recheck=TRUE;
|
||||
supported=TRUE;
|
||||
break;
|
||||
default:
|
||||
m->chip_family=MSPFAMILY_34x0D;
|
||||
}
|
||||
break;
|
||||
case 7: /* 34xxG */
|
||||
switch(product_code){
|
||||
case 0x00:
|
||||
case 0x0A:
|
||||
case 0x1E:
|
||||
case 0x28:
|
||||
case 0x32:
|
||||
m->chip_family=MSPFAMILY_34x0G;
|
||||
supported=TRUE;
|
||||
break;
|
||||
case 0x0f:
|
||||
case 0x19:
|
||||
case 0x2d:
|
||||
case 0x37:
|
||||
case 0x41:
|
||||
m->chip_family=MSPFAMILY_34x5G;
|
||||
supported=TRUE;
|
||||
#ifdef MSP_DEBUG
|
||||
memset(m->registers_present, 0, 256);
|
||||
#define A(num) m->registers_present[(num)]=1;
|
||||
#define B(num1, num2) memset(&(m->registers_present[num1]), 1, num2-num1);
|
||||
A(0x20)
|
||||
A(0x30)
|
||||
A(0x40)
|
||||
A(0x00)
|
||||
B(0x01, 0x08)
|
||||
B(0x0B, 0x0E)
|
||||
A(0x10)
|
||||
B(0x12,0x14)
|
||||
A(0x16)
|
||||
A(0x29)
|
||||
#undef B
|
||||
#undef A
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
m->chip_family=MSPFAMILY_UNKNOWN;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
m->chip_family=MSPFAMILY_UNKNOWN;
|
||||
}
|
||||
|
||||
xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO, "Found %s%s, rom version 0x%02x, chip_id=0x%04x\n",
|
||||
MSP_getProductName(m->chip_id), supported?"":" (unsupported)", rom_version, m->chip_id);
|
||||
|
||||
if (!supported) {
|
||||
xfree(m->d.DevName);
|
||||
xfree(m);
|
||||
return NULL;
|
||||
}
|
||||
if(!I2CDevInit(&(m->d)))
|
||||
{
|
||||
xfree(m->d.DevName);
|
||||
xfree(m);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
void ResetMSP3430(MSP3430Ptr m)
|
||||
{
|
||||
/* Reset the MSP3430 */
|
||||
SetMSP3430Control(m, 0x00, 0x80, 0x00);
|
||||
/* Set it back to normal operation */
|
||||
SetMSP3430Control(m, 0x00, 0x00, 0x00);
|
||||
|
||||
m->c_format=MSPFORMAT_UNKNOWN;
|
||||
m->c_standard=MSPSTANDARD_UNKNOWN;
|
||||
m->c_matrix=m->c_fmmatrix=m->c_source=0;
|
||||
m->volume=0;
|
||||
}
|
||||
|
||||
void MSP3430SetVolume (MSP3430Ptr m, CARD8 value)
|
||||
{
|
||||
CARD8 result;
|
||||
CARD8 old_volume;
|
||||
|
||||
#if 0
|
||||
GetMSP3430Data(m, RD_DSP, 0x00, 0x00, &old_volume, &result);
|
||||
xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO, "MSP3430 result 0x%02x\n", result);
|
||||
#endif
|
||||
/* save an extra Get call */
|
||||
result=0;
|
||||
|
||||
SetMSP3430Data(m, WR_DSP, 0x00, 0x00, value, result);
|
||||
|
||||
SetMSP3430Data(m, WR_DSP, 0x00, 0x07, value, 0);
|
||||
m->volume=value;
|
||||
|
||||
#if __MSPDEBUG__ > 2
|
||||
MSP3430DumpStatus(m);
|
||||
__MSPBEEP
|
||||
GetMSP3430Data(m, RD_DSP, 0x00, 0x00, &old_volume, &result);
|
||||
xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO, "MSP3430 volume 0x%02x\n",value);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void MSP3430SetSAP (MSP3430Ptr m, int mode)
|
||||
{
|
||||
xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO, "Put actual code to change SAP here\n");
|
||||
|
||||
SetMSP3430Data(m, WR_DSP, 0x00, 0x08, mode & 0xff, 0x20);
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
void MSP3430SetSource(MSP3430Ptr m, CARD8 value)
|
||||
{
|
||||
/* Write to DSP, register 0x0008, (loudspeaker channel source/matrix) */
|
||||
/* This sets the source to the TV tuner, for stereo operation */
|
||||
SetMSP3430Data(m, WR_DSP, 0x00, 0x08, value, 0x20);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
char *MSP_getProductName (CARD16 product_id)
|
||||
{
|
||||
switch (product_id) {
|
||||
case 0x0400: return "MSP3400D";
|
||||
case 0x040a: return "MSP3410D";
|
||||
case 0x0405: return "MSP3405D";
|
||||
case 0x040f: return "MSP3415D";
|
||||
case 0x0700: return "MSP3400G";
|
||||
case 0x070a: return "MSP3410G";
|
||||
case 0x071e: return "MSP3430G";
|
||||
case 0x0728: return "MSP3440G";
|
||||
case 0x0732: return "MSP3450G";
|
||||
case 0x070f: return "MSP3415G";
|
||||
case 0x0719: return "MSP3425G";
|
||||
case 0x072d: return "MSP3445G";
|
||||
case 0x0737: return "MSP3455G";
|
||||
case 0x0741: return "MSP3465G";
|
||||
}
|
||||
return "MSP - unknown type";
|
||||
}
|
||||
|
||||
#if __MSPDEBUG__ > 2
|
||||
/*puts beep in MSP output
|
||||
freq = 0x01 - 16Hz ... 0x40 - 1kHz ... 0xff - 4kHz
|
||||
*/
|
||||
void MSPBeep(MSP3430Ptr m, CARD8 freq) {
|
||||
SetMSP3430Data (m, WR_DSP, 0x00, freq, 0x7f, 0x40);
|
||||
mpause(100);
|
||||
SetMSP3430Data (m, WR_DSP, 0x00, 0x14, 0x00, 0x00);
|
||||
}
|
||||
#endif
|
||||
|
||||
void mpause(int milliseconds) {
|
||||
int i,m;
|
||||
m=milliseconds/20;
|
||||
for (i=0;i<m;i++) usleep(20000);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------
|
||||
| specific functions for all MSP34xxG chips
|
||||
|----------------------------------------------------------------*/
|
||||
|
||||
void InitMSP34xxG(MSP3430Ptr m)
|
||||
{
|
||||
|
||||
#if __MSPDEBUG__ > 1
|
||||
xf86DrvMsg(m->d.pI2CBus->scrnIndex,X_INFO,"InitMSP34xxG(m->connector=%d, m->standard=%d, m->chip_family=%d)\n",
|
||||
m->connector, m->standard, m->chip_family);
|
||||
#endif
|
||||
/* Reset MSP3430 */
|
||||
SetMSP3430Control(m, 0x00, 0x80, 0x00);
|
||||
/* Set it back to normal operation */
|
||||
SetMSP3430Control(m, 0x00, 0x00, 0x00);
|
||||
|
||||
/*set MODUS register */
|
||||
/* bits: 0 - automatic sound detection */
|
||||
/* 1 - enable STATUS change */
|
||||
/* 12 - detect 6.5 Mhz carrier as D/K1, D/K2 or D/K NICAM (does not seem to work ) */
|
||||
/* 13 - detect 4.5 Mhz carrier as BTSC */
|
||||
if ( (m->standard & 0xff) == MSP3430_PAL )
|
||||
{
|
||||
SetMSP3430Data(m, WR_DEM, 0x00, 0x30, 0x30, 0x03|0x08); /* make O_ pins tristate */
|
||||
/* PAL standard */
|
||||
SetMSP3430Data(m, WR_DEM, 0x00, 0x20, 0x00, 0x01); /* possibly wrong */
|
||||
} else {
|
||||
SetMSP3430Data(m, WR_DEM, 0x00, 0x30, 0x20, 0x03|0x08);
|
||||
/* standard selection is M-BTSC-Stereo */
|
||||
SetMSP3430Data(m, WR_DEM, 0x00, 0x20, 0x00, 0x20);
|
||||
}
|
||||
|
||||
switch(m->connector){
|
||||
case MSP3430_CONNECTOR_1:
|
||||
SetMSP3430Data(m, WR_DSP, 0x00, 0x08, 0x03, 0x20);
|
||||
break;
|
||||
case MSP3430_CONNECTOR_2:
|
||||
/* this has not been checked yet.. could be bogus */
|
||||
/* SCART Input Prescale: 0 dB gain */
|
||||
SetMSP3430Data(m, WR_DSP, 0x00, 0x0d, 0x19, 0x00);
|
||||
SetMSP3430Data(m, WR_DSP, 0x00, 0x08, 0x02, 0x20);
|
||||
break;
|
||||
case MSP3430_CONNECTOR_3:
|
||||
default:
|
||||
/* SCART Input Prescale: 0 dB gain */
|
||||
SetMSP3430Data(m, WR_DSP, 0x00, 0x0d, 0x19, 0x00);
|
||||
|
||||
SetMSP3430Data(m, WR_DSP, 0x00, 0x08, 0x02, 0x20);
|
||||
break;
|
||||
}
|
||||
|
||||
switch(m->standard){
|
||||
case MSP3430_PAL:
|
||||
SetMSP3430Data(m, WR_DSP, 0x00, 0x0e, 0x24, 0x03);
|
||||
SetMSP3430Data(m, WR_DSP, 0x00, 0x10, 0x00, 0x5a);
|
||||
SetMSP3430Data(m, WR_DEM, 0x00, 0x20, 0x00, 0x03);
|
||||
/* Set volume to FAST_MUTE. */
|
||||
SetMSP3430Data(m, WR_DSP, 0x00, 0x00, 0xFF, 0x00);
|
||||
break;
|
||||
case MSP3430_PAL_DK1:
|
||||
SetMSP3430Data(m, WR_DSP, 0x00, 0x0e, 0x24, 0x03);
|
||||
SetMSP3430Data(m, WR_DSP, 0x00, 0x10, 0x00, 0x5a);
|
||||
SetMSP3430Data(m, WR_DEM, 0x00, 0x20, 0x00, 0x04);
|
||||
/* Set volume to FAST_MUTE. */
|
||||
SetMSP3430Data(m, WR_DSP, 0x00, 0x00, 0xFF, 0x00);
|
||||
break;
|
||||
case MSP3430_SECAM: /* is this right ? */
|
||||
case MSP3430_NTSC:
|
||||
/* Write to DSP, register 0x000E, (prescale FM/FM matrix) */
|
||||
SetMSP3430Data(m, WR_DSP, 0x00, 0x0e, 0x24, 0x03);
|
||||
|
||||
/* Set volume to FAST_MUTE. */
|
||||
SetMSP3430Data(m, WR_DSP, 0x00, 0x00, 0xFF, 0x00);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------
|
||||
| specific functions for all MSP34x5D chips
|
||||
|----------------------------------------------------------------*/
|
||||
|
||||
void InitMSP34x5D(MSP3430Ptr m)
|
||||
{
|
||||
int count;
|
||||
CARD8 high,low;
|
||||
CARD16 result,standard;
|
||||
CARD16 peak;
|
||||
|
||||
|
||||
if (m->c_format==MSPFORMAT_UNKNOWN) ResetMSP3430(m);
|
||||
else {
|
||||
/*mute volume*/
|
||||
SetMSP3430Data (m, WR_DSP, 0x00, 0x00, 0x00, 0x00);
|
||||
}
|
||||
|
||||
|
||||
|
||||
switch(m->connector){
|
||||
case MSP3430_CONNECTOR_2:
|
||||
case MSP3430_CONNECTOR_3:
|
||||
if (m->c_format!=MSPFORMAT_SCART) {
|
||||
/* SCART Input Prescale: 0 dB gain */
|
||||
SetMSP3430Data (m, WR_DSP, 0x00, 0x0d, 0x19, 0x00);
|
||||
/* this has not been checked yet.. could be bogus */
|
||||
m->c_format=MSPFORMAT_SCART; /*stereo*/
|
||||
}
|
||||
break;
|
||||
case MSP3430_CONNECTOR_1:
|
||||
default:
|
||||
|
||||
switch ( m->standard & 0x00ff ) {
|
||||
case MSP3430_PAL:
|
||||
switch( m->standard ) {
|
||||
case MSP3430_PAL_DK1:
|
||||
standard=MSPSTANDARD_FM_DK1;
|
||||
break;
|
||||
/* case MSP3430_PAL_DK2:
|
||||
standard=MSPSTANDARD_FM_DK2;
|
||||
break;
|
||||
case MSP3430_PAL_BG:
|
||||
may be FM stereo (Germany) or FM NICAM (Scandinavia,spain)
|
||||
standard=MSPSTANDARD_AUTO;
|
||||
break;
|
||||
*/
|
||||
default:
|
||||
standard=MSPSTANDARD_AUTO;
|
||||
}
|
||||
break;
|
||||
case MSP3430_SECAM:
|
||||
standard=MSPSTANDARD_AUTO;
|
||||
case MSP3430_NTSC:
|
||||
/* Only MSP34x5 supported format - Korean NTSC-M*/
|
||||
standard=MSPSTANDARD_FM_M;
|
||||
default:
|
||||
standard=MSPSTANDARD_AUTO;
|
||||
}
|
||||
|
||||
/*no NICAM support in MSP3410D - force to autodetect*/
|
||||
if ((m->chip_id==0x405) && (standard>=MSPSTANDARD_NICAM_BG))
|
||||
standard=MSPSTANDARD_AUTO;
|
||||
|
||||
if (m->c_standard != standard) {
|
||||
|
||||
SetMSP3430Data (m, WR_DEM, 0x00, 0x20, standard>>8, standard & 0xFF);
|
||||
if (standard==MSPSTANDARD_AUTO) {
|
||||
count = 50; /* time shouldn't exceed 1s, just in case */
|
||||
do {
|
||||
usleep(20000);
|
||||
GetMSP3430Data (m, RD_DEM, 0x00, 0x7e, &high, &low);
|
||||
result = ( high << 8 ) | low;
|
||||
--count;
|
||||
} while( result > 0x07ff && count > 0 );
|
||||
|
||||
if ((result > MSPSTANDARD_AUTO))
|
||||
standard=result;
|
||||
else standard=MSPSTANDARD_UNKNOWN;
|
||||
#if __MSPDEBUG__ > 1
|
||||
xf86DrvMsg(m->d.pI2CBus->scrnIndex,X_INFO,"Detected audio standard: %d\n",result);
|
||||
#endif
|
||||
/* result = MSPSTANDARD_NICAM_L can be one of:
|
||||
SECAM_L - MSPSTANDARD_NICAM_L
|
||||
D/K1 - MSPSTANDARD_FM_DK1
|
||||
D/K2 - MSPSTANDARD_FM_DK2
|
||||
D/K-NICAM - MSPSTANDARD_NICAM_DK*/
|
||||
if( standard == MSPSTANDARD_NICAM_L ) {
|
||||
if ((m->standard & 0x00ff)==MSP3430_PAL) {
|
||||
/* force PAL D/K */
|
||||
standard=MSPSTANDARD_FM_DK1;
|
||||
SetMSP3430Data (m, WR_DEM, 0x00, 0x20, standard>>8, standard & 0xFF);
|
||||
#if __MSPDEBUG__ > 1
|
||||
xf86DrvMsg(m->d.pI2CBus->scrnIndex,X_INFO, "Detected 6.5MHz carrier - forced to D/K1 !!!\n" );
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
m->c_standard=standard;
|
||||
} /*end - standard changed*/
|
||||
else {
|
||||
if (standard<MSPSTANDARD_NICAM_BG) {
|
||||
/* get old value of ident. mode register*/
|
||||
GetMSP3430Data (m, RD_DSP, 0x00, 0x15, &high, &low);
|
||||
/* reset Ident-Filter */
|
||||
SetMSP3430Data (m, WR_DSP, 0x00, 0x14, 0x00, 0x3F);
|
||||
/* put back old value to ident. mode register*/
|
||||
SetMSP3430Data (m, WR_DSP, 0x00, 0x14, 0x00, low);
|
||||
}
|
||||
}
|
||||
|
||||
if (standard<=MSPSTANDARD_AUTO) {
|
||||
m->c_format=MSPFORMAT_1xFM;
|
||||
}
|
||||
else if (standard<MSPSTANDARD_NICAM_BG) {
|
||||
/* set FM prescale */
|
||||
SetMSP3430Data (m, WR_DSP, 0x00, 0x0e, 0x30, 0);
|
||||
/* set FM deemphasis*/
|
||||
SetMSP3430Data (m, WR_DSP, 0x00, 0x0f, ((standard==MSPSTANDARD_FM_M)?0:1), 0);
|
||||
|
||||
/* check if FM2 carrier is present */
|
||||
/*turn off FM DC Notch*/
|
||||
SetMSP3430Data (m, WR_DSP, 0x00, 0x17, 0x00, 0x3f);
|
||||
/*matrix source for Quasi-Peak Detector - stereo: ch2->L ch1->R*/
|
||||
SetMSP3430Data (m, WR_DSP, 0x00, 0x0c, 0x00, 0x20);
|
||||
|
||||
mpause(250);
|
||||
GetMSP3430Data (m, RD_DSP, 0x00, 0x1A, &high, &low);
|
||||
peak = (high << 8) | low;
|
||||
#if __MSPDEBUG__ > 1
|
||||
xf86DrvMsg(m->d.pI2CBus->scrnIndex,X_INFO,"Second carrier Quasi-Peak detection: %d\n",peak);
|
||||
#endif
|
||||
/*turn on FM DC Notch*/
|
||||
SetMSP3430Data (m, WR_DSP, 0x00, 0x17, 0x00, 0x00);
|
||||
|
||||
if (peak<5) {
|
||||
/* if second carrier not detected - only mono from first carrier*/
|
||||
m->c_format=MSPFORMAT_1xFM;
|
||||
}
|
||||
else {
|
||||
m->c_format=MSPFORMAT_2xFM;
|
||||
/*start of FM identification process - FM_WAIT
|
||||
wait at least 0.5s - used 1s - gives beter resolution*/
|
||||
mpause(1000);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (standard==MSPSTANDARD_NICAM_L) {
|
||||
m->c_format=MSPFORMAT_NICAM_AM;
|
||||
/* set AM prescale */
|
||||
SetMSP3430Data (m, WR_DSP, 0x00, 0x0e, 0x7C, 0);
|
||||
}
|
||||
else {
|
||||
m->c_format=MSPFORMAT_NICAM_FM;
|
||||
/* set FM prescale */
|
||||
SetMSP3430Data (m, WR_DSP, 0x00, 0x0e, 0x30, 0);
|
||||
}
|
||||
/* set FM deemphasis*/
|
||||
SetMSP3430Data (m, WR_DSP, 0x00, 0x0f, 0x00, 0);
|
||||
/* set NICAM prescale to 0dB */
|
||||
SetMSP3430Data (m, WR_DSP, 0x00, 0x10, 0x20, 0);
|
||||
}
|
||||
|
||||
break;
|
||||
} /*end - case conector*/
|
||||
|
||||
CheckModeMSP34x5D(m);
|
||||
|
||||
/* Set volume to FAST_MUTE. */
|
||||
/*SetMSP3430Data(m, WR_DSP, 0x00, 0x00, 0xFF, 0x00);*/
|
||||
/*set volume*/
|
||||
MSP3430SetVolume(m,m->volume);
|
||||
|
||||
__MSPBEEP
|
||||
|
||||
|
||||
} /* EnableMSP34x5D ()... */
|
||||
|
||||
|
||||
|
||||
|
||||
void CheckModeMSP34x5D(MSP3430Ptr m) {
|
||||
const char stereo_on=25;
|
||||
const char stereo_off=20;
|
||||
const char dual_on=-stereo_on;
|
||||
const char dual_off=-stereo_off;
|
||||
char detect;
|
||||
CARD8 matrix, fmmatrix, source, high, low;
|
||||
char *msg;
|
||||
|
||||
fmmatrix=0; /*no matrix*/
|
||||
source=0; /*FM*/
|
||||
switch (m->c_format) {
|
||||
case MSPFORMAT_NICAM_FM:
|
||||
case MSPFORMAT_NICAM_AM:
|
||||
case MSPFORMAT_SCART:
|
||||
source=( (m->c_format == MSPFORMAT_SCART)?2:1 );
|
||||
switch (m->mode) {
|
||||
case MSPMODE_MONO:
|
||||
matrix=0x30; /*MONO*/
|
||||
break;
|
||||
case MSPMODE_A:
|
||||
matrix=0x00; /*A*/
|
||||
break;
|
||||
case MSPMODE_B:
|
||||
matrix=0x10; /*B*/
|
||||
break;
|
||||
default:
|
||||
matrix=0x20; /*STEREO*/
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
case MSPFORMAT_1xFM:
|
||||
matrix=0x00; /*A*/
|
||||
break;
|
||||
case MSPFORMAT_2xFM:
|
||||
switch (m->mode) {
|
||||
case MSPMODE_MONO:
|
||||
matrix=0x30; /*MONO*/
|
||||
break;
|
||||
case MSPMODE_STEREO:
|
||||
matrix=0x20; /*STEREO*/
|
||||
fmmatrix=((m->c_standard==MSPSTANDARD_FM_M)?2:1);
|
||||
break;
|
||||
case MSPMODE_AB:
|
||||
matrix=0x20; /*STEREO*/
|
||||
break;
|
||||
case MSPMODE_A:
|
||||
matrix=0x00; /*A*/
|
||||
break;
|
||||
case MSPMODE_B:
|
||||
matrix=0x10; /*B*/
|
||||
break;
|
||||
default:
|
||||
/*FM_IDENT_CHECK*/
|
||||
GetMSP3430Data (m, RD_DSP, 0x00, 0x18, &high, &low);
|
||||
detect=(char)high;
|
||||
#if __MSPDEBUG__ > 1
|
||||
xf86DrvMsg(m->d.pI2CBus->scrnIndex,X_INFO,"Stereo Detection Register: %d\n",detect);
|
||||
#endif
|
||||
if (detect>=((m->c_mode==MSPMODE_STEREO)?stereo_off:stereo_on)) {
|
||||
m->c_mode=MSPMODE_STEREO;
|
||||
matrix=0x20; /*STEREO*/
|
||||
fmmatrix=((m->c_standard==MSPSTANDARD_FM_M)?2:1);
|
||||
}
|
||||
else if (detect<=((m->c_mode==MSPMODE_AB)?dual_off:dual_on)) {
|
||||
m->c_mode=MSPMODE_AB;
|
||||
switch (m->mode) {
|
||||
case MSPMODE_STEREO_AB: matrix=0x20; break;
|
||||
case MSPMODE_STEREO_B: matrix=0x10; break;
|
||||
default:
|
||||
case MSPMODE_A: matrix=0x00; break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
m->c_mode=MSPMODE_MONO;
|
||||
matrix=0x30; /*MONO*/
|
||||
}
|
||||
break;
|
||||
} /* end - case mode*/
|
||||
break;
|
||||
}
|
||||
|
||||
if (m->c_fmmatrix != fmmatrix) {
|
||||
GetMSP3430Data (m, RD_DSP, 0x00, 0x0e, &high, &low);
|
||||
SetMSP3430Data (m, WR_DSP, 0x00, 0x0e, high, fmmatrix);
|
||||
m->c_fmmatrix = fmmatrix;
|
||||
}
|
||||
|
||||
if ((m->c_matrix != matrix) || (m->c_source != source)) {
|
||||
/*set chanel source and matrix for loudspeaker*/
|
||||
SetMSP3430Data (m, WR_DSP, 0x00, 0x08, source, matrix);
|
||||
|
||||
m->c_matrix = matrix;
|
||||
m->c_source = source;
|
||||
}
|
||||
|
||||
if ( ((m->c_format) & 0xF0) == MSPFORMAT_NICAM)
|
||||
SetMSP3430Data (m, WR_DEM, 0x00, 0x21, 0, 1);
|
||||
|
||||
#if __MSPDEBUG__ > 0
|
||||
switch (matrix) {
|
||||
case 0x30: /*MONO*/
|
||||
msg="MONO";
|
||||
break;
|
||||
case 0x00: /*LEFT*/
|
||||
msg="MONO/CHANNEL_1";
|
||||
break;
|
||||
case 0x10: /*RIGHT*/
|
||||
msg="MONO/CHANNEL_2";
|
||||
break;
|
||||
case 0x20: /*LEFT*/
|
||||
msg="STEREO";
|
||||
break;
|
||||
default:
|
||||
msg="unknown";
|
||||
break;
|
||||
}
|
||||
xf86DrvMsg(m->d.pI2CBus->scrnIndex,X_INFO,"Audio mode set to: %s\n",msg);
|
||||
#endif
|
||||
}
|
||||
|
126
hw/xfree86/i2c/msp3430.h
Normal file
126
hw/xfree86/i2c/msp3430.h
Normal file
@ -0,0 +1,126 @@
|
||||
#ifndef __MSP3430_H__
|
||||
#define __MSP3430_H__
|
||||
|
||||
#include "xf86i2c.h"
|
||||
|
||||
typedef struct {
|
||||
I2CDevRec d;
|
||||
|
||||
int standard;
|
||||
int connector;
|
||||
int mode;
|
||||
|
||||
CARD8 hardware_version, major_revision, product_code, rom_version;
|
||||
#ifdef MSP_DEBUG
|
||||
CARD8 registers_present[256];
|
||||
#endif
|
||||
|
||||
CARD16 chip_id;
|
||||
CARD8 chip_family;
|
||||
Bool recheck; /*reinitialization needed after channel change */
|
||||
CARD8 c_format; /*current state of audio format */
|
||||
CARD16 c_standard; /*current state of standard register */
|
||||
CARD8 c_source; /*current state of source register */
|
||||
CARD8 c_matrix; /*current state of matrix register */
|
||||
CARD8 c_fmmatrix; /*current state of fmmatrix register */
|
||||
int c_mode; /* current state of mode for autoswitchimg */
|
||||
CARD8 volume;
|
||||
} MSP3430Rec, * MSP3430Ptr;
|
||||
|
||||
|
||||
#define MSP3430_ADDR_1 0x80
|
||||
#define MSP3430_ADDR_2 0x84
|
||||
#define MSP3430_ADDR_3 0x88
|
||||
|
||||
#define MSP3430_PAL 1
|
||||
#define MSP3430_NTSC 2
|
||||
#define MSP3430_PAL_DK1 (0x100 | MSP3430_PAL)
|
||||
#define MSP3430_SECAM 3
|
||||
|
||||
#define MSP3430_CONNECTOR_1 1 /* tuner on AIW cards */
|
||||
#define MSP3430_CONNECTOR_2 2 /* SVideo on AIW cards */
|
||||
#define MSP3430_CONNECTOR_3 3 /* composite on AIW cards */
|
||||
|
||||
#define MSP3430_ADDR(a) ((a)->d.SlaveAddr)
|
||||
|
||||
#define MSP3430_FAST_MUTE 0xFF
|
||||
/* a handy volume transform function, -1000..1000 -> 0x01..0x7F */
|
||||
#define MSP3430_VOLUME(value) (0x01+(0x7F-0x01)*log(value+1001)/log(2001))
|
||||
|
||||
/*----------------------------------------------------------*/
|
||||
|
||||
/* MSP chip families */
|
||||
#define MSPFAMILY_UNKNOWN 0
|
||||
#define MSPFAMILY_34x0D 1
|
||||
#define MSPFAMILY_34x5D 2
|
||||
#define MSPFAMILY_34x0G 3
|
||||
#define MSPFAMILY_34x5G 4
|
||||
|
||||
/* values for MSP standard */
|
||||
#define MSPSTANDARD_UNKNOWN 0x00
|
||||
#define MSPSTANDARD_AUTO 0x01
|
||||
#define MSPSTANDARD_FM_M 0x02
|
||||
#define MSPSTANDARD_FM_BG 0x03
|
||||
#define MSPSTANDARD_FM_DK1 0x04
|
||||
#define MSPSTANDARD_FM_DK2 0x04
|
||||
#define MSPSTANDARD_NICAM_BG 0x08
|
||||
#define MSPSTANDARD_NICAM_L 0x09
|
||||
#define MSPSTANDARD_NICAM_I 0x0A
|
||||
#define MSPSTANDARD_NICAM_DK 0x0B
|
||||
|
||||
/* values for MSP format */
|
||||
#define MSPFORMAT_UNKNOWN 0x00
|
||||
#define MSPFORMAT_FM 0x10
|
||||
#define MSPFORMAT_1xFM 0x00|MSPFORMAT_FM
|
||||
#define MSPFORMAT_2xFM 0x01|MSPFORMAT_FM
|
||||
#define MSPFORMAT_NICAM 0x20
|
||||
#define MSPFORMAT_NICAM_FM 0x00|MSPFORMAT_NICAM
|
||||
#define MSPFORMAT_NICAM_AM 0x01|MSPFORMAT_NICAM
|
||||
#define MSPFORMAT_SCART 0x30
|
||||
|
||||
/* values for MSP mode */
|
||||
#define MSPMODE_UNKNOWN 0
|
||||
/* automatic modes */
|
||||
#define MSPMODE_STEREO_AB 1
|
||||
#define MSPMODE_STEREO_A 2
|
||||
#define MSPMODE_STEREO_B 3
|
||||
/* forced modes */
|
||||
#define MSPMODE_MONO 4
|
||||
#define MSPMODE_STEREO 5
|
||||
#define MSPMODE_AB 6
|
||||
#define MSPMODE_A 7
|
||||
#define MSPMODE_B 8
|
||||
/*----------------------------------------------------------*/
|
||||
|
||||
void InitMSP3430(MSP3430Ptr m);
|
||||
MSP3430Ptr DetectMSP3430(I2CBusPtr b, I2CSlaveAddr addr);
|
||||
void ResetMSP3430(MSP3430Ptr m);
|
||||
void MSP3430SetVolume (MSP3430Ptr m, CARD8 value);
|
||||
void MSP3430SetSAP (MSP3430Ptr m, int mode);
|
||||
|
||||
#define MSP3430SymbolsList \
|
||||
"InitMSP3430", \
|
||||
"DetectMSP3430", \
|
||||
"ResetMSP3430", \
|
||||
"MSP3430SetVolume", \
|
||||
"MSP3430SetSAP"
|
||||
|
||||
#ifdef XFree86LOADER
|
||||
|
||||
#define xf86_DetectMSP3430 ((MSP3430Ptr (*)(I2CBusPtr, I2CSlaveAddr))LoaderSymbol("DetectMSP3430"))
|
||||
#define xf86_ResetMSP3430 ((void (*)(MSP3430Ptr))LoaderSymbol("ResetMSP3430"))
|
||||
#define xf86_MSP3430SetVolume ((void (*)(MSP3430Ptr, CARD8))LoaderSymbol("MSP3430SetVolume"))
|
||||
#define xf86_MSP3430SetSAP ((void (*)(MSP3430Ptr, int))LoaderSymbol("MSP3430SetSAP"))
|
||||
#define xf86_InitMSP3430 ((void (*)(MSP3430Ptr))LoaderSymbol("InitMSP3430"))
|
||||
|
||||
#else
|
||||
|
||||
#define xf86_DetectMSP3430 DetectMSP3430
|
||||
#define xf86_ResetMSP3430 ResetMSP3430
|
||||
#define xf86_MSP3430SetVolume MSP3430SetVolume
|
||||
#define xf86_MSP3430SetSAP MSP3430SetSAP
|
||||
#define xf86_InitMSP3430 InitMSP3430
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
26
hw/xfree86/i2c/msp3430_module.c
Normal file
26
hw/xfree86/i2c/msp3430_module.c
Normal file
@ -0,0 +1,26 @@
|
||||
|
||||
#include "xf86Module.h"
|
||||
|
||||
static MODULESETUPPROTO(msp3430Setup);
|
||||
|
||||
|
||||
static XF86ModuleVersionInfo msp3430VersRec =
|
||||
{
|
||||
"msp3430",
|
||||
MODULEVENDORSTRING,
|
||||
MODINFOSTRING1,
|
||||
MODINFOSTRING2,
|
||||
XF86_VERSION_CURRENT,
|
||||
1, 0, 0,
|
||||
ABI_CLASS_VIDEODRV, /* This needs the video driver ABI */
|
||||
ABI_VIDEODRV_VERSION,
|
||||
MOD_CLASS_NONE,
|
||||
{0,0,0,0}
|
||||
};
|
||||
|
||||
XF86ModuleData msp3430ModuleData = { &msp3430VersRec, msp3430Setup, NULL };
|
||||
|
||||
static pointer
|
||||
msp3430Setup(pointer module, pointer opts, int *errmaj, int *errmin) {
|
||||
return (pointer)1;
|
||||
}
|
74
hw/xfree86/i2c/tda8425.c
Normal file
74
hw/xfree86/i2c/tda8425.c
Normal file
@ -0,0 +1,74 @@
|
||||
#include "xf86.h"
|
||||
#include "xf86i2c.h"
|
||||
#include "tda8425.h"
|
||||
#include "i2c_def.h"
|
||||
|
||||
#define TDA8425(a,b) { \
|
||||
data[0]=a; \
|
||||
data[1]=b; \
|
||||
I2C_WriteRead(&(t->d), data, 2, NULL, 0); \
|
||||
}
|
||||
|
||||
TDA8425Ptr Detect_tda8425(I2CBusPtr b, I2CSlaveAddr addr, Bool force)
|
||||
{
|
||||
TDA8425Ptr t;
|
||||
|
||||
t = xcalloc(1, sizeof(TDA8425Rec));
|
||||
if(t == NULL) return NULL;
|
||||
t->d.DevName = "TDA8425 BTSC Stereo Audio Processor";
|
||||
t->d.SlaveAddr = addr;
|
||||
t->d.pI2CBus = b;
|
||||
t->d.NextDev = NULL;
|
||||
t->d.StartTimeout = b->StartTimeout;
|
||||
t->d.BitTimeout = b->BitTimeout;
|
||||
t->d.AcknTimeout = b->AcknTimeout;
|
||||
t->d.ByteTimeout = b->ByteTimeout;
|
||||
|
||||
if(!force && !I2CProbeAddress(b, addr))
|
||||
{
|
||||
xfree(t);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* set default parameters */
|
||||
if(!I2CDevInit(&(t->d)))
|
||||
{
|
||||
xfree(t);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
Bool tda8425_init(TDA8425Ptr t)
|
||||
{
|
||||
t->stereo = 3; /* 3 = Spacial 2 = Linear 1 = Pseudo 0 = Forced mono */
|
||||
t->v_left = 0xFF; /* FF - C0 */
|
||||
t->v_right = 0xFF; /* FF - C0 */
|
||||
t->bass = 0xF6; /* 0xFF - 0xF0 */
|
||||
t->treble = 0xF6; /* 0xFF - 0xF0 */
|
||||
t->src_sel = 3; /* 3 - stereo */
|
||||
t->mute = TRUE;
|
||||
t->mux = 0; /* 0 - source one, 1 -source 2 */
|
||||
|
||||
tda8425_setaudio(t);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void tda8425_setaudio(TDA8425Ptr t)
|
||||
{
|
||||
I2CByte data[2];
|
||||
|
||||
TDA8425(0x00, t->v_left );
|
||||
TDA8425(0x01, t->v_right );
|
||||
TDA8425(0x02, t->bass );
|
||||
TDA8425(0x03, t->treble );
|
||||
TDA8425(0x08, 0xC0 | (t->mute ? 0x20 : 0x0) | (t->stereo << 3) | (t->src_sel << 1) |
|
||||
t->mux);
|
||||
}
|
||||
|
||||
void tda8425_mute(TDA8425Ptr t, Bool mute)
|
||||
{
|
||||
t->mute = mute;
|
||||
tda8425_setaudio(t);
|
||||
}
|
53
hw/xfree86/i2c/tda8425.h
Normal file
53
hw/xfree86/i2c/tda8425.h
Normal file
@ -0,0 +1,53 @@
|
||||
#ifndef __TDA8425_H__
|
||||
#define __TDA8425_H__
|
||||
|
||||
#include "xf86i2c.h"
|
||||
|
||||
typedef struct {
|
||||
I2CDevRec d;
|
||||
|
||||
int mux;
|
||||
int stereo;
|
||||
int v_left;
|
||||
int v_right;
|
||||
int bass;
|
||||
int treble;
|
||||
int src_sel;
|
||||
Bool mute;
|
||||
} TDA8425Rec, *TDA8425Ptr;
|
||||
|
||||
#define TDA8425_ADDR_1 0x82
|
||||
|
||||
/* the third parameter is meant to force detection of tda8425.
|
||||
This is because tda8425 is write-only and complete implementation
|
||||
of I2C protocol is not always available. Besides address there is no good
|
||||
way to autodetect it so we have to _know_ it is there anyway */
|
||||
|
||||
TDA8425Ptr Detect_tda8425(I2CBusPtr b, I2CSlaveAddr addr,Bool force);
|
||||
Bool tda8425_init(TDA8425Ptr t);
|
||||
void tda8425_setaudio(TDA8425Ptr t);
|
||||
void tda8425_mute(TDA8425Ptr t, Bool mute);
|
||||
|
||||
#define TDA8425SymbolsList \
|
||||
"Detect_tda8425", \
|
||||
"tda8425_init", \
|
||||
"tda8425_setaudio", \
|
||||
"tda8425_mute"
|
||||
|
||||
#ifdef XFree86LOADER
|
||||
|
||||
#define xf86_Detect_tda8425 ((TDA8425Ptr (*)(I2CBusPtr, I2CSlaveAddr,Bool))LoaderSymbol("Detect_tda8425"))
|
||||
#define xf86_tda8425_init ((Bool (*)(TDA8425Ptr))LoaderSymbol("tda8425_init"))
|
||||
#define xf86_tda8425_setaudio ((void (*)(TDA8425Ptr))LoaderSymbol("tda8425_setaudio"))
|
||||
#define xf86_tda8425_mute ((void (*)(TDA8425Ptr, Bool))LoaderSymbol("tda8425_mute"))
|
||||
|
||||
#else
|
||||
|
||||
#define xf86_Detect_tda8425 Detect_tda8425
|
||||
#define xf86_tda8425_init tda8425_init
|
||||
#define xf86_tda8425_setaudio tda8425_setaudio
|
||||
#define xf86_tda8425_mute tda8425_mute
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
26
hw/xfree86/i2c/tda8425_module.c
Normal file
26
hw/xfree86/i2c/tda8425_module.c
Normal file
@ -0,0 +1,26 @@
|
||||
|
||||
#include "xf86Module.h"
|
||||
|
||||
static MODULESETUPPROTO(tda8425Setup);
|
||||
|
||||
|
||||
static XF86ModuleVersionInfo tda8425VersRec =
|
||||
{
|
||||
"tda8425",
|
||||
MODULEVENDORSTRING,
|
||||
MODINFOSTRING1,
|
||||
MODINFOSTRING2,
|
||||
XF86_VERSION_CURRENT,
|
||||
1, 0, 0,
|
||||
ABI_CLASS_VIDEODRV, /* This needs the video driver ABI */
|
||||
ABI_VIDEODRV_VERSION,
|
||||
MOD_CLASS_NONE,
|
||||
{0,0,0,0}
|
||||
};
|
||||
|
||||
XF86ModuleData tda8425ModuleData = { &tda8425VersRec, tda8425Setup, NULL };
|
||||
|
||||
static pointer
|
||||
tda8425Setup(pointer module, pointer opts, int *errmaj, int *errmin) {
|
||||
return (pointer)1;
|
||||
}
|
108
hw/xfree86/i2c/tda9850.c
Normal file
108
hw/xfree86/i2c/tda9850.c
Normal file
@ -0,0 +1,108 @@
|
||||
#include "xf86.h"
|
||||
#include "xf86i2c.h"
|
||||
#include "tda9850.h"
|
||||
#include "i2c_def.h"
|
||||
|
||||
#define TDA9850(a,b) { \
|
||||
data[0]=a; \
|
||||
data[1]=b; \
|
||||
I2C_WriteRead(&(t->d), data, 2, NULL, 0); \
|
||||
}
|
||||
|
||||
TDA9850Ptr Detect_tda9850(I2CBusPtr b, I2CSlaveAddr addr)
|
||||
{
|
||||
TDA9850Ptr t;
|
||||
I2CByte a;
|
||||
|
||||
t = xcalloc(1, sizeof(TDA9850Rec));
|
||||
if(t == NULL) return NULL;
|
||||
switch(addr)
|
||||
{
|
||||
case TDA9850_ADDR_1:
|
||||
t->d.DevName = "TDA9850 BTSC Stereo+SAP Audio Processor";
|
||||
break;
|
||||
default:
|
||||
t->d.DevName = "Generic TDAxxxx";
|
||||
break;
|
||||
}
|
||||
t->d.SlaveAddr = addr;
|
||||
t->d.pI2CBus = b;
|
||||
t->d.NextDev = NULL;
|
||||
t->d.StartTimeout = b->StartTimeout;
|
||||
t->d.BitTimeout = b->BitTimeout;
|
||||
t->d.AcknTimeout = b->AcknTimeout;
|
||||
t->d.ByteTimeout = b->ByteTimeout;
|
||||
|
||||
if(!I2C_WriteRead(&(t->d), NULL, 0, &a, 1))
|
||||
{
|
||||
xfree(t);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* set default parameters */
|
||||
if(!I2CDevInit(&(t->d)))
|
||||
{
|
||||
xfree(t);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
Bool tda9850_init(TDA9850Ptr t)
|
||||
{
|
||||
t->stereo = 1;
|
||||
t->sap = 0;
|
||||
t->mute = TRUE;
|
||||
t->sap_mute = TRUE;
|
||||
tda9850_setaudio(t);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void tda9850_setaudio(TDA9850Ptr t)
|
||||
{
|
||||
CARD8 data[2];
|
||||
|
||||
if(t->mux==2)
|
||||
{
|
||||
TDA9850(0x04,0x0F); TDA9850(0x05,0x0F); TDA9850(0x06, 0x58);
|
||||
TDA9850(0x07,0x07); TDA9850(0x08,0x00);
|
||||
TDA9850(0x09,0x00); TDA9850(0x0A,0x03);
|
||||
} else
|
||||
{
|
||||
TDA9850(0x04,0x07); TDA9850(0x05,0x07);
|
||||
TDA9850(0x06,0x58); TDA9850(0x07,0x07);
|
||||
TDA9850(0x08,0x10); TDA9850(0x09,0x10);
|
||||
TDA9850(0x0A,0x03);
|
||||
}
|
||||
|
||||
TDA9850(0x06,(t->stereo<<6)|(t->sap<<7)|(t->mute?0x8:0)|(t->sap_mute?0x10:0x0));
|
||||
}
|
||||
|
||||
void tda9850_mute(TDA9850Ptr t, Bool mute)
|
||||
{
|
||||
CARD8 data[2];
|
||||
|
||||
xf86DrvMsg(t->d.pI2CBus->scrnIndex, X_INFO, "tda9850_mute %s\n", mute ? "on" : "off");
|
||||
t->mute = mute;
|
||||
|
||||
TDA9850(0x06,(t->stereo<<6)|(t->sap<<7)|(t->mute?0x8:0x0)|(t->sap_mute?0x10:0x0));
|
||||
}
|
||||
|
||||
void tda9850_sap_mute(TDA9850Ptr t, Bool sap_mute)
|
||||
{
|
||||
CARD8 data[2];
|
||||
|
||||
xf86DrvMsg(t->d.pI2CBus->scrnIndex, X_INFO, "tda9850_sap_mute %s\n", sap_mute ? "on" : "off");
|
||||
t->sap_mute = sap_mute;
|
||||
|
||||
TDA9850(0x06,(t->stereo<<6)|(t->sap<<7)|(t->mute?0x8:0x0)|(t->sap_mute?0x10:0x0));
|
||||
}
|
||||
|
||||
CARD16 tda9850_getstatus(TDA9850Ptr t)
|
||||
{
|
||||
CARD16 status;
|
||||
|
||||
I2C_WriteRead(&(t->d), NULL, 0, &status, 2);
|
||||
return status;
|
||||
}
|
52
hw/xfree86/i2c/tda9850.h
Normal file
52
hw/xfree86/i2c/tda9850.h
Normal file
@ -0,0 +1,52 @@
|
||||
#ifndef __TDA9850_H__
|
||||
#define __TDA9850_H__
|
||||
|
||||
#include "xf86i2c.h"
|
||||
|
||||
typedef struct {
|
||||
I2CDevRec d;
|
||||
|
||||
int mux;
|
||||
int stereo;
|
||||
int sap;
|
||||
Bool mute;
|
||||
Bool sap_mute;
|
||||
} TDA9850Rec, *TDA9850Ptr;
|
||||
|
||||
#define TDA9850_ADDR_1 0xB4
|
||||
|
||||
TDA9850Ptr Detect_tda9850(I2CBusPtr b, I2CSlaveAddr addr);
|
||||
Bool tda9850_init(TDA9850Ptr t);
|
||||
void tda9850_setaudio(TDA9850Ptr t);
|
||||
void tda9850_mute(TDA9850Ptr t, Bool mute);
|
||||
void tda9850_sap_mute(TDA9850Ptr t, Bool sap_mute);
|
||||
CARD16 tda9850_getstatus(TDA9850Ptr t);
|
||||
|
||||
#define TDA9850SymbolsList \
|
||||
"Detect_tda9850", \
|
||||
"tda9850_init", \
|
||||
"tda9850_setaudio", \
|
||||
"tda9850_mute", \
|
||||
"tda9850_sap_mute"
|
||||
|
||||
#ifdef XFree86LOADER
|
||||
|
||||
#define xf86_Detect_tda9850 ((TDA9850Ptr (*)(I2CBusPtr, I2CSlaveAddr))LoaderSymbol("Detect_tda9850"))
|
||||
#define xf86_tda9850_init ((Bool (*)(TDA9850Ptr))LoaderSymbol("tda9850_init"))
|
||||
#define xf86_tda9850_setaudio ((void (*)(TDA9850Ptr))LoaderSymbol("tda9850_setaudio"))
|
||||
#define xf86_tda9850_mute ((void (*)(TDA9850Ptr, Bool))LoaderSymbol("tda9850_mute"))
|
||||
#define xf86_tda9850_sap_mute ((void (*)(TDA9850Ptr, Bool))LoaderSymbol("tda9850_sap_mute"))
|
||||
#define xf86_tda9850_getstatus ((CARD16 (*)(TDA9850Ptr))LoaderSymbol("tda9850_getstatus"))
|
||||
|
||||
#else
|
||||
|
||||
#define xf86_Detect_tda9850 Detect_tda9850
|
||||
#define xf86_tda9850_init tda9850_init
|
||||
#define xf86_tda9850_setaudio tda9850_setaudio
|
||||
#define xf86_tda9850_mute tda9850_mute
|
||||
#define xf86_tda9850_sap_mute tda9850_sap_mute
|
||||
#define xf86_tda9850_getstatus tda9850_getstatus
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
26
hw/xfree86/i2c/tda9850_module.c
Normal file
26
hw/xfree86/i2c/tda9850_module.c
Normal file
@ -0,0 +1,26 @@
|
||||
|
||||
#include "xf86Module.h"
|
||||
|
||||
static MODULESETUPPROTO(tda9850Setup);
|
||||
|
||||
|
||||
static XF86ModuleVersionInfo tda9850VersRec =
|
||||
{
|
||||
"tda9850",
|
||||
MODULEVENDORSTRING,
|
||||
MODINFOSTRING1,
|
||||
MODINFOSTRING2,
|
||||
XF86_VERSION_CURRENT,
|
||||
1, 0, 0,
|
||||
ABI_CLASS_VIDEODRV, /* This needs the video driver ABI */
|
||||
ABI_VIDEODRV_VERSION,
|
||||
MOD_CLASS_NONE,
|
||||
{0,0,0,0}
|
||||
};
|
||||
|
||||
XF86ModuleData tda9850ModuleData = { &tda9850VersRec, tda9850Setup, NULL };
|
||||
|
||||
static pointer
|
||||
tda9850Setup(pointer module, pointer opts, int *errmaj, int *errmin) {
|
||||
return (pointer)1;
|
||||
}
|
98
hw/xfree86/i2c/tda9885.c
Normal file
98
hw/xfree86/i2c/tda9885.c
Normal file
@ -0,0 +1,98 @@
|
||||
#include "xf86.h"
|
||||
#include "xf86i2c.h"
|
||||
#include "tda9885.h"
|
||||
#include "i2c_def.h"
|
||||
|
||||
|
||||
TDA9885Ptr Detect_tda9885(I2CBusPtr b, I2CSlaveAddr addr)
|
||||
{
|
||||
TDA9885Ptr t;
|
||||
I2CByte a;
|
||||
|
||||
t = xcalloc(1, sizeof(TDA9885Rec));
|
||||
if(t == NULL) return NULL;
|
||||
switch(addr)
|
||||
{
|
||||
case TDA9885_ADDR_1:
|
||||
case TDA9885_ADDR_2:
|
||||
case TDA9885_ADDR_3:
|
||||
case TDA9885_ADDR_4:
|
||||
t->d.DevName = "TDA9885 Alignment-free IF-PLL";
|
||||
break;
|
||||
default:
|
||||
t->d.DevName = "Generic TDAxxxx";
|
||||
break;
|
||||
}
|
||||
t->d.SlaveAddr = addr;
|
||||
t->d.pI2CBus = b;
|
||||
t->d.NextDev = NULL;
|
||||
t->d.StartTimeout = b->StartTimeout;
|
||||
t->d.BitTimeout = b->BitTimeout;
|
||||
t->d.AcknTimeout = b->AcknTimeout;
|
||||
t->d.ByteTimeout = b->ByteTimeout;
|
||||
|
||||
if(!I2C_WriteRead(&(t->d), NULL, 0, &a, 1))
|
||||
{
|
||||
xfree(t);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* set default parameters */
|
||||
if(!I2CDevInit(&(t->d)))
|
||||
{
|
||||
xfree(t);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
Bool tda9885_init(TDA9885Ptr t)
|
||||
{
|
||||
t->forced_mute_audio=1;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void tda9885_getstatus(TDA9885Ptr t)
|
||||
{
|
||||
CARD8 value;
|
||||
|
||||
I2C_WriteRead(&(t->d), NULL, 0, &value, 1);
|
||||
t->after_reset=value & 1;
|
||||
t->afc_status=(value >> 1) & 0xf;
|
||||
t->fm_carrier=(value>>5)& 1;
|
||||
t->vif_level=(value >>6) & 1;
|
||||
t->afc_win=(value >> 7)&1;
|
||||
}
|
||||
|
||||
void tda9885_setparameters(TDA9885Ptr t)
|
||||
{
|
||||
CARD8 data[4];
|
||||
|
||||
data[0]=0; /* start with subaddress 0 */
|
||||
data[1]=(t->sound_trap & 1) |
|
||||
((t->auto_mute_fm &1)<<1) |
|
||||
((t->carrier_mode &1)<<2) |
|
||||
((t->modulation &3)<<3) |
|
||||
((t->forced_mute_audio &1)<<5) |
|
||||
((t->port1 & 1)<<6) |
|
||||
((t->port2 &1)<<7); /* B data */
|
||||
data[2]=(t->top_adjustment & 0x1f) |
|
||||
((t->deemphasis & 0x3)<<5) |
|
||||
((t->audio_gain & 1) << 7); /* C data */
|
||||
data[3]=(t->standard_sound_carrier & 0x3) |
|
||||
((t->standard_video_if & 0x07)<<2) |
|
||||
((t->minimum_gain & 0x01)<<5) |
|
||||
((t->gating & 0x01)<<6) |
|
||||
((t->vif_agc & 0x01)<<7); /* E data */
|
||||
|
||||
I2C_WriteRead(&(t->d), data, 4, NULL, 0);
|
||||
}
|
||||
|
||||
void tda9885_dumpstatus(TDA9885Ptr t)
|
||||
{
|
||||
xf86DrvMsg(t->d.pI2CBus->scrnIndex,X_INFO,"TDA9885 status: after_reset=%d afc_status=%d (%3.1f kHz off) fm_carrier=%d vif_level=%d afc_win=%d %s\n",
|
||||
t->after_reset, t->afc_status,
|
||||
(t->afc_status<8)?-12.5-t->afc_status*25.0:-12.5+(16-t->afc_status)*25.0,
|
||||
t->fm_carrier, t->vif_level, t->afc_win, t->afc_win?"VCO in": "VCO out");
|
||||
}
|
72
hw/xfree86/i2c/tda9885.h
Normal file
72
hw/xfree86/i2c/tda9885.h
Normal file
@ -0,0 +1,72 @@
|
||||
#ifndef __TDA9885_H__
|
||||
#define __TDA9885_H__
|
||||
|
||||
#include "xf86i2c.h"
|
||||
|
||||
typedef struct {
|
||||
I2CDevRec d;
|
||||
|
||||
/* write-only parameters */
|
||||
/* B DATA */
|
||||
CARD8 sound_trap;
|
||||
CARD8 auto_mute_fm;
|
||||
CARD8 carrier_mode;
|
||||
CARD8 modulation;
|
||||
CARD8 forced_mute_audio;
|
||||
CARD8 port1;
|
||||
CARD8 port2;
|
||||
/* C DATA */
|
||||
CARD8 top_adjustment;
|
||||
CARD8 deemphasis;
|
||||
CARD8 audio_gain;
|
||||
/* E DATA */
|
||||
CARD8 standard_sound_carrier;
|
||||
CARD8 standard_video_if;
|
||||
CARD8 minimum_gain;
|
||||
CARD8 gating;
|
||||
CARD8 vif_agc;
|
||||
/* read-only values */
|
||||
|
||||
CARD8 after_reset;
|
||||
CARD8 afc_status;
|
||||
CARD8 vif_level;
|
||||
CARD8 afc_win;
|
||||
CARD8 fm_carrier;
|
||||
} TDA9885Rec, *TDA9885Ptr;
|
||||
|
||||
#define TDA9885_ADDR_1 0x86
|
||||
#define TDA9885_ADDR_2 0x84
|
||||
#define TDA9885_ADDR_3 0x96
|
||||
#define TDA9885_ADDR_4 0x94
|
||||
|
||||
TDA9885Ptr Detect_tda9885(I2CBusPtr b, I2CSlaveAddr addr);
|
||||
Bool tda9885_init(TDA9885Ptr t);
|
||||
void tda9885_setparameters(TDA9885Ptr t);
|
||||
void tda9885_getstatus(TDA9885Ptr t);
|
||||
void tda9885_dumpstatus(TDA9885Ptr t);
|
||||
|
||||
#define TDA9885SymbolsList \
|
||||
"Detect_tda9885", \
|
||||
"tda9885_init", \
|
||||
"tda9885_setaudio", \
|
||||
"tda9885_mute"
|
||||
|
||||
#ifdef XFree86LOADER
|
||||
|
||||
#define xf86_Detect_tda9885 ((TDA9885Ptr (*)(I2CBusPtr, I2CSlaveAddr))LoaderSymbol("Detect_tda9885"))
|
||||
#define xf86_tda9885_init ((Bool (*)(TDA9885Ptr))LoaderSymbol("tda9885_init"))
|
||||
#define xf86_tda9885_setparameters ((void (*)(TDA9885Ptr))LoaderSymbol("tda9885_setparameters"))
|
||||
#define xf86_tda9885_getstatus ((void (*)(TDA9885Ptr))LoaderSymbol("tda9885_getstatus"))
|
||||
#define xf86_tda9885_dumpstatus ((void (*)(TDA9885Ptr))LoaderSymbol("tda9885_dumpstatus"))
|
||||
|
||||
#else
|
||||
|
||||
#define xf86_Detect_tda9885 Detect_tda9885
|
||||
#define xf86_tda9885_init tda9885_init
|
||||
#define xf86_tda9885_setparameters tda9885_setparameters
|
||||
#define xf86_tda9885_getstatus tda9885_getstatus
|
||||
#define xf86_tda9885_dumpstatus tda9885_dumpstatus
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
26
hw/xfree86/i2c/tda9885_module.c
Normal file
26
hw/xfree86/i2c/tda9885_module.c
Normal file
@ -0,0 +1,26 @@
|
||||
|
||||
#include "xf86Module.h"
|
||||
|
||||
static MODULESETUPPROTO(tda9885Setup);
|
||||
|
||||
|
||||
static XF86ModuleVersionInfo tda9885VersRec =
|
||||
{
|
||||
"tda9885",
|
||||
MODULEVENDORSTRING,
|
||||
MODINFOSTRING1,
|
||||
MODINFOSTRING2,
|
||||
XF86_VERSION_CURRENT,
|
||||
1, 0, 0,
|
||||
ABI_CLASS_VIDEODRV, /* This needs the video driver ABI */
|
||||
ABI_VIDEODRV_VERSION,
|
||||
MOD_CLASS_NONE,
|
||||
{0,0,0,0}
|
||||
};
|
||||
|
||||
XF86ModuleData tda9885ModuleData = { &tda9885VersRec, tda9885Setup, NULL };
|
||||
|
||||
static pointer
|
||||
tda9885Setup(pointer module, pointer opts, int *errmaj, int *errmin) {
|
||||
return (pointer)1;
|
||||
}
|
Loading…
Reference in New Issue
Block a user