4f58590a42
Tested by naddy@, jsg@ & kettenis@
780 lines
23 KiB
C
780 lines
23 KiB
C
#ifdef HAVE_XORG_CONFIG_H
|
|
#include <xorg-config.h>
|
|
#endif
|
|
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#include "xf86.h"
|
|
#include "xf86i2c.h"
|
|
#include "msp3430.h"
|
|
#include "i2c_def.h"
|
|
|
|
#define CONTROL 0x00
|
|
#define WR_DEM 0x10
|
|
#define RD_DEM 0x11
|
|
#define WR_DSP 0x12
|
|
#define RD_DSP 0x13
|
|
|
|
void InitMSP34xxG(MSP3430Ptr m);
|
|
void InitMSP34x5D(MSP3430Ptr m);
|
|
void CheckModeMSP34x5D(MSP3430Ptr m);
|
|
static const char *MSP_getProductName(CARD16 product_id);
|
|
void mpause(int milliseconds);
|
|
|
|
#define __MSPDEBUG__ 0
|
|
|
|
#if __MSPDEBUG__ > 3
|
|
|
|
void MSPBeep(MSP3430Ptr m, CARD8 freq);
|
|
|
|
#define __MSPBEEP MSPBeep(m,0x14);
|
|
|
|
#else
|
|
|
|
#define __MSPBEEP
|
|
#endif
|
|
|
|
static void
|
|
SetMSP3430Control(MSP3430Ptr m, CARD8 RegAddress, CARD8 RegValueHigh,
|
|
CARD8 RegValueLow)
|
|
{
|
|
I2CByte data[3];
|
|
|
|
data[0] = RegAddress;
|
|
data[1] = RegValueHigh;
|
|
data[2] = RegValueLow;
|
|
|
|
I2C_WriteRead(&(m->d), data, 3, NULL, 0);
|
|
}
|
|
|
|
static void
|
|
SetMSP3430Data(MSP3430Ptr m, CARD8 RegAddress, CARD8 RegSubAddressHigh,
|
|
CARD8 RegSubAddressLow, CARD8 RegValueHigh, CARD8 RegValueLow)
|
|
{
|
|
I2CByte data[5];
|
|
|
|
#ifdef MSP_DEBUG
|
|
if (!m->registers_present[RegSubAddressLow]) {
|
|
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",
|
|
RegAddress, RegSubAddressHigh, RegSubAddressLow,
|
|
RegValueHigh, RegValueLow);
|
|
}
|
|
#endif
|
|
|
|
data[0] = RegAddress;
|
|
data[1] = RegSubAddressHigh;
|
|
data[2] = RegSubAddressLow;
|
|
data[3] = RegValueHigh;
|
|
data[4] = RegValueLow;
|
|
|
|
I2C_WriteRead(&(m->d), data, 5, NULL, 0);
|
|
}
|
|
|
|
static void
|
|
GetMSP3430Data(MSP3430Ptr m, CARD8 RegAddress, CARD8 RegSubAddressHigh,
|
|
CARD8 RegSubAddressLow, CARD8 *RegValueHigh, CARD8 *RegValueLow)
|
|
{
|
|
I2CByte send[3];
|
|
I2CByte receive[2];
|
|
|
|
send[0] = RegAddress;
|
|
send[1] = RegSubAddressHigh;
|
|
send[2] = RegSubAddressLow;
|
|
|
|
I2C_WriteRead(&(m->d), send, 3, receive, 2);
|
|
|
|
*RegValueHigh = receive[0];
|
|
*RegValueLow = receive[1];
|
|
}
|
|
|
|
#if __MSPDEBUG__ > 2
|
|
static void
|
|
MSP3430DumpStatus(MSP3430Ptr m)
|
|
{
|
|
CARD8 status_hi, status_lo;
|
|
CARD8 subaddr, data[2];
|
|
|
|
GetMSP3430Data(m, RD_DEM, 0x02, 0x00, &status_hi, &status_lo);
|
|
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",
|
|
status_hi & 1, (status_lo >> 7) & 1, (status_lo >> 6) & 1,
|
|
(status_lo >> 5) ? ((status_hi >> 1) & 1 ? "bad NICAM reception"
|
|
: "NICAM") : ((status_hi >> 1) & 1 ? "bogus"
|
|
: "ANALOG FM/AM"),
|
|
(status_lo >> 4) & 1, (status_lo >> 3) & 1,
|
|
!((status_lo >> 2) & 1), !((status_lo >> 1) & 1));
|
|
|
|
GetMSP3430Data(m, RD_DEM, 0x00, 0x7E, &status_hi, &status_lo);
|
|
xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO,
|
|
"MSP34xx: standard result=0x%02x%02x\n", status_hi, status_lo);
|
|
subaddr = 0x0;
|
|
I2C_WriteRead(&(m->d), &subaddr, 1, data, 2);
|
|
xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO, "MSP34xx: control=0x%02x%02x\n",
|
|
data[1], data[0]);
|
|
}
|
|
#endif
|
|
|
|
/* wrapper */
|
|
void
|
|
InitMSP3430(MSP3430Ptr m)
|
|
{
|
|
#if __MSPDEBUG__ > 1
|
|
xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO,
|
|
"InitMSP3430(m->connector=%d, m->standard=%d, m->chip_family=%d)\n",
|
|
m->connector, m->standard, m->chip_family);
|
|
#endif
|
|
switch (m->chip_family) {
|
|
case MSPFAMILY_34x0G:
|
|
InitMSP34xxG(m);
|
|
break;
|
|
case MSPFAMILY_34x5G:
|
|
InitMSP34xxG(m);
|
|
break;
|
|
case MSPFAMILY_34x5D:
|
|
InitMSP34x5D(m);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*-----------------------------------------------------------------
|
|
| common functions for all MSP34xx chips
|
|
|----------------------------------------------------------------*/
|
|
|
|
MSP3430Ptr
|
|
DetectMSP3430(I2CBusPtr b, I2CSlaveAddr addr)
|
|
{
|
|
MSP3430Ptr m;
|
|
I2CByte a;
|
|
CARD8 hardware_version, major_revision, product_code, rom_version;
|
|
Bool supported;
|
|
|
|
m = calloc(1, sizeof(MSP3430Rec));
|
|
if (m == NULL)
|
|
return NULL;
|
|
m->d.DevName = strdup("MSP34xx");
|
|
m->d.SlaveAddr = addr;
|
|
m->d.pI2CBus = b;
|
|
m->d.NextDev = NULL;
|
|
m->d.StartTimeout = b->StartTimeout;
|
|
m->d.BitTimeout = b->BitTimeout;
|
|
m->d.AcknTimeout = b->AcknTimeout;
|
|
m->d.ByteTimeout = b->ByteTimeout;
|
|
|
|
if (!I2C_WriteRead(&(m->d), NULL, 0, &a, 1)) {
|
|
free((void *) m->d.DevName);
|
|
free(m);
|
|
return NULL;
|
|
}
|
|
|
|
m->standard = MSP3430_NTSC;
|
|
m->connector = MSP3430_CONNECTOR_1;
|
|
m->mode = MSPMODE_STEREO_A; /*stereo or chanel A if avail. */
|
|
m->c_format = MSPFORMAT_UNKNOWN;
|
|
m->c_standard = MSPSTANDARD_UNKNOWN;
|
|
m->c_matrix = m->c_fmmatrix = m->c_source = 0;
|
|
m->volume = 0;
|
|
m->recheck = FALSE;
|
|
|
|
GetMSP3430Data(m, RD_DSP, 0x00, 0x1E, &hardware_version, &major_revision);
|
|
GetMSP3430Data(m, RD_DSP, 0x00, 0x1F, &product_code, &rom_version);
|
|
m->hardware_version = hardware_version;
|
|
m->major_revision = major_revision;
|
|
m->product_code = product_code;
|
|
m->rom_version = rom_version;
|
|
|
|
m->chip_id = ((major_revision << 8) | product_code);
|
|
|
|
supported = FALSE;
|
|
switch (major_revision) {
|
|
case 4: /* 34xxD */
|
|
switch (product_code) {
|
|
case 0x05: /* 3405D */
|
|
case 0x0A: /* 3410D */
|
|
case 0x0F: /* 3415D */
|
|
m->chip_family = MSPFAMILY_34x5D;
|
|
m->recheck = TRUE;
|
|
supported = TRUE;
|
|
break;
|
|
default:
|
|
m->chip_family = MSPFAMILY_34x0D;
|
|
}
|
|
break;
|
|
case 7: /* 34xxG */
|
|
switch (product_code) {
|
|
case 0x00:
|
|
case 0x0A:
|
|
case 0x1E:
|
|
case 0x28:
|
|
case 0x32:
|
|
m->chip_family = MSPFAMILY_34x0G;
|
|
supported = TRUE;
|
|
break;
|
|
case 0x0f:
|
|
case 0x19:
|
|
case 0x2d:
|
|
case 0x37:
|
|
case 0x41:
|
|
m->chip_family = MSPFAMILY_34x5G;
|
|
supported = TRUE;
|
|
#ifdef MSP_DEBUG
|
|
memset(m->registers_present, 0, 256);
|
|
#define A(num) m->registers_present[(num)]=1;
|
|
#define B(num1, num2) memset(&(m->registers_present[num1]), 1, num2-num1);
|
|
A(0x20)
|
|
A(0x30)
|
|
A(0x40)
|
|
A(0x00)
|
|
B(0x01, 0x08)
|
|
B(0x0B, 0x0E)
|
|
A(0x10)
|
|
B(0x12, 0x14)
|
|
A(0x16)
|
|
A(0x29)
|
|
#undef B
|
|
#undef A
|
|
#endif
|
|
break;
|
|
default:
|
|
m->chip_family = MSPFAMILY_UNKNOWN;
|
|
}
|
|
break;
|
|
default:
|
|
m->chip_family = MSPFAMILY_UNKNOWN;
|
|
}
|
|
|
|
xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO,
|
|
"Found %s%s, rom version 0x%02x, chip_id=0x%04x\n",
|
|
MSP_getProductName(m->chip_id),
|
|
supported ? "" : " (unsupported)", rom_version, m->chip_id);
|
|
|
|
if (!supported) {
|
|
free((void *) m->d.DevName);
|
|
free(m);
|
|
return NULL;
|
|
}
|
|
if (!I2CDevInit(&(m->d))) {
|
|
free((void *) m->d.DevName);
|
|
free(m);
|
|
return NULL;
|
|
}
|
|
|
|
return m;
|
|
}
|
|
|
|
void
|
|
ResetMSP3430(MSP3430Ptr m)
|
|
{
|
|
/* Reset the MSP3430 */
|
|
SetMSP3430Control(m, 0x00, 0x80, 0x00);
|
|
/* Set it back to normal operation */
|
|
SetMSP3430Control(m, 0x00, 0x00, 0x00);
|
|
|
|
m->c_format = MSPFORMAT_UNKNOWN;
|
|
m->c_standard = MSPSTANDARD_UNKNOWN;
|
|
m->c_matrix = m->c_fmmatrix = m->c_source = 0;
|
|
m->volume = 0;
|
|
}
|
|
|
|
void
|
|
MSP3430SetVolume(MSP3430Ptr m, CARD8 value)
|
|
{
|
|
CARD8 result;
|
|
|
|
#if 0
|
|
CARD8 old_volume;
|
|
|
|
GetMSP3430Data(m, RD_DSP, 0x00, 0x00, &old_volume, &result);
|
|
xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO, "MSP3430 result 0x%02x\n",
|
|
result);
|
|
#endif
|
|
/* save an extra Get call */
|
|
result = 0;
|
|
|
|
SetMSP3430Data(m, WR_DSP, 0x00, 0x00, value, result);
|
|
|
|
SetMSP3430Data(m, WR_DSP, 0x00, 0x07, value, 0);
|
|
m->volume = value;
|
|
|
|
#if __MSPDEBUG__ > 2
|
|
MSP3430DumpStatus(m);
|
|
__MSPBEEP GetMSP3430Data(m, RD_DSP, 0x00, 0x00, &old_volume, &result);
|
|
xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO, "MSP3430 volume 0x%02x\n",
|
|
value);
|
|
#endif
|
|
}
|
|
|
|
void
|
|
MSP3430SetSAP(MSP3430Ptr m, int mode)
|
|
{
|
|
xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO,
|
|
"Put actual code to change SAP here\n");
|
|
|
|
SetMSP3430Data(m, WR_DSP, 0x00, 0x08, mode & 0xff, 0x20);
|
|
}
|
|
|
|
#if 0
|
|
void
|
|
MSP3430SetSource(MSP3430Ptr m, CARD8 value)
|
|
{
|
|
/* Write to DSP, register 0x0008, (loudspeaker channel source/matrix) */
|
|
/* This sets the source to the TV tuner, for stereo operation */
|
|
SetMSP3430Data(m, WR_DSP, 0x00, 0x08, value, 0x20);
|
|
}
|
|
#endif
|
|
|
|
static const char *
|
|
MSP_getProductName(CARD16 product_id)
|
|
{
|
|
switch (product_id) {
|
|
case 0x0400:
|
|
return "MSP3400D";
|
|
case 0x040a:
|
|
return "MSP3410D";
|
|
case 0x0405:
|
|
return "MSP3405D";
|
|
case 0x040f:
|
|
return "MSP3415D";
|
|
case 0x0700:
|
|
return "MSP3400G";
|
|
case 0x070a:
|
|
return "MSP3410G";
|
|
case 0x071e:
|
|
return "MSP3430G";
|
|
case 0x0728:
|
|
return "MSP3440G";
|
|
case 0x0732:
|
|
return "MSP3450G";
|
|
case 0x070f:
|
|
return "MSP3415G";
|
|
case 0x0719:
|
|
return "MSP3425G";
|
|
case 0x072d:
|
|
return "MSP3445G";
|
|
case 0x0737:
|
|
return "MSP3455G";
|
|
case 0x0741:
|
|
return "MSP3465G";
|
|
}
|
|
return "MSP - unknown type";
|
|
}
|
|
|
|
#if __MSPDEBUG__ > 2
|
|
/*puts beep in MSP output
|
|
freq = 0x01 - 16Hz ... 0x40 - 1kHz ... 0xff - 4kHz
|
|
*/
|
|
void
|
|
MSPBeep(MSP3430Ptr m, CARD8 freq)
|
|
{
|
|
SetMSP3430Data(m, WR_DSP, 0x00, freq, 0x7f, 0x40);
|
|
mpause(100);
|
|
SetMSP3430Data(m, WR_DSP, 0x00, 0x14, 0x00, 0x00);
|
|
}
|
|
#endif
|
|
|
|
void
|
|
mpause(int milliseconds)
|
|
{
|
|
int i, m;
|
|
|
|
m = milliseconds / 20;
|
|
for (i = 0; i < m; i++)
|
|
usleep(20000);
|
|
}
|
|
|
|
/*-----------------------------------------------------------------
|
|
| specific functions for all MSP34xxG chips
|
|
|----------------------------------------------------------------*/
|
|
|
|
void
|
|
InitMSP34xxG(MSP3430Ptr m)
|
|
{
|
|
|
|
#if __MSPDEBUG__ > 1
|
|
xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO,
|
|
"InitMSP34xxG(m->connector=%d, m->standard=%d, m->chip_family=%d)\n",
|
|
m->connector, m->standard, m->chip_family);
|
|
#endif
|
|
/* Reset MSP3430 */
|
|
SetMSP3430Control(m, 0x00, 0x80, 0x00);
|
|
/* Set it back to normal operation */
|
|
SetMSP3430Control(m, 0x00, 0x00, 0x00);
|
|
|
|
/*set MODUS register */
|
|
/* bits: 0 - automatic sound detection */
|
|
/* 1 - enable STATUS change */
|
|
/* 12 - detect 6.5 Mhz carrier as D/K1, D/K2 or D/K NICAM (does not seem to work ) */
|
|
/* 13 - detect 4.5 Mhz carrier as BTSC */
|
|
if ((m->standard & 0xff) == MSP3430_PAL) {
|
|
SetMSP3430Data(m, WR_DEM, 0x00, 0x30, 0x30, 0x03 | 0x08); /* make O_ pins tristate */
|
|
/* PAL standard */
|
|
SetMSP3430Data(m, WR_DEM, 0x00, 0x20, 0x00, 0x01); /* possibly wrong */
|
|
}
|
|
else {
|
|
SetMSP3430Data(m, WR_DEM, 0x00, 0x30, 0x20, 0x03 | 0x08);
|
|
/* standard selection is M-BTSC-Stereo */
|
|
SetMSP3430Data(m, WR_DEM, 0x00, 0x20, 0x00, 0x20);
|
|
}
|
|
|
|
switch (m->connector) {
|
|
case MSP3430_CONNECTOR_1:
|
|
SetMSP3430Data(m, WR_DSP, 0x00, 0x08, 0x03, 0x20);
|
|
break;
|
|
case MSP3430_CONNECTOR_2:
|
|
/* this has not been checked yet.. could be bogus */
|
|
/* SCART Input Prescale: 0 dB gain */
|
|
SetMSP3430Data(m, WR_DSP, 0x00, 0x0d, 0x19, 0x00);
|
|
SetMSP3430Data(m, WR_DSP, 0x00, 0x08, 0x02, 0x20);
|
|
break;
|
|
case MSP3430_CONNECTOR_3:
|
|
default:
|
|
/* SCART Input Prescale: 0 dB gain */
|
|
SetMSP3430Data(m, WR_DSP, 0x00, 0x0d, 0x19, 0x00);
|
|
|
|
SetMSP3430Data(m, WR_DSP, 0x00, 0x08, 0x02, 0x20);
|
|
break;
|
|
}
|
|
|
|
switch (m->standard) {
|
|
case MSP3430_PAL:
|
|
SetMSP3430Data(m, WR_DSP, 0x00, 0x0e, 0x24, 0x03);
|
|
SetMSP3430Data(m, WR_DSP, 0x00, 0x10, 0x00, 0x5a);
|
|
SetMSP3430Data(m, WR_DEM, 0x00, 0x20, 0x00, 0x03);
|
|
/* Set volume to FAST_MUTE. */
|
|
SetMSP3430Data(m, WR_DSP, 0x00, 0x00, 0xFF, 0x00);
|
|
break;
|
|
case MSP3430_PAL_DK1:
|
|
SetMSP3430Data(m, WR_DSP, 0x00, 0x0e, 0x24, 0x03);
|
|
SetMSP3430Data(m, WR_DSP, 0x00, 0x10, 0x00, 0x5a);
|
|
SetMSP3430Data(m, WR_DEM, 0x00, 0x20, 0x00, 0x04);
|
|
/* Set volume to FAST_MUTE. */
|
|
SetMSP3430Data(m, WR_DSP, 0x00, 0x00, 0xFF, 0x00);
|
|
break;
|
|
case MSP3430_SECAM: /* is this right ? */
|
|
case MSP3430_NTSC:
|
|
/* Write to DSP, register 0x000E, (prescale FM/FM matrix) */
|
|
SetMSP3430Data(m, WR_DSP, 0x00, 0x0e, 0x24, 0x03);
|
|
|
|
/* Set volume to FAST_MUTE. */
|
|
SetMSP3430Data(m, WR_DSP, 0x00, 0x00, 0xFF, 0x00);
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
/*-----------------------------------------------------------------
|
|
| specific functions for all MSP34x5D chips
|
|
|----------------------------------------------------------------*/
|
|
|
|
void
|
|
InitMSP34x5D(MSP3430Ptr m)
|
|
{
|
|
int count;
|
|
CARD8 high, low;
|
|
CARD16 result, standard;
|
|
CARD16 peak;
|
|
|
|
if (m->c_format == MSPFORMAT_UNKNOWN)
|
|
ResetMSP3430(m);
|
|
else {
|
|
/*mute volume */
|
|
SetMSP3430Data(m, WR_DSP, 0x00, 0x00, 0x00, 0x00);
|
|
}
|
|
|
|
switch (m->connector) {
|
|
case MSP3430_CONNECTOR_2:
|
|
case MSP3430_CONNECTOR_3:
|
|
if (m->c_format != MSPFORMAT_SCART) {
|
|
/* SCART Input Prescale: 0 dB gain */
|
|
SetMSP3430Data(m, WR_DSP, 0x00, 0x0d, 0x19, 0x00);
|
|
/* this has not been checked yet.. could be bogus */
|
|
m->c_format = MSPFORMAT_SCART; /*stereo */
|
|
}
|
|
break;
|
|
case MSP3430_CONNECTOR_1:
|
|
default:
|
|
|
|
switch (m->standard & 0x00ff) {
|
|
case MSP3430_PAL:
|
|
switch (m->standard) {
|
|
case MSP3430_PAL_DK1:
|
|
standard = MSPSTANDARD_FM_DK1;
|
|
break;
|
|
/* case MSP3430_PAL_DK2:
|
|
standard=MSPSTANDARD_FM_DK2;
|
|
break;
|
|
case MSP3430_PAL_BG:
|
|
may be FM stereo (Germany) or FM NICAM (Scandinavia,spain)
|
|
standard=MSPSTANDARD_AUTO;
|
|
break;
|
|
*/
|
|
default:
|
|
standard = MSPSTANDARD_AUTO;
|
|
}
|
|
break;
|
|
case MSP3430_SECAM:
|
|
standard = MSPSTANDARD_AUTO;
|
|
case MSP3430_NTSC:
|
|
/* Only MSP34x5 supported format - Korean NTSC-M */
|
|
standard = MSPSTANDARD_FM_M;
|
|
default:
|
|
standard = MSPSTANDARD_AUTO;
|
|
}
|
|
|
|
/*no NICAM support in MSP3410D - force to autodetect */
|
|
if ((m->chip_id == 0x405) && (standard >= MSPSTANDARD_NICAM_BG))
|
|
standard = MSPSTANDARD_AUTO;
|
|
|
|
if (m->c_standard != standard) {
|
|
|
|
SetMSP3430Data(m, WR_DEM, 0x00, 0x20, standard >> 8,
|
|
standard & 0xFF);
|
|
if (standard == MSPSTANDARD_AUTO) {
|
|
count = 50; /* time shouldn't exceed 1s, just in case */
|
|
do {
|
|
usleep(20000);
|
|
GetMSP3430Data(m, RD_DEM, 0x00, 0x7e, &high, &low);
|
|
result = (high << 8) | low;
|
|
--count;
|
|
} while (result > 0x07ff && count > 0);
|
|
|
|
if ((result > MSPSTANDARD_AUTO))
|
|
standard = result;
|
|
else
|
|
standard = MSPSTANDARD_UNKNOWN;
|
|
#if __MSPDEBUG__ > 1
|
|
xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO,
|
|
"Detected audio standard: %d\n", result);
|
|
#endif
|
|
/* result = MSPSTANDARD_NICAM_L can be one of:
|
|
SECAM_L - MSPSTANDARD_NICAM_L
|
|
D/K1 - MSPSTANDARD_FM_DK1
|
|
D/K2 - MSPSTANDARD_FM_DK2
|
|
D/K-NICAM - MSPSTANDARD_NICAM_DK */
|
|
if (standard == MSPSTANDARD_NICAM_L) {
|
|
if ((m->standard & 0x00ff) == MSP3430_PAL) {
|
|
/* force PAL D/K */
|
|
standard = MSPSTANDARD_FM_DK1;
|
|
SetMSP3430Data(m, WR_DEM, 0x00, 0x20, standard >> 8,
|
|
standard & 0xFF);
|
|
#if __MSPDEBUG__ > 1
|
|
xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO,
|
|
"Detected 6.5MHz carrier - forced to D/K1 !!!\n");
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
m->c_standard = standard;
|
|
} /*end - standard changed */
|
|
else {
|
|
if (standard < MSPSTANDARD_NICAM_BG) {
|
|
/* get old value of ident. mode register */
|
|
GetMSP3430Data(m, RD_DSP, 0x00, 0x15, &high, &low);
|
|
/* reset Ident-Filter */
|
|
SetMSP3430Data(m, WR_DSP, 0x00, 0x14, 0x00, 0x3F);
|
|
/* put back old value to ident. mode register */
|
|
SetMSP3430Data(m, WR_DSP, 0x00, 0x14, 0x00, low);
|
|
}
|
|
}
|
|
|
|
if (standard <= MSPSTANDARD_AUTO) {
|
|
m->c_format = MSPFORMAT_1xFM;
|
|
}
|
|
else if (standard < MSPSTANDARD_NICAM_BG) {
|
|
/* set FM prescale */
|
|
SetMSP3430Data(m, WR_DSP, 0x00, 0x0e, 0x30, 0);
|
|
/* set FM deemphasis */
|
|
SetMSP3430Data(m, WR_DSP, 0x00, 0x0f,
|
|
((standard == MSPSTANDARD_FM_M) ? 0 : 1), 0);
|
|
|
|
/* check if FM2 carrier is present */
|
|
/*turn off FM DC Notch */
|
|
SetMSP3430Data(m, WR_DSP, 0x00, 0x17, 0x00, 0x3f);
|
|
/*matrix source for Quasi-Peak Detector - stereo: ch2->L ch1->R */
|
|
SetMSP3430Data(m, WR_DSP, 0x00, 0x0c, 0x00, 0x20);
|
|
|
|
mpause(250);
|
|
GetMSP3430Data(m, RD_DSP, 0x00, 0x1A, &high, &low);
|
|
peak = (high << 8) | low;
|
|
#if __MSPDEBUG__ > 1
|
|
xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO,
|
|
"Second carrier Quasi-Peak detection: %d\n", peak);
|
|
#endif
|
|
/*turn on FM DC Notch */
|
|
SetMSP3430Data(m, WR_DSP, 0x00, 0x17, 0x00, 0x00);
|
|
|
|
if (peak < 5) {
|
|
/* if second carrier not detected - only mono from first carrier */
|
|
m->c_format = MSPFORMAT_1xFM;
|
|
}
|
|
else {
|
|
m->c_format = MSPFORMAT_2xFM;
|
|
/*start of FM identification process - FM_WAIT
|
|
wait at least 0.5s - used 1s - gives beter resolution */
|
|
mpause(1000);
|
|
}
|
|
}
|
|
else {
|
|
if (standard == MSPSTANDARD_NICAM_L) {
|
|
m->c_format = MSPFORMAT_NICAM_AM;
|
|
/* set AM prescale */
|
|
SetMSP3430Data(m, WR_DSP, 0x00, 0x0e, 0x7C, 0);
|
|
}
|
|
else {
|
|
m->c_format = MSPFORMAT_NICAM_FM;
|
|
/* set FM prescale */
|
|
SetMSP3430Data(m, WR_DSP, 0x00, 0x0e, 0x30, 0);
|
|
}
|
|
/* set FM deemphasis */
|
|
SetMSP3430Data(m, WR_DSP, 0x00, 0x0f, 0x00, 0);
|
|
/* set NICAM prescale to 0dB */
|
|
SetMSP3430Data(m, WR_DSP, 0x00, 0x10, 0x20, 0);
|
|
}
|
|
|
|
break;
|
|
} /*end - case conector */
|
|
|
|
CheckModeMSP34x5D(m);
|
|
|
|
/* Set volume to FAST_MUTE. */
|
|
/*SetMSP3430Data(m, WR_DSP, 0x00, 0x00, 0xFF, 0x00); */
|
|
/*set volume */
|
|
MSP3430SetVolume(m, m->volume);
|
|
|
|
__MSPBEEP} /* EnableMSP34x5D ()... */
|
|
|
|
void
|
|
CheckModeMSP34x5D(MSP3430Ptr m)
|
|
{
|
|
const char stereo_on = 25;
|
|
const char stereo_off = 20;
|
|
const char dual_on = -stereo_on;
|
|
const char dual_off = -stereo_off;
|
|
char detect;
|
|
CARD8 matrix, fmmatrix, source, high, low;
|
|
|
|
fmmatrix = 0; /*no matrix */
|
|
source = 0;
|
|
/*FM*/ switch (m->c_format) {
|
|
case MSPFORMAT_NICAM_FM:
|
|
case MSPFORMAT_NICAM_AM:
|
|
case MSPFORMAT_SCART:
|
|
source = ((m->c_format == MSPFORMAT_SCART) ? 2 : 1);
|
|
switch (m->mode) {
|
|
case MSPMODE_MONO:
|
|
matrix = 0x30;
|
|
/*MONO*/ break;
|
|
case MSPMODE_A:
|
|
matrix = 0x00;
|
|
/*A*/ break;
|
|
case MSPMODE_B:
|
|
matrix = 0x10;
|
|
/*B*/ break;
|
|
default:
|
|
matrix = 0x20;
|
|
/*STEREO*/ break;
|
|
}
|
|
break;
|
|
default:
|
|
case MSPFORMAT_1xFM:
|
|
matrix = 0x00;
|
|
/*A*/ break;
|
|
case MSPFORMAT_2xFM:
|
|
switch (m->mode) {
|
|
case MSPMODE_MONO:
|
|
matrix = 0x30;
|
|
/*MONO*/ break;
|
|
case MSPMODE_STEREO:
|
|
matrix = 0x20;
|
|
/*STEREO*/ fmmatrix = ((m->c_standard == MSPSTANDARD_FM_M) ? 2 : 1);
|
|
break;
|
|
case MSPMODE_AB:
|
|
matrix = 0x20;
|
|
/*STEREO*/ break;
|
|
case MSPMODE_A:
|
|
matrix = 0x00;
|
|
/*A*/ break;
|
|
case MSPMODE_B:
|
|
matrix = 0x10;
|
|
/*B*/ break;
|
|
default:
|
|
/*FM_IDENT_CHECK */
|
|
GetMSP3430Data(m, RD_DSP, 0x00, 0x18, &high, &low);
|
|
detect = (char) high;
|
|
#if __MSPDEBUG__ > 1
|
|
xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO,
|
|
"Stereo Detection Register: %d\n", detect);
|
|
#endif
|
|
if (detect >=
|
|
((m->c_mode == MSPMODE_STEREO) ? stereo_off : stereo_on)) {
|
|
m->c_mode = MSPMODE_STEREO;
|
|
matrix = 0x20;
|
|
/*STEREO*/
|
|
fmmatrix = ((m->c_standard == MSPSTANDARD_FM_M) ? 2 : 1);
|
|
}
|
|
else if (detect <= ((m->c_mode == MSPMODE_AB) ? dual_off : dual_on)) {
|
|
m->c_mode = MSPMODE_AB;
|
|
switch (m->mode) {
|
|
case MSPMODE_STEREO_AB:
|
|
matrix = 0x20;
|
|
break;
|
|
case MSPMODE_STEREO_B:
|
|
matrix = 0x10;
|
|
break;
|
|
default:
|
|
case MSPMODE_A:
|
|
matrix = 0x00;
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
m->c_mode = MSPMODE_MONO;
|
|
matrix = 0x30;
|
|
/*MONO*/}
|
|
break;
|
|
} /* end - case mode */
|
|
break;
|
|
}
|
|
|
|
if (m->c_fmmatrix != fmmatrix) {
|
|
GetMSP3430Data(m, RD_DSP, 0x00, 0x0e, &high, &low);
|
|
SetMSP3430Data(m, WR_DSP, 0x00, 0x0e, high, fmmatrix);
|
|
m->c_fmmatrix = fmmatrix;
|
|
}
|
|
|
|
if ((m->c_matrix != matrix) || (m->c_source != source)) {
|
|
/*set chanel source and matrix for loudspeaker */
|
|
SetMSP3430Data(m, WR_DSP, 0x00, 0x08, source, matrix);
|
|
|
|
m->c_matrix = matrix;
|
|
m->c_source = source;
|
|
}
|
|
|
|
if (((m->c_format) & 0xF0) == MSPFORMAT_NICAM)
|
|
SetMSP3430Data(m, WR_DEM, 0x00, 0x21, 0, 1);
|
|
|
|
#if __MSPDEBUG__ > 0
|
|
char *msg;
|
|
|
|
switch (matrix) {
|
|
case 0x30:
|
|
/*MONO*/ msg = "MONO";
|
|
break;
|
|
case 0x00:
|
|
/*LEFT*/ msg = "MONO/CHANNEL_1";
|
|
break;
|
|
case 0x10:
|
|
/*RIGHT*/ msg = "MONO/CHANNEL_2";
|
|
break;
|
|
case 0x20:
|
|
/*LEFT*/ msg = "STEREO";
|
|
break;
|
|
default:
|
|
msg = "unknown";
|
|
break;
|
|
}
|
|
xf86DrvMsg(m->d.pI2CBus->scrnIndex, X_INFO, "Audio mode set to: %s\n", msg);
|
|
#endif
|
|
}
|