1 #ifdef HAVE_XORG_CONFIG_H
2 #include <xorg-config.h>
19 void InitMSP34xxG(MSP3430Ptr m
);
20 void InitMSP34x5D(MSP3430Ptr m
);
21 void CheckModeMSP34x5D(MSP3430Ptr m
);
22 static const char *MSP_getProductName(CARD16 product_id
);
23 void mpause(int milliseconds
);
25 #define __MSPDEBUG__ 0
29 void MSPBeep(MSP3430Ptr m
, CARD8 freq
);
31 #define __MSPBEEP MSPBeep(m,0x14);
39 SetMSP3430Control(MSP3430Ptr m
, CARD8 RegAddress
, CARD8 RegValueHigh
,
45 data
[1] = RegValueHigh
;
46 data
[2] = RegValueLow
;
48 I2C_WriteRead(&(m
->d
), data
, 3, NULL
, 0);
52 SetMSP3430Data(MSP3430Ptr m
, CARD8 RegAddress
, CARD8 RegSubAddressHigh
,
53 CARD8 RegSubAddressLow
, CARD8 RegValueHigh
, CARD8 RegValueLow
)
58 if (!m
->registers_present
[RegSubAddressLow
]) {
59 xf86DrvMsg(m
->d
.pI2CBus
->scrnIndex
, X_ERROR
,
60 "Attempt to access non-existent register in MSP34xxX: 0x%02x 0x%02x 0x%02x <- 0x%02x 0x%02x\n",
61 RegAddress
, RegSubAddressHigh
, RegSubAddressLow
,
62 RegValueHigh
, RegValueLow
);
67 data
[1] = RegSubAddressHigh
;
68 data
[2] = RegSubAddressLow
;
69 data
[3] = RegValueHigh
;
70 data
[4] = RegValueLow
;
72 I2C_WriteRead(&(m
->d
), data
, 5, NULL
, 0);
76 GetMSP3430Data(MSP3430Ptr m
, CARD8 RegAddress
, CARD8 RegSubAddressHigh
,
77 CARD8 RegSubAddressLow
, CARD8
*RegValueHigh
, CARD8
*RegValueLow
)
83 send
[1] = RegSubAddressHigh
;
84 send
[2] = RegSubAddressLow
;
86 I2C_WriteRead(&(m
->d
), send
, 3, receive
, 2);
88 *RegValueHigh
= receive
[0];
89 *RegValueLow
= receive
[1];
94 MSP3430DumpStatus(MSP3430Ptr m
)
96 CARD8 status_hi
, status_lo
;
97 CARD8 subaddr
, data
[2];
99 GetMSP3430Data(m
, RD_DEM
, 0x02, 0x00, &status_hi
, &status_lo
);
100 xf86DrvMsg(m
->d
.pI2CBus
->scrnIndex
, X_INFO
,
101 "MSP34xx: SAP(8)=%d mono/NICAM(7)=%d stereo=%d %s O_1=%d O_0=%d 2nd car=%d 1st car=%d\n",
102 status_hi
& 1, (status_lo
>> 7) & 1, (status_lo
>> 6) & 1,
103 (status_lo
>> 5) ? ((status_hi
>> 1) & 1 ? "bad NICAM reception"
104 : "NICAM") : ((status_hi
>> 1) & 1 ? "bogus"
106 (status_lo
>> 4) & 1, (status_lo
>> 3) & 1,
107 !((status_lo
>> 2) & 1), !((status_lo
>> 1) & 1));
109 GetMSP3430Data(m
, RD_DEM
, 0x00, 0x7E, &status_hi
, &status_lo
);
110 xf86DrvMsg(m
->d
.pI2CBus
->scrnIndex
, X_INFO
,
111 "MSP34xx: standard result=0x%02x%02x\n", status_hi
, status_lo
);
113 I2C_WriteRead(&(m
->d
), &subaddr
, 1, data
, 2);
114 xf86DrvMsg(m
->d
.pI2CBus
->scrnIndex
, X_INFO
, "MSP34xx: control=0x%02x%02x\n",
121 InitMSP3430(MSP3430Ptr m
)
124 xf86DrvMsg(m
->d
.pI2CBus
->scrnIndex
, X_INFO
,
125 "InitMSP3430(m->connector=%d, m->standard=%d, m->chip_family=%d)\n",
126 m
->connector
, m
->standard
, m
->chip_family
);
128 switch (m
->chip_family
) {
129 case MSPFAMILY_34x0G
:
132 case MSPFAMILY_34x5G
:
135 case MSPFAMILY_34x5D
:
141 /*-----------------------------------------------------------------
142 | common functions for all MSP34xx chips
143 |----------------------------------------------------------------*/
146 DetectMSP3430(I2CBusPtr b
, I2CSlaveAddr addr
)
150 CARD8 hardware_version
, major_revision
, product_code
, rom_version
;
153 m
= calloc(1, sizeof(MSP3430Rec
));
156 m
->d
.DevName
= strdup("MSP34xx");
157 m
->d
.SlaveAddr
= addr
;
160 m
->d
.StartTimeout
= b
->StartTimeout
;
161 m
->d
.BitTimeout
= b
->BitTimeout
;
162 m
->d
.AcknTimeout
= b
->AcknTimeout
;
163 m
->d
.ByteTimeout
= b
->ByteTimeout
;
165 if (!I2C_WriteRead(&(m
->d
), NULL
, 0, &a
, 1)) {
171 m
->standard
= MSP3430_NTSC
;
172 m
->connector
= MSP3430_CONNECTOR_1
;
173 m
->mode
= MSPMODE_STEREO_A
; /*stereo or chanel A if avail. */
174 m
->c_format
= MSPFORMAT_UNKNOWN
;
175 m
->c_standard
= MSPSTANDARD_UNKNOWN
;
176 m
->c_matrix
= m
->c_fmmatrix
= m
->c_source
= 0;
180 GetMSP3430Data(m
, RD_DSP
, 0x00, 0x1E, &hardware_version
, &major_revision
);
181 GetMSP3430Data(m
, RD_DSP
, 0x00, 0x1F, &product_code
, &rom_version
);
182 m
->hardware_version
= hardware_version
;
183 m
->major_revision
= major_revision
;
184 m
->product_code
= product_code
;
185 m
->rom_version
= rom_version
;
187 m
->chip_id
= ((major_revision
<< 8) | product_code
);
190 switch (major_revision
) {
192 switch (product_code
) {
193 case 0x05: /* 3405D */
194 case 0x0A: /* 3410D */
195 case 0x0F: /* 3415D */
196 m
->chip_family
= MSPFAMILY_34x5D
;
201 m
->chip_family
= MSPFAMILY_34x0D
;
205 switch (product_code
) {
211 m
->chip_family
= MSPFAMILY_34x0G
;
219 m
->chip_family
= MSPFAMILY_34x5G
;
222 memset(m
->registers_present
, 0, 256);
223 #define A(num) m->registers_present[(num)]=1;
224 #define B(num1, num2) memset(&(m->registers_present[num1]), 1, num2-num1);
240 m
->chip_family
= MSPFAMILY_UNKNOWN
;
244 m
->chip_family
= MSPFAMILY_UNKNOWN
;
247 xf86DrvMsg(m
->d
.pI2CBus
->scrnIndex
, X_INFO
,
248 "Found %s%s, rom version 0x%02x, chip_id=0x%04x\n",
249 MSP_getProductName(m
->chip_id
),
250 supported
? "" : " (unsupported)", rom_version
, m
->chip_id
);
257 if (!I2CDevInit(&(m
->d
))) {
267 ResetMSP3430(MSP3430Ptr m
)
269 /* Reset the MSP3430 */
270 SetMSP3430Control(m
, 0x00, 0x80, 0x00);
271 /* Set it back to normal operation */
272 SetMSP3430Control(m
, 0x00, 0x00, 0x00);
274 m
->c_format
= MSPFORMAT_UNKNOWN
;
275 m
->c_standard
= MSPSTANDARD_UNKNOWN
;
276 m
->c_matrix
= m
->c_fmmatrix
= m
->c_source
= 0;
281 MSP3430SetVolume(MSP3430Ptr m
, CARD8 value
)
288 GetMSP3430Data(m
, RD_DSP
, 0x00, 0x00, &old_volume
, &result
);
289 xf86DrvMsg(m
->d
.pI2CBus
->scrnIndex
, X_INFO
, "MSP3430 result 0x%02x\n",
292 /* save an extra Get call */
295 SetMSP3430Data(m
, WR_DSP
, 0x00, 0x00, value
, result
);
297 SetMSP3430Data(m
, WR_DSP
, 0x00, 0x07, value
, 0);
301 MSP3430DumpStatus(m
);
302 __MSPBEEP
GetMSP3430Data(m
, RD_DSP
, 0x00, 0x00, &old_volume
, &result
);
303 xf86DrvMsg(m
->d
.pI2CBus
->scrnIndex
, X_INFO
, "MSP3430 volume 0x%02x\n",
309 MSP3430SetSAP(MSP3430Ptr m
, int mode
)
311 xf86DrvMsg(m
->d
.pI2CBus
->scrnIndex
, X_INFO
,
312 "Put actual code to change SAP here\n");
314 SetMSP3430Data(m
, WR_DSP
, 0x00, 0x08, mode
& 0xff, 0x20);
319 MSP3430SetSource(MSP3430Ptr m
, CARD8 value
)
321 /* Write to DSP, register 0x0008, (loudspeaker channel source/matrix) */
322 /* This sets the source to the TV tuner, for stereo operation */
323 SetMSP3430Data(m
, WR_DSP
, 0x00, 0x08, value
, 0x20);
328 MSP_getProductName(CARD16 product_id
)
330 switch (product_id
) {
360 return "MSP - unknown type";
364 /*puts beep in MSP output
365 freq = 0x01 - 16Hz ... 0x40 - 1kHz ... 0xff - 4kHz
368 MSPBeep(MSP3430Ptr m
, CARD8 freq
)
370 SetMSP3430Data(m
, WR_DSP
, 0x00, freq
, 0x7f, 0x40);
372 SetMSP3430Data(m
, WR_DSP
, 0x00, 0x14, 0x00, 0x00);
377 mpause(int milliseconds
)
381 m
= milliseconds
/ 20;
382 for (i
= 0; i
< m
; i
++)
386 /*-----------------------------------------------------------------
387 | specific functions for all MSP34xxG chips
388 |----------------------------------------------------------------*/
391 InitMSP34xxG(MSP3430Ptr m
)
395 xf86DrvMsg(m
->d
.pI2CBus
->scrnIndex
, X_INFO
,
396 "InitMSP34xxG(m->connector=%d, m->standard=%d, m->chip_family=%d)\n",
397 m
->connector
, m
->standard
, m
->chip_family
);
400 SetMSP3430Control(m
, 0x00, 0x80, 0x00);
401 /* Set it back to normal operation */
402 SetMSP3430Control(m
, 0x00, 0x00, 0x00);
404 /*set MODUS register */
405 /* bits: 0 - automatic sound detection */
406 /* 1 - enable STATUS change */
407 /* 12 - detect 6.5 Mhz carrier as D/K1, D/K2 or D/K NICAM (does not seem to work ) */
408 /* 13 - detect 4.5 Mhz carrier as BTSC */
409 if ((m
->standard
& 0xff) == MSP3430_PAL
) {
410 SetMSP3430Data(m
, WR_DEM
, 0x00, 0x30, 0x30, 0x03 | 0x08); /* make O_ pins tristate */
412 SetMSP3430Data(m
, WR_DEM
, 0x00, 0x20, 0x00, 0x01); /* possibly wrong */
415 SetMSP3430Data(m
, WR_DEM
, 0x00, 0x30, 0x20, 0x03 | 0x08);
416 /* standard selection is M-BTSC-Stereo */
417 SetMSP3430Data(m
, WR_DEM
, 0x00, 0x20, 0x00, 0x20);
420 switch (m
->connector
) {
421 case MSP3430_CONNECTOR_1
:
422 SetMSP3430Data(m
, WR_DSP
, 0x00, 0x08, 0x03, 0x20);
424 case MSP3430_CONNECTOR_2
:
425 /* this has not been checked yet.. could be bogus */
426 /* SCART Input Prescale: 0 dB gain */
427 SetMSP3430Data(m
, WR_DSP
, 0x00, 0x0d, 0x19, 0x00);
428 SetMSP3430Data(m
, WR_DSP
, 0x00, 0x08, 0x02, 0x20);
430 case MSP3430_CONNECTOR_3
:
432 /* SCART Input Prescale: 0 dB gain */
433 SetMSP3430Data(m
, WR_DSP
, 0x00, 0x0d, 0x19, 0x00);
435 SetMSP3430Data(m
, WR_DSP
, 0x00, 0x08, 0x02, 0x20);
439 switch (m
->standard
) {
441 SetMSP3430Data(m
, WR_DSP
, 0x00, 0x0e, 0x24, 0x03);
442 SetMSP3430Data(m
, WR_DSP
, 0x00, 0x10, 0x00, 0x5a);
443 SetMSP3430Data(m
, WR_DEM
, 0x00, 0x20, 0x00, 0x03);
444 /* Set volume to FAST_MUTE. */
445 SetMSP3430Data(m
, WR_DSP
, 0x00, 0x00, 0xFF, 0x00);
447 case MSP3430_PAL_DK1
:
448 SetMSP3430Data(m
, WR_DSP
, 0x00, 0x0e, 0x24, 0x03);
449 SetMSP3430Data(m
, WR_DSP
, 0x00, 0x10, 0x00, 0x5a);
450 SetMSP3430Data(m
, WR_DEM
, 0x00, 0x20, 0x00, 0x04);
451 /* Set volume to FAST_MUTE. */
452 SetMSP3430Data(m
, WR_DSP
, 0x00, 0x00, 0xFF, 0x00);
454 case MSP3430_SECAM
: /* is this right ? */
456 /* Write to DSP, register 0x000E, (prescale FM/FM matrix) */
457 SetMSP3430Data(m
, WR_DSP
, 0x00, 0x0e, 0x24, 0x03);
459 /* Set volume to FAST_MUTE. */
460 SetMSP3430Data(m
, WR_DSP
, 0x00, 0x00, 0xFF, 0x00);
466 /*-----------------------------------------------------------------
467 | specific functions for all MSP34x5D chips
468 |----------------------------------------------------------------*/
471 InitMSP34x5D(MSP3430Ptr m
)
475 CARD16 result
, standard
;
478 if (m
->c_format
== MSPFORMAT_UNKNOWN
)
482 SetMSP3430Data(m
, WR_DSP
, 0x00, 0x00, 0x00, 0x00);
485 switch (m
->connector
) {
486 case MSP3430_CONNECTOR_2
:
487 case MSP3430_CONNECTOR_3
:
488 if (m
->c_format
!= MSPFORMAT_SCART
) {
489 /* SCART Input Prescale: 0 dB gain */
490 SetMSP3430Data(m
, WR_DSP
, 0x00, 0x0d, 0x19, 0x00);
491 /* this has not been checked yet.. could be bogus */
492 m
->c_format
= MSPFORMAT_SCART
; /*stereo */
495 case MSP3430_CONNECTOR_1
:
498 switch (m
->standard
& 0x00ff) {
500 switch (m
->standard
) {
501 case MSP3430_PAL_DK1
:
502 standard
= MSPSTANDARD_FM_DK1
;
504 /* case MSP3430_PAL_DK2:
505 standard=MSPSTANDARD_FM_DK2;
508 may be FM stereo (Germany) or FM NICAM (Scandinavia,spain)
509 standard=MSPSTANDARD_AUTO;
513 standard
= MSPSTANDARD_AUTO
;
517 standard
= MSPSTANDARD_AUTO
;
519 /* Only MSP34x5 supported format - Korean NTSC-M */
520 standard
= MSPSTANDARD_FM_M
;
522 standard
= MSPSTANDARD_AUTO
;
525 /*no NICAM support in MSP3410D - force to autodetect */
526 if ((m
->chip_id
== 0x405) && (standard
>= MSPSTANDARD_NICAM_BG
))
527 standard
= MSPSTANDARD_AUTO
;
529 if (m
->c_standard
!= standard
) {
531 SetMSP3430Data(m
, WR_DEM
, 0x00, 0x20, standard
>> 8,
533 if (standard
== MSPSTANDARD_AUTO
) {
534 count
= 50; /* time shouldn't exceed 1s, just in case */
537 GetMSP3430Data(m
, RD_DEM
, 0x00, 0x7e, &high
, &low
);
538 result
= (high
<< 8) | low
;
540 } while (result
> 0x07ff && count
> 0);
542 if ((result
> MSPSTANDARD_AUTO
))
545 standard
= MSPSTANDARD_UNKNOWN
;
547 xf86DrvMsg(m
->d
.pI2CBus
->scrnIndex
, X_INFO
,
548 "Detected audio standard: %d\n", result
);
550 /* result = MSPSTANDARD_NICAM_L can be one of:
551 SECAM_L - MSPSTANDARD_NICAM_L
552 D/K1 - MSPSTANDARD_FM_DK1
553 D/K2 - MSPSTANDARD_FM_DK2
554 D/K-NICAM - MSPSTANDARD_NICAM_DK */
555 if (standard
== MSPSTANDARD_NICAM_L
) {
556 if ((m
->standard
& 0x00ff) == MSP3430_PAL
) {
558 standard
= MSPSTANDARD_FM_DK1
;
559 SetMSP3430Data(m
, WR_DEM
, 0x00, 0x20, standard
>> 8,
562 xf86DrvMsg(m
->d
.pI2CBus
->scrnIndex
, X_INFO
,
563 "Detected 6.5MHz carrier - forced to D/K1 !!!\n");
568 m
->c_standard
= standard
;
569 } /*end - standard changed */
571 if (standard
< MSPSTANDARD_NICAM_BG
) {
572 /* get old value of ident. mode register */
573 GetMSP3430Data(m
, RD_DSP
, 0x00, 0x15, &high
, &low
);
574 /* reset Ident-Filter */
575 SetMSP3430Data(m
, WR_DSP
, 0x00, 0x14, 0x00, 0x3F);
576 /* put back old value to ident. mode register */
577 SetMSP3430Data(m
, WR_DSP
, 0x00, 0x14, 0x00, low
);
581 if (standard
<= MSPSTANDARD_AUTO
) {
582 m
->c_format
= MSPFORMAT_1xFM
;
584 else if (standard
< MSPSTANDARD_NICAM_BG
) {
585 /* set FM prescale */
586 SetMSP3430Data(m
, WR_DSP
, 0x00, 0x0e, 0x30, 0);
587 /* set FM deemphasis */
588 SetMSP3430Data(m
, WR_DSP
, 0x00, 0x0f,
589 ((standard
== MSPSTANDARD_FM_M
) ? 0 : 1), 0);
591 /* check if FM2 carrier is present */
592 /*turn off FM DC Notch */
593 SetMSP3430Data(m
, WR_DSP
, 0x00, 0x17, 0x00, 0x3f);
594 /*matrix source for Quasi-Peak Detector - stereo: ch2->L ch1->R */
595 SetMSP3430Data(m
, WR_DSP
, 0x00, 0x0c, 0x00, 0x20);
598 GetMSP3430Data(m
, RD_DSP
, 0x00, 0x1A, &high
, &low
);
599 peak
= (high
<< 8) | low
;
601 xf86DrvMsg(m
->d
.pI2CBus
->scrnIndex
, X_INFO
,
602 "Second carrier Quasi-Peak detection: %d\n", peak
);
604 /*turn on FM DC Notch */
605 SetMSP3430Data(m
, WR_DSP
, 0x00, 0x17, 0x00, 0x00);
608 /* if second carrier not detected - only mono from first carrier */
609 m
->c_format
= MSPFORMAT_1xFM
;
612 m
->c_format
= MSPFORMAT_2xFM
;
613 /*start of FM identification process - FM_WAIT
614 wait at least 0.5s - used 1s - gives beter resolution */
619 if (standard
== MSPSTANDARD_NICAM_L
) {
620 m
->c_format
= MSPFORMAT_NICAM_AM
;
621 /* set AM prescale */
622 SetMSP3430Data(m
, WR_DSP
, 0x00, 0x0e, 0x7C, 0);
625 m
->c_format
= MSPFORMAT_NICAM_FM
;
626 /* set FM prescale */
627 SetMSP3430Data(m
, WR_DSP
, 0x00, 0x0e, 0x30, 0);
629 /* set FM deemphasis */
630 SetMSP3430Data(m
, WR_DSP
, 0x00, 0x0f, 0x00, 0);
631 /* set NICAM prescale to 0dB */
632 SetMSP3430Data(m
, WR_DSP
, 0x00, 0x10, 0x20, 0);
636 } /*end - case conector */
638 CheckModeMSP34x5D(m
);
640 /* Set volume to FAST_MUTE. */
641 /*SetMSP3430Data(m, WR_DSP, 0x00, 0x00, 0xFF, 0x00); */
643 MSP3430SetVolume(m
, m
->volume
);
645 __MSPBEEP
} /* EnableMSP34x5D ()... */
648 CheckModeMSP34x5D(MSP3430Ptr m
)
650 const char stereo_on
= 25;
651 const char stereo_off
= 20;
652 const char dual_on
= -stereo_on
;
653 const char dual_off
= -stereo_off
;
655 CARD8 matrix
, fmmatrix
, source
, high
, low
;
657 fmmatrix
= 0; /*no matrix */
659 /*FM*/ switch (m
->c_format
) {
660 case MSPFORMAT_NICAM_FM
:
661 case MSPFORMAT_NICAM_AM
:
662 case MSPFORMAT_SCART
:
663 source
= ((m
->c_format
== MSPFORMAT_SCART
) ? 2 : 1);
690 /*STEREO*/ fmmatrix
= ((m
->c_standard
== MSPSTANDARD_FM_M
) ? 2 : 1);
703 GetMSP3430Data(m
, RD_DSP
, 0x00, 0x18, &high
, &low
);
704 detect
= (char) high
;
706 xf86DrvMsg(m
->d
.pI2CBus
->scrnIndex
, X_INFO
,
707 "Stereo Detection Register: %d\n", detect
);
710 ((m
->c_mode
== MSPMODE_STEREO
) ? stereo_off
: stereo_on
)) {
711 m
->c_mode
= MSPMODE_STEREO
;
714 fmmatrix
= ((m
->c_standard
== MSPSTANDARD_FM_M
) ? 2 : 1);
716 else if (detect
<= ((m
->c_mode
== MSPMODE_AB
) ? dual_off
: dual_on
)) {
717 m
->c_mode
= MSPMODE_AB
;
719 case MSPMODE_STEREO_AB
:
722 case MSPMODE_STEREO_B
:
732 m
->c_mode
= MSPMODE_MONO
;
736 } /* end - case mode */
740 if (m
->c_fmmatrix
!= fmmatrix
) {
741 GetMSP3430Data(m
, RD_DSP
, 0x00, 0x0e, &high
, &low
);
742 SetMSP3430Data(m
, WR_DSP
, 0x00, 0x0e, high
, fmmatrix
);
743 m
->c_fmmatrix
= fmmatrix
;
746 if ((m
->c_matrix
!= matrix
) || (m
->c_source
!= source
)) {
747 /*set chanel source and matrix for loudspeaker */
748 SetMSP3430Data(m
, WR_DSP
, 0x00, 0x08, source
, matrix
);
750 m
->c_matrix
= matrix
;
751 m
->c_source
= source
;
754 if (((m
->c_format
) & 0xF0) == MSPFORMAT_NICAM
)
755 SetMSP3430Data(m
, WR_DEM
, 0x00, 0x21, 0, 1);
762 /*MONO*/ msg
= "MONO";
765 /*LEFT*/ msg
= "MONO/CHANNEL_1";
768 /*RIGHT*/ msg
= "MONO/CHANNEL_2";
771 /*LEFT*/ msg
= "STEREO";
777 xf86DrvMsg(m
->d
.pI2CBus
->scrnIndex
, X_INFO
, "Audio mode set to: %s\n", msg
);