1 #ifdef HAVE_XORG_CONFIG_H
2 #include <xorg-config.h>
20 void InitMSP34xxG(MSP3430Ptr m
);
21 void InitMSP34x5D(MSP3430Ptr m
);
22 void CheckModeMSP34x5D(MSP3430Ptr m
);
23 char *MSP_getProductName (CARD16 product_id
);
24 void mpause(int milliseconds
);
26 #define __MSPDEBUG__ 0
30 void MSPBeep(MSP3430Ptr m
, CARD8 freq
);
31 #define __MSPBEEP MSPBeep(m,0x14);
38 static void SetMSP3430Control(MSP3430Ptr m
, CARD8 RegAddress
, CARD8 RegValueHigh
, CARD8 RegValueLow
)
46 I2C_WriteRead(&(m
->d
),data
,3,NULL
,0);
49 static void SetMSP3430Data(MSP3430Ptr m
, CARD8 RegAddress
, CARD8 RegSubAddressHigh
, CARD8 RegSubAddressLow
,
50 CARD8 RegValueHigh
, CARD8 RegValueLow
)
54 if(!m
->registers_present
[RegSubAddressLow
]){
55 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",
56 RegAddress
, RegSubAddressHigh
, RegSubAddressLow
, RegValueHigh
, RegValueLow
);
61 data
[1] = RegSubAddressHigh
;
62 data
[2] = RegSubAddressLow
;
63 data
[3] = RegValueHigh
;
64 data
[4] = RegValueLow
;
66 I2C_WriteRead(&(m
->d
),data
,5,NULL
,0);
69 static void GetMSP3430Data(MSP3430Ptr m
, CARD8 RegAddress
, CARD8 RegSubAddressHigh
, CARD8 RegSubAddressLow
,
70 CARD8
*RegValueHigh
, CARD8
*RegValueLow
)
76 send
[1] = RegSubAddressHigh
;
77 send
[2] = RegSubAddressLow
;
79 I2C_WriteRead(&(m
->d
), send
, 3, receive
, 2);
81 *RegValueHigh
= receive
[0];
82 *RegValueLow
= receive
[1];
86 static void MSP3430DumpStatus(MSP3430Ptr m
)
88 CARD8 status_hi
, status_lo
;
89 CARD8 subaddr
, data
[2];
91 GetMSP3430Data(m
, RD_DEM
, 0x02, 0x00, &status_hi
, &status_lo
);
92 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",
93 status_hi
& 1, (status_lo
>>7) & 1, (status_lo
>>6)&1,
94 (status_lo
>>5)? ( (status_hi
>>1)&1? "bad NICAM reception" : "NICAM" ) :
95 ((status_hi
>>1)&1 ? "bogus" : "ANALOG FM/AM") ,
96 (status_lo
>>4)&1, (status_lo
>>3)&1,!( (status_lo
>>2)&1), !((status_lo
>>1)&1));
98 GetMSP3430Data(m
, RD_DEM
, 0x00, 0x7E, &status_hi
, &status_lo
);
99 xf86DrvMsg(m
->d
.pI2CBus
->scrnIndex
, X_INFO
, "MSP34xx: standard result=0x%02x%02x\n",
100 status_hi
, status_lo
);
102 I2C_WriteRead(&(m
->d
), &subaddr
, 1, data
, 2);
103 xf86DrvMsg(m
->d
.pI2CBus
->scrnIndex
, X_INFO
, "MSP34xx: control=0x%02x%02x\n",
109 void InitMSP3430(MSP3430Ptr m
)
112 xf86DrvMsg(m
->d
.pI2CBus
->scrnIndex
,X_INFO
,"InitMSP3430(m->connector=%d, m->standard=%d, m->chip_family=%d)\n",
113 m
->connector
, m
->standard
, m
->chip_family
);
115 switch (m
->chip_family
) {
116 case MSPFAMILY_34x0G
:
119 case MSPFAMILY_34x5G
:
122 case MSPFAMILY_34x5D
:
128 /*-----------------------------------------------------------------
129 | common functions for all MSP34xx chips
130 |----------------------------------------------------------------*/
132 MSP3430Ptr
DetectMSP3430(I2CBusPtr b
, I2CSlaveAddr addr
)
136 CARD8 hardware_version
, major_revision
, product_code
, rom_version
;
139 m
= xcalloc(1,sizeof(MSP3430Rec
));
140 if(m
== NULL
)return NULL
;
141 m
->d
.DevName
= strdup("MSP34xx");
142 m
->d
.SlaveAddr
= addr
;
145 m
->d
.StartTimeout
= b
->StartTimeout
;
146 m
->d
.BitTimeout
= b
->BitTimeout
;
147 m
->d
.AcknTimeout
= b
->AcknTimeout
;
148 m
->d
.ByteTimeout
= b
->ByteTimeout
;
150 if(!I2C_WriteRead(&(m
->d
), NULL
, 0, &a
, 1))
158 m
->standard
=MSP3430_NTSC
;
159 m
->connector
=MSP3430_CONNECTOR_1
;
160 m
->mode
=MSPMODE_STEREO_A
; /*stereo or chanel A if avail. */
161 m
->c_format
=MSPFORMAT_UNKNOWN
;
162 m
->c_standard
=MSPSTANDARD_UNKNOWN
;
163 m
->c_matrix
=m
->c_fmmatrix
=m
->c_source
=0;
167 GetMSP3430Data(m
, RD_DSP
, 0x00, 0x1E, &hardware_version
, &major_revision
);
168 GetMSP3430Data(m
, RD_DSP
, 0x00, 0x1F, &product_code
, &rom_version
);
169 m
->hardware_version
=hardware_version
;
170 m
->major_revision
=major_revision
;
171 m
->product_code
=product_code
;
172 m
->rom_version
=rom_version
;
174 m
->chip_id
=((major_revision
<< 8) | product_code
);
177 switch (major_revision
) {
179 switch (product_code
) {
180 case 0x05: /* 3405D */
181 case 0x0A: /* 3410D */
182 case 0x0F: /* 3415D */
183 m
->chip_family
=MSPFAMILY_34x5D
;
188 m
->chip_family
=MSPFAMILY_34x0D
;
192 switch(product_code
){
198 m
->chip_family
=MSPFAMILY_34x0G
;
206 m
->chip_family
=MSPFAMILY_34x5G
;
209 memset(m
->registers_present
, 0, 256);
210 #define A(num) m->registers_present[(num)]=1;
211 #define B(num1, num2) memset(&(m->registers_present[num1]), 1, num2-num1);
227 m
->chip_family
=MSPFAMILY_UNKNOWN
;
231 m
->chip_family
=MSPFAMILY_UNKNOWN
;
234 xf86DrvMsg(m
->d
.pI2CBus
->scrnIndex
, X_INFO
, "Found %s%s, rom version 0x%02x, chip_id=0x%04x\n",
235 MSP_getProductName(m
->chip_id
), supported
?"":" (unsupported)", rom_version
, m
->chip_id
);
242 if(!I2CDevInit(&(m
->d
)))
252 void ResetMSP3430(MSP3430Ptr m
)
254 /* Reset the MSP3430 */
255 SetMSP3430Control(m
, 0x00, 0x80, 0x00);
256 /* Set it back to normal operation */
257 SetMSP3430Control(m
, 0x00, 0x00, 0x00);
259 m
->c_format
=MSPFORMAT_UNKNOWN
;
260 m
->c_standard
=MSPSTANDARD_UNKNOWN
;
261 m
->c_matrix
=m
->c_fmmatrix
=m
->c_source
=0;
265 void MSP3430SetVolume (MSP3430Ptr m
, CARD8 value
)
270 GetMSP3430Data(m
, RD_DSP
, 0x00, 0x00, &old_volume
, &result
);
271 xf86DrvMsg(m
->d
.pI2CBus
->scrnIndex
, X_INFO
, "MSP3430 result 0x%02x\n", result
);
273 /* save an extra Get call */
276 SetMSP3430Data(m
, WR_DSP
, 0x00, 0x00, value
, result
);
278 SetMSP3430Data(m
, WR_DSP
, 0x00, 0x07, value
, 0);
282 MSP3430DumpStatus(m
);
284 GetMSP3430Data(m
, RD_DSP
, 0x00, 0x00, &old_volume
, &result
);
285 xf86DrvMsg(m
->d
.pI2CBus
->scrnIndex
, X_INFO
, "MSP3430 volume 0x%02x\n",value
);
290 void MSP3430SetSAP (MSP3430Ptr m
, int mode
)
292 xf86DrvMsg(m
->d
.pI2CBus
->scrnIndex
, X_INFO
, "Put actual code to change SAP here\n");
294 SetMSP3430Data(m
, WR_DSP
, 0x00, 0x08, mode
& 0xff, 0x20);
299 void MSP3430SetSource(MSP3430Ptr m
, CARD8 value
)
301 /* Write to DSP, register 0x0008, (loudspeaker channel source/matrix) */
302 /* This sets the source to the TV tuner, for stereo operation */
303 SetMSP3430Data(m
, WR_DSP
, 0x00, 0x08, value
, 0x20);
308 char *MSP_getProductName (CARD16 product_id
)
310 switch (product_id
) {
311 case 0x0400: return "MSP3400D";
312 case 0x040a: return "MSP3410D";
313 case 0x0405: return "MSP3405D";
314 case 0x040f: return "MSP3415D";
315 case 0x0700: return "MSP3400G";
316 case 0x070a: return "MSP3410G";
317 case 0x071e: return "MSP3430G";
318 case 0x0728: return "MSP3440G";
319 case 0x0732: return "MSP3450G";
320 case 0x070f: return "MSP3415G";
321 case 0x0719: return "MSP3425G";
322 case 0x072d: return "MSP3445G";
323 case 0x0737: return "MSP3455G";
324 case 0x0741: return "MSP3465G";
326 return "MSP - unknown type";
330 /*puts beep in MSP output
331 freq = 0x01 - 16Hz ... 0x40 - 1kHz ... 0xff - 4kHz
333 void MSPBeep(MSP3430Ptr m
, CARD8 freq
) {
334 SetMSP3430Data (m
, WR_DSP
, 0x00, freq
, 0x7f, 0x40);
336 SetMSP3430Data (m
, WR_DSP
, 0x00, 0x14, 0x00, 0x00);
340 void mpause(int milliseconds
) {
343 for (i
=0;i
<m
;i
++) usleep(20000);
346 /*-----------------------------------------------------------------
347 | specific functions for all MSP34xxG chips
348 |----------------------------------------------------------------*/
350 void InitMSP34xxG(MSP3430Ptr m
)
354 xf86DrvMsg(m
->d
.pI2CBus
->scrnIndex
,X_INFO
,"InitMSP34xxG(m->connector=%d, m->standard=%d, m->chip_family=%d)\n",
355 m
->connector
, m
->standard
, m
->chip_family
);
358 SetMSP3430Control(m
, 0x00, 0x80, 0x00);
359 /* Set it back to normal operation */
360 SetMSP3430Control(m
, 0x00, 0x00, 0x00);
362 /*set MODUS register */
363 /* bits: 0 - automatic sound detection */
364 /* 1 - enable STATUS change */
365 /* 12 - detect 6.5 Mhz carrier as D/K1, D/K2 or D/K NICAM (does not seem to work ) */
366 /* 13 - detect 4.5 Mhz carrier as BTSC */
367 if ( (m
->standard
& 0xff) == MSP3430_PAL
)
369 SetMSP3430Data(m
, WR_DEM
, 0x00, 0x30, 0x30, 0x03|0x08); /* make O_ pins tristate */
371 SetMSP3430Data(m
, WR_DEM
, 0x00, 0x20, 0x00, 0x01); /* possibly wrong */
373 SetMSP3430Data(m
, WR_DEM
, 0x00, 0x30, 0x20, 0x03|0x08);
374 /* standard selection is M-BTSC-Stereo */
375 SetMSP3430Data(m
, WR_DEM
, 0x00, 0x20, 0x00, 0x20);
378 switch(m
->connector
){
379 case MSP3430_CONNECTOR_1
:
380 SetMSP3430Data(m
, WR_DSP
, 0x00, 0x08, 0x03, 0x20);
382 case MSP3430_CONNECTOR_2
:
383 /* this has not been checked yet.. could be bogus */
384 /* SCART Input Prescale: 0 dB gain */
385 SetMSP3430Data(m
, WR_DSP
, 0x00, 0x0d, 0x19, 0x00);
386 SetMSP3430Data(m
, WR_DSP
, 0x00, 0x08, 0x02, 0x20);
388 case MSP3430_CONNECTOR_3
:
390 /* SCART Input Prescale: 0 dB gain */
391 SetMSP3430Data(m
, WR_DSP
, 0x00, 0x0d, 0x19, 0x00);
393 SetMSP3430Data(m
, WR_DSP
, 0x00, 0x08, 0x02, 0x20);
399 SetMSP3430Data(m
, WR_DSP
, 0x00, 0x0e, 0x24, 0x03);
400 SetMSP3430Data(m
, WR_DSP
, 0x00, 0x10, 0x00, 0x5a);
401 SetMSP3430Data(m
, WR_DEM
, 0x00, 0x20, 0x00, 0x03);
402 /* Set volume to FAST_MUTE. */
403 SetMSP3430Data(m
, WR_DSP
, 0x00, 0x00, 0xFF, 0x00);
405 case MSP3430_PAL_DK1
:
406 SetMSP3430Data(m
, WR_DSP
, 0x00, 0x0e, 0x24, 0x03);
407 SetMSP3430Data(m
, WR_DSP
, 0x00, 0x10, 0x00, 0x5a);
408 SetMSP3430Data(m
, WR_DEM
, 0x00, 0x20, 0x00, 0x04);
409 /* Set volume to FAST_MUTE. */
410 SetMSP3430Data(m
, WR_DSP
, 0x00, 0x00, 0xFF, 0x00);
412 case MSP3430_SECAM
: /* is this right ? */
414 /* Write to DSP, register 0x000E, (prescale FM/FM matrix) */
415 SetMSP3430Data(m
, WR_DSP
, 0x00, 0x0e, 0x24, 0x03);
417 /* Set volume to FAST_MUTE. */
418 SetMSP3430Data(m
, WR_DSP
, 0x00, 0x00, 0xFF, 0x00);
424 /*-----------------------------------------------------------------
425 | specific functions for all MSP34x5D chips
426 |----------------------------------------------------------------*/
428 void InitMSP34x5D(MSP3430Ptr m
)
432 CARD16 result
,standard
;
436 if (m
->c_format
==MSPFORMAT_UNKNOWN
) ResetMSP3430(m
);
439 SetMSP3430Data (m
, WR_DSP
, 0x00, 0x00, 0x00, 0x00);
444 switch(m
->connector
){
445 case MSP3430_CONNECTOR_2
:
446 case MSP3430_CONNECTOR_3
:
447 if (m
->c_format
!=MSPFORMAT_SCART
) {
448 /* SCART Input Prescale: 0 dB gain */
449 SetMSP3430Data (m
, WR_DSP
, 0x00, 0x0d, 0x19, 0x00);
450 /* this has not been checked yet.. could be bogus */
451 m
->c_format
=MSPFORMAT_SCART
; /*stereo*/
454 case MSP3430_CONNECTOR_1
:
457 switch ( m
->standard
& 0x00ff ) {
459 switch( m
->standard
) {
460 case MSP3430_PAL_DK1
:
461 standard
=MSPSTANDARD_FM_DK1
;
463 /* case MSP3430_PAL_DK2:
464 standard=MSPSTANDARD_FM_DK2;
467 may be FM stereo (Germany) or FM NICAM (Scandinavia,spain)
468 standard=MSPSTANDARD_AUTO;
472 standard
=MSPSTANDARD_AUTO
;
476 standard
=MSPSTANDARD_AUTO
;
478 /* Only MSP34x5 supported format - Korean NTSC-M*/
479 standard
=MSPSTANDARD_FM_M
;
481 standard
=MSPSTANDARD_AUTO
;
484 /*no NICAM support in MSP3410D - force to autodetect*/
485 if ((m
->chip_id
==0x405) && (standard
>=MSPSTANDARD_NICAM_BG
))
486 standard
=MSPSTANDARD_AUTO
;
488 if (m
->c_standard
!= standard
) {
490 SetMSP3430Data (m
, WR_DEM
, 0x00, 0x20, standard
>>8, standard
& 0xFF);
491 if (standard
==MSPSTANDARD_AUTO
) {
492 count
= 50; /* time shouldn't exceed 1s, just in case */
495 GetMSP3430Data (m
, RD_DEM
, 0x00, 0x7e, &high
, &low
);
496 result
= ( high
<< 8 ) | low
;
498 } while( result
> 0x07ff && count
> 0 );
500 if ((result
> MSPSTANDARD_AUTO
))
502 else standard
=MSPSTANDARD_UNKNOWN
;
504 xf86DrvMsg(m
->d
.pI2CBus
->scrnIndex
,X_INFO
,"Detected audio standard: %d\n",result
);
506 /* result = MSPSTANDARD_NICAM_L can be one of:
507 SECAM_L - MSPSTANDARD_NICAM_L
508 D/K1 - MSPSTANDARD_FM_DK1
509 D/K2 - MSPSTANDARD_FM_DK2
510 D/K-NICAM - MSPSTANDARD_NICAM_DK*/
511 if( standard
== MSPSTANDARD_NICAM_L
) {
512 if ((m
->standard
& 0x00ff)==MSP3430_PAL
) {
514 standard
=MSPSTANDARD_FM_DK1
;
515 SetMSP3430Data (m
, WR_DEM
, 0x00, 0x20, standard
>>8, standard
& 0xFF);
517 xf86DrvMsg(m
->d
.pI2CBus
->scrnIndex
,X_INFO
, "Detected 6.5MHz carrier - forced to D/K1 !!!\n" );
522 m
->c_standard
=standard
;
523 } /*end - standard changed*/
525 if (standard
<MSPSTANDARD_NICAM_BG
) {
526 /* get old value of ident. mode register*/
527 GetMSP3430Data (m
, RD_DSP
, 0x00, 0x15, &high
, &low
);
528 /* reset Ident-Filter */
529 SetMSP3430Data (m
, WR_DSP
, 0x00, 0x14, 0x00, 0x3F);
530 /* put back old value to ident. mode register*/
531 SetMSP3430Data (m
, WR_DSP
, 0x00, 0x14, 0x00, low
);
535 if (standard
<=MSPSTANDARD_AUTO
) {
536 m
->c_format
=MSPFORMAT_1xFM
;
538 else if (standard
<MSPSTANDARD_NICAM_BG
) {
539 /* set FM prescale */
540 SetMSP3430Data (m
, WR_DSP
, 0x00, 0x0e, 0x30, 0);
541 /* set FM deemphasis*/
542 SetMSP3430Data (m
, WR_DSP
, 0x00, 0x0f, ((standard
==MSPSTANDARD_FM_M
)?0:1), 0);
544 /* check if FM2 carrier is present */
545 /*turn off FM DC Notch*/
546 SetMSP3430Data (m
, WR_DSP
, 0x00, 0x17, 0x00, 0x3f);
547 /*matrix source for Quasi-Peak Detector - stereo: ch2->L ch1->R*/
548 SetMSP3430Data (m
, WR_DSP
, 0x00, 0x0c, 0x00, 0x20);
551 GetMSP3430Data (m
, RD_DSP
, 0x00, 0x1A, &high
, &low
);
552 peak
= (high
<< 8) | low
;
554 xf86DrvMsg(m
->d
.pI2CBus
->scrnIndex
,X_INFO
,"Second carrier Quasi-Peak detection: %d\n",peak
);
556 /*turn on FM DC Notch*/
557 SetMSP3430Data (m
, WR_DSP
, 0x00, 0x17, 0x00, 0x00);
560 /* if second carrier not detected - only mono from first carrier*/
561 m
->c_format
=MSPFORMAT_1xFM
;
564 m
->c_format
=MSPFORMAT_2xFM
;
565 /*start of FM identification process - FM_WAIT
566 wait at least 0.5s - used 1s - gives beter resolution*/
571 if (standard
==MSPSTANDARD_NICAM_L
) {
572 m
->c_format
=MSPFORMAT_NICAM_AM
;
573 /* set AM prescale */
574 SetMSP3430Data (m
, WR_DSP
, 0x00, 0x0e, 0x7C, 0);
577 m
->c_format
=MSPFORMAT_NICAM_FM
;
578 /* set FM prescale */
579 SetMSP3430Data (m
, WR_DSP
, 0x00, 0x0e, 0x30, 0);
581 /* set FM deemphasis*/
582 SetMSP3430Data (m
, WR_DSP
, 0x00, 0x0f, 0x00, 0);
583 /* set NICAM prescale to 0dB */
584 SetMSP3430Data (m
, WR_DSP
, 0x00, 0x10, 0x20, 0);
588 } /*end - case conector*/
590 CheckModeMSP34x5D(m
);
592 /* Set volume to FAST_MUTE. */
593 /*SetMSP3430Data(m, WR_DSP, 0x00, 0x00, 0xFF, 0x00);*/
595 MSP3430SetVolume(m
,m
->volume
);
600 } /* EnableMSP34x5D ()... */
605 void CheckModeMSP34x5D(MSP3430Ptr m
) {
606 const char stereo_on
=25;
607 const char stereo_off
=20;
608 const char dual_on
=-stereo_on
;
609 const char dual_off
=-stereo_off
;
611 CARD8 matrix
, fmmatrix
, source
, high
, low
;
613 fmmatrix
=0; /*no matrix*/
615 switch (m
->c_format
) {
616 case MSPFORMAT_NICAM_FM
:
617 case MSPFORMAT_NICAM_AM
:
618 case MSPFORMAT_SCART
:
619 source
=( (m
->c_format
== MSPFORMAT_SCART
)?2:1 );
622 matrix
=0x30; /*MONO*/
631 matrix
=0x20; /*STEREO*/
642 matrix
=0x30; /*MONO*/
645 matrix
=0x20; /*STEREO*/
646 fmmatrix
=((m
->c_standard
==MSPSTANDARD_FM_M
)?2:1);
649 matrix
=0x20; /*STEREO*/
659 GetMSP3430Data (m
, RD_DSP
, 0x00, 0x18, &high
, &low
);
662 xf86DrvMsg(m
->d
.pI2CBus
->scrnIndex
,X_INFO
,"Stereo Detection Register: %d\n",detect
);
664 if (detect
>=((m
->c_mode
==MSPMODE_STEREO
)?stereo_off
:stereo_on
)) {
665 m
->c_mode
=MSPMODE_STEREO
;
666 matrix
=0x20; /*STEREO*/
667 fmmatrix
=((m
->c_standard
==MSPSTANDARD_FM_M
)?2:1);
669 else if (detect
<=((m
->c_mode
==MSPMODE_AB
)?dual_off
:dual_on
)) {
670 m
->c_mode
=MSPMODE_AB
;
672 case MSPMODE_STEREO_AB
: matrix
=0x20; break;
673 case MSPMODE_STEREO_B
: matrix
=0x10; break;
675 case MSPMODE_A
: matrix
=0x00; break;
679 m
->c_mode
=MSPMODE_MONO
;
680 matrix
=0x30; /*MONO*/
683 } /* end - case mode*/
687 if (m
->c_fmmatrix
!= fmmatrix
) {
688 GetMSP3430Data (m
, RD_DSP
, 0x00, 0x0e, &high
, &low
);
689 SetMSP3430Data (m
, WR_DSP
, 0x00, 0x0e, high
, fmmatrix
);
690 m
->c_fmmatrix
= fmmatrix
;
693 if ((m
->c_matrix
!= matrix
) || (m
->c_source
!= source
)) {
694 /*set chanel source and matrix for loudspeaker*/
695 SetMSP3430Data (m
, WR_DSP
, 0x00, 0x08, source
, matrix
);
697 m
->c_matrix
= matrix
;
698 m
->c_source
= source
;
701 if ( ((m
->c_format
) & 0xF0) == MSPFORMAT_NICAM
)
702 SetMSP3430Data (m
, WR_DEM
, 0x00, 0x21, 0, 1);
711 msg
="MONO/CHANNEL_1";
714 msg
="MONO/CHANNEL_2";
723 xf86DrvMsg(m
->d
.pI2CBus
->scrnIndex
,X_INFO
,"Audio mode set to: %s\n",msg
);