Imported Upstream version 1.15.1
[deb_xorg-server.git] / hw / xfree86 / i2c / msp3430.c
CommitLineData
a09e091a
JB
1#ifdef HAVE_XORG_CONFIG_H
2#include <xorg-config.h>
3#endif
4
5#include <string.h>
6#include <unistd.h>
7
8#include "xf86.h"
9#include "xf86i2c.h"
10#include "msp3430.h"
11#include "i2c_def.h"
12
13#define CONTROL 0x00
14#define WR_DEM 0x10
15#define RD_DEM 0x11
16#define WR_DSP 0x12
17#define RD_DSP 0x13
18
19void InitMSP34xxG(MSP3430Ptr m);
20void InitMSP34x5D(MSP3430Ptr m);
21void CheckModeMSP34x5D(MSP3430Ptr m);
22static const char *MSP_getProductName(CARD16 product_id);
23void mpause(int milliseconds);
24
25#define __MSPDEBUG__ 0
26
27#if __MSPDEBUG__ > 3
28
29void MSPBeep(MSP3430Ptr m, CARD8 freq);
30
31#define __MSPBEEP MSPBeep(m,0x14);
32
33#else
34
35#define __MSPBEEP
36#endif
37
38static void
39SetMSP3430Control(MSP3430Ptr m, CARD8 RegAddress, CARD8 RegValueHigh,
40 CARD8 RegValueLow)
41{
42 I2CByte data[3];
43
44 data[0] = RegAddress;
45 data[1] = RegValueHigh;
46 data[2] = RegValueLow;
47
48 I2C_WriteRead(&(m->d), data, 3, NULL, 0);
49}
50
51static void
52SetMSP3430Data(MSP3430Ptr m, CARD8 RegAddress, CARD8 RegSubAddressHigh,
53 CARD8 RegSubAddressLow, CARD8 RegValueHigh, CARD8 RegValueLow)
54{
55 I2CByte data[5];
56
57#ifdef MSP_DEBUG
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);
63 }
64#endif
65
66 data[0] = RegAddress;
67 data[1] = RegSubAddressHigh;
68 data[2] = RegSubAddressLow;
69 data[3] = RegValueHigh;
70 data[4] = RegValueLow;
71
72 I2C_WriteRead(&(m->d), data, 5, NULL, 0);
73}
74
75static void
76GetMSP3430Data(MSP3430Ptr m, CARD8 RegAddress, CARD8 RegSubAddressHigh,
77 CARD8 RegSubAddressLow, CARD8 *RegValueHigh, CARD8 *RegValueLow)
78{
79 I2CByte send[3];
80 I2CByte receive[2];
81
82 send[0] = RegAddress;
83 send[1] = RegSubAddressHigh;
84 send[2] = RegSubAddressLow;
85
86 I2C_WriteRead(&(m->d), send, 3, receive, 2);
87
88 *RegValueHigh = receive[0];
89 *RegValueLow = receive[1];
90}
91
92#if __MSPDEBUG__ > 2
93static void
94MSP3430DumpStatus(MSP3430Ptr m)
95{
96 CARD8 status_hi, status_lo;
97 CARD8 subaddr, data[2];
98
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"
105 : "ANALOG FM/AM"),
106 (status_lo >> 4) & 1, (status_lo >> 3) & 1,
107 !((status_lo >> 2) & 1), !((status_lo >> 1) & 1));
108
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);
112 subaddr = 0x0;
113 I2C_WriteRead(&(m->d), &subaddr, 1, data, 2);
114 xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO, "MSP34xx: control=0x%02x%02x\n",
115 data[1], data[0]);
116}
117#endif
118
119/* wrapper */
120void
121InitMSP3430(MSP3430Ptr m)
122{
123#if __MSPDEBUG__ > 1
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);
127#endif
128 switch (m->chip_family) {
129 case MSPFAMILY_34x0G:
130 InitMSP34xxG(m);
131 break;
132 case MSPFAMILY_34x5G:
133 InitMSP34xxG(m);
134 break;
135 case MSPFAMILY_34x5D:
136 InitMSP34x5D(m);
137 break;
138 }
139}
140
141/*-----------------------------------------------------------------
142| common functions for all MSP34xx chips
143|----------------------------------------------------------------*/
144
145MSP3430Ptr
146DetectMSP3430(I2CBusPtr b, I2CSlaveAddr addr)
147{
148 MSP3430Ptr m;
149 I2CByte a;
150 CARD8 hardware_version, major_revision, product_code, rom_version;
151 Bool supported;
152
153 m = calloc(1, sizeof(MSP3430Rec));
154 if (m == NULL)
155 return NULL;
156 m->d.DevName = strdup("MSP34xx");
157 m->d.SlaveAddr = addr;
158 m->d.pI2CBus = b;
159 m->d.NextDev = NULL;
160 m->d.StartTimeout = b->StartTimeout;
161 m->d.BitTimeout = b->BitTimeout;
162 m->d.AcknTimeout = b->AcknTimeout;
163 m->d.ByteTimeout = b->ByteTimeout;
164
165 if (!I2C_WriteRead(&(m->d), NULL, 0, &a, 1)) {
166 free(m->d.DevName);
167 free(m);
168 return NULL;
169 }
170
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;
177 m->volume = 0;
178 m->recheck = FALSE;
179
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;
186
187 m->chip_id = ((major_revision << 8) | product_code);
188
189 supported = FALSE;
190 switch (major_revision) {
191 case 4: /* 34xxD */
192 switch (product_code) {
193 case 0x05: /* 3405D */
194 case 0x0A: /* 3410D */
195 case 0x0F: /* 3415D */
196 m->chip_family = MSPFAMILY_34x5D;
197 m->recheck = TRUE;
198 supported = TRUE;
199 break;
200 default:
201 m->chip_family = MSPFAMILY_34x0D;
202 }
203 break;
204 case 7: /* 34xxG */
205 switch (product_code) {
206 case 0x00:
207 case 0x0A:
208 case 0x1E:
209 case 0x28:
210 case 0x32:
211 m->chip_family = MSPFAMILY_34x0G;
212 supported = TRUE;
213 break;
214 case 0x0f:
215 case 0x19:
216 case 0x2d:
217 case 0x37:
218 case 0x41:
219 m->chip_family = MSPFAMILY_34x5G;
220 supported = TRUE;
221#ifdef MSP_DEBUG
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);
225 A(0x20)
226 A(0x30)
227 A(0x40)
228 A(0x00)
229 B(0x01, 0x08)
230 B(0x0B, 0x0E)
231 A(0x10)
232 B(0x12, 0x14)
233 A(0x16)
234 A(0x29)
235#undef B
236#undef A
237#endif
238 break;
239 default:
240 m->chip_family = MSPFAMILY_UNKNOWN;
241 }
242 break;
243 default:
244 m->chip_family = MSPFAMILY_UNKNOWN;
245 }
246
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);
251
252 if (!supported) {
253 free(m->d.DevName);
254 free(m);
255 return NULL;
256 }
257 if (!I2CDevInit(&(m->d))) {
258 free(m->d.DevName);
259 free(m);
260 return NULL;
261 }
262
263 return m;
264}
265
266void
267ResetMSP3430(MSP3430Ptr m)
268{
269 /* Reset the MSP3430 */
270 SetMSP3430Control(m, 0x00, 0x80, 0x00);
271 /* Set it back to normal operation */
272 SetMSP3430Control(m, 0x00, 0x00, 0x00);
273
274 m->c_format = MSPFORMAT_UNKNOWN;
275 m->c_standard = MSPSTANDARD_UNKNOWN;
276 m->c_matrix = m->c_fmmatrix = m->c_source = 0;
277 m->volume = 0;
278}
279
280void
281MSP3430SetVolume(MSP3430Ptr m, CARD8 value)
282{
283 CARD8 result;
284
285#if 0
286 CARD8 old_volume;
287
288 GetMSP3430Data(m, RD_DSP, 0x00, 0x00, &old_volume, &result);
289 xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO, "MSP3430 result 0x%02x\n",
290 result);
291#endif
292 /* save an extra Get call */
293 result = 0;
294
295 SetMSP3430Data(m, WR_DSP, 0x00, 0x00, value, result);
296
297 SetMSP3430Data(m, WR_DSP, 0x00, 0x07, value, 0);
298 m->volume = value;
299
300#if __MSPDEBUG__ > 2
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",
304 value);
305#endif
306}
307
308void
309MSP3430SetSAP(MSP3430Ptr m, int mode)
310{
311 xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO,
312 "Put actual code to change SAP here\n");
313
314 SetMSP3430Data(m, WR_DSP, 0x00, 0x08, mode & 0xff, 0x20);
315}
316
317#if 0
318void
319MSP3430SetSource(MSP3430Ptr m, CARD8 value)
320{
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);
324}
325#endif
326
327static const char *
328MSP_getProductName(CARD16 product_id)
329{
330 switch (product_id) {
331 case 0x0400:
332 return "MSP3400D";
333 case 0x040a:
334 return "MSP3410D";
335 case 0x0405:
336 return "MSP3405D";
337 case 0x040f:
338 return "MSP3415D";
339 case 0x0700:
340 return "MSP3400G";
341 case 0x070a:
342 return "MSP3410G";
343 case 0x071e:
344 return "MSP3430G";
345 case 0x0728:
346 return "MSP3440G";
347 case 0x0732:
348 return "MSP3450G";
349 case 0x070f:
350 return "MSP3415G";
351 case 0x0719:
352 return "MSP3425G";
353 case 0x072d:
354 return "MSP3445G";
355 case 0x0737:
356 return "MSP3455G";
357 case 0x0741:
358 return "MSP3465G";
359 }
360 return "MSP - unknown type";
361}
362
363#if __MSPDEBUG__ > 2
364/*puts beep in MSP output
365 freq = 0x01 - 16Hz ... 0x40 - 1kHz ... 0xff - 4kHz
366*/
367void
368MSPBeep(MSP3430Ptr m, CARD8 freq)
369{
370 SetMSP3430Data(m, WR_DSP, 0x00, freq, 0x7f, 0x40);
371 mpause(100);
372 SetMSP3430Data(m, WR_DSP, 0x00, 0x14, 0x00, 0x00);
373}
374#endif
375
376void
377mpause(int milliseconds)
378{
379 int i, m;
380
381 m = milliseconds / 20;
382 for (i = 0; i < m; i++)
383 usleep(20000);
384}
385
386/*-----------------------------------------------------------------
387| specific functions for all MSP34xxG chips
388|----------------------------------------------------------------*/
389
390void
391InitMSP34xxG(MSP3430Ptr m)
392{
393
394#if __MSPDEBUG__ > 1
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);
398#endif
399 /* Reset MSP3430 */
400 SetMSP3430Control(m, 0x00, 0x80, 0x00);
401 /* Set it back to normal operation */
402 SetMSP3430Control(m, 0x00, 0x00, 0x00);
403
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 */
411 /* PAL standard */
412 SetMSP3430Data(m, WR_DEM, 0x00, 0x20, 0x00, 0x01); /* possibly wrong */
413 }
414 else {
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);
418 }
419
420 switch (m->connector) {
421 case MSP3430_CONNECTOR_1:
422 SetMSP3430Data(m, WR_DSP, 0x00, 0x08, 0x03, 0x20);
423 break;
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);
429 break;
430 case MSP3430_CONNECTOR_3:
431 default:
432 /* SCART Input Prescale: 0 dB gain */
433 SetMSP3430Data(m, WR_DSP, 0x00, 0x0d, 0x19, 0x00);
434
435 SetMSP3430Data(m, WR_DSP, 0x00, 0x08, 0x02, 0x20);
436 break;
437 }
438
439 switch (m->standard) {
440 case MSP3430_PAL:
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);
446 break;
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);
453 break;
454 case MSP3430_SECAM: /* is this right ? */
455 case MSP3430_NTSC:
456 /* Write to DSP, register 0x000E, (prescale FM/FM matrix) */
457 SetMSP3430Data(m, WR_DSP, 0x00, 0x0e, 0x24, 0x03);
458
459 /* Set volume to FAST_MUTE. */
460 SetMSP3430Data(m, WR_DSP, 0x00, 0x00, 0xFF, 0x00);
461 break;
462 }
463
464}
465
466/*-----------------------------------------------------------------
467| specific functions for all MSP34x5D chips
468|----------------------------------------------------------------*/
469
470void
471InitMSP34x5D(MSP3430Ptr m)
472{
473 int count;
474 CARD8 high, low;
475 CARD16 result, standard;
476 CARD16 peak;
477
478 if (m->c_format == MSPFORMAT_UNKNOWN)
479 ResetMSP3430(m);
480 else {
481 /*mute volume */
482 SetMSP3430Data(m, WR_DSP, 0x00, 0x00, 0x00, 0x00);
483 }
484
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 */
493 }
494 break;
495 case MSP3430_CONNECTOR_1:
496 default:
497
498 switch (m->standard & 0x00ff) {
499 case MSP3430_PAL:
500 switch (m->standard) {
501 case MSP3430_PAL_DK1:
502 standard = MSPSTANDARD_FM_DK1;
503 break;
504/* case MSP3430_PAL_DK2:
505 standard=MSPSTANDARD_FM_DK2;
506 break;
507 case MSP3430_PAL_BG:
508 may be FM stereo (Germany) or FM NICAM (Scandinavia,spain)
509 standard=MSPSTANDARD_AUTO;
510 break;
511*/
512 default:
513 standard = MSPSTANDARD_AUTO;
514 }
515 break;
516 case MSP3430_SECAM:
517 standard = MSPSTANDARD_AUTO;
518 case MSP3430_NTSC:
519 /* Only MSP34x5 supported format - Korean NTSC-M */
520 standard = MSPSTANDARD_FM_M;
521 default:
522 standard = MSPSTANDARD_AUTO;
523 }
524
525 /*no NICAM support in MSP3410D - force to autodetect */
526 if ((m->chip_id == 0x405) && (standard >= MSPSTANDARD_NICAM_BG))
527 standard = MSPSTANDARD_AUTO;
528
529 if (m->c_standard != standard) {
530
531 SetMSP3430Data(m, WR_DEM, 0x00, 0x20, standard >> 8,
532 standard & 0xFF);
533 if (standard == MSPSTANDARD_AUTO) {
534 count = 50; /* time shouldn't exceed 1s, just in case */
535 do {
536 usleep(20000);
537 GetMSP3430Data(m, RD_DEM, 0x00, 0x7e, &high, &low);
538 result = (high << 8) | low;
539 --count;
540 } while (result > 0x07ff && count > 0);
541
542 if ((result > MSPSTANDARD_AUTO))
543 standard = result;
544 else
545 standard = MSPSTANDARD_UNKNOWN;
546#if __MSPDEBUG__ > 1
547 xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO,
548 "Detected audio standard: %d\n", result);
549#endif
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) {
557 /* force PAL D/K */
558 standard = MSPSTANDARD_FM_DK1;
559 SetMSP3430Data(m, WR_DEM, 0x00, 0x20, standard >> 8,
560 standard & 0xFF);
561#if __MSPDEBUG__ > 1
562 xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO,
563 "Detected 6.5MHz carrier - forced to D/K1 !!!\n");
564#endif
565 }
566 }
567 }
568 m->c_standard = standard;
569 } /*end - standard changed */
570 else {
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);
578 }
579 }
580
581 if (standard <= MSPSTANDARD_AUTO) {
582 m->c_format = MSPFORMAT_1xFM;
583 }
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);
590
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);
596
597 mpause(250);
598 GetMSP3430Data(m, RD_DSP, 0x00, 0x1A, &high, &low);
599 peak = (high << 8) | low;
600#if __MSPDEBUG__ > 1
601 xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO,
602 "Second carrier Quasi-Peak detection: %d\n", peak);
603#endif
604 /*turn on FM DC Notch */
605 SetMSP3430Data(m, WR_DSP, 0x00, 0x17, 0x00, 0x00);
606
607 if (peak < 5) {
608 /* if second carrier not detected - only mono from first carrier */
609 m->c_format = MSPFORMAT_1xFM;
610 }
611 else {
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 */
615 mpause(1000);
616 }
617 }
618 else {
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);
623 }
624 else {
625 m->c_format = MSPFORMAT_NICAM_FM;
626 /* set FM prescale */
627 SetMSP3430Data(m, WR_DSP, 0x00, 0x0e, 0x30, 0);
628 }
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);
633 }
634
635 break;
636 } /*end - case conector */
637
638 CheckModeMSP34x5D(m);
639
640 /* Set volume to FAST_MUTE. */
641 /*SetMSP3430Data(m, WR_DSP, 0x00, 0x00, 0xFF, 0x00); */
642 /*set volume */
643 MSP3430SetVolume(m, m->volume);
644
645__MSPBEEP} /* EnableMSP34x5D ()... */
646
647void
648CheckModeMSP34x5D(MSP3430Ptr m)
649{
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;
654 char detect;
655 CARD8 matrix, fmmatrix, source, high, low;
656
657 fmmatrix = 0; /*no matrix */
658 source = 0;
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);
664 switch (m->mode) {
665 case MSPMODE_MONO:
666 matrix = 0x30;
667 /*MONO*/ break;
668 case MSPMODE_A:
669 matrix = 0x00;
670 /*A*/ break;
671 case MSPMODE_B:
672 matrix = 0x10;
673 /*B*/ break;
674 default:
675 matrix = 0x20;
676 /*STEREO*/ break;
677 }
678 break;
679 default:
680 case MSPFORMAT_1xFM:
681 matrix = 0x00;
682 /*A*/ break;
683 case MSPFORMAT_2xFM:
684 switch (m->mode) {
685 case MSPMODE_MONO:
686 matrix = 0x30;
687 /*MONO*/ break;
688 case MSPMODE_STEREO:
689 matrix = 0x20;
690 /*STEREO*/ fmmatrix = ((m->c_standard == MSPSTANDARD_FM_M) ? 2 : 1);
691 break;
692 case MSPMODE_AB:
693 matrix = 0x20;
694 /*STEREO*/ break;
695 case MSPMODE_A:
696 matrix = 0x00;
697 /*A*/ break;
698 case MSPMODE_B:
699 matrix = 0x10;
700 /*B*/ break;
701 default:
702 /*FM_IDENT_CHECK */
703 GetMSP3430Data(m, RD_DSP, 0x00, 0x18, &high, &low);
704 detect = (char) high;
705#if __MSPDEBUG__ > 1
706 xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO,
707 "Stereo Detection Register: %d\n", detect);
708#endif
709 if (detect >=
710 ((m->c_mode == MSPMODE_STEREO) ? stereo_off : stereo_on)) {
711 m->c_mode = MSPMODE_STEREO;
712 matrix = 0x20;
713 /*STEREO*/
714 fmmatrix = ((m->c_standard == MSPSTANDARD_FM_M) ? 2 : 1);
715 }
716 else if (detect <= ((m->c_mode == MSPMODE_AB) ? dual_off : dual_on)) {
717 m->c_mode = MSPMODE_AB;
718 switch (m->mode) {
719 case MSPMODE_STEREO_AB:
720 matrix = 0x20;
721 break;
722 case MSPMODE_STEREO_B:
723 matrix = 0x10;
724 break;
725 default:
726 case MSPMODE_A:
727 matrix = 0x00;
728 break;
729 }
730 }
731 else {
732 m->c_mode = MSPMODE_MONO;
733 matrix = 0x30;
734 /*MONO*/}
735 break;
736 } /* end - case mode */
737 break;
738 }
739
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;
744 }
745
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);
749
750 m->c_matrix = matrix;
751 m->c_source = source;
752 }
753
754 if (((m->c_format) & 0xF0) == MSPFORMAT_NICAM)
755 SetMSP3430Data(m, WR_DEM, 0x00, 0x21, 0, 1);
756
757#if __MSPDEBUG__ > 0
758 char *msg;
759
760 switch (matrix) {
761 case 0x30:
762 /*MONO*/ msg = "MONO";
763 break;
764 case 0x00:
765 /*LEFT*/ msg = "MONO/CHANNEL_1";
766 break;
767 case 0x10:
768 /*RIGHT*/ msg = "MONO/CHANNEL_2";
769 break;
770 case 0x20:
771 /*LEFT*/ msg = "STEREO";
772 break;
773 default:
774 msg = "unknown";
775 break;
776 }
777 xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO, "Audio mode set to: %s\n", msg);
778#endif
779}