📄 nim_audio.c
字号:
/*
* Copyright (c) 1998,1999 by TriMedia Technologies.
*
* +------------------------------------------------------------------+
* | This software is furnished under a license and may only be used |
* | and copied in accordance with the terms and conditions of such |
* | a license and with the inclusion of this copyright notice. This |
* | software or any other copies of this software may not be provided|
* | or otherwise made available to any other person. The ownership |
* | and title of this software is not transferred. |
* | |
* | The information in this software is subject to change without |
* | any prior notice and should not be construed as a commitment by |
* | TriMedia Technologies. |
* | |
* | this code and information is provided "as is" without any |
* | warranty of any kind, either expressed or implied, including but |
* | not limited to the implied warranties of merchantability and/or |
* | fitness for any particular purpose. |
* +------------------------------------------------------------------+
*
* Module name : nim_audio.c 1.14
*
* Last update : 18:52:02 - 00/11/09
*
* Description :
* This file covers the nim AUDIO IN Board dependent code
*
* Revision :
*
*
*/
/*
* Notes on unfinished business in NIM audio:
* 1) There is no way to have two NIM's at the same time.
* This is supposed to be fixed with rev 3 of the DTV Ref4 board.
* The two IIC lines will be isolated so that they can be addressed individually.
* It's possible that when this is fixed, there will not be a need for two
* sets of NIM functions.
*
* 2) The SPDIF input code expects the tda1315 to be run in stand alone mode.
* In this mode, you cannot read from the internal registers, so you can't
* find out whether the input is PCM or non-PCM.
* Also, the current code masks off the lock bit by writing zero to the
* IIC exander bit. This is probably a bus contention issue, but it keeps
* us from getting too many ISR's when we disconnect a cable.
*
* CJP, July 10, 1999
*/
#include <tmlib/dprintf.h>
#include <tm1/tmAssert.h>
#include <tm1/tmProcessor.h>
#include <tm1/tmAvFormats.h>
#include <tm1/mmio.h>
#include <tm1/tmAI.h>
#include <tm1/tmIIC.h>
#include "iicDirection.h"
#include "nim.h"
#include "tda1315.h"
/* determined from procID at start */
static Float CPUClock = 1.0;
static Bool use9xMode = False;
static Char inputL3Regs[2] = {0x0, 0x0};
static l3Param_t inputL3Params =
{
l3ModeIIC, /* mode */
VIDMUX_IIC_EXPANDER_ADDRESS, /* address */
TDA1315_L3_ADDRESS, /* l3Address */
NIM_INPUT_L3_DATA, /* l3Data */
NIM_INPUT_L3_MODE, /* l3Mode */
NIM_INPUT_L3_CLOCK, /* l3Clock */
NIM_INPUT_L3_STROBE, /* usrPin0 */
0, /* usrPin1 */
0, /* usrPin2 */
0, /* l3AddressAdd */
0, /* l3DataAdd */
0, /* l3ModeAdd */
0, /* l3ClockAdd */
0, /* usrPin0Add */
0, /* usrPin2Add */
0, /* usrPin3Add */
2, /* numberOfBytes */
Null /* data */
};
/********************* AUDIO INPUT **********************************/
/* Input IIC expander, the interrupt pin of this iic expander (low active) is
connected to the user IRQ pin of the TriMedia. An interrupt is generated when
the level changes on one of its inputs.
address 0x72
bit 0 Tuner audio (1= enable, 0 = disable)
bit 1 Analog audio (1 = enable, 0 = disable)
bit 2 copyprotection input
bit 3 powerdown output
bit 4 lock/unlock input
bit 5 48.0 kHz input
bit 6 44.1 kHz input
bit 7 32.0 kHz input
*/
/* L3 IIC expander:
address: 0x74
bit 0 Dout L3 mode
bit 1 Dout L3 clock
bit 2 Dout L3 data
bit 3 Dout L3 strobe
bit 4 Mute SPDIF TX
bit 5 AOSD GATE
bit 6 unused
bit 7 unused
*/
/* There are NIM functions for both AI's, but until Ref4v3, there is no
* way to tell which one is which.
*/
/***********************************************************************************************
*
* AI 1 support (used on TM1 and TM2)
*
***********************************************************************************************/
static UInt nimAi1Input;
static UInt nimAi1AudioTypeFormat;
static UInt nimAi1AudioSbtypeFormat;
static Float nimAi1SRate;
static Int nimAi1Size;
/* function called in aiInstanceSetup(): On success, must leave
* the audio input system "stopped" but otherwise ready for action.
* MMIO setup will be done, as well as other board or codec specific
* actions like setting IIC control bits or initializing codec registers.
*/
extern tmLibdevErr_t nim_AI1_Init(boardAIParam_t *param)
{
UInt iicd;
Float val;
pprocCapabilities_t procCap;
Int err = TMLIBDEV_OK;
Bool nimBoardRevision2 = True;
UInt32 ID;
Char *boardName;
err = tsaBoardGetBoard(&ID, &boardName);
if (err)
return err;
/* get the clock frequency of the TriMedia CPU */
err = procGetCapabilities(&procCap);
if (err) return err;
CPUClock = (Float) procCap->cpuClockFrequency;
if (procCap->deviceID == PROC_DEVICE_TM1000) use9xMode = False;
else use9xMode = True;
err = iicDirectionSelect(IIC_DIRECTION_NIM1);
if (err != TMLIBDEV_OK)
return err;
err = iicReadReg(AUDIO_SELECT_ID_EXPANDER_ADDRESS, -1, &iicd);
if (err)
nimBoardRevision2 = False;
/* set strobe to zero */
err = iicReadReg(VIDMUX_IIC_EXPANDER_ADDRESS, -1, &iicd);
iicd &= ~(NIM_INPUT_L3_STROBE);
err |= iicWriteReg(VIDMUX_IIC_EXPANDER_ADDRESS, -1, iicd);
if (err)
goto nim_AI1_InitExit;
/* reset input iic expander */
iicd = 0xEC; /* disable both CS53331's, mask off lock ISR */
err |= iicWriteReg(INPUT_IIC_EXPANDER_ADDRESS, -1, iicd);
if (err)
goto nim_AI1_InitExit;
aiRESETM(AI1_STATUS);
/* clock freq is in hz. Math is 32 bit- should be 64 bit!
In the digital input mode the clock is only needed to use the L3 interface.
In this case is the TriMedia clock slave.
In the analog input mode the clocks are needed because the CS5331 is clock
slave. */
val = param->sRate * 256; /* 256 * sampleRate */
if (use9xMode)
{
val = 0.5 + (477218588.0 * (val / CPUClock)); /* 2**32 / 9 */
aiSetFREQM(AI1_STATUS, ((UInt) val) | 0x80000000);
}
else
{
val = 0.5 + (1431655765.0 * (val / CPUClock)); /* 2**32 / 3 */
aiSetFREQM(AI1_STATUS, (UInt) val);
}
if (param->input == aaaNone)
{
param->input = aaaLineInput; /* line input is the default */
}
switch (param->input)
{
case aaaDigitalInput: /* use TDA 1315 */
if (nimBoardRevision2)
{
err = iicReadReg(AUDIO_SELECT_ID_EXPANDER_ADDRESS, -1, &iicd);
tmAssert(err == TMLIBDEV_OK, err);
iicd &= ~NIM_AUDIO_SELECT_MASK;
iicd |= NIM_AUDIO_SELECT_DIGITAL;
err = iicWriteReg(AUDIO_SELECT_ID_EXPANDER_ADDRESS, -1, iicd);
tmAssert(err == TMLIBDEV_OK, err);
}
/* set a small value for the input DDS frequency to disable the CS5331 */
aiSetFREQM(AI1_STATUS, ((UInt) val & 0x7fffffff) >> 4);
/* set powerdown for input TDA1315 to zero (normal operation) */
err = iicReadReg(INPUT_IIC_EXPANDER_ADDRESS, -1, &iicd);
tmAssert(err == TMLIBDEV_OK, err);
iicd &= ~(NIM_TDA1315_IN_IIC_POWERDOWN);
/* Enable Analog audio input */
iicd &= ~(NIM_TDA1315_IN_IIC_TUNER_AUDIO | NIM_TDA1315_IN_IIC_ANALOG_AUDIO);
err = iicWriteReg(INPUT_IIC_EXPANDER_ADDRESS, -1, iicd);
tmAssert(err == TMLIBDEV_OK, err);
microsleep(1000);
/* initalize the tda1315 */
inputL3Params.data = &inputL3Regs[0];
err = tda1315InitInput(&inputL3Params, param);
aiDisableSER_MASTERM(AI1_STATUS); /* tda1315 is master of clock */
microsleep(10); /* wait until internal state of audio in unit is stable */
if (err == TMLIBDEV_OK)
{
aiSetCAP_MODEM(AI1_STATUS, 3); /* Stereo 16 bits per sample */
aiDisableSIGN_CONVERTM(AI1_STATUS);
aiMsbFirstM(AI1_STATUS); /* MSB first */
aiSetFRAMEMODEM(AI1_STATUS, 0); /* ignore valid bit */
aiSampleRisingCLOCK_EDGEM(AI1_STATUS); /* sample on rising edge */
aiStartFallingEdgeWSM(AI1_STATUS);
aiSetSSPOSM(AI1_STATUS, 0);
aiSetLEFTPOSM(AI1_STATUS, 0);
aiSetRIGHTPOSM(AI1_STATUS, 32);
aiSetSIZEM(AI1_STATUS, param->size);
#ifdef __LITTLE_ENDIAN__
aiEnableLITTLE_ENDIANM(AI1_STATUS);
#else
aiDisableLITTLE_ENDIANM(AI1_STATUS);
#endif
}
else
goto nim_AI1_InitExit;
nimAi1Input = aaaDigitalInput;
break;
case aaaLineInput: /* use CS5331 */
case aaaAuxInput1: /* tuner audio in, use CS5331 */
if (nimBoardRevision2)
{
err = iicReadReg(AUDIO_SELECT_ID_EXPANDER_ADDRESS, -1, &iicd);
tmAssert(err == TMLIBDEV_OK, err);
iicd &= ~NIM_AUDIO_SELECT_MASK;
if (param->input == aaaAuxInput1)
iicd |= NIM_AUDIO_SELECT_TUNER;
else
iicd |= NIM_AUDIO_SELECT_ANALOG;
err = iicWriteReg(AUDIO_SELECT_ID_EXPANDER_ADDRESS, -1, iicd);
tmAssert(err == TMLIBDEV_OK, err);
}
else
{
if (param->input == aaaAuxInput1)
return AIO_ERR_UNSUPPORTED_INPUT; /* tuner is only supported on rev2 */
}
aiDisableSER_MASTERM(AI1_STATUS); /* TM is master of clock */
microsleep(2); /* wait until internal state of audio in unit is stable */
/* set powerdown for input TDA1315 to one (disable it) */
err = iicReadReg(INPUT_IIC_EXPANDER_ADDRESS, -1, &iicd);
iicd |= NIM_TDA1315_IN_IIC_POWERDOWN;
/* Set over sampling clock for the right ADC */
iicd &= ~(NIM_TDA1315_IN_IIC_TUNER_AUDIO | NIM_TDA1315_IN_IIC_ANALOG_AUDIO);
/* Enable clock to the requested ADC */
if (param->input == aaaAuxInput1)
iicd |= (NIM_TDA1315_IN_IIC_TUNER_AUDIO);
else
iicd |= (NIM_TDA1315_IN_IIC_ANALOG_AUDIO);
err |= iicWriteReg(INPUT_IIC_EXPANDER_ADDRESS, -1, iicd);
if (err)
goto nim_AI1_InitExit;
microsleep(1000);
aiSetWSDIVM(AI1_STATUS, 63);
aiSetSCKDIVM(AI1_STATUS, 3);
aiSetCAP_MODEM(AI1_STATUS, 3); /* Stereo 16 bits per sample */
aiDisableSIGN_CONVERTM(AI1_STATUS);
aiMsbFirstM(AI1_STATUS); /* MSB first */
aiSetFRAMEMODEM(AI1_STATUS, 0); /* ignore valid bit */
aiSampleRisingCLOCK_EDGEM(AI1_STATUS); /* sample on rising edge */
aiStartFallingEdgeWSM(AI1_STATUS); /* left sample starts on neg. AI_WS */
aiSetSSPOSM(AI1_STATUS, 0);
aiSetLEFTPOSM(AI1_STATUS, 0);
aiSetRIGHTPOSM(AI1_STATUS, 32);
aiSetSIZEM(AI1_STATUS, param->size);
#ifdef __LITTLE_ENDIAN__
aiEnableLITTLE_ENDIANM(AI1_STATUS);
#else
aiDisableLITTLE_ENDIANM(AI1_STATUS);
#endif
nimAi1Input = aaaLineInput;
break;
default:
err = AIO_ERR_UNSUPPORTED_INPUT;
break;
}
/* store parameters */
nimAi1AudioTypeFormat = param->audioTypeFormat;
nimAi1AudioSbtypeFormat = param->audioSubtypeFormat;
nimAi1SRate = param->sRate;
nimAi1Size = param->size;
nim_AI1_InitExit:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -