From 0d474149f1cb68a60927529f6eac611a12acf5e6 Mon Sep 17 00:00:00 2001 From: Vladimir Dergachev Date: Thu, 30 Sep 2004 22:58:07 +0000 Subject: [PATCH] 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 --- hw/xfree86/i2c/bt829.c | 737 ++++++++++++++++++++++++++++++++ hw/xfree86/i2c/bt829.h | 115 +++++ hw/xfree86/i2c/bt829_module.c | 26 ++ hw/xfree86/i2c/fi1236.c | 550 ++++++++++++++++++++++++ hw/xfree86/i2c/fi1236.h | 116 +++++ hw/xfree86/i2c/fi1236_module.c | 26 ++ hw/xfree86/i2c/i2c_def.h | 29 ++ hw/xfree86/i2c/msp3430.c | 718 +++++++++++++++++++++++++++++++ hw/xfree86/i2c/msp3430.h | 126 ++++++ hw/xfree86/i2c/msp3430_module.c | 26 ++ hw/xfree86/i2c/tda8425.c | 74 ++++ hw/xfree86/i2c/tda8425.h | 53 +++ hw/xfree86/i2c/tda8425_module.c | 26 ++ hw/xfree86/i2c/tda9850.c | 108 +++++ hw/xfree86/i2c/tda9850.h | 52 +++ hw/xfree86/i2c/tda9850_module.c | 26 ++ hw/xfree86/i2c/tda9885.c | 98 +++++ hw/xfree86/i2c/tda9885.h | 72 ++++ hw/xfree86/i2c/tda9885_module.c | 26 ++ 19 files changed, 3004 insertions(+) create mode 100644 hw/xfree86/i2c/bt829.c create mode 100644 hw/xfree86/i2c/bt829.h create mode 100644 hw/xfree86/i2c/bt829_module.c create mode 100644 hw/xfree86/i2c/fi1236.c create mode 100644 hw/xfree86/i2c/fi1236.h create mode 100644 hw/xfree86/i2c/fi1236_module.c create mode 100644 hw/xfree86/i2c/i2c_def.h create mode 100644 hw/xfree86/i2c/msp3430.c create mode 100644 hw/xfree86/i2c/msp3430.h create mode 100644 hw/xfree86/i2c/msp3430_module.c create mode 100644 hw/xfree86/i2c/tda8425.c create mode 100644 hw/xfree86/i2c/tda8425.h create mode 100644 hw/xfree86/i2c/tda8425_module.c create mode 100644 hw/xfree86/i2c/tda9850.c create mode 100644 hw/xfree86/i2c/tda9850.h create mode 100644 hw/xfree86/i2c/tda9850_module.c create mode 100644 hw/xfree86/i2c/tda9885.c create mode 100644 hw/xfree86/i2c/tda9885.h create mode 100644 hw/xfree86/i2c/tda9885_module.c diff --git a/hw/xfree86/i2c/bt829.c b/hw/xfree86/i2c/bt829.c new file mode 100644 index 000000000..2cb5e53a0 --- /dev/null +++ b/hw/xfree86/i2c/bt829.c @@ -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_validnum_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) ; } +}*/ diff --git a/hw/xfree86/i2c/bt829.h b/hw/xfree86/i2c/bt829.h new file mode 100644 index 000000000..2c7c00d34 --- /dev/null +++ b/hw/xfree86/i2c/bt829.h @@ -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 diff --git a/hw/xfree86/i2c/bt829_module.c b/hw/xfree86/i2c/bt829_module.c new file mode 100644 index 000000000..7d13f69d7 --- /dev/null +++ b/hw/xfree86/i2c/bt829_module.c @@ -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; +} diff --git a/hw/xfree86/i2c/fi1236.c b/hw/xfree86/i2c/fi1236.c new file mode 100644 index 000000000..f56716b38 --- /dev/null +++ b/hw/xfree86/i2c/fi1236.c @@ -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); + } +} diff --git a/hw/xfree86/i2c/fi1236.h b/hw/xfree86/i2c/fi1236.h new file mode 100644 index 000000000..8c9808f05 --- /dev/null +++ b/hw/xfree86/i2c/fi1236.h @@ -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 diff --git a/hw/xfree86/i2c/fi1236_module.c b/hw/xfree86/i2c/fi1236_module.c new file mode 100644 index 000000000..1363b60ba --- /dev/null +++ b/hw/xfree86/i2c/fi1236_module.c @@ -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; +} diff --git a/hw/xfree86/i2c/i2c_def.h b/hw/xfree86/i2c/i2c_def.h new file mode 100644 index 000000000..84b9c5d91 --- /dev/null +++ b/hw/xfree86/i2c/i2c_def.h @@ -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 diff --git a/hw/xfree86/i2c/msp3430.c b/hw/xfree86/i2c/msp3430.c new file mode 100644 index 000000000..699cfa495 --- /dev/null +++ b/hw/xfree86/i2c/msp3430.c @@ -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 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 (standardc_format=MSPFORMAT_1xFM; + } + else if (standardL 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 +} + diff --git a/hw/xfree86/i2c/msp3430.h b/hw/xfree86/i2c/msp3430.h new file mode 100644 index 000000000..8726bacf5 --- /dev/null +++ b/hw/xfree86/i2c/msp3430.h @@ -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 diff --git a/hw/xfree86/i2c/msp3430_module.c b/hw/xfree86/i2c/msp3430_module.c new file mode 100644 index 000000000..5d963e914 --- /dev/null +++ b/hw/xfree86/i2c/msp3430_module.c @@ -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; +} diff --git a/hw/xfree86/i2c/tda8425.c b/hw/xfree86/i2c/tda8425.c new file mode 100644 index 000000000..8ddf7267e --- /dev/null +++ b/hw/xfree86/i2c/tda8425.c @@ -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); +} diff --git a/hw/xfree86/i2c/tda8425.h b/hw/xfree86/i2c/tda8425.h new file mode 100644 index 000000000..ec1908ba9 --- /dev/null +++ b/hw/xfree86/i2c/tda8425.h @@ -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 diff --git a/hw/xfree86/i2c/tda8425_module.c b/hw/xfree86/i2c/tda8425_module.c new file mode 100644 index 000000000..8ae222268 --- /dev/null +++ b/hw/xfree86/i2c/tda8425_module.c @@ -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; +} diff --git a/hw/xfree86/i2c/tda9850.c b/hw/xfree86/i2c/tda9850.c new file mode 100644 index 000000000..708dcccbb --- /dev/null +++ b/hw/xfree86/i2c/tda9850.c @@ -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; +} diff --git a/hw/xfree86/i2c/tda9850.h b/hw/xfree86/i2c/tda9850.h new file mode 100644 index 000000000..2c8ddcc6e --- /dev/null +++ b/hw/xfree86/i2c/tda9850.h @@ -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 diff --git a/hw/xfree86/i2c/tda9850_module.c b/hw/xfree86/i2c/tda9850_module.c new file mode 100644 index 000000000..ec57a8a2d --- /dev/null +++ b/hw/xfree86/i2c/tda9850_module.c @@ -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; +} diff --git a/hw/xfree86/i2c/tda9885.c b/hw/xfree86/i2c/tda9885.c new file mode 100644 index 000000000..f91d0fdfe --- /dev/null +++ b/hw/xfree86/i2c/tda9885.c @@ -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"); +} diff --git a/hw/xfree86/i2c/tda9885.h b/hw/xfree86/i2c/tda9885.h new file mode 100644 index 000000000..a63b34764 --- /dev/null +++ b/hw/xfree86/i2c/tda9885.h @@ -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 diff --git a/hw/xfree86/i2c/tda9885_module.c b/hw/xfree86/i2c/tda9885_module.c new file mode 100644 index 000000000..b66a0176b --- /dev/null +++ b/hw/xfree86/i2c/tda9885_module.c @@ -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; +}