/****************************************************************************
 * 3430.C                                                                   *
 *                                                                          *
 * Purpose: functions that enable the MSP3430 sound chip on AiW128 boards   *
 *                                                                          *
 * Copyright (C) 1999 ATI Technologies Inc.  All rights reserved.           *
 ****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <ctype.h>
#include <string.h>
#include "main.h"
#include "defines.h"
#include "regdef.h"

extern _I2C_INFO I2C_INFO;

void EnableMSP3430 (void)
{
    // Reset the MSP3430
    SetMSP3430Control (0x00, 0x80, 0x00);
    // Set it back to normal operation
    SetMSP3430Control (0x00, 0x00, 0x00);

    // Set MODUS register for:
    // bit 0 - automatic sound selection
    // bit 1 - enable STATUS change
    // bit 13 - detect 4.5 MHz carrier as BTSC
    SetMSP3430Data (WR_DEM, 0x00, 0x30, 0x20, 0x03);

    // Set STANDARD SELECTION register to M-BTSC-Stereo
    SetMSP3430Data (WR_DEM, 0x00, 0x20, 0x00, 0x20);

    // Write to DSP, register 0x000E, (prescale FM/FM matrix)
    SetMSP3430Data (WR_DSP, 0x00, 0x0e, 0x24, 0x03);

    // Write to DSP, register 0x0008, (loudspeaker channel source/matrix)
    // This sets the source to the TV tuner, for stereo operation
    SetMSP3430Data (WR_DSP, 0x00, 0x08, 0x03, 0x20);

    // Set volume to 0 db.
    SetMSP3430Data (WR_DSP, 0x00, 0x00, 0x73, 0x00);

    // Write to DSP, register 0x0008, (loudspeaker channel source/matrix)
    // This sets the source to the TV tuner, for stereo operation
    SetMSP3430Data (WR_DSP, 0x00, 0x08, 0x03, 0x20);

    return;

} // EnableMSP3430 ()...


void DisableMSP3430 (void)
{
    ResetMSP3430 ();
    SetMSP3430Data (0x12, 0x00, 0x00, 0xFF, 0x00);
}


void SetMSP3430Data (BYTE RegAddress, BYTE RegSubAddressHigh, BYTE RegSubAddressLow,
                     BYTE RegValueHigh, BYTE RegValueLow)
{
    BYTE  retval, data[16], counter;
    _I2C_PACKET Packet;

    // set data
    data[0] = RegAddress;
    data[1] = RegSubAddressHigh;
    data[2] = RegSubAddressLow;
    data[3] = RegValueHigh;
    data[4] = RegValueLow;
    Packet.data = data;
    Packet.start = 1;
    Packet.stop = 1;
    Packet.number_of_bytes = 5;
    Packet.address = MSP3430;
    counter = 0;

    do
    {
        retval = I2C_Set (&Packet);
        counter += 1;
    }
    while ((counter < 5) && (retval != I2C_DONE));

    return;

} // SetMSP3430Data ()...


void SetMSP3430Control (BYTE RegAddress, BYTE RegValueHigh, BYTE RegValueLow)
{
    BYTE  retval, data[16];
    BYTE counter = 0;
    _I2C_PACKET Packet;

    // set data
    data[0] = RegAddress;
    data[1] = RegValueHigh;
    data[2] = RegValueLow;
    Packet.data = data;
    Packet.start = 1;
    Packet.stop = 1;
    Packet.number_of_bytes = 3;
    Packet.address = MSP3430;

    do
    {
        retval = I2C_Set (&Packet);
        counter += 1;
    }
    while ((counter < 5) && (retval != I2C_DONE));

    return;

} // SetMSP3430Control ()...


void GetMSP3430Data (BYTE RegAddress, BYTE RegSubAddressHigh, BYTE RegSubAddressLow,
                 BYTE *RegValueHigh, BYTE *RegValueLow)
{
    BYTE  retval, data[16];
    BYTE counter = 0;
    _I2C_PACKET Packet;

    // set data
    data[0] = RegAddress;
    data[1] = RegSubAddressHigh;
    data[2] = RegSubAddressLow;

    Packet.data = data;
    Packet.start = 1;
    // NO STOP BIT!! The 3430 does not want a stop bit during this particular
    // transfer.  See the spec.
    Packet.stop = 0;
    Packet.number_of_bytes = 3;
    Packet.address = MSP3430;

    do
    {
        retval = I2C_Set (&Packet);
        counter += 1;
    }
    while ((counter < 5) && (retval != I2C_DONE));

    // set data
    Packet.address = MSP3430 | 0x1;
    Packet.number_of_bytes = 2;
    Packet.start = 1;
    Packet.stop = 1;
    do
    {
        retval = I2C_Get (&Packet);
        counter += 1;
    }
    while ((counter < 5) && (retval != I2C_DONE));

    *RegValueHigh = data[0];
    *RegValueLow = data[1];

    return;
}  // GetMSP3430Data ()...


WORD ReadI2CWord (WORD Register, WORD SubAddr)
{
    BYTE RegValueHi, RegValueLo;
    WORD retval = 0;

    GetMSP3430Data (Register, (BYTE)((SubAddr >> 8) & 0x00FF), (BYTE)(SubAddr & 0x00FF),
                    &RegValueHi, &RegValueLo);

    retval = (RegValueHi << 8) | RegValueLo & 0xFFFF;

    return (retval);

} // ReadI2CWord ()...


void WriteI2CWord (WORD Register, WORD SubAddr, WORD Data)
{

    SetMSP3430Data (Register, (BYTE)((SubAddr >> 8) & 0x00FF), (BYTE)(SubAddr & 0xFF00),
                    (Data >> 8 & 0x00FF), (Data & 0x00FF));

    return;

} // WriteI2CWord ()...


void ResetMSP3430 (void)
{
    // Reset the MSP3430
    SetMSP3430Control (0x00, 0x80, 0x00);
    // Set it back to normal operation
    SetMSP3430Control (0x00, 0x00, 0x00);
}

void MSP3430_SetVolume (BYTE value)
{
    WORD result;

    result = ReadI2CWord (RD_DSP, 0x0000);
    result &= 0x00FF; // clear volume bits.

    WriteI2CWord (WR_DSP, 0x0000, ((value << 8) | result) );
}
