More es1371 bij Pieter Hijma.

This commit is contained in:
Ben Gras 2007-11-23 11:52:34 +00:00
parent c67a56708e
commit b79b305ba1
6 changed files with 944 additions and 0 deletions

502
drivers/audio/es1371/AC97.c Normal file
View file

@ -0,0 +1,502 @@
#include "AC97.h"
/* AC97 Mixer and Mode control function prototypes */
FORWARD _PROTOTYPE( int AC97_read,
(DEV_STRUCT * pCC, u16_t wAddr, u16_t *data) );
FORWARD _PROTOTYPE( int AC97_write,
(DEV_STRUCT * pCC, u16_t wAddr, u16_t wData) );
FORWARD _PROTOTYPE( void set_src_sync_state, (int state) );
FORWARD _PROTOTYPE( int AC97_write_unsynced,
(DEV_STRUCT * pCC, u16_t wAddr, u16_t wData) );
FORWARD _PROTOTYPE( int AC97_read_unsynced,
(DEV_STRUCT * pCC, u16_t wAddr, u16_t *data) );
FORWARD _PROTOTYPE( void set_nice_volume, (void) );
FORWARD _PROTOTYPE( int AC97_get_volume, (struct volume_level *level) );
FORWARD _PROTOTYPE( int AC97_set_volume, (struct volume_level *level) );
#define AC97_0DB_GAIN 0x0008
#define AC97_MAX_ATTN 0x003f
#define AC97_MUTE 0x8000U
/* Control function defines */
#define AC97_CTL_4SPKR 0x00U /* 4-spkr output mode enable */
#define AC97_CTL_MICBOOST 0x01U /* Mic boost (+30 dB) enable */
#define AC97_CTL_PWRDOWN 0x02U /* power-down mode */
#define AC97_CTL_DOSMODE 0x03U /* A/D sync to DAC1 */
/* Timeout waiting for: */
#define AC97_ERR_WIP_TIMEOUT -1 /* write in progress complete */
#define AC97_ERR_DATA_TIMEOUT -2 /* data ready */
#define AC97_ERR_SRC_NOT_BUSY_TIMEOUT -3 /* SRC not busy */
#define AC97_ERR_SRC_SYNC_TIMEOUT -4 /* state #1 */
/* Timeouts in milliseconds */
#define WIP_TIMEOUT 250UL
#define DRDY_TIMEOUT 250UL
/* The default SRC syncronization state number is 1. This state occurs
just after de-assertion of SYNC. This is supposed to be the safest
state for accessing the codec with an ES1371 Rev 1. Later versions
of the chip allegedly don't require syncronization. Be very careful
if you change this ! */
#define SRC_UNSYNCED 0xffffffffUL
static u32_t SrcSyncState = 0x00010000UL;
static DEV_STRUCT *dev;
PRIVATE void set_src_sync_state (int state)
{
if (state < 0)
SrcSyncState = SRC_UNSYNCED;
else {
SrcSyncState = (u32_t)state << 16;
SrcSyncState &= 0x00070000Ul;
}
}
PRIVATE int AC97_write (DEV_STRUCT * pCC, u16_t wAddr, u16_t wData)
{
u32_t dtemp, i;
u16_t wBaseAddr = pCC->base;
/* wait for WIP bit (Write In Progress) to go away */
/* remember, register CODEC_READ (0x14)
is a pseudo read-write register */
if (WaitBitd (wBaseAddr + CODEC_READ, 30, 0, WIP_TIMEOUT)){
printf("AC97_ERR_WIP_TIMEOUT\n");
return (AC97_ERR_WIP_TIMEOUT);
}
if (SRC_UNSYNCED != SrcSyncState)
{
/* enable SRC state data in SRC mux */
if (WaitBitd (wBaseAddr + SAMPLE_RATE_CONV, SRC_BUSY_BIT, 0, 1000))
return (AC97_ERR_SRC_NOT_BUSY_TIMEOUT);
/* todo: why are we writing an undefined register? */
dtemp = pci_inl(wBaseAddr + SAMPLE_RATE_CONV);
pci_outl(wBaseAddr + SAMPLE_RATE_CONV, (dtemp & SRC_CTLMASK) |
0x00010000UL);
/* wait for a SAFE time to write addr/data and then do it */
/*_disable(); */
for( i = 0; i < 0x1000UL; ++i )
if( (pci_inl(wBaseAddr + SAMPLE_RATE_CONV) & 0x00070000UL) ==
SrcSyncState )
break;
if (i >= 0x1000UL) {
/* _enable(); */
return (AC97_ERR_SRC_SYNC_TIMEOUT);
}
}
/* A test for 5880 - prime the PCI data bus */
{
u32_t dat = ((u32_t) wAddr << 16) | wData;
char page = pci_inb(wBaseAddr + MEM_PAGE);
pci_outl (wBaseAddr + MEM_PAGE, dat);
/* write addr and data */
pci_outl(wBaseAddr + CODEC_READ, dat);
pci_outb(wBaseAddr + MEM_PAGE, page); /* restore page reg */
}
if (SRC_UNSYNCED != SrcSyncState)
{
/* _enable(); */
/* restore SRC reg */
if (WaitBitd (wBaseAddr + SAMPLE_RATE_CONV, SRC_BUSY_BIT, 0, 1000))
return (AC97_ERR_SRC_NOT_BUSY_TIMEOUT);
pci_outl(wBaseAddr + SAMPLE_RATE_CONV, dtemp & 0xfff8ffffUL);
}
return 0;
}
PRIVATE int AC97_read (DEV_STRUCT * pCC, u16_t wAddr, u16_t *data)
{
u32_t dtemp, i;
u16_t base = pCC->base;
/* wait for WIP to go away */
if (WaitBitd (base + CODEC_READ, 30, 0, WIP_TIMEOUT))
return (AC97_ERR_WIP_TIMEOUT);
if (SRC_UNSYNCED != SrcSyncState)
{
/* enable SRC state data in SRC mux */
if (WaitBitd (base + SAMPLE_RATE_CONV, SRC_BUSY_BIT, 0, 1000))
return (AC97_ERR_SRC_NOT_BUSY_TIMEOUT);
dtemp = pci_inl(base + SAMPLE_RATE_CONV);
pci_outl(base + SAMPLE_RATE_CONV, (dtemp & SRC_CTLMASK) |
0x00010000UL);
/* wait for a SAFE time to write a read request and then do it */
/* todo: how do we solve the lock() problem? */
/* _disable(); */
for( i = 0; i < 0x1000UL; ++i )
if( (pci_inl(base + SAMPLE_RATE_CONV) & 0x00070000UL) ==
SrcSyncState )
break;
if (i >= 0x1000UL) {
/*_enable();*/
return (AC97_ERR_SRC_SYNC_TIMEOUT);
}
}
/* A test for 5880 - prime the PCI data bus */
{
/* set bit 23, this means read in stead of write. */
u32_t dat = ((u32_t) wAddr << 16) | (1UL << 23);
char page = pci_inb(base + MEM_PAGE);
/* todo: why are we putting data in the mem page register??? */
pci_outl(base + MEM_PAGE, dat);
/* write addr w/data=0 and assert read request */
pci_outl(base + CODEC_READ, dat);
pci_outb(base + MEM_PAGE, page); /* restore page reg */
}
if (SRC_UNSYNCED != SrcSyncState)
{
/*_enable();*/
/* restore SRC reg */
if (WaitBitd (base + SAMPLE_RATE_CONV, SRC_BUSY_BIT, 0, 1000))
return (AC97_ERR_SRC_NOT_BUSY_TIMEOUT);
pci_outl(base + SAMPLE_RATE_CONV, dtemp & 0xfff8ffffUL);
}
/* now wait for the stinkin' data (DRDY = data ready) */
if (WaitBitd (base + CODEC_READ, 31, 1, DRDY_TIMEOUT))
return (AC97_ERR_DATA_TIMEOUT);
dtemp = pci_inl(base + CODEC_READ);
if (data)
*data = (u16_t) dtemp;
return 0;
}
PRIVATE int AC97_write_unsynced (DEV_STRUCT * pCC, u16_t wAddr, u16_t wData)
{
/* wait for WIP to go away */
if (WaitBitd (pCC->base + CODEC_READ, 30, 0, WIP_TIMEOUT))
return (AC97_ERR_WIP_TIMEOUT);
/* write addr and data */
pci_outl(pCC->base + CODEC_READ, ((u32_t) wAddr << 16) | wData);
return 0;
}
PRIVATE int AC97_read_unsynced (DEV_STRUCT * pCC, u16_t wAddr, u16_t *data)
{
u32_t dtemp;
/* wait for WIP to go away */
if (WaitBitd (pCC->base + CODEC_READ, 30, 0, WIP_TIMEOUT))
return (AC97_ERR_WIP_TIMEOUT);
/* write addr w/data=0 and assert read request */
pci_outl(pCC->base + CODEC_READ, ((u32_t) wAddr << 16) | (1UL << 23));
/* now wait for the stinkin' data (RDY) */
if (WaitBitd (pCC->base + CODEC_READ, 31, 1, DRDY_TIMEOUT))
return (AC97_ERR_DATA_TIMEOUT);
dtemp = pci_inl(pCC->base + CODEC_READ);
if (data)
*data = (u16_t) dtemp;
return 0;
}
int AC97_init( DEV_STRUCT * pCC ) {
int retVal;
/* All powerdown modes: off */
dev = pCC;
retVal = AC97_write (pCC, AC97_POWERDOWN_CONTROL_STAT, 0x0000U);
if (OK != retVal)
return (retVal);
/* Mute Line Out & set to 0dB attenuation */
retVal = AC97_write (pCC, AC97_MASTER_VOLUME, 0x0000U);
if (OK != retVal)
return (retVal);
retVal = AC97_write (pCC, AC97_MONO_VOLUME, 0x8000U);
if (OK != retVal)
return (retVal);
retVal = AC97_write (pCC, AC97_PHONE_VOLUME, 0x8008U);
if (OK != retVal)
return (retVal);
retVal = AC97_write (pCC, AC97_MIC_VOLUME, 0x0008U);
if (OK != retVal)
return (retVal);
retVal = AC97_write (pCC, AC97_LINE_IN_VOLUME, 0x0808U);
if (OK != retVal)
return (retVal);
retVal = AC97_write (pCC, AC97_CD_VOLUME, 0x0808U);
if (OK != retVal)
return (retVal);
retVal = AC97_write (pCC, AC97_AUX_IN_VOLUME, 0x0808U);
if (OK != retVal)
return (retVal);
retVal = AC97_write (pCC, AC97_PCM_OUT_VOLUME, 0x0808U);
if (OK != retVal)
return (retVal);
retVal = AC97_write (pCC, AC97_RECORD_GAIN_VOLUME, 0x0000U);
if (OK != retVal)
return (retVal);
/* Connect Line In to ADC */
retVal = AC97_write (pCC, AC97_RECORD_SELECT, 0x0404U);
if (OK != retVal)
return (retVal);
retVal = AC97_write (pCC, AC97_GENERAL_PURPOSE, 0x0000U);
if (OK != retVal)
return (retVal);
set_nice_volume();
return OK;
}
PRIVATE void set_nice_volume(void) {
/* goofy code to set the DAC1 channel to an audibe volume
to be able to test it without using the mixer */
AC97_write_unsynced(dev, AC97_PCM_OUT_VOLUME, 0x0808);/* the higher,
the softer */
AC97_write_unsynced(dev, AC97_MASTER_VOLUME, 0x0101);
AC97_write_unsynced(dev, 0x38, 0); /* not crucial */
AC97_write_unsynced(dev, AC97_LINE_IN_VOLUME, 0x0303);
AC97_write_unsynced(dev, AC97_MIC_VOLUME, 0x005f);
/* mute record gain */
AC97_write_unsynced(dev, AC97_RECORD_GAIN_VOLUME, 0xFFFF);
/* mic record volume high */
AC97_write_unsynced(dev, AC97_RECORD_GAIN_MIC_VOL, 0x0000);
/* Also, to be able test recording without mixer:
select ONE channel as input below. */
/* select LINE IN */
/*AC97_write_unsynced(dev, AC97_RECORD_SELECT, 0x0404);*/
/* select MIC */
AC97_write_unsynced(dev, AC97_RECORD_SELECT, 0x0000);
/* unmute record gain */
AC97_write_unsynced(dev, AC97_RECORD_GAIN_VOLUME, 0x0000);
}
PRIVATE int get_volume(u8_t *left, u8_t *right, int cmd) {
u16_t value;
AC97_read_unsynced(dev, (u16_t)cmd, &value);
*left = value>>8;
*right = value&0xff;
return OK;
}
PRIVATE int set_volume(int left, int right, int cmd) {
u16_t waarde;
waarde = (u16_t)((left<<8)|right);
AC97_write_unsynced(dev, (u16_t)cmd, waarde);
return OK;
}
void convert(int left_in, int right_in, int max_in, int *left_out,
int *right_out, int max_out, int swaplr) {
int tmp;
if(left_in < 0) left_in = 0;
else if(left_in > max_in) left_in = max_in;
if(right_in < 0) right_in = 0;
else if(right_in > max_in) right_in = max_in;
if (swaplr) {
tmp = left_in;
left_in = right_in;
right_in = tmp;
}
*left_out = (-left_in) + max_out;
*right_out = (-right_in) + max_out;
}
int AC97_get_set_volume(struct volume_level *level, int flag) {
if (flag) {
return AC97_set_volume(level);
}
else {
return AC97_get_volume(level);
}
}
PRIVATE int AC97_get_volume(struct volume_level *level) {
int cmd;
u8_t left;
u8_t right;
switch(level->device) {
case Master:
cmd = AC97_MASTER_VOLUME;
get_volume(&left, &right, cmd);
convert(left, right, 0x1f,
&(level->left), &(level->right), 0x1f, 0);
break;
case Dac:
return EINVAL;
break;
case Fm:
cmd = AC97_PCM_OUT_VOLUME;
get_volume(&left, &right, cmd);
convert(left, right, 0x1f,
&(level->left), &(level->right), 0x1f, 0);
break;
case Cd:
cmd = AC97_CD_VOLUME;
get_volume(&left, &right, cmd);
convert(left, right, 0x1f,
&(level->left), &(level->right), 0x1f, 0);
break;
case Line:
cmd = AC97_LINE_IN_VOLUME;
get_volume(&left, &right, cmd);
convert(left, right, 0x1f,
&(level->left), &(level->right), 0x1f, 0);
break;
case Mic:
cmd = AC97_MIC_VOLUME;
get_volume(&left, &right, cmd);
convert(left, right, 0x1f,
&(level->left), &(level->right), 0x1f, 1);
break;
case Speaker:
cmd = AC97_PC_BEEP_VOLUME;
return EINVAL;
break;
case Treble:
cmd = AC97_MASTER_TONE;
get_volume(&left, &right, cmd);
convert(left, right, 0xf,
&(level->left), &(level->right), 0xf, 1);
break;
case Bass:
cmd = AC97_MASTER_TONE;
get_volume(&left, &right, cmd);
convert(left, right, 0xf,
&(level->left), &(level->right), 0xf, 1);
break;
default:
return EINVAL;
}
return OK;
}
PRIVATE int AC97_set_volume(struct volume_level *level) {
int cmd;
int left;
int right;
switch(level->device) {
case Master:
cmd = AC97_MASTER_VOLUME;
convert(level->left, level->right, 0x1f, &left, &right, 0x1f, 0);
break;
case Dac:
return EINVAL;
break;
case Fm:
cmd = AC97_PCM_OUT_VOLUME;
convert(level->left, level->right, 0x1f, &left, &right, 0x1f, 0);
break;
case Cd:
cmd = AC97_CD_VOLUME;
convert(level->left, level->right, 0x1f, &left, &right, 0x1f, 0);
break;
case Line:
cmd = AC97_LINE_IN_VOLUME;
convert(level->left, level->right, 0x1f, &left, &right, 0x1f, 0);
break;
case Mic:
cmd = AC97_MIC_VOLUME;
convert(level->left, level->right, 0x1f, &left, &right, 0x1f, 1);
break;
case Speaker:
cmd = AC97_PC_BEEP_VOLUME;
return EINVAL;
break;
case Treble:
cmd = AC97_MASTER_TONE;
return EINVAL;
break;
case Bass:
cmd = AC97_MASTER_TONE;
return EINVAL;
break;
default:
return EINVAL;
}
set_volume(left, right, cmd);
return OK;
}

View file

@ -0,0 +1,98 @@
#ifndef AC97_H
#define AC97_H
#include "es1371.h"
#include "wait.h"
#include "pci_helper.h"
#include "sample_rate_converter.h"
/*
This function initializes the AC97 to a default mode.
*/
int AC97_init( DEV_STRUCT * pCC );
int AC97_get_set_volume(struct volume_level *level, int flag);
/* This is a main memory cache copy of the codec's ac97 configuration
registers. See Intel's Audio Codec 97 standard (rev2.3) for info. */
typedef struct ac97_struct {
u16_t Reset; /* 0x00 */
u16_t MasterVolume; /* 0x02 */
u16_t AUXOutVolume; /* 0x04 */
u16_t MonoVolume; /* 0x06 */
u16_t MasterTone; /* 0x08 */
u16_t PCBeepVolume; /* 0x0A */
u16_t PhoneVolume; /* 0x0C */
u16_t MicVolume; /* 0x0E */
u16_t LineInVolume; /* 0x10 */
u16_t CDVolume; /* 0x12 */
u16_t VideoVolume; /* 0x14 */
u16_t AUXInVolume; /* 0x16 */
u16_t PCMOutVolume; /* 0x18 */
u16_t RecordSelect; /* 0x1A */
u16_t RecordGain; /* 0x1C */
u16_t RecordGainMic; /* 0x1E */
u16_t GeneralPurpose; /* 0x20 */
u16_t Control3D; /* 0x22 */
u16_t AudioIntAndPaging; /* 0x24 */
u16_t PowerdownControlAndStat; /* 0x26 */
u16_t ExtendedAudio1; /* 0x28 */
u16_t ExtendedAudio2; /* 0x2A */
/* ... */
u16_t VendorID1; /* 0x7C */
u16_t VendorID2; /* 0x7E */
} ac97_t;
/* Source and output volume control register defines */
#define AC97_MASTER_VOLUME 0x02U /* Master out */
#define AC97_AUX_OUT_VOLUME 0x04U /* Auxiliary out volume */
#define AC97_MONO_VOLUME 0x06U /* Mono out volume */
#define AC97_MASTER_TONE 0x08U /* high byte= bass, low byte= treble*/
#define AC97_PC_BEEP_VOLUME 0x0aU /* PC speaker volume */
#define AC97_PHONE_VOLUME 0x0cU /* Phone volume */
#define AC97_MIC_VOLUME 0x0eU /* Mic, mono */
#define AC97_LINE_IN_VOLUME 0x10U /* Line volume */
#define AC97_CD_VOLUME 0x12U /* CD audio volume */
#define AC97_VIDEO_VOLUME 0x14U /* Video (TV) volume */
#define AC97_AUX_IN_VOLUME 0x16U /* Aux line source, left */
#define AC97_PCM_OUT_VOLUME 0x18U /* The DACs - wav+synth */
#define AC97_RECORD_GAIN_VOLUME 0x1cU /* Record input level */
#define AC97_RECORD_GAIN_MIC_VOL 0x1eU /* Record input level */
/* Other AC97 control register defines */
#define AC97_RESET 0x00U /* any write here to reset AC97 */
#define AC97_GENERAL_PURPOSE 0x20U /* */
#define AC97_POWERDOWN_CONTROL_STAT 0x26U /* */
#define AC97_RECORD_SELECT 0x1aU /* record mux select */
#define AC97_VENDOR_ID1 0x7cU /* 1st two Vendor ID bytes */
#define AC97_VENDOR_ID2 0x7eU /* last Vendor ID byte plus rev.
number */
/* Record Select defines */
#define AC97_RECORD_MIC 0
#define AC97_RECORD_CD 1
#define AC97_RECORD_VIDEO 2
#define AC97_RECORD_AUX 3
#define AC97_RECORD_LINE 4
#define AC97_RECORD_STEREO_MIX 5
#define AC97_RECORD_MONO_MIX 6
#define AC97_RECORD_PHONE 7
#define MASTER_VOL_MASK 0x1F
#define DAC_VOL_MASK 0x1F
#define AUX_IN_VOL_MASK 0x1F
#define MUTE_MASK 0x8000
#endif /* AC97_H */

View file

@ -0,0 +1,65 @@
/* best viewed with tabsize 4 */
#include "../../drivers.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <minix/sysutil.h>
#include <errno.h>
#include "pci_helper.h"
#include "es1371.h"
/*===========================================================================*
* helper functions for I/O *
*===========================================================================*/
PUBLIC unsigned pci_inb(U16_t port) {
u32_t value;
int s;
if ((s=sys_inb(port, &value)) !=OK)
printf("%s: warning, sys_inb failed: %d\n", DRIVER_NAME, s);
return value;
}
PUBLIC unsigned pci_inw(U16_t port) {
u32_t value;
int s;
if ((s=sys_inw(port, &value)) !=OK)
printf("%s: warning, sys_inw failed: %d\n", DRIVER_NAME, s);
return value;
}
PUBLIC unsigned pci_inl(U16_t port) {
U32_t value;
int s;
if ((s=sys_inl(port, &value)) !=OK)
printf("%s: warning, sys_inl failed: %d\n", DRIVER_NAME, s);
return value;
}
PUBLIC void pci_outb(U16_t port, U8_t value) {
int s;
if ((s=sys_outb(port, value)) !=OK)
printf("%s: warning, sys_outb failed: %d\n", DRIVER_NAME, s);
}
PUBLIC void pci_outw(U16_t port, U16_t value) {
int s;
if ((s=sys_outw(port, value)) !=OK)
printf("%s: warning, sys_outw failed: %d\n", DRIVER_NAME, s);
}
PUBLIC void pci_outl(U16_t port, U32_t value) {
int s;
if ((s=sys_outl(port, value)) !=OK)
printf("%s: warning, sys_outl failed: %d\n", DRIVER_NAME, s);
}

View file

@ -0,0 +1,12 @@
#ifndef PCI_HELPER
#define PCI_HELPER
_PROTOTYPE( unsigned pci_inb, (U16_t port) );
_PROTOTYPE( unsigned pci_inw, (U16_t port) );
_PROTOTYPE( unsigned pci_inl, (U16_t port) );
_PROTOTYPE( void pci_outb, (U16_t port, U8_t value) );
_PROTOTYPE( void pci_outw, (U16_t port, U16_t value) );
_PROTOTYPE( void pci_outl, (U16_t port, U32_t value) );
#endif

View file

@ -0,0 +1,241 @@
#include "sample_rate_converter.h"
#define SRC_RATE 48000U
#define reg(n) DSP->base + n
/* register/base and control equates for the SRC RAM */
#define SRC_SYNTH_FIFO 0x00
#define SRC_DAC_FIFO 0x20
#define SRC_ADC_FIFO 0x40
#define SRC_SYNTH_LVOL 0x7c
#define SRC_SYNTH_RVOL 0x7d
#define SRC_DAC_LVOL 0x7e
#define SRC_DAC_RVOL 0x7f
#define SRC_ADC_LVOL 0x6c
#define SRC_ADC_RVOL 0x6d
#define SRC_TRUNC_N_OFF 0x00
#define SRC_INT_REGS_OFF 0x01
#define SRC_ACCUM_FRAC_OFF 0x02
#define SRC_VFREQ_FRAC_OFF 0x03
/* miscellaneous control defines */
#define SRC_IOPOLL_COUNT 0x1000UL
#define SRC_SYNTHFREEZE (1UL << 21)
#define SRC_DACFREEZE (1UL << 20)
#define SRC_ADCFREEZE (1UL << 19)
FORWARD _PROTOTYPE( int src_reg_read, (DEV_STRUCT * DSP,
u16_t reg, u16_t *data) );
FORWARD _PROTOTYPE( int src_reg_write, (DEV_STRUCT * DSP,
u16_t reg, u16_t val) );
int src_init ( DEV_STRUCT * DSP ) {
u32_t i;
int retVal;
/* Clear all SRC RAM then init - keep SRC disabled until done */
/* Wait till SRC_RAM_BUSY is 0 */
if (WaitBitd (reg(SAMPLE_RATE_CONV), SRC_BUSY_BIT, 0, 1000))
return (SRC_ERR_NOT_BUSY_TIMEOUT);
pci_outl(reg(SAMPLE_RATE_CONV), SRC_DISABLE);
/* from the opensound system driver, no idea where the specification is */
/* there are indeed 7 bits for the addresses of the SRC */
for( i = 0; i < 0x80; ++i ) {
if (SRC_SUCCESS != (retVal = src_reg_write(DSP, (u16_t)i, 0U)))
return (retVal);
}
if (SRC_SUCCESS != (retVal =
src_reg_write(DSP, SRC_SYNTH_BASE + SRC_TRUNC_N_OFF, 16 << 4)))
return (retVal);
if (SRC_SUCCESS != (retVal = src_reg_write(DSP,
SRC_SYNTH_BASE + SRC_INT_REGS_OFF, 16 << 10)))
return (retVal);
if (SRC_SUCCESS != (retVal =
src_reg_write(DSP, SRC_DAC_BASE + SRC_TRUNC_N_OFF, 16 << 4)))
return (retVal);
if (SRC_SUCCESS != (retVal =
src_reg_write(DSP, SRC_DAC_BASE + SRC_INT_REGS_OFF, 16 << 10)))
return (retVal);
if (SRC_SUCCESS != (retVal =
src_reg_write(DSP, SRC_SYNTH_LVOL, 1 << 12)))
return (retVal);
if (SRC_SUCCESS != (retVal =
src_reg_write(DSP, SRC_SYNTH_RVOL, 1 << 12)))
return (retVal);
if (SRC_SUCCESS != (retVal =
src_reg_write(DSP, SRC_DAC_LVOL, 1 << 12)))
return (retVal);
if (SRC_SUCCESS != (retVal =
src_reg_write(DSP, SRC_DAC_RVOL, 1 << 12)))
return (retVal);
if (SRC_SUCCESS != (retVal =
src_reg_write(DSP, SRC_ADC_LVOL, 1 << 12)))
return (retVal);
if (SRC_SUCCESS != (retVal =
src_reg_write(DSP, SRC_ADC_RVOL, 1 << 12)))
return (retVal);
/* default some rates */
src_set_rate(DSP, SRC_SYNTH_BASE, SRC_RATE);
src_set_rate(DSP, SRC_DAC_BASE, SRC_RATE);
src_set_rate(DSP, SRC_ADC_BASE, SRC_RATE);
/* now enable the whole deal */
if (WaitBitd (reg(SAMPLE_RATE_CONV), SRC_BUSY_BIT, 0, 1000))
return (SRC_ERR_NOT_BUSY_TIMEOUT);
pci_outl(reg(SAMPLE_RATE_CONV), 0UL);
return 0;
}
PRIVATE int src_reg_read(DEV_STRUCT * DSP, u16_t reg, u16_t *data) {
u32_t dtemp;
/* wait for ready */
if (WaitBitd (reg(SAMPLE_RATE_CONV), SRC_BUSY_BIT, 0, 1000))
return (SRC_ERR_NOT_BUSY_TIMEOUT);
dtemp = pci_inl(reg(SAMPLE_RATE_CONV));
/* assert a read request */
/*pci_outl(reg(SAMPLE_RATE_CONV),
(dtemp & SRC_CTLMASK) | ((u32_t) reg << 25));*/
pci_outl(reg(SAMPLE_RATE_CONV), (dtemp &
(DIS_REC|DIS_P2|DIS_P1|SRC_DISABLE)) | ((u32_t) reg << 25));
/* now wait for the data */
if (WaitBitd (reg(SAMPLE_RATE_CONV), SRC_BUSY_BIT, 0, 1000))
return (SRC_ERR_NOT_BUSY_TIMEOUT);
if (NULL != data)
*data = (u16_t) pci_inl(reg(SAMPLE_RATE_CONV));
return 0;
}
PRIVATE int src_reg_write(DEV_STRUCT * DSP, u16_t reg, u16_t val) {
u32_t dtemp;
/* wait for ready */
if (WaitBitd (reg(SAMPLE_RATE_CONV), SRC_BUSY_BIT, 0, 1000))
return (SRC_ERR_NOT_BUSY_TIMEOUT);
dtemp = pci_inl(reg(SAMPLE_RATE_CONV));
/* assert the write request */
pci_outl(reg(SAMPLE_RATE_CONV),
(dtemp & SRC_CTLMASK) | SRC_RAM_WE | ((u32_t) reg << 25) | val);
return 0;
}
void src_set_rate(DEV_STRUCT * DSP, char base, u16_t rate) {
u32_t freq, dtemp, i;
u16_t N, truncM, truncStart, wtemp;
if( base != SRC_ADC_BASE )
{
/* freeze the channel */
dtemp = base == SRC_SYNTH_BASE ? SRC_SYNTHFREEZE : SRC_DACFREEZE;
for( i = 0; i < SRC_IOPOLL_COUNT; ++i )
if( !(pci_inl(reg(SAMPLE_RATE_CONV)) & SRC_RAM_BUSY) )
break;
pci_outl(reg(SAMPLE_RATE_CONV),
(pci_inl(reg(SAMPLE_RATE_CONV)) & SRC_CTLMASK) |
dtemp);
/* calculate new frequency and write it - preserve accum */
/* please don't try to understand. */
freq = ((u32_t) rate << 16) / 3000U;
src_reg_read(DSP, base + SRC_INT_REGS_OFF, &wtemp);
src_reg_write(DSP, base + SRC_INT_REGS_OFF,
(wtemp & 0x00ffU) |
(u16_t) (freq >> 6) & 0xfc00);
src_reg_write(DSP, base + SRC_VFREQ_FRAC_OFF, (u16_t) freq >> 1);
/* un-freeze the channel */
dtemp = base == SRC_SYNTH_BASE ? SRC_SYNTHFREEZE : SRC_DACFREEZE;
for( i = 0; i < SRC_IOPOLL_COUNT; ++i )
if( !(pci_inl(reg(SAMPLE_RATE_CONV)) & SRC_RAM_BUSY) )
break;
pci_outl(reg(SAMPLE_RATE_CONV),
(pci_inl(reg(SAMPLE_RATE_CONV)) & SRC_CTLMASK) &
~dtemp);
}
else /* setting ADC rate */
{
/* freeze the channel */
for( i = 0; i < SRC_IOPOLL_COUNT; ++i )
if( !(pci_inl(reg(SAMPLE_RATE_CONV)) & SRC_RAM_BUSY) )
break;
pci_outl(reg(SAMPLE_RATE_CONV),
(pci_inl(reg(SAMPLE_RATE_CONV)) & SRC_CTLMASK) |
SRC_ADCFREEZE);
/* derive oversample ratio */
N = rate/3000U;
if( N == 15 || N == 13 || N == 11 || N == 9 )
--N;
src_reg_write(DSP, SRC_ADC_LVOL, N << 8);
src_reg_write(DSP, SRC_ADC_RVOL, N << 8);
/* truncate the filter and write n/trunc_start */
truncM = (21*N - 1) | 1;
if( rate >= 24000U )
{
if( truncM > 239 )
truncM = 239;
truncStart = (239 - truncM) >> 1;
src_reg_write(DSP, base + SRC_TRUNC_N_OFF,
(truncStart << 9) | (N << 4));
}
else
{
if( truncM > 119 )
truncM = 119;
truncStart = (119 - truncM) >> 1;
src_reg_write(DSP, base + SRC_TRUNC_N_OFF,
0x8000U | (truncStart << 9) | (N << 4));
}
/* calculate new frequency and write it - preserve accum */
freq = ((48000UL << 16) / rate) * N;
src_reg_read(DSP, base + SRC_INT_REGS_OFF, &wtemp);
src_reg_write(DSP, base + SRC_INT_REGS_OFF,
(wtemp & 0x00ffU) |
(u16_t) (freq >> 6) & 0xfc00);
src_reg_write(DSP, base + SRC_VFREQ_FRAC_OFF, (u16_t) freq >> 1);
/* un-freeze the channel */
for( i = 0; i < SRC_IOPOLL_COUNT; ++i )
if( !(pci_inl(reg(SAMPLE_RATE_CONV)) & SRC_RAM_BUSY) )
break;
pci_outl(reg(SAMPLE_RATE_CONV),
(pci_inl(reg(SAMPLE_RATE_CONV)) & SRC_CTLMASK) &
~SRC_ADCFREEZE);
}
return;
}

View file

@ -0,0 +1,26 @@
#ifndef SRC_H
#define SRC_H
#include "es1371.h"
#include "wait.h"
#include "pci_helper.h"
_PROTOTYPE( int src_init, (DEV_STRUCT * DSP) );
_PROTOTYPE( void src_set_rate, (DEV_STRUCT * DSP, char src_base, u16_t rate) );
#define SRC_SYNTH_BASE 0x70
#define SRC_DAC_BASE 0x74
#define SRC_ADC_BASE 0x78
#define SRC_BUSY_BIT 23
#define SRC_RAM_WE 0x01000000
#define SRC_RAM_BUSY 0x00800000
#define SRC_DISABLE 0x00400000
#define DIS_P1 0x00200000
#define DIS_P2 0x00100000
#define DIS_REC 0x00080000
#define SRC_CTLMASK (DIS_REC|DIS_P2|DIS_P1|SRC_DISABLE)
#endif /* SRC_H */