1016a45b2Smrg#ifdef HAVE_XORG_CONFIG_H 2016a45b2Smrg#include <xorg-config.h> 3016a45b2Smrg#endif 4016a45b2Smrg 5016a45b2Smrg#include <string.h> 6016a45b2Smrg#include <unistd.h> 7016a45b2Smrg 8016a45b2Smrg#include "xf86.h" 9016a45b2Smrg#include "xf86i2c.h" 10016a45b2Smrg#include "msp3430.h" 11016a45b2Smrg#include "i2c_def.h" 12016a45b2Smrg 13016a45b2Smrg#define CONTROL 0x00 14016a45b2Smrg#define WR_DEM 0x10 15016a45b2Smrg#define RD_DEM 0x11 16016a45b2Smrg#define WR_DSP 0x12 17016a45b2Smrg#define RD_DSP 0x13 18016a45b2Smrg 19016a45b2Smrg 20016a45b2Smrgvoid InitMSP34xxG(MSP3430Ptr m); 21016a45b2Smrgvoid InitMSP34x5D(MSP3430Ptr m); 22016a45b2Smrgvoid CheckModeMSP34x5D(MSP3430Ptr m); 23016a45b2Smrgchar *MSP_getProductName (CARD16 product_id); 24016a45b2Smrgvoid mpause(int milliseconds); 25016a45b2Smrg 26016a45b2Smrg#define __MSPDEBUG__ 0 27016a45b2Smrg 28016a45b2Smrg#if __MSPDEBUG__ > 3 29016a45b2Smrg 30016a45b2Smrgvoid MSPBeep(MSP3430Ptr m, CARD8 freq); 31016a45b2Smrg#define __MSPBEEP MSPBeep(m,0x14); 32016a45b2Smrg 33016a45b2Smrg#else 34016a45b2Smrg 35016a45b2Smrg#define __MSPBEEP 36016a45b2Smrg#endif 37016a45b2Smrg 38016a45b2Smrgstatic void SetMSP3430Control(MSP3430Ptr m, CARD8 RegAddress, CARD8 RegValueHigh, CARD8 RegValueLow) 39016a45b2Smrg{ 40016a45b2Smrg I2CByte data[3]; 41016a45b2Smrg 42016a45b2Smrg data[0]=RegAddress; 43016a45b2Smrg data[1]=RegValueHigh; 44016a45b2Smrg data[2]=RegValueLow; 45016a45b2Smrg 46016a45b2Smrg I2C_WriteRead(&(m->d),data,3,NULL,0); 47016a45b2Smrg} 48016a45b2Smrg 49016a45b2Smrgstatic void SetMSP3430Data(MSP3430Ptr m, CARD8 RegAddress, CARD8 RegSubAddressHigh, CARD8 RegSubAddressLow, 50016a45b2Smrg CARD8 RegValueHigh, CARD8 RegValueLow) 51016a45b2Smrg{ 52016a45b2Smrg I2CByte data[5]; 53016a45b2Smrg#ifdef MSP_DEBUG 54016a45b2Smrg if(!m->registers_present[RegSubAddressLow]){ 55016a45b2Smrg 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", 56016a45b2Smrg RegAddress, RegSubAddressHigh, RegSubAddressLow, RegValueHigh, RegValueLow); 57016a45b2Smrg } 58016a45b2Smrg#endif 59016a45b2Smrg 60016a45b2Smrg data[0] = RegAddress; 61016a45b2Smrg data[1] = RegSubAddressHigh; 62016a45b2Smrg data[2] = RegSubAddressLow; 63016a45b2Smrg data[3] = RegValueHigh; 64016a45b2Smrg data[4] = RegValueLow; 65016a45b2Smrg 66016a45b2Smrg I2C_WriteRead(&(m->d),data,5,NULL,0); 67016a45b2Smrg} 68016a45b2Smrg 69016a45b2Smrgstatic void GetMSP3430Data(MSP3430Ptr m, CARD8 RegAddress, CARD8 RegSubAddressHigh, CARD8 RegSubAddressLow, 70016a45b2Smrg CARD8 *RegValueHigh, CARD8 *RegValueLow) 71016a45b2Smrg{ 72016a45b2Smrg I2CByte send[3]; 73016a45b2Smrg I2CByte receive[2]; 74016a45b2Smrg 75016a45b2Smrg send[0] = RegAddress; 76016a45b2Smrg send[1] = RegSubAddressHigh; 77016a45b2Smrg send[2] = RegSubAddressLow; 78016a45b2Smrg 79016a45b2Smrg I2C_WriteRead(&(m->d), send, 3, receive, 2); 80016a45b2Smrg 81016a45b2Smrg *RegValueHigh = receive[0]; 82016a45b2Smrg *RegValueLow = receive[1]; 83016a45b2Smrg} 84016a45b2Smrg 85016a45b2Smrg#if __MSPDEBUG__ > 2 86016a45b2Smrgstatic void MSP3430DumpStatus(MSP3430Ptr m) 87016a45b2Smrg{ 88016a45b2SmrgCARD8 status_hi, status_lo; 89016a45b2SmrgCARD8 subaddr, data[2]; 90016a45b2Smrg 91016a45b2SmrgGetMSP3430Data(m, RD_DEM, 0x02, 0x00, &status_hi, &status_lo); 92016a45b2Smrgxf86DrvMsg(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", 93016a45b2Smrg status_hi & 1, (status_lo>>7) & 1, (status_lo>>6)&1, 94016a45b2Smrg (status_lo>>5)? ( (status_hi>>1)&1? "bad NICAM reception" : "NICAM" ) : 95016a45b2Smrg ((status_hi>>1)&1 ? "bogus" : "ANALOG FM/AM") , 96016a45b2Smrg (status_lo>>4)&1, (status_lo>>3)&1,!( (status_lo>>2)&1), !((status_lo>>1)&1)); 97016a45b2Smrg 98016a45b2SmrgGetMSP3430Data(m, RD_DEM, 0x00, 0x7E, &status_hi, &status_lo); 99016a45b2Smrgxf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO, "MSP34xx: standard result=0x%02x%02x\n", 100016a45b2Smrg status_hi, status_lo); 101016a45b2Smrgsubaddr=0x0; 102016a45b2SmrgI2C_WriteRead(&(m->d), &subaddr, 1, data, 2); 103016a45b2Smrgxf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO, "MSP34xx: control=0x%02x%02x\n", 104016a45b2Smrg data[1], data[0]); 105016a45b2Smrg} 106016a45b2Smrg#endif 107016a45b2Smrg 108016a45b2Smrg/* wrapper */ 109016a45b2Smrgvoid InitMSP3430(MSP3430Ptr m) 110016a45b2Smrg{ 111016a45b2Smrg #if __MSPDEBUG__ > 1 112016a45b2Smrg xf86DrvMsg(m->d.pI2CBus->scrnIndex,X_INFO,"InitMSP3430(m->connector=%d, m->standard=%d, m->chip_family=%d)\n", 113016a45b2Smrg m->connector, m->standard, m->chip_family); 114016a45b2Smrg #endif 115016a45b2Smrg switch (m->chip_family) { 116016a45b2Smrg case MSPFAMILY_34x0G: 117016a45b2Smrg InitMSP34xxG(m); 118016a45b2Smrg break; 119016a45b2Smrg case MSPFAMILY_34x5G: 120016a45b2Smrg InitMSP34xxG(m); 121016a45b2Smrg break; 122016a45b2Smrg case MSPFAMILY_34x5D: 123016a45b2Smrg InitMSP34x5D(m); 124016a45b2Smrg break; 125016a45b2Smrg } 126016a45b2Smrg} 127016a45b2Smrg 128016a45b2Smrg/*----------------------------------------------------------------- 129016a45b2Smrg| common functions for all MSP34xx chips 130016a45b2Smrg|----------------------------------------------------------------*/ 131016a45b2Smrg 132016a45b2SmrgMSP3430Ptr DetectMSP3430(I2CBusPtr b, I2CSlaveAddr addr) 133016a45b2Smrg{ 134016a45b2Smrg MSP3430Ptr m; 135016a45b2Smrg I2CByte a; 136016a45b2Smrg CARD8 hardware_version, major_revision, product_code, rom_version; 137016a45b2Smrg Bool supported; 138016a45b2Smrg 139016a45b2Smrg m = calloc(1,sizeof(MSP3430Rec)); 140016a45b2Smrg if(m == NULL)return NULL; 141016a45b2Smrg m->d.DevName = strdup("MSP34xx"); 142016a45b2Smrg m->d.SlaveAddr = addr; 143016a45b2Smrg m->d.pI2CBus = b; 144016a45b2Smrg m->d.NextDev = NULL; 145016a45b2Smrg m->d.StartTimeout = b->StartTimeout; 146016a45b2Smrg m->d.BitTimeout = b->BitTimeout; 147016a45b2Smrg m->d.AcknTimeout = b->AcknTimeout; 148016a45b2Smrg m->d.ByteTimeout = b->ByteTimeout; 149016a45b2Smrg 150016a45b2Smrg if(!I2C_WriteRead(&(m->d), NULL, 0, &a, 1)) 151016a45b2Smrg { 152861b9feeSmrg free(__UNCONST(m->d.DevName)); 153016a45b2Smrg free(m); 154016a45b2Smrg return NULL; 155016a45b2Smrg } 156016a45b2Smrg 157016a45b2Smrg 158016a45b2Smrg m->standard=MSP3430_NTSC; 159016a45b2Smrg m->connector=MSP3430_CONNECTOR_1; 160016a45b2Smrg m->mode=MSPMODE_STEREO_A; /*stereo or chanel A if avail. */ 161016a45b2Smrg m->c_format=MSPFORMAT_UNKNOWN; 162016a45b2Smrg m->c_standard=MSPSTANDARD_UNKNOWN; 163016a45b2Smrg m->c_matrix=m->c_fmmatrix=m->c_source=0; 164016a45b2Smrg m->volume=0; 165016a45b2Smrg m->recheck=FALSE; 166016a45b2Smrg 167016a45b2Smrg GetMSP3430Data(m, RD_DSP, 0x00, 0x1E, &hardware_version, &major_revision); 168016a45b2Smrg GetMSP3430Data(m, RD_DSP, 0x00, 0x1F, &product_code, &rom_version); 169016a45b2Smrg m->hardware_version=hardware_version; 170016a45b2Smrg m->major_revision=major_revision; 171016a45b2Smrg m->product_code=product_code; 172016a45b2Smrg m->rom_version=rom_version; 173016a45b2Smrg 174016a45b2Smrg m->chip_id=((major_revision << 8) | product_code); 175016a45b2Smrg 176016a45b2Smrg supported=FALSE; 177016a45b2Smrg switch (major_revision) { 178016a45b2Smrg case 4: /* 34xxD */ 179016a45b2Smrg switch (product_code) { 180016a45b2Smrg case 0x05: /* 3405D */ 181016a45b2Smrg case 0x0A: /* 3410D */ 182016a45b2Smrg case 0x0F: /* 3415D */ 183016a45b2Smrg m->chip_family=MSPFAMILY_34x5D; 184016a45b2Smrg m->recheck=TRUE; 185016a45b2Smrg supported=TRUE; 186016a45b2Smrg break; 187016a45b2Smrg default: 188016a45b2Smrg m->chip_family=MSPFAMILY_34x0D; 189016a45b2Smrg } 190016a45b2Smrg break; 191016a45b2Smrg case 7: /* 34xxG */ 192016a45b2Smrg switch(product_code){ 193016a45b2Smrg case 0x00: 194016a45b2Smrg case 0x0A: 195016a45b2Smrg case 0x1E: 196016a45b2Smrg case 0x28: 197016a45b2Smrg case 0x32: 198016a45b2Smrg m->chip_family=MSPFAMILY_34x0G; 199016a45b2Smrg supported=TRUE; 200016a45b2Smrg break; 201016a45b2Smrg case 0x0f: 202016a45b2Smrg case 0x19: 203016a45b2Smrg case 0x2d: 204016a45b2Smrg case 0x37: 205016a45b2Smrg case 0x41: 206016a45b2Smrg m->chip_family=MSPFAMILY_34x5G; 207016a45b2Smrg supported=TRUE; 208016a45b2Smrg #ifdef MSP_DEBUG 209016a45b2Smrg memset(m->registers_present, 0, 256); 210016a45b2Smrg #define A(num) m->registers_present[(num)]=1; 211016a45b2Smrg #define B(num1, num2) memset(&(m->registers_present[num1]), 1, num2-num1); 212016a45b2Smrg A(0x20) 213016a45b2Smrg A(0x30) 214016a45b2Smrg A(0x40) 215016a45b2Smrg A(0x00) 216016a45b2Smrg B(0x01, 0x08) 217016a45b2Smrg B(0x0B, 0x0E) 218016a45b2Smrg A(0x10) 219016a45b2Smrg B(0x12,0x14) 220016a45b2Smrg A(0x16) 221016a45b2Smrg A(0x29) 222016a45b2Smrg #undef B 223016a45b2Smrg #undef A 224016a45b2Smrg #endif 225016a45b2Smrg break; 226016a45b2Smrg default: 227016a45b2Smrg m->chip_family=MSPFAMILY_UNKNOWN; 228016a45b2Smrg } 229016a45b2Smrg break; 230016a45b2Smrg default: 231016a45b2Smrg m->chip_family=MSPFAMILY_UNKNOWN; 232016a45b2Smrg } 233016a45b2Smrg 234016a45b2Smrg xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO, "Found %s%s, rom version 0x%02x, chip_id=0x%04x\n", 235016a45b2Smrg MSP_getProductName(m->chip_id), supported?"":" (unsupported)", rom_version, m->chip_id); 236016a45b2Smrg 237016a45b2Smrg if (!supported) { 238861b9feeSmrg free(__UNCONST(m->d.DevName)); 239016a45b2Smrg free(m); 240016a45b2Smrg return NULL; 241016a45b2Smrg } 242016a45b2Smrg if(!I2CDevInit(&(m->d))) 243016a45b2Smrg { 244861b9feeSmrg free(__UNCONST(m->d.DevName)); 245016a45b2Smrg free(m); 246016a45b2Smrg return NULL; 247016a45b2Smrg } 248016a45b2Smrg 249016a45b2Smrg return m; 250016a45b2Smrg} 251016a45b2Smrg 252016a45b2Smrgvoid ResetMSP3430(MSP3430Ptr m) 253016a45b2Smrg{ 254016a45b2Smrg /* Reset the MSP3430 */ 255016a45b2Smrg SetMSP3430Control(m, 0x00, 0x80, 0x00); 256016a45b2Smrg /* Set it back to normal operation */ 257016a45b2Smrg SetMSP3430Control(m, 0x00, 0x00, 0x00); 258016a45b2Smrg 259016a45b2Smrg m->c_format=MSPFORMAT_UNKNOWN; 260016a45b2Smrg m->c_standard=MSPSTANDARD_UNKNOWN; 261016a45b2Smrg m->c_matrix=m->c_fmmatrix=m->c_source=0; 262016a45b2Smrg m->volume=0; 263016a45b2Smrg} 264016a45b2Smrg 265016a45b2Smrgvoid MSP3430SetVolume (MSP3430Ptr m, CARD8 value) 266016a45b2Smrg{ 267016a45b2Smrg CARD8 result; 268016a45b2Smrg#if 0 269016a45b2Smrg CARD8 old_volume; 270016a45b2Smrg GetMSP3430Data(m, RD_DSP, 0x00, 0x00, &old_volume, &result); 271016a45b2Smrg xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO, "MSP3430 result 0x%02x\n", result); 272016a45b2Smrg#endif 273016a45b2Smrg /* save an extra Get call */ 274016a45b2Smrg result=0; 275016a45b2Smrg 276016a45b2Smrg SetMSP3430Data(m, WR_DSP, 0x00, 0x00, value, result); 277016a45b2Smrg 278016a45b2Smrg SetMSP3430Data(m, WR_DSP, 0x00, 0x07, value, 0); 279016a45b2Smrg m->volume=value; 280016a45b2Smrg 281016a45b2Smrg#if __MSPDEBUG__ > 2 282016a45b2Smrg MSP3430DumpStatus(m); 283016a45b2Smrg __MSPBEEP 284016a45b2Smrg GetMSP3430Data(m, RD_DSP, 0x00, 0x00, &old_volume, &result); 285016a45b2Smrg xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO, "MSP3430 volume 0x%02x\n",value); 286016a45b2Smrg#endif 287016a45b2Smrg} 288016a45b2Smrg 289016a45b2Smrg 290016a45b2Smrgvoid MSP3430SetSAP (MSP3430Ptr m, int mode) 291016a45b2Smrg{ 292016a45b2Smrg xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO, "Put actual code to change SAP here\n"); 293016a45b2Smrg 294016a45b2Smrg SetMSP3430Data(m, WR_DSP, 0x00, 0x08, mode & 0xff, 0x20); 295016a45b2Smrg} 296016a45b2Smrg 297016a45b2Smrg 298016a45b2Smrg#if 0 299016a45b2Smrgvoid MSP3430SetSource(MSP3430Ptr m, CARD8 value) 300016a45b2Smrg{ 301016a45b2Smrg /* Write to DSP, register 0x0008, (loudspeaker channel source/matrix) */ 302016a45b2Smrg /* This sets the source to the TV tuner, for stereo operation */ 303016a45b2Smrg SetMSP3430Data(m, WR_DSP, 0x00, 0x08, value, 0x20); 304016a45b2Smrg} 305016a45b2Smrg#endif 306016a45b2Smrg 307016a45b2Smrg 308016a45b2Smrgchar *MSP_getProductName (CARD16 product_id) 309016a45b2Smrg{ 310016a45b2Smrg switch (product_id) { 311016a45b2Smrg case 0x0400: return "MSP3400D"; 312016a45b2Smrg case 0x040a: return "MSP3410D"; 313016a45b2Smrg case 0x0405: return "MSP3405D"; 314016a45b2Smrg case 0x040f: return "MSP3415D"; 315016a45b2Smrg case 0x0700: return "MSP3400G"; 316016a45b2Smrg case 0x070a: return "MSP3410G"; 317016a45b2Smrg case 0x071e: return "MSP3430G"; 318016a45b2Smrg case 0x0728: return "MSP3440G"; 319016a45b2Smrg case 0x0732: return "MSP3450G"; 320016a45b2Smrg case 0x070f: return "MSP3415G"; 321016a45b2Smrg case 0x0719: return "MSP3425G"; 322016a45b2Smrg case 0x072d: return "MSP3445G"; 323016a45b2Smrg case 0x0737: return "MSP3455G"; 324016a45b2Smrg case 0x0741: return "MSP3465G"; 325016a45b2Smrg } 326016a45b2Smrg return "MSP - unknown type"; 327016a45b2Smrg} 328016a45b2Smrg 329016a45b2Smrg#if __MSPDEBUG__ > 2 330016a45b2Smrg/*puts beep in MSP output 331016a45b2Smrg freq = 0x01 - 16Hz ... 0x40 - 1kHz ... 0xff - 4kHz 332016a45b2Smrg*/ 333016a45b2Smrgvoid MSPBeep(MSP3430Ptr m, CARD8 freq) { 334016a45b2Smrg SetMSP3430Data (m, WR_DSP, 0x00, freq, 0x7f, 0x40); 335016a45b2Smrg mpause(100); 336016a45b2Smrg SetMSP3430Data (m, WR_DSP, 0x00, 0x14, 0x00, 0x00); 337016a45b2Smrg} 338016a45b2Smrg#endif 339016a45b2Smrg 340016a45b2Smrgvoid mpause(int milliseconds) { 341016a45b2Smrg int i,m; 342016a45b2Smrg m=milliseconds/20; 343016a45b2Smrg for (i=0;i<m;i++) usleep(20000); 344016a45b2Smrg} 345016a45b2Smrg 346016a45b2Smrg/*----------------------------------------------------------------- 347016a45b2Smrg| specific functions for all MSP34xxG chips 348016a45b2Smrg|----------------------------------------------------------------*/ 349016a45b2Smrg 350016a45b2Smrgvoid InitMSP34xxG(MSP3430Ptr m) 351016a45b2Smrg{ 352016a45b2Smrg 353016a45b2Smrg #if __MSPDEBUG__ > 1 354016a45b2Smrg xf86DrvMsg(m->d.pI2CBus->scrnIndex,X_INFO,"InitMSP34xxG(m->connector=%d, m->standard=%d, m->chip_family=%d)\n", 355016a45b2Smrg m->connector, m->standard, m->chip_family); 356016a45b2Smrg #endif 357016a45b2Smrg /* Reset MSP3430 */ 358016a45b2Smrg SetMSP3430Control(m, 0x00, 0x80, 0x00); 359016a45b2Smrg /* Set it back to normal operation */ 360016a45b2Smrg SetMSP3430Control(m, 0x00, 0x00, 0x00); 361016a45b2Smrg 362016a45b2Smrg /*set MODUS register */ 363016a45b2Smrg /* bits: 0 - automatic sound detection */ 364016a45b2Smrg /* 1 - enable STATUS change */ 365016a45b2Smrg /* 12 - detect 6.5 Mhz carrier as D/K1, D/K2 or D/K NICAM (does not seem to work ) */ 366016a45b2Smrg /* 13 - detect 4.5 Mhz carrier as BTSC */ 367016a45b2Smrg if ( (m->standard & 0xff) == MSP3430_PAL ) 368016a45b2Smrg { 369016a45b2Smrg SetMSP3430Data(m, WR_DEM, 0x00, 0x30, 0x30, 0x03|0x08); /* make O_ pins tristate */ 370016a45b2Smrg /* PAL standard */ 371016a45b2Smrg SetMSP3430Data(m, WR_DEM, 0x00, 0x20, 0x00, 0x01); /* possibly wrong */ 372016a45b2Smrg } else { 373016a45b2Smrg SetMSP3430Data(m, WR_DEM, 0x00, 0x30, 0x20, 0x03|0x08); 374016a45b2Smrg /* standard selection is M-BTSC-Stereo */ 375016a45b2Smrg SetMSP3430Data(m, WR_DEM, 0x00, 0x20, 0x00, 0x20); 376016a45b2Smrg } 377016a45b2Smrg 378016a45b2Smrg switch(m->connector){ 379016a45b2Smrg case MSP3430_CONNECTOR_1: 380016a45b2Smrg SetMSP3430Data(m, WR_DSP, 0x00, 0x08, 0x03, 0x20); 381016a45b2Smrg break; 382016a45b2Smrg case MSP3430_CONNECTOR_2: 383016a45b2Smrg /* this has not been checked yet.. could be bogus */ 384016a45b2Smrg /* SCART Input Prescale: 0 dB gain */ 385016a45b2Smrg SetMSP3430Data(m, WR_DSP, 0x00, 0x0d, 0x19, 0x00); 386016a45b2Smrg SetMSP3430Data(m, WR_DSP, 0x00, 0x08, 0x02, 0x20); 387016a45b2Smrg break; 388016a45b2Smrg case MSP3430_CONNECTOR_3: 389016a45b2Smrg default: 390016a45b2Smrg /* SCART Input Prescale: 0 dB gain */ 391016a45b2Smrg SetMSP3430Data(m, WR_DSP, 0x00, 0x0d, 0x19, 0x00); 392016a45b2Smrg 393016a45b2Smrg SetMSP3430Data(m, WR_DSP, 0x00, 0x08, 0x02, 0x20); 394016a45b2Smrg break; 395016a45b2Smrg } 396016a45b2Smrg 397016a45b2Smrg switch(m->standard){ 398016a45b2Smrg case MSP3430_PAL: 399016a45b2Smrg SetMSP3430Data(m, WR_DSP, 0x00, 0x0e, 0x24, 0x03); 400016a45b2Smrg SetMSP3430Data(m, WR_DSP, 0x00, 0x10, 0x00, 0x5a); 401016a45b2Smrg SetMSP3430Data(m, WR_DEM, 0x00, 0x20, 0x00, 0x03); 402016a45b2Smrg /* Set volume to FAST_MUTE. */ 403016a45b2Smrg SetMSP3430Data(m, WR_DSP, 0x00, 0x00, 0xFF, 0x00); 404016a45b2Smrg break; 405016a45b2Smrg case MSP3430_PAL_DK1: 406016a45b2Smrg SetMSP3430Data(m, WR_DSP, 0x00, 0x0e, 0x24, 0x03); 407016a45b2Smrg SetMSP3430Data(m, WR_DSP, 0x00, 0x10, 0x00, 0x5a); 408016a45b2Smrg SetMSP3430Data(m, WR_DEM, 0x00, 0x20, 0x00, 0x04); 409016a45b2Smrg /* Set volume to FAST_MUTE. */ 410016a45b2Smrg SetMSP3430Data(m, WR_DSP, 0x00, 0x00, 0xFF, 0x00); 411016a45b2Smrg break; 412016a45b2Smrg case MSP3430_SECAM: /* is this right ? */ 413016a45b2Smrg case MSP3430_NTSC: 414016a45b2Smrg /* Write to DSP, register 0x000E, (prescale FM/FM matrix) */ 415016a45b2Smrg SetMSP3430Data(m, WR_DSP, 0x00, 0x0e, 0x24, 0x03); 416016a45b2Smrg 417016a45b2Smrg /* Set volume to FAST_MUTE. */ 418016a45b2Smrg SetMSP3430Data(m, WR_DSP, 0x00, 0x00, 0xFF, 0x00); 419016a45b2Smrg break; 420016a45b2Smrg } 421016a45b2Smrg 422016a45b2Smrg} 423016a45b2Smrg 424016a45b2Smrg/*----------------------------------------------------------------- 425016a45b2Smrg| specific functions for all MSP34x5D chips 426016a45b2Smrg|----------------------------------------------------------------*/ 427016a45b2Smrg 428016a45b2Smrgvoid InitMSP34x5D(MSP3430Ptr m) 429016a45b2Smrg{ 430016a45b2Smrgint count; 431016a45b2SmrgCARD8 high,low; 432016a45b2SmrgCARD16 result,standard; 433016a45b2SmrgCARD16 peak; 434016a45b2Smrg 435016a45b2Smrg 436016a45b2Smrgif (m->c_format==MSPFORMAT_UNKNOWN) ResetMSP3430(m); 437016a45b2Smrgelse { 438016a45b2Smrg /*mute volume*/ 439016a45b2Smrg SetMSP3430Data (m, WR_DSP, 0x00, 0x00, 0x00, 0x00); 440016a45b2Smrg} 441016a45b2Smrg 442016a45b2Smrg 443016a45b2Smrg 444016a45b2Smrg switch(m->connector){ 445016a45b2Smrg case MSP3430_CONNECTOR_2: 446016a45b2Smrg case MSP3430_CONNECTOR_3: 447016a45b2Smrg if (m->c_format!=MSPFORMAT_SCART) { 448016a45b2Smrg /* SCART Input Prescale: 0 dB gain */ 449016a45b2Smrg SetMSP3430Data (m, WR_DSP, 0x00, 0x0d, 0x19, 0x00); 450016a45b2Smrg /* this has not been checked yet.. could be bogus */ 451016a45b2Smrg m->c_format=MSPFORMAT_SCART; /*stereo*/ 452016a45b2Smrg } 453016a45b2Smrg break; 454016a45b2Smrg case MSP3430_CONNECTOR_1: 455016a45b2Smrg default: 456016a45b2Smrg 457016a45b2Smrg switch ( m->standard & 0x00ff ) { 458016a45b2Smrg case MSP3430_PAL: 459016a45b2Smrg switch( m->standard ) { 460016a45b2Smrg case MSP3430_PAL_DK1: 461016a45b2Smrg standard=MSPSTANDARD_FM_DK1; 462016a45b2Smrg break; 463016a45b2Smrg/* case MSP3430_PAL_DK2: 464016a45b2Smrg standard=MSPSTANDARD_FM_DK2; 465016a45b2Smrg break; 466016a45b2Smrg case MSP3430_PAL_BG: 467016a45b2Smrg may be FM stereo (Germany) or FM NICAM (Scandinavia,spain) 468016a45b2Smrg standard=MSPSTANDARD_AUTO; 469016a45b2Smrg break; 470016a45b2Smrg*/ 471016a45b2Smrg default: 472016a45b2Smrg standard=MSPSTANDARD_AUTO; 473016a45b2Smrg } 474016a45b2Smrg break; 475016a45b2Smrg case MSP3430_SECAM: 476016a45b2Smrg standard=MSPSTANDARD_AUTO; 477016a45b2Smrg case MSP3430_NTSC: 478016a45b2Smrg /* Only MSP34x5 supported format - Korean NTSC-M*/ 479016a45b2Smrg standard=MSPSTANDARD_FM_M; 480016a45b2Smrg default: 481016a45b2Smrg standard=MSPSTANDARD_AUTO; 482016a45b2Smrg } 483016a45b2Smrg 484016a45b2Smrg /*no NICAM support in MSP3410D - force to autodetect*/ 485016a45b2Smrg if ((m->chip_id==0x405) && (standard>=MSPSTANDARD_NICAM_BG)) 486016a45b2Smrg standard=MSPSTANDARD_AUTO; 487016a45b2Smrg 488016a45b2Smrg if (m->c_standard != standard) { 489016a45b2Smrg 490016a45b2Smrg SetMSP3430Data (m, WR_DEM, 0x00, 0x20, standard>>8, standard & 0xFF); 491016a45b2Smrg if (standard==MSPSTANDARD_AUTO) { 492016a45b2Smrg count = 50; /* time shouldn't exceed 1s, just in case */ 493016a45b2Smrg do { 494016a45b2Smrg usleep(20000); 495016a45b2Smrg GetMSP3430Data (m, RD_DEM, 0x00, 0x7e, &high, &low); 496016a45b2Smrg result = ( high << 8 ) | low; 497016a45b2Smrg --count; 498016a45b2Smrg } while( result > 0x07ff && count > 0 ); 499016a45b2Smrg 500016a45b2Smrg if ((result > MSPSTANDARD_AUTO)) 501016a45b2Smrg standard=result; 502016a45b2Smrg else standard=MSPSTANDARD_UNKNOWN; 503016a45b2Smrg#if __MSPDEBUG__ > 1 504016a45b2Smrg xf86DrvMsg(m->d.pI2CBus->scrnIndex,X_INFO,"Detected audio standard: %d\n",result); 505016a45b2Smrg#endif 506016a45b2Smrg /* result = MSPSTANDARD_NICAM_L can be one of: 507016a45b2Smrg SECAM_L - MSPSTANDARD_NICAM_L 508016a45b2Smrg D/K1 - MSPSTANDARD_FM_DK1 509016a45b2Smrg D/K2 - MSPSTANDARD_FM_DK2 510016a45b2Smrg D/K-NICAM - MSPSTANDARD_NICAM_DK*/ 511016a45b2Smrg if( standard == MSPSTANDARD_NICAM_L ) { 512016a45b2Smrg if ((m->standard & 0x00ff)==MSP3430_PAL) { 513016a45b2Smrg /* force PAL D/K */ 514016a45b2Smrg standard=MSPSTANDARD_FM_DK1; 515016a45b2Smrg SetMSP3430Data (m, WR_DEM, 0x00, 0x20, standard>>8, standard & 0xFF); 516016a45b2Smrg#if __MSPDEBUG__ > 1 517016a45b2Smrg xf86DrvMsg(m->d.pI2CBus->scrnIndex,X_INFO, "Detected 6.5MHz carrier - forced to D/K1 !!!\n" ); 518016a45b2Smrg#endif 519016a45b2Smrg } 520016a45b2Smrg } 521016a45b2Smrg } 522016a45b2Smrg m->c_standard=standard; 523016a45b2Smrg } /*end - standard changed*/ 524016a45b2Smrg else { 525016a45b2Smrg if (standard<MSPSTANDARD_NICAM_BG) { 526016a45b2Smrg /* get old value of ident. mode register*/ 527016a45b2Smrg GetMSP3430Data (m, RD_DSP, 0x00, 0x15, &high, &low); 528016a45b2Smrg /* reset Ident-Filter */ 529016a45b2Smrg SetMSP3430Data (m, WR_DSP, 0x00, 0x14, 0x00, 0x3F); 530016a45b2Smrg /* put back old value to ident. mode register*/ 531016a45b2Smrg SetMSP3430Data (m, WR_DSP, 0x00, 0x14, 0x00, low); 532016a45b2Smrg } 533016a45b2Smrg } 534016a45b2Smrg 535016a45b2Smrg if (standard<=MSPSTANDARD_AUTO) { 536016a45b2Smrg m->c_format=MSPFORMAT_1xFM; 537016a45b2Smrg } 538016a45b2Smrg else if (standard<MSPSTANDARD_NICAM_BG) { 539016a45b2Smrg /* set FM prescale */ 540016a45b2Smrg SetMSP3430Data (m, WR_DSP, 0x00, 0x0e, 0x30, 0); 541016a45b2Smrg /* set FM deemphasis*/ 542016a45b2Smrg SetMSP3430Data (m, WR_DSP, 0x00, 0x0f, ((standard==MSPSTANDARD_FM_M)?0:1), 0); 543016a45b2Smrg 544016a45b2Smrg /* check if FM2 carrier is present */ 545016a45b2Smrg /*turn off FM DC Notch*/ 546016a45b2Smrg SetMSP3430Data (m, WR_DSP, 0x00, 0x17, 0x00, 0x3f); 547016a45b2Smrg /*matrix source for Quasi-Peak Detector - stereo: ch2->L ch1->R*/ 548016a45b2Smrg SetMSP3430Data (m, WR_DSP, 0x00, 0x0c, 0x00, 0x20); 549016a45b2Smrg 550016a45b2Smrg mpause(250); 551016a45b2Smrg GetMSP3430Data (m, RD_DSP, 0x00, 0x1A, &high, &low); 552016a45b2Smrg peak = (high << 8) | low; 553016a45b2Smrg#if __MSPDEBUG__ > 1 554016a45b2Smrg xf86DrvMsg(m->d.pI2CBus->scrnIndex,X_INFO,"Second carrier Quasi-Peak detection: %d\n",peak); 555016a45b2Smrg#endif 556016a45b2Smrg /*turn on FM DC Notch*/ 557016a45b2Smrg SetMSP3430Data (m, WR_DSP, 0x00, 0x17, 0x00, 0x00); 558016a45b2Smrg 559016a45b2Smrg if (peak<5) { 560016a45b2Smrg /* if second carrier not detected - only mono from first carrier*/ 561016a45b2Smrg m->c_format=MSPFORMAT_1xFM; 562016a45b2Smrg } 563016a45b2Smrg else { 564016a45b2Smrg m->c_format=MSPFORMAT_2xFM; 565016a45b2Smrg /*start of FM identification process - FM_WAIT 566016a45b2Smrg wait at least 0.5s - used 1s - gives beter resolution*/ 567016a45b2Smrg mpause(1000); 568016a45b2Smrg } 569016a45b2Smrg } 570016a45b2Smrg else { 571016a45b2Smrg if (standard==MSPSTANDARD_NICAM_L) { 572016a45b2Smrg m->c_format=MSPFORMAT_NICAM_AM; 573016a45b2Smrg /* set AM prescale */ 574016a45b2Smrg SetMSP3430Data (m, WR_DSP, 0x00, 0x0e, 0x7C, 0); 575016a45b2Smrg } 576016a45b2Smrg else { 577016a45b2Smrg m->c_format=MSPFORMAT_NICAM_FM; 578016a45b2Smrg /* set FM prescale */ 579016a45b2Smrg SetMSP3430Data (m, WR_DSP, 0x00, 0x0e, 0x30, 0); 580016a45b2Smrg } 581016a45b2Smrg /* set FM deemphasis*/ 582016a45b2Smrg SetMSP3430Data (m, WR_DSP, 0x00, 0x0f, 0x00, 0); 583016a45b2Smrg /* set NICAM prescale to 0dB */ 584016a45b2Smrg SetMSP3430Data (m, WR_DSP, 0x00, 0x10, 0x20, 0); 585016a45b2Smrg } 586016a45b2Smrg 587016a45b2Smrg break; 588016a45b2Smrg } /*end - case conector*/ 589016a45b2Smrg 590016a45b2Smrg CheckModeMSP34x5D(m); 591016a45b2Smrg 592016a45b2Smrg /* Set volume to FAST_MUTE. */ 593016a45b2Smrg /*SetMSP3430Data(m, WR_DSP, 0x00, 0x00, 0xFF, 0x00);*/ 594016a45b2Smrg /*set volume*/ 595016a45b2Smrg MSP3430SetVolume(m,m->volume); 596016a45b2Smrg 597016a45b2Smrg __MSPBEEP 598016a45b2Smrg 599016a45b2Smrg 600016a45b2Smrg} /* EnableMSP34x5D ()... */ 601016a45b2Smrg 602016a45b2Smrg 603016a45b2Smrg 604016a45b2Smrg 605016a45b2Smrgvoid CheckModeMSP34x5D(MSP3430Ptr m) { 606016a45b2Smrg const char stereo_on=25; 607016a45b2Smrg const char stereo_off=20; 608016a45b2Smrg const char dual_on=-stereo_on; 609016a45b2Smrg const char dual_off=-stereo_off; 610016a45b2Smrg char detect; 611016a45b2Smrg CARD8 matrix, fmmatrix, source, high, low; 612016a45b2Smrg 613016a45b2Smrg fmmatrix=0; /*no matrix*/ 614016a45b2Smrg source=0; /*FM*/ 615016a45b2Smrg switch (m->c_format) { 616016a45b2Smrg case MSPFORMAT_NICAM_FM: 617016a45b2Smrg case MSPFORMAT_NICAM_AM: 618016a45b2Smrg case MSPFORMAT_SCART: 619016a45b2Smrg source=( (m->c_format == MSPFORMAT_SCART)?2:1 ); 620016a45b2Smrg switch (m->mode) { 621016a45b2Smrg case MSPMODE_MONO: 622016a45b2Smrg matrix=0x30; /*MONO*/ 623016a45b2Smrg break; 624016a45b2Smrg case MSPMODE_A: 625016a45b2Smrg matrix=0x00; /*A*/ 626016a45b2Smrg break; 627016a45b2Smrg case MSPMODE_B: 628016a45b2Smrg matrix=0x10; /*B*/ 629016a45b2Smrg break; 630016a45b2Smrg default: 631016a45b2Smrg matrix=0x20; /*STEREO*/ 632016a45b2Smrg break; 633016a45b2Smrg } 634016a45b2Smrg break; 635016a45b2Smrg default: 636016a45b2Smrg case MSPFORMAT_1xFM: 637016a45b2Smrg matrix=0x00; /*A*/ 638016a45b2Smrg break; 639016a45b2Smrg case MSPFORMAT_2xFM: 640016a45b2Smrg switch (m->mode) { 641016a45b2Smrg case MSPMODE_MONO: 642016a45b2Smrg matrix=0x30; /*MONO*/ 643016a45b2Smrg break; 644016a45b2Smrg case MSPMODE_STEREO: 645016a45b2Smrg matrix=0x20; /*STEREO*/ 646016a45b2Smrg fmmatrix=((m->c_standard==MSPSTANDARD_FM_M)?2:1); 647016a45b2Smrg break; 648016a45b2Smrg case MSPMODE_AB: 649016a45b2Smrg matrix=0x20; /*STEREO*/ 650016a45b2Smrg break; 651016a45b2Smrg case MSPMODE_A: 652016a45b2Smrg matrix=0x00; /*A*/ 653016a45b2Smrg break; 654016a45b2Smrg case MSPMODE_B: 655016a45b2Smrg matrix=0x10; /*B*/ 656016a45b2Smrg break; 657016a45b2Smrg default: 658016a45b2Smrg /*FM_IDENT_CHECK*/ 659016a45b2Smrg GetMSP3430Data (m, RD_DSP, 0x00, 0x18, &high, &low); 660016a45b2Smrg detect=(char)high; 661016a45b2Smrg#if __MSPDEBUG__ > 1 662016a45b2Smrg xf86DrvMsg(m->d.pI2CBus->scrnIndex,X_INFO,"Stereo Detection Register: %d\n",detect); 663016a45b2Smrg#endif 664016a45b2Smrg if (detect>=((m->c_mode==MSPMODE_STEREO)?stereo_off:stereo_on)) { 665016a45b2Smrg m->c_mode=MSPMODE_STEREO; 666016a45b2Smrg matrix=0x20; /*STEREO*/ 667016a45b2Smrg fmmatrix=((m->c_standard==MSPSTANDARD_FM_M)?2:1); 668016a45b2Smrg } 669016a45b2Smrg else if (detect<=((m->c_mode==MSPMODE_AB)?dual_off:dual_on)) { 670016a45b2Smrg m->c_mode=MSPMODE_AB; 671016a45b2Smrg switch (m->mode) { 672016a45b2Smrg case MSPMODE_STEREO_AB: matrix=0x20; break; 673016a45b2Smrg case MSPMODE_STEREO_B: matrix=0x10; break; 674016a45b2Smrg default: 675016a45b2Smrg case MSPMODE_A: matrix=0x00; break; 676016a45b2Smrg } 677016a45b2Smrg } 678016a45b2Smrg else { 679016a45b2Smrg m->c_mode=MSPMODE_MONO; 680016a45b2Smrg matrix=0x30; /*MONO*/ 681016a45b2Smrg } 682016a45b2Smrg break; 683016a45b2Smrg } /* end - case mode*/ 684016a45b2Smrg break; 685016a45b2Smrg } 686016a45b2Smrg 687016a45b2Smrg if (m->c_fmmatrix != fmmatrix) { 688016a45b2Smrg GetMSP3430Data (m, RD_DSP, 0x00, 0x0e, &high, &low); 689016a45b2Smrg SetMSP3430Data (m, WR_DSP, 0x00, 0x0e, high, fmmatrix); 690016a45b2Smrg m->c_fmmatrix = fmmatrix; 691016a45b2Smrg } 692016a45b2Smrg 693016a45b2Smrg if ((m->c_matrix != matrix) || (m->c_source != source)) { 694016a45b2Smrg /*set chanel source and matrix for loudspeaker*/ 695016a45b2Smrg SetMSP3430Data (m, WR_DSP, 0x00, 0x08, source, matrix); 696016a45b2Smrg 697016a45b2Smrg m->c_matrix = matrix; 698016a45b2Smrg m->c_source = source; 699016a45b2Smrg } 700016a45b2Smrg 701016a45b2Smrg if ( ((m->c_format) & 0xF0) == MSPFORMAT_NICAM) 702016a45b2Smrg SetMSP3430Data (m, WR_DEM, 0x00, 0x21, 0, 1); 703016a45b2Smrg 704016a45b2Smrg#if __MSPDEBUG__ > 0 705016a45b2Smrg char *msg; 706016a45b2Smrg switch (matrix) { 707016a45b2Smrg case 0x30: /*MONO*/ 708016a45b2Smrg msg="MONO"; 709016a45b2Smrg break; 710016a45b2Smrg case 0x00: /*LEFT*/ 711016a45b2Smrg msg="MONO/CHANNEL_1"; 712016a45b2Smrg break; 713016a45b2Smrg case 0x10: /*RIGHT*/ 714016a45b2Smrg msg="MONO/CHANNEL_2"; 715016a45b2Smrg break; 716016a45b2Smrg case 0x20: /*LEFT*/ 717016a45b2Smrg msg="STEREO"; 718016a45b2Smrg break; 719016a45b2Smrg default: 720016a45b2Smrg msg="unknown"; 721016a45b2Smrg break; 722016a45b2Smrg } 723016a45b2Smrg xf86DrvMsg(m->d.pI2CBus->scrnIndex,X_INFO,"Audio mode set to: %s\n",msg); 724016a45b2Smrg#endif 725016a45b2Smrg} 726016a45b2Smrg 727