1706f2543Smrg#ifdef HAVE_XORG_CONFIG_H 2706f2543Smrg#include <xorg-config.h> 3706f2543Smrg#endif 4706f2543Smrg 5706f2543Smrg#include <string.h> 6706f2543Smrg#include <unistd.h> 7706f2543Smrg 8706f2543Smrg#include "xf86.h" 9706f2543Smrg#include "xf86i2c.h" 10706f2543Smrg#include "msp3430.h" 11706f2543Smrg#include "i2c_def.h" 12706f2543Smrg 13706f2543Smrg#define CONTROL 0x00 14706f2543Smrg#define WR_DEM 0x10 15706f2543Smrg#define RD_DEM 0x11 16706f2543Smrg#define WR_DSP 0x12 17706f2543Smrg#define RD_DSP 0x13 18706f2543Smrg 19706f2543Smrg 20706f2543Smrgvoid InitMSP34xxG(MSP3430Ptr m); 21706f2543Smrgvoid InitMSP34x5D(MSP3430Ptr m); 22706f2543Smrgvoid CheckModeMSP34x5D(MSP3430Ptr m); 23706f2543Smrgchar *MSP_getProductName (CARD16 product_id); 24706f2543Smrgvoid mpause(int milliseconds); 25706f2543Smrg 26706f2543Smrg#define __MSPDEBUG__ 0 27706f2543Smrg 28706f2543Smrg#if __MSPDEBUG__ > 3 29706f2543Smrg 30706f2543Smrgvoid MSPBeep(MSP3430Ptr m, CARD8 freq); 31706f2543Smrg#define __MSPBEEP MSPBeep(m,0x14); 32706f2543Smrg 33706f2543Smrg#else 34706f2543Smrg 35706f2543Smrg#define __MSPBEEP 36706f2543Smrg#endif 37706f2543Smrg 38706f2543Smrgstatic void SetMSP3430Control(MSP3430Ptr m, CARD8 RegAddress, CARD8 RegValueHigh, CARD8 RegValueLow) 39706f2543Smrg{ 40706f2543Smrg I2CByte data[3]; 41706f2543Smrg 42706f2543Smrg data[0]=RegAddress; 43706f2543Smrg data[1]=RegValueHigh; 44706f2543Smrg data[2]=RegValueLow; 45706f2543Smrg 46706f2543Smrg I2C_WriteRead(&(m->d),data,3,NULL,0); 47706f2543Smrg} 48706f2543Smrg 49706f2543Smrgstatic void SetMSP3430Data(MSP3430Ptr m, CARD8 RegAddress, CARD8 RegSubAddressHigh, CARD8 RegSubAddressLow, 50706f2543Smrg CARD8 RegValueHigh, CARD8 RegValueLow) 51706f2543Smrg{ 52706f2543Smrg I2CByte data[5]; 53706f2543Smrg#ifdef MSP_DEBUG 54706f2543Smrg if(!m->registers_present[RegSubAddressLow]){ 55706f2543Smrg 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", 56706f2543Smrg RegAddress, RegSubAddressHigh, RegSubAddressLow, RegValueHigh, RegValueLow); 57706f2543Smrg } 58706f2543Smrg#endif 59706f2543Smrg 60706f2543Smrg data[0] = RegAddress; 61706f2543Smrg data[1] = RegSubAddressHigh; 62706f2543Smrg data[2] = RegSubAddressLow; 63706f2543Smrg data[3] = RegValueHigh; 64706f2543Smrg data[4] = RegValueLow; 65706f2543Smrg 66706f2543Smrg I2C_WriteRead(&(m->d),data,5,NULL,0); 67706f2543Smrg} 68706f2543Smrg 69706f2543Smrgstatic void GetMSP3430Data(MSP3430Ptr m, CARD8 RegAddress, CARD8 RegSubAddressHigh, CARD8 RegSubAddressLow, 70706f2543Smrg CARD8 *RegValueHigh, CARD8 *RegValueLow) 71706f2543Smrg{ 72706f2543Smrg I2CByte send[3]; 73706f2543Smrg I2CByte receive[2]; 74706f2543Smrg 75706f2543Smrg send[0] = RegAddress; 76706f2543Smrg send[1] = RegSubAddressHigh; 77706f2543Smrg send[2] = RegSubAddressLow; 78706f2543Smrg 79706f2543Smrg I2C_WriteRead(&(m->d), send, 3, receive, 2); 80706f2543Smrg 81706f2543Smrg *RegValueHigh = receive[0]; 82706f2543Smrg *RegValueLow = receive[1]; 83706f2543Smrg} 84706f2543Smrg 85706f2543Smrg#if __MSPDEBUG__ > 2 86706f2543Smrgstatic void MSP3430DumpStatus(MSP3430Ptr m) 87706f2543Smrg{ 88706f2543SmrgCARD8 status_hi, status_lo; 89706f2543SmrgCARD8 subaddr, data[2]; 90706f2543Smrg 91706f2543SmrgGetMSP3430Data(m, RD_DEM, 0x02, 0x00, &status_hi, &status_lo); 92706f2543Smrgxf86DrvMsg(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", 93706f2543Smrg status_hi & 1, (status_lo>>7) & 1, (status_lo>>6)&1, 94706f2543Smrg (status_lo>>5)? ( (status_hi>>1)&1? "bad NICAM reception" : "NICAM" ) : 95706f2543Smrg ((status_hi>>1)&1 ? "bogus" : "ANALOG FM/AM") , 96706f2543Smrg (status_lo>>4)&1, (status_lo>>3)&1,!( (status_lo>>2)&1), !((status_lo>>1)&1)); 97706f2543Smrg 98706f2543SmrgGetMSP3430Data(m, RD_DEM, 0x00, 0x7E, &status_hi, &status_lo); 99706f2543Smrgxf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO, "MSP34xx: standard result=0x%02x%02x\n", 100706f2543Smrg status_hi, status_lo); 101706f2543Smrgsubaddr=0x0; 102706f2543SmrgI2C_WriteRead(&(m->d), &subaddr, 1, data, 2); 103706f2543Smrgxf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO, "MSP34xx: control=0x%02x%02x\n", 104706f2543Smrg data[1], data[0]); 105706f2543Smrg} 106706f2543Smrg#endif 107706f2543Smrg 108706f2543Smrg/* wrapper */ 109706f2543Smrgvoid InitMSP3430(MSP3430Ptr m) 110706f2543Smrg{ 111706f2543Smrg #if __MSPDEBUG__ > 1 112706f2543Smrg xf86DrvMsg(m->d.pI2CBus->scrnIndex,X_INFO,"InitMSP3430(m->connector=%d, m->standard=%d, m->chip_family=%d)\n", 113706f2543Smrg m->connector, m->standard, m->chip_family); 114706f2543Smrg #endif 115706f2543Smrg switch (m->chip_family) { 116706f2543Smrg case MSPFAMILY_34x0G: 117706f2543Smrg InitMSP34xxG(m); 118706f2543Smrg break; 119706f2543Smrg case MSPFAMILY_34x5G: 120706f2543Smrg InitMSP34xxG(m); 121706f2543Smrg break; 122706f2543Smrg case MSPFAMILY_34x5D: 123706f2543Smrg InitMSP34x5D(m); 124706f2543Smrg break; 125706f2543Smrg } 126706f2543Smrg} 127706f2543Smrg 128706f2543Smrg/*----------------------------------------------------------------- 129706f2543Smrg| common functions for all MSP34xx chips 130706f2543Smrg|----------------------------------------------------------------*/ 131706f2543Smrg 132706f2543SmrgMSP3430Ptr DetectMSP3430(I2CBusPtr b, I2CSlaveAddr addr) 133706f2543Smrg{ 134706f2543Smrg MSP3430Ptr m; 135706f2543Smrg I2CByte a; 136706f2543Smrg CARD8 hardware_version, major_revision, product_code, rom_version; 137706f2543Smrg Bool supported; 138706f2543Smrg 139706f2543Smrg m = calloc(1,sizeof(MSP3430Rec)); 140706f2543Smrg if(m == NULL)return NULL; 141706f2543Smrg m->d.DevName = strdup("MSP34xx"); 142706f2543Smrg m->d.SlaveAddr = addr; 143706f2543Smrg m->d.pI2CBus = b; 144706f2543Smrg m->d.NextDev = NULL; 145706f2543Smrg m->d.StartTimeout = b->StartTimeout; 146706f2543Smrg m->d.BitTimeout = b->BitTimeout; 147706f2543Smrg m->d.AcknTimeout = b->AcknTimeout; 148706f2543Smrg m->d.ByteTimeout = b->ByteTimeout; 149706f2543Smrg 150706f2543Smrg if(!I2C_WriteRead(&(m->d), NULL, 0, &a, 1)) 151706f2543Smrg { 152706f2543Smrg free(m->d.DevName); 153706f2543Smrg free(m); 154706f2543Smrg return NULL; 155706f2543Smrg } 156706f2543Smrg 157706f2543Smrg 158706f2543Smrg m->standard=MSP3430_NTSC; 159706f2543Smrg m->connector=MSP3430_CONNECTOR_1; 160706f2543Smrg m->mode=MSPMODE_STEREO_A; /*stereo or chanel A if avail. */ 161706f2543Smrg m->c_format=MSPFORMAT_UNKNOWN; 162706f2543Smrg m->c_standard=MSPSTANDARD_UNKNOWN; 163706f2543Smrg m->c_matrix=m->c_fmmatrix=m->c_source=0; 164706f2543Smrg m->volume=0; 165706f2543Smrg m->recheck=FALSE; 166706f2543Smrg 167706f2543Smrg GetMSP3430Data(m, RD_DSP, 0x00, 0x1E, &hardware_version, &major_revision); 168706f2543Smrg GetMSP3430Data(m, RD_DSP, 0x00, 0x1F, &product_code, &rom_version); 169706f2543Smrg m->hardware_version=hardware_version; 170706f2543Smrg m->major_revision=major_revision; 171706f2543Smrg m->product_code=product_code; 172706f2543Smrg m->rom_version=rom_version; 173706f2543Smrg 174706f2543Smrg m->chip_id=((major_revision << 8) | product_code); 175706f2543Smrg 176706f2543Smrg supported=FALSE; 177706f2543Smrg switch (major_revision) { 178706f2543Smrg case 4: /* 34xxD */ 179706f2543Smrg switch (product_code) { 180706f2543Smrg case 0x05: /* 3405D */ 181706f2543Smrg case 0x0A: /* 3410D */ 182706f2543Smrg case 0x0F: /* 3415D */ 183706f2543Smrg m->chip_family=MSPFAMILY_34x5D; 184706f2543Smrg m->recheck=TRUE; 185706f2543Smrg supported=TRUE; 186706f2543Smrg break; 187706f2543Smrg default: 188706f2543Smrg m->chip_family=MSPFAMILY_34x0D; 189706f2543Smrg } 190706f2543Smrg break; 191706f2543Smrg case 7: /* 34xxG */ 192706f2543Smrg switch(product_code){ 193706f2543Smrg case 0x00: 194706f2543Smrg case 0x0A: 195706f2543Smrg case 0x1E: 196706f2543Smrg case 0x28: 197706f2543Smrg case 0x32: 198706f2543Smrg m->chip_family=MSPFAMILY_34x0G; 199706f2543Smrg supported=TRUE; 200706f2543Smrg break; 201706f2543Smrg case 0x0f: 202706f2543Smrg case 0x19: 203706f2543Smrg case 0x2d: 204706f2543Smrg case 0x37: 205706f2543Smrg case 0x41: 206706f2543Smrg m->chip_family=MSPFAMILY_34x5G; 207706f2543Smrg supported=TRUE; 208706f2543Smrg #ifdef MSP_DEBUG 209706f2543Smrg memset(m->registers_present, 0, 256); 210706f2543Smrg #define A(num) m->registers_present[(num)]=1; 211706f2543Smrg #define B(num1, num2) memset(&(m->registers_present[num1]), 1, num2-num1); 212706f2543Smrg A(0x20) 213706f2543Smrg A(0x30) 214706f2543Smrg A(0x40) 215706f2543Smrg A(0x00) 216706f2543Smrg B(0x01, 0x08) 217706f2543Smrg B(0x0B, 0x0E) 218706f2543Smrg A(0x10) 219706f2543Smrg B(0x12,0x14) 220706f2543Smrg A(0x16) 221706f2543Smrg A(0x29) 222706f2543Smrg #undef B 223706f2543Smrg #undef A 224706f2543Smrg #endif 225706f2543Smrg break; 226706f2543Smrg default: 227706f2543Smrg m->chip_family=MSPFAMILY_UNKNOWN; 228706f2543Smrg } 229706f2543Smrg break; 230706f2543Smrg default: 231706f2543Smrg m->chip_family=MSPFAMILY_UNKNOWN; 232706f2543Smrg } 233706f2543Smrg 234706f2543Smrg xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO, "Found %s%s, rom version 0x%02x, chip_id=0x%04x\n", 235706f2543Smrg MSP_getProductName(m->chip_id), supported?"":" (unsupported)", rom_version, m->chip_id); 236706f2543Smrg 237706f2543Smrg if (!supported) { 238706f2543Smrg free(m->d.DevName); 239706f2543Smrg free(m); 240706f2543Smrg return NULL; 241706f2543Smrg } 242706f2543Smrg if(!I2CDevInit(&(m->d))) 243706f2543Smrg { 244706f2543Smrg free(m->d.DevName); 245706f2543Smrg free(m); 246706f2543Smrg return NULL; 247706f2543Smrg } 248706f2543Smrg 249706f2543Smrg return m; 250706f2543Smrg} 251706f2543Smrg 252706f2543Smrgvoid ResetMSP3430(MSP3430Ptr m) 253706f2543Smrg{ 254706f2543Smrg /* Reset the MSP3430 */ 255706f2543Smrg SetMSP3430Control(m, 0x00, 0x80, 0x00); 256706f2543Smrg /* Set it back to normal operation */ 257706f2543Smrg SetMSP3430Control(m, 0x00, 0x00, 0x00); 258706f2543Smrg 259706f2543Smrg m->c_format=MSPFORMAT_UNKNOWN; 260706f2543Smrg m->c_standard=MSPSTANDARD_UNKNOWN; 261706f2543Smrg m->c_matrix=m->c_fmmatrix=m->c_source=0; 262706f2543Smrg m->volume=0; 263706f2543Smrg} 264706f2543Smrg 265706f2543Smrgvoid MSP3430SetVolume (MSP3430Ptr m, CARD8 value) 266706f2543Smrg{ 267706f2543Smrg CARD8 result; 268706f2543Smrg#if 0 269706f2543Smrg CARD8 old_volume; 270706f2543Smrg GetMSP3430Data(m, RD_DSP, 0x00, 0x00, &old_volume, &result); 271706f2543Smrg xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO, "MSP3430 result 0x%02x\n", result); 272706f2543Smrg#endif 273706f2543Smrg /* save an extra Get call */ 274706f2543Smrg result=0; 275706f2543Smrg 276706f2543Smrg SetMSP3430Data(m, WR_DSP, 0x00, 0x00, value, result); 277706f2543Smrg 278706f2543Smrg SetMSP3430Data(m, WR_DSP, 0x00, 0x07, value, 0); 279706f2543Smrg m->volume=value; 280706f2543Smrg 281706f2543Smrg#if __MSPDEBUG__ > 2 282706f2543Smrg MSP3430DumpStatus(m); 283706f2543Smrg __MSPBEEP 284706f2543Smrg GetMSP3430Data(m, RD_DSP, 0x00, 0x00, &old_volume, &result); 285706f2543Smrg xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO, "MSP3430 volume 0x%02x\n",value); 286706f2543Smrg#endif 287706f2543Smrg} 288706f2543Smrg 289706f2543Smrg 290706f2543Smrgvoid MSP3430SetSAP (MSP3430Ptr m, int mode) 291706f2543Smrg{ 292706f2543Smrg xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO, "Put actual code to change SAP here\n"); 293706f2543Smrg 294706f2543Smrg SetMSP3430Data(m, WR_DSP, 0x00, 0x08, mode & 0xff, 0x20); 295706f2543Smrg} 296706f2543Smrg 297706f2543Smrg 298706f2543Smrg#if 0 299706f2543Smrgvoid MSP3430SetSource(MSP3430Ptr m, CARD8 value) 300706f2543Smrg{ 301706f2543Smrg /* Write to DSP, register 0x0008, (loudspeaker channel source/matrix) */ 302706f2543Smrg /* This sets the source to the TV tuner, for stereo operation */ 303706f2543Smrg SetMSP3430Data(m, WR_DSP, 0x00, 0x08, value, 0x20); 304706f2543Smrg} 305706f2543Smrg#endif 306706f2543Smrg 307706f2543Smrg 308706f2543Smrgchar *MSP_getProductName (CARD16 product_id) 309706f2543Smrg{ 310706f2543Smrg switch (product_id) { 311706f2543Smrg case 0x0400: return "MSP3400D"; 312706f2543Smrg case 0x040a: return "MSP3410D"; 313706f2543Smrg case 0x0405: return "MSP3405D"; 314706f2543Smrg case 0x040f: return "MSP3415D"; 315706f2543Smrg case 0x0700: return "MSP3400G"; 316706f2543Smrg case 0x070a: return "MSP3410G"; 317706f2543Smrg case 0x071e: return "MSP3430G"; 318706f2543Smrg case 0x0728: return "MSP3440G"; 319706f2543Smrg case 0x0732: return "MSP3450G"; 320706f2543Smrg case 0x070f: return "MSP3415G"; 321706f2543Smrg case 0x0719: return "MSP3425G"; 322706f2543Smrg case 0x072d: return "MSP3445G"; 323706f2543Smrg case 0x0737: return "MSP3455G"; 324706f2543Smrg case 0x0741: return "MSP3465G"; 325706f2543Smrg } 326706f2543Smrg return "MSP - unknown type"; 327706f2543Smrg} 328706f2543Smrg 329706f2543Smrg#if __MSPDEBUG__ > 2 330706f2543Smrg/*puts beep in MSP output 331706f2543Smrg freq = 0x01 - 16Hz ... 0x40 - 1kHz ... 0xff - 4kHz 332706f2543Smrg*/ 333706f2543Smrgvoid MSPBeep(MSP3430Ptr m, CARD8 freq) { 334706f2543Smrg SetMSP3430Data (m, WR_DSP, 0x00, freq, 0x7f, 0x40); 335706f2543Smrg mpause(100); 336706f2543Smrg SetMSP3430Data (m, WR_DSP, 0x00, 0x14, 0x00, 0x00); 337706f2543Smrg} 338706f2543Smrg#endif 339706f2543Smrg 340706f2543Smrgvoid mpause(int milliseconds) { 341706f2543Smrg int i,m; 342706f2543Smrg m=milliseconds/20; 343706f2543Smrg for (i=0;i<m;i++) usleep(20000); 344706f2543Smrg} 345706f2543Smrg 346706f2543Smrg/*----------------------------------------------------------------- 347706f2543Smrg| specific functions for all MSP34xxG chips 348706f2543Smrg|----------------------------------------------------------------*/ 349706f2543Smrg 350706f2543Smrgvoid InitMSP34xxG(MSP3430Ptr m) 351706f2543Smrg{ 352706f2543Smrg 353706f2543Smrg #if __MSPDEBUG__ > 1 354706f2543Smrg xf86DrvMsg(m->d.pI2CBus->scrnIndex,X_INFO,"InitMSP34xxG(m->connector=%d, m->standard=%d, m->chip_family=%d)\n", 355706f2543Smrg m->connector, m->standard, m->chip_family); 356706f2543Smrg #endif 357706f2543Smrg /* Reset MSP3430 */ 358706f2543Smrg SetMSP3430Control(m, 0x00, 0x80, 0x00); 359706f2543Smrg /* Set it back to normal operation */ 360706f2543Smrg SetMSP3430Control(m, 0x00, 0x00, 0x00); 361706f2543Smrg 362706f2543Smrg /*set MODUS register */ 363706f2543Smrg /* bits: 0 - automatic sound detection */ 364706f2543Smrg /* 1 - enable STATUS change */ 365706f2543Smrg /* 12 - detect 6.5 Mhz carrier as D/K1, D/K2 or D/K NICAM (does not seem to work ) */ 366706f2543Smrg /* 13 - detect 4.5 Mhz carrier as BTSC */ 367706f2543Smrg if ( (m->standard & 0xff) == MSP3430_PAL ) 368706f2543Smrg { 369706f2543Smrg SetMSP3430Data(m, WR_DEM, 0x00, 0x30, 0x30, 0x03|0x08); /* make O_ pins tristate */ 370706f2543Smrg /* PAL standard */ 371706f2543Smrg SetMSP3430Data(m, WR_DEM, 0x00, 0x20, 0x00, 0x01); /* possibly wrong */ 372706f2543Smrg } else { 373706f2543Smrg SetMSP3430Data(m, WR_DEM, 0x00, 0x30, 0x20, 0x03|0x08); 374706f2543Smrg /* standard selection is M-BTSC-Stereo */ 375706f2543Smrg SetMSP3430Data(m, WR_DEM, 0x00, 0x20, 0x00, 0x20); 376706f2543Smrg } 377706f2543Smrg 378706f2543Smrg switch(m->connector){ 379706f2543Smrg case MSP3430_CONNECTOR_1: 380706f2543Smrg SetMSP3430Data(m, WR_DSP, 0x00, 0x08, 0x03, 0x20); 381706f2543Smrg break; 382706f2543Smrg case MSP3430_CONNECTOR_2: 383706f2543Smrg /* this has not been checked yet.. could be bogus */ 384706f2543Smrg /* SCART Input Prescale: 0 dB gain */ 385706f2543Smrg SetMSP3430Data(m, WR_DSP, 0x00, 0x0d, 0x19, 0x00); 386706f2543Smrg SetMSP3430Data(m, WR_DSP, 0x00, 0x08, 0x02, 0x20); 387706f2543Smrg break; 388706f2543Smrg case MSP3430_CONNECTOR_3: 389706f2543Smrg default: 390706f2543Smrg /* SCART Input Prescale: 0 dB gain */ 391706f2543Smrg SetMSP3430Data(m, WR_DSP, 0x00, 0x0d, 0x19, 0x00); 392706f2543Smrg 393706f2543Smrg SetMSP3430Data(m, WR_DSP, 0x00, 0x08, 0x02, 0x20); 394706f2543Smrg break; 395706f2543Smrg } 396706f2543Smrg 397706f2543Smrg switch(m->standard){ 398706f2543Smrg case MSP3430_PAL: 399706f2543Smrg SetMSP3430Data(m, WR_DSP, 0x00, 0x0e, 0x24, 0x03); 400706f2543Smrg SetMSP3430Data(m, WR_DSP, 0x00, 0x10, 0x00, 0x5a); 401706f2543Smrg SetMSP3430Data(m, WR_DEM, 0x00, 0x20, 0x00, 0x03); 402706f2543Smrg /* Set volume to FAST_MUTE. */ 403706f2543Smrg SetMSP3430Data(m, WR_DSP, 0x00, 0x00, 0xFF, 0x00); 404706f2543Smrg break; 405706f2543Smrg case MSP3430_PAL_DK1: 406706f2543Smrg SetMSP3430Data(m, WR_DSP, 0x00, 0x0e, 0x24, 0x03); 407706f2543Smrg SetMSP3430Data(m, WR_DSP, 0x00, 0x10, 0x00, 0x5a); 408706f2543Smrg SetMSP3430Data(m, WR_DEM, 0x00, 0x20, 0x00, 0x04); 409706f2543Smrg /* Set volume to FAST_MUTE. */ 410706f2543Smrg SetMSP3430Data(m, WR_DSP, 0x00, 0x00, 0xFF, 0x00); 411706f2543Smrg break; 412706f2543Smrg case MSP3430_SECAM: /* is this right ? */ 413706f2543Smrg case MSP3430_NTSC: 414706f2543Smrg /* Write to DSP, register 0x000E, (prescale FM/FM matrix) */ 415706f2543Smrg SetMSP3430Data(m, WR_DSP, 0x00, 0x0e, 0x24, 0x03); 416706f2543Smrg 417706f2543Smrg /* Set volume to FAST_MUTE. */ 418706f2543Smrg SetMSP3430Data(m, WR_DSP, 0x00, 0x00, 0xFF, 0x00); 419706f2543Smrg break; 420706f2543Smrg } 421706f2543Smrg 422706f2543Smrg} 423706f2543Smrg 424706f2543Smrg/*----------------------------------------------------------------- 425706f2543Smrg| specific functions for all MSP34x5D chips 426706f2543Smrg|----------------------------------------------------------------*/ 427706f2543Smrg 428706f2543Smrgvoid InitMSP34x5D(MSP3430Ptr m) 429706f2543Smrg{ 430706f2543Smrgint count; 431706f2543SmrgCARD8 high,low; 432706f2543SmrgCARD16 result,standard; 433706f2543SmrgCARD16 peak; 434706f2543Smrg 435706f2543Smrg 436706f2543Smrgif (m->c_format==MSPFORMAT_UNKNOWN) ResetMSP3430(m); 437706f2543Smrgelse { 438706f2543Smrg /*mute volume*/ 439706f2543Smrg SetMSP3430Data (m, WR_DSP, 0x00, 0x00, 0x00, 0x00); 440706f2543Smrg} 441706f2543Smrg 442706f2543Smrg 443706f2543Smrg 444706f2543Smrg switch(m->connector){ 445706f2543Smrg case MSP3430_CONNECTOR_2: 446706f2543Smrg case MSP3430_CONNECTOR_3: 447706f2543Smrg if (m->c_format!=MSPFORMAT_SCART) { 448706f2543Smrg /* SCART Input Prescale: 0 dB gain */ 449706f2543Smrg SetMSP3430Data (m, WR_DSP, 0x00, 0x0d, 0x19, 0x00); 450706f2543Smrg /* this has not been checked yet.. could be bogus */ 451706f2543Smrg m->c_format=MSPFORMAT_SCART; /*stereo*/ 452706f2543Smrg } 453706f2543Smrg break; 454706f2543Smrg case MSP3430_CONNECTOR_1: 455706f2543Smrg default: 456706f2543Smrg 457706f2543Smrg switch ( m->standard & 0x00ff ) { 458706f2543Smrg case MSP3430_PAL: 459706f2543Smrg switch( m->standard ) { 460706f2543Smrg case MSP3430_PAL_DK1: 461706f2543Smrg standard=MSPSTANDARD_FM_DK1; 462706f2543Smrg break; 463706f2543Smrg/* case MSP3430_PAL_DK2: 464706f2543Smrg standard=MSPSTANDARD_FM_DK2; 465706f2543Smrg break; 466706f2543Smrg case MSP3430_PAL_BG: 467706f2543Smrg may be FM stereo (Germany) or FM NICAM (Scandinavia,spain) 468706f2543Smrg standard=MSPSTANDARD_AUTO; 469706f2543Smrg break; 470706f2543Smrg*/ 471706f2543Smrg default: 472706f2543Smrg standard=MSPSTANDARD_AUTO; 473706f2543Smrg } 474706f2543Smrg break; 475706f2543Smrg case MSP3430_SECAM: 476706f2543Smrg standard=MSPSTANDARD_AUTO; 477706f2543Smrg case MSP3430_NTSC: 478706f2543Smrg /* Only MSP34x5 supported format - Korean NTSC-M*/ 479706f2543Smrg standard=MSPSTANDARD_FM_M; 480706f2543Smrg default: 481706f2543Smrg standard=MSPSTANDARD_AUTO; 482706f2543Smrg } 483706f2543Smrg 484706f2543Smrg /*no NICAM support in MSP3410D - force to autodetect*/ 485706f2543Smrg if ((m->chip_id==0x405) && (standard>=MSPSTANDARD_NICAM_BG)) 486706f2543Smrg standard=MSPSTANDARD_AUTO; 487706f2543Smrg 488706f2543Smrg if (m->c_standard != standard) { 489706f2543Smrg 490706f2543Smrg SetMSP3430Data (m, WR_DEM, 0x00, 0x20, standard>>8, standard & 0xFF); 491706f2543Smrg if (standard==MSPSTANDARD_AUTO) { 492706f2543Smrg count = 50; /* time shouldn't exceed 1s, just in case */ 493706f2543Smrg do { 494706f2543Smrg usleep(20000); 495706f2543Smrg GetMSP3430Data (m, RD_DEM, 0x00, 0x7e, &high, &low); 496706f2543Smrg result = ( high << 8 ) | low; 497706f2543Smrg --count; 498706f2543Smrg } while( result > 0x07ff && count > 0 ); 499706f2543Smrg 500706f2543Smrg if ((result > MSPSTANDARD_AUTO)) 501706f2543Smrg standard=result; 502706f2543Smrg else standard=MSPSTANDARD_UNKNOWN; 503706f2543Smrg#if __MSPDEBUG__ > 1 504706f2543Smrg xf86DrvMsg(m->d.pI2CBus->scrnIndex,X_INFO,"Detected audio standard: %d\n",result); 505706f2543Smrg#endif 506706f2543Smrg /* result = MSPSTANDARD_NICAM_L can be one of: 507706f2543Smrg SECAM_L - MSPSTANDARD_NICAM_L 508706f2543Smrg D/K1 - MSPSTANDARD_FM_DK1 509706f2543Smrg D/K2 - MSPSTANDARD_FM_DK2 510706f2543Smrg D/K-NICAM - MSPSTANDARD_NICAM_DK*/ 511706f2543Smrg if( standard == MSPSTANDARD_NICAM_L ) { 512706f2543Smrg if ((m->standard & 0x00ff)==MSP3430_PAL) { 513706f2543Smrg /* force PAL D/K */ 514706f2543Smrg standard=MSPSTANDARD_FM_DK1; 515706f2543Smrg SetMSP3430Data (m, WR_DEM, 0x00, 0x20, standard>>8, standard & 0xFF); 516706f2543Smrg#if __MSPDEBUG__ > 1 517706f2543Smrg xf86DrvMsg(m->d.pI2CBus->scrnIndex,X_INFO, "Detected 6.5MHz carrier - forced to D/K1 !!!\n" ); 518706f2543Smrg#endif 519706f2543Smrg } 520706f2543Smrg } 521706f2543Smrg } 522706f2543Smrg m->c_standard=standard; 523706f2543Smrg } /*end - standard changed*/ 524706f2543Smrg else { 525706f2543Smrg if (standard<MSPSTANDARD_NICAM_BG) { 526706f2543Smrg /* get old value of ident. mode register*/ 527706f2543Smrg GetMSP3430Data (m, RD_DSP, 0x00, 0x15, &high, &low); 528706f2543Smrg /* reset Ident-Filter */ 529706f2543Smrg SetMSP3430Data (m, WR_DSP, 0x00, 0x14, 0x00, 0x3F); 530706f2543Smrg /* put back old value to ident. mode register*/ 531706f2543Smrg SetMSP3430Data (m, WR_DSP, 0x00, 0x14, 0x00, low); 532706f2543Smrg } 533706f2543Smrg } 534706f2543Smrg 535706f2543Smrg if (standard<=MSPSTANDARD_AUTO) { 536706f2543Smrg m->c_format=MSPFORMAT_1xFM; 537706f2543Smrg } 538706f2543Smrg else if (standard<MSPSTANDARD_NICAM_BG) { 539706f2543Smrg /* set FM prescale */ 540706f2543Smrg SetMSP3430Data (m, WR_DSP, 0x00, 0x0e, 0x30, 0); 541706f2543Smrg /* set FM deemphasis*/ 542706f2543Smrg SetMSP3430Data (m, WR_DSP, 0x00, 0x0f, ((standard==MSPSTANDARD_FM_M)?0:1), 0); 543706f2543Smrg 544706f2543Smrg /* check if FM2 carrier is present */ 545706f2543Smrg /*turn off FM DC Notch*/ 546706f2543Smrg SetMSP3430Data (m, WR_DSP, 0x00, 0x17, 0x00, 0x3f); 547706f2543Smrg /*matrix source for Quasi-Peak Detector - stereo: ch2->L ch1->R*/ 548706f2543Smrg SetMSP3430Data (m, WR_DSP, 0x00, 0x0c, 0x00, 0x20); 549706f2543Smrg 550706f2543Smrg mpause(250); 551706f2543Smrg GetMSP3430Data (m, RD_DSP, 0x00, 0x1A, &high, &low); 552706f2543Smrg peak = (high << 8) | low; 553706f2543Smrg#if __MSPDEBUG__ > 1 554706f2543Smrg xf86DrvMsg(m->d.pI2CBus->scrnIndex,X_INFO,"Second carrier Quasi-Peak detection: %d\n",peak); 555706f2543Smrg#endif 556706f2543Smrg /*turn on FM DC Notch*/ 557706f2543Smrg SetMSP3430Data (m, WR_DSP, 0x00, 0x17, 0x00, 0x00); 558706f2543Smrg 559706f2543Smrg if (peak<5) { 560706f2543Smrg /* if second carrier not detected - only mono from first carrier*/ 561706f2543Smrg m->c_format=MSPFORMAT_1xFM; 562706f2543Smrg } 563706f2543Smrg else { 564706f2543Smrg m->c_format=MSPFORMAT_2xFM; 565706f2543Smrg /*start of FM identification process - FM_WAIT 566706f2543Smrg wait at least 0.5s - used 1s - gives beter resolution*/ 567706f2543Smrg mpause(1000); 568706f2543Smrg } 569706f2543Smrg } 570706f2543Smrg else { 571706f2543Smrg if (standard==MSPSTANDARD_NICAM_L) { 572706f2543Smrg m->c_format=MSPFORMAT_NICAM_AM; 573706f2543Smrg /* set AM prescale */ 574706f2543Smrg SetMSP3430Data (m, WR_DSP, 0x00, 0x0e, 0x7C, 0); 575706f2543Smrg } 576706f2543Smrg else { 577706f2543Smrg m->c_format=MSPFORMAT_NICAM_FM; 578706f2543Smrg /* set FM prescale */ 579706f2543Smrg SetMSP3430Data (m, WR_DSP, 0x00, 0x0e, 0x30, 0); 580706f2543Smrg } 581706f2543Smrg /* set FM deemphasis*/ 582706f2543Smrg SetMSP3430Data (m, WR_DSP, 0x00, 0x0f, 0x00, 0); 583706f2543Smrg /* set NICAM prescale to 0dB */ 584706f2543Smrg SetMSP3430Data (m, WR_DSP, 0x00, 0x10, 0x20, 0); 585706f2543Smrg } 586706f2543Smrg 587706f2543Smrg break; 588706f2543Smrg } /*end - case conector*/ 589706f2543Smrg 590706f2543Smrg CheckModeMSP34x5D(m); 591706f2543Smrg 592706f2543Smrg /* Set volume to FAST_MUTE. */ 593706f2543Smrg /*SetMSP3430Data(m, WR_DSP, 0x00, 0x00, 0xFF, 0x00);*/ 594706f2543Smrg /*set volume*/ 595706f2543Smrg MSP3430SetVolume(m,m->volume); 596706f2543Smrg 597706f2543Smrg __MSPBEEP 598706f2543Smrg 599706f2543Smrg 600706f2543Smrg} /* EnableMSP34x5D ()... */ 601706f2543Smrg 602706f2543Smrg 603706f2543Smrg 604706f2543Smrg 605706f2543Smrgvoid CheckModeMSP34x5D(MSP3430Ptr m) { 606706f2543Smrg const char stereo_on=25; 607706f2543Smrg const char stereo_off=20; 608706f2543Smrg const char dual_on=-stereo_on; 609706f2543Smrg const char dual_off=-stereo_off; 610706f2543Smrg char detect; 611706f2543Smrg CARD8 matrix, fmmatrix, source, high, low; 612706f2543Smrg 613706f2543Smrg fmmatrix=0; /*no matrix*/ 614706f2543Smrg source=0; /*FM*/ 615706f2543Smrg switch (m->c_format) { 616706f2543Smrg case MSPFORMAT_NICAM_FM: 617706f2543Smrg case MSPFORMAT_NICAM_AM: 618706f2543Smrg case MSPFORMAT_SCART: 619706f2543Smrg source=( (m->c_format == MSPFORMAT_SCART)?2:1 ); 620706f2543Smrg switch (m->mode) { 621706f2543Smrg case MSPMODE_MONO: 622706f2543Smrg matrix=0x30; /*MONO*/ 623706f2543Smrg break; 624706f2543Smrg case MSPMODE_A: 625706f2543Smrg matrix=0x00; /*A*/ 626706f2543Smrg break; 627706f2543Smrg case MSPMODE_B: 628706f2543Smrg matrix=0x10; /*B*/ 629706f2543Smrg break; 630706f2543Smrg default: 631706f2543Smrg matrix=0x20; /*STEREO*/ 632706f2543Smrg break; 633706f2543Smrg } 634706f2543Smrg break; 635706f2543Smrg default: 636706f2543Smrg case MSPFORMAT_1xFM: 637706f2543Smrg matrix=0x00; /*A*/ 638706f2543Smrg break; 639706f2543Smrg case MSPFORMAT_2xFM: 640706f2543Smrg switch (m->mode) { 641706f2543Smrg case MSPMODE_MONO: 642706f2543Smrg matrix=0x30; /*MONO*/ 643706f2543Smrg break; 644706f2543Smrg case MSPMODE_STEREO: 645706f2543Smrg matrix=0x20; /*STEREO*/ 646706f2543Smrg fmmatrix=((m->c_standard==MSPSTANDARD_FM_M)?2:1); 647706f2543Smrg break; 648706f2543Smrg case MSPMODE_AB: 649706f2543Smrg matrix=0x20; /*STEREO*/ 650706f2543Smrg break; 651706f2543Smrg case MSPMODE_A: 652706f2543Smrg matrix=0x00; /*A*/ 653706f2543Smrg break; 654706f2543Smrg case MSPMODE_B: 655706f2543Smrg matrix=0x10; /*B*/ 656706f2543Smrg break; 657706f2543Smrg default: 658706f2543Smrg /*FM_IDENT_CHECK*/ 659706f2543Smrg GetMSP3430Data (m, RD_DSP, 0x00, 0x18, &high, &low); 660706f2543Smrg detect=(char)high; 661706f2543Smrg#if __MSPDEBUG__ > 1 662706f2543Smrg xf86DrvMsg(m->d.pI2CBus->scrnIndex,X_INFO,"Stereo Detection Register: %d\n",detect); 663706f2543Smrg#endif 664706f2543Smrg if (detect>=((m->c_mode==MSPMODE_STEREO)?stereo_off:stereo_on)) { 665706f2543Smrg m->c_mode=MSPMODE_STEREO; 666706f2543Smrg matrix=0x20; /*STEREO*/ 667706f2543Smrg fmmatrix=((m->c_standard==MSPSTANDARD_FM_M)?2:1); 668706f2543Smrg } 669706f2543Smrg else if (detect<=((m->c_mode==MSPMODE_AB)?dual_off:dual_on)) { 670706f2543Smrg m->c_mode=MSPMODE_AB; 671706f2543Smrg switch (m->mode) { 672706f2543Smrg case MSPMODE_STEREO_AB: matrix=0x20; break; 673706f2543Smrg case MSPMODE_STEREO_B: matrix=0x10; break; 674706f2543Smrg default: 675706f2543Smrg case MSPMODE_A: matrix=0x00; break; 676706f2543Smrg } 677706f2543Smrg } 678706f2543Smrg else { 679706f2543Smrg m->c_mode=MSPMODE_MONO; 680706f2543Smrg matrix=0x30; /*MONO*/ 681706f2543Smrg } 682706f2543Smrg break; 683706f2543Smrg } /* end - case mode*/ 684706f2543Smrg break; 685706f2543Smrg } 686706f2543Smrg 687706f2543Smrg if (m->c_fmmatrix != fmmatrix) { 688706f2543Smrg GetMSP3430Data (m, RD_DSP, 0x00, 0x0e, &high, &low); 689706f2543Smrg SetMSP3430Data (m, WR_DSP, 0x00, 0x0e, high, fmmatrix); 690706f2543Smrg m->c_fmmatrix = fmmatrix; 691706f2543Smrg } 692706f2543Smrg 693706f2543Smrg if ((m->c_matrix != matrix) || (m->c_source != source)) { 694706f2543Smrg /*set chanel source and matrix for loudspeaker*/ 695706f2543Smrg SetMSP3430Data (m, WR_DSP, 0x00, 0x08, source, matrix); 696706f2543Smrg 697706f2543Smrg m->c_matrix = matrix; 698706f2543Smrg m->c_source = source; 699706f2543Smrg } 700706f2543Smrg 701706f2543Smrg if ( ((m->c_format) & 0xF0) == MSPFORMAT_NICAM) 702706f2543Smrg SetMSP3430Data (m, WR_DEM, 0x00, 0x21, 0, 1); 703706f2543Smrg 704706f2543Smrg#if __MSPDEBUG__ > 0 705706f2543Smrg char *msg; 706706f2543Smrg switch (matrix) { 707706f2543Smrg case 0x30: /*MONO*/ 708706f2543Smrg msg="MONO"; 709706f2543Smrg break; 710706f2543Smrg case 0x00: /*LEFT*/ 711706f2543Smrg msg="MONO/CHANNEL_1"; 712706f2543Smrg break; 713706f2543Smrg case 0x10: /*RIGHT*/ 714706f2543Smrg msg="MONO/CHANNEL_2"; 715706f2543Smrg break; 716706f2543Smrg case 0x20: /*LEFT*/ 717706f2543Smrg msg="STEREO"; 718706f2543Smrg break; 719706f2543Smrg default: 720706f2543Smrg msg="unknown"; 721706f2543Smrg break; 722706f2543Smrg } 723706f2543Smrg xf86DrvMsg(m->d.pI2CBus->scrnIndex,X_INFO,"Audio mode set to: %s\n",msg); 724706f2543Smrg#endif 725706f2543Smrg} 726706f2543Smrg 727