diff options
Diffstat (limited to 'sound/oss/cs4281/cs4281m.c')
-rw-r--r-- | sound/oss/cs4281/cs4281m.c | 4487 |
1 files changed, 0 insertions, 4487 deletions
diff --git a/sound/oss/cs4281/cs4281m.c b/sound/oss/cs4281/cs4281m.c deleted file mode 100644 index 0400a416dc93..000000000000 --- a/sound/oss/cs4281/cs4281m.c +++ /dev/null @@ -1,4487 +0,0 @@ -/******************************************************************************* -* -* "cs4281.c" -- Cirrus Logic-Crystal CS4281 linux audio driver. -* -* Copyright (C) 2000,2001 Cirrus Logic Corp. -* -- adapted from drivers by Thomas Sailer, -* -- but don't bug him; Problems should go to: -* -- tom woller (twoller@crystal.cirrus.com) or -* (audio@crystal.cirrus.com). -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -* -* Module command line parameters: -* none -* -* Supported devices: -* /dev/dsp standard /dev/dsp device, (mostly) OSS compatible -* /dev/mixer standard /dev/mixer device, (mostly) OSS compatible -* /dev/midi simple MIDI UART interface, no ioctl -* -* Modification History -* 08/20/00 trw - silence and no stopping DAC until release -* 08/23/00 trw - added CS_DBG statements, fix interrupt hang issue on DAC stop. -* 09/18/00 trw - added 16bit only record with conversion -* 09/24/00 trw - added Enhanced Full duplex (separate simultaneous -* capture/playback rates) -* 10/03/00 trw - fixed mmap (fixed GRECORD and the XMMS mmap test plugin -* libOSSm.so) -* 10/11/00 trw - modified for 2.4.0-test9 kernel enhancements (NR_MAP removal) -* 11/03/00 trw - fixed interrupt loss/stutter, added debug. -* 11/10/00 bkz - added __devinit to cs4281_hw_init() -* 11/10/00 trw - fixed SMP and capture spinlock hang. -* 12/04/00 trw - cleaned up CSDEBUG flags and added "defaultorder" moduleparm. -* 12/05/00 trw - fixed polling (myth2), and added underrun swptr fix. -* 12/08/00 trw - added PM support. -* 12/14/00 trw - added wrapper code, builds under 2.4.0, 2.2.17-20, 2.2.17-8 -* (RH/Dell base), 2.2.18, 2.2.12. cleaned up code mods by ident. -* 12/19/00 trw - added PM support for 2.2 base (apm_callback). other PM cleanup. -* 12/21/00 trw - added fractional "defaultorder" inputs. if >100 then use -* defaultorder-100 as power of 2 for the buffer size. example: -* 106 = 2^(106-100) = 2^6 = 64 bytes for the buffer size. -* -*******************************************************************************/ - -/* uncomment the following line to disable building PM support into the driver */ -//#define NOT_CS4281_PM 1 - -#include <linux/list.h> -#include <linux/module.h> -#include <linux/string.h> -#include <linux/ioport.h> -#include <linux/sched.h> -#include <linux/delay.h> -#include <linux/sound.h> -#include <linux/slab.h> -#include <linux/soundcard.h> -#include <linux/pci.h> -#include <linux/bitops.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/poll.h> -#include <linux/fs.h> -#include <linux/wait.h> - -#include <asm/current.h> -#include <asm/io.h> -#include <asm/dma.h> -#include <asm/page.h> -#include <asm/uaccess.h> - -//#include "cs_dm.h" -#include "cs4281_hwdefs.h" -#include "cs4281pm.h" - -struct cs4281_state; - -static void stop_dac(struct cs4281_state *s); -static void stop_adc(struct cs4281_state *s); -static void start_dac(struct cs4281_state *s); -static void start_adc(struct cs4281_state *s); -#undef OSS_DOCUMENTED_MIXER_SEMANTICS - -// --------------------------------------------------------------------- - -#ifndef PCI_VENDOR_ID_CIRRUS -#define PCI_VENDOR_ID_CIRRUS 0x1013 -#endif -#ifndef PCI_DEVICE_ID_CRYSTAL_CS4281 -#define PCI_DEVICE_ID_CRYSTAL_CS4281 0x6005 -#endif - -#define CS4281_MAGIC ((PCI_DEVICE_ID_CRYSTAL_CS4281<<16) | PCI_VENDOR_ID_CIRRUS) -#define CS4281_CFLR_DEFAULT 0x00000001 /* CFLR must be in AC97 link mode */ - -// buffer order determines the size of the dma buffer for the driver. -// under Linux, a smaller buffer allows more responsiveness from many of the -// applications (e.g. games). A larger buffer allows some of the apps (esound) -// to not underrun the dma buffer as easily. As default, use 32k (order=3) -// rather than 64k as some of the games work more responsively. -// log base 2( buff sz = 32k). -static unsigned long defaultorder = 3; -module_param(defaultorder, ulong, 0); - -// -// Turn on/off debugging compilation by commenting out "#define CSDEBUG" -// -#define CSDEBUG 1 -#if CSDEBUG -#define CSDEBUG_INTERFACE 1 -#else -#undef CSDEBUG_INTERFACE -#endif -// -// cs_debugmask areas -// -#define CS_INIT 0x00000001 // initialization and probe functions -#define CS_ERROR 0x00000002 // tmp debugging bit placeholder -#define CS_INTERRUPT 0x00000004 // interrupt handler (separate from all other) -#define CS_FUNCTION 0x00000008 // enter/leave functions -#define CS_WAVE_WRITE 0x00000010 // write information for wave -#define CS_WAVE_READ 0x00000020 // read information for wave -#define CS_MIDI_WRITE 0x00000040 // write information for midi -#define CS_MIDI_READ 0x00000080 // read information for midi -#define CS_MPU401_WRITE 0x00000100 // write information for mpu401 -#define CS_MPU401_READ 0x00000200 // read information for mpu401 -#define CS_OPEN 0x00000400 // all open functions in the driver -#define CS_RELEASE 0x00000800 // all release functions in the driver -#define CS_PARMS 0x00001000 // functional and operational parameters -#define CS_IOCTL 0x00002000 // ioctl (non-mixer) -#define CS_PM 0x00004000 // power management -#define CS_TMP 0x10000000 // tmp debug mask bit - -#define CS_IOCTL_CMD_SUSPEND 0x1 // suspend -#define CS_IOCTL_CMD_RESUME 0x2 // resume -// -// CSDEBUG is usual mode is set to 1, then use the -// cs_debuglevel and cs_debugmask to turn on or off debugging. -// Debug level of 1 has been defined to be kernel errors and info -// that should be printed on any released driver. -// -#if CSDEBUG -#define CS_DBGOUT(mask,level,x) if((cs_debuglevel >= (level)) && ((mask) & cs_debugmask) ) {x;} -#else -#define CS_DBGOUT(mask,level,x) -#endif - -#if CSDEBUG -static unsigned long cs_debuglevel = 1; // levels range from 1-9 -static unsigned long cs_debugmask = CS_INIT | CS_ERROR; // use CS_DBGOUT with various mask values -module_param(cs_debuglevel, ulong, 0); -module_param(cs_debugmask, ulong, 0); -#endif -#define CS_TRUE 1 -#define CS_FALSE 0 - -// MIDI buffer sizes -#define MIDIINBUF 500 -#define MIDIOUTBUF 500 - -#define FMODE_MIDI_SHIFT 3 -#define FMODE_MIDI_READ (FMODE_READ << FMODE_MIDI_SHIFT) -#define FMODE_MIDI_WRITE (FMODE_WRITE << FMODE_MIDI_SHIFT) - -#define CS4281_MAJOR_VERSION 1 -#define CS4281_MINOR_VERSION 13 -#ifdef __ia64__ -#define CS4281_ARCH 64 //architecture key -#else -#define CS4281_ARCH 32 //architecture key -#endif - -#define CS_TYPE_ADC 0 -#define CS_TYPE_DAC 1 - - -static const char invalid_magic[] = - KERN_CRIT "cs4281: invalid magic value\n"; - -#define VALIDATE_STATE(s) \ -({ \ - if (!(s) || (s)->magic != CS4281_MAGIC) { \ - printk(invalid_magic); \ - return -ENXIO; \ - } \ -}) - -//LIST_HEAD(cs4281_devs); -static struct list_head cs4281_devs = { &cs4281_devs, &cs4281_devs }; - -struct cs4281_state; - -#include "cs4281_wrapper-24.c" - -struct cs4281_state { - // magic - unsigned int magic; - - // we keep the cards in a linked list - struct cs4281_state *next; - - // pcidev is needed to turn off the DDMA controller at driver shutdown - struct pci_dev *pcidev; - struct list_head list; - - // soundcore stuff - int dev_audio; - int dev_mixer; - int dev_midi; - - // hardware resources - unsigned int pBA0phys, pBA1phys; - char __iomem *pBA0; - char __iomem *pBA1; - unsigned int irq; - - // mixer registers - struct { - unsigned short vol[10]; - unsigned int recsrc; - unsigned int modcnt; - unsigned short micpreamp; - } mix; - - // wave stuff - struct properties { - unsigned fmt; - unsigned fmt_original; // original requested format - unsigned channels; - unsigned rate; - unsigned char clkdiv; - } prop_dac, prop_adc; - unsigned conversion:1; // conversion from 16 to 8 bit in progress - void *tmpbuff; // tmp buffer for sample conversions - unsigned ena; - spinlock_t lock; - struct mutex open_sem; - struct mutex open_sem_adc; - struct mutex open_sem_dac; - mode_t open_mode; - wait_queue_head_t open_wait; - wait_queue_head_t open_wait_adc; - wait_queue_head_t open_wait_dac; - - dma_addr_t dmaaddr_tmpbuff; - unsigned buforder_tmpbuff; // Log base 2 of 'rawbuf' size in bytes.. - struct dmabuf { - void *rawbuf; // Physical address of - dma_addr_t dmaaddr; - unsigned buforder; // Log base 2 of 'rawbuf' size in bytes.. - unsigned numfrag; // # of 'fragments' in the buffer. - unsigned fragshift; // Log base 2 of fragment size. - unsigned hwptr, swptr; - unsigned total_bytes; // # bytes process since open. - unsigned blocks; // last returned blocks value GETOPTR - unsigned wakeup; // interrupt occurred on block - int count; - unsigned underrun; // underrun flag - unsigned error; // over/underrun - wait_queue_head_t wait; - // redundant, but makes calculations easier - unsigned fragsize; // 2**fragshift.. - unsigned dmasize; // 2**buforder. - unsigned fragsamples; - // OSS stuff - unsigned mapped:1; // Buffer mapped in cs4281_mmap()? - unsigned ready:1; // prog_dmabuf_dac()/adc() successful? - unsigned endcleared:1; - unsigned type:1; // adc or dac buffer (CS_TYPE_XXX) - unsigned ossfragshift; - int ossmaxfrags; - unsigned subdivision; - } dma_dac, dma_adc; - - // midi stuff - struct { - unsigned ird, iwr, icnt; - unsigned ord, owr, ocnt; - wait_queue_head_t iwait; - wait_queue_head_t owait; - struct timer_list timer; - unsigned char ibuf[MIDIINBUF]; - unsigned char obuf[MIDIOUTBUF]; - } midi; - - struct cs4281_pm pm; - struct cs4281_pipeline pl[CS4281_NUMBER_OF_PIPELINES]; -}; - -#include "cs4281pm-24.c" - -#if CSDEBUG - -// DEBUG ROUTINES - -#define SOUND_MIXER_CS_GETDBGLEVEL _SIOWR('M',120, int) -#define SOUND_MIXER_CS_SETDBGLEVEL _SIOWR('M',121, int) -#define SOUND_MIXER_CS_GETDBGMASK _SIOWR('M',122, int) -#define SOUND_MIXER_CS_SETDBGMASK _SIOWR('M',123, int) - -#define SOUND_MIXER_CS_APM _SIOWR('M',124, int) - - -static void cs_printioctl(unsigned int x) -{ - unsigned int i; - unsigned char vidx; - // Index of mixtable1[] member is Device ID - // and must be <= SOUND_MIXER_NRDEVICES. - // Value of array member is index into s->mix.vol[] - static const unsigned char mixtable1[SOUND_MIXER_NRDEVICES] = { - [SOUND_MIXER_PCM] = 1, // voice - [SOUND_MIXER_LINE1] = 2, // AUX - [SOUND_MIXER_CD] = 3, // CD - [SOUND_MIXER_LINE] = 4, // Line - [SOUND_MIXER_SYNTH] = 5, // FM - [SOUND_MIXER_MIC] = 6, // Mic - [SOUND_MIXER_SPEAKER] = 7, // Speaker - [SOUND_MIXER_RECLEV] = 8, // Recording level - [SOUND_MIXER_VOLUME] = 9 // Master Volume - }; - - switch (x) { - case SOUND_MIXER_CS_GETDBGMASK: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_MIXER_CS_GETDBGMASK:\n")); - break; - case SOUND_MIXER_CS_GETDBGLEVEL: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_MIXER_CS_GETDBGLEVEL:\n")); - break; - case SOUND_MIXER_CS_SETDBGMASK: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_MIXER_CS_SETDBGMASK:\n")); - break; - case SOUND_MIXER_CS_SETDBGLEVEL: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_MIXER_CS_SETDBGLEVEL:\n")); - break; - case OSS_GETVERSION: - CS_DBGOUT(CS_IOCTL, 4, printk("OSS_GETVERSION:\n")); - break; - case SNDCTL_DSP_SYNC: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SYNC:\n")); - break; - case SNDCTL_DSP_SETDUPLEX: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETDUPLEX:\n")); - break; - case SNDCTL_DSP_GETCAPS: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETCAPS:\n")); - break; - case SNDCTL_DSP_RESET: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_RESET:\n")); - break; - case SNDCTL_DSP_SPEED: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SPEED:\n")); - break; - case SNDCTL_DSP_STEREO: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_STEREO:\n")); - break; - case SNDCTL_DSP_CHANNELS: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_CHANNELS:\n")); - break; - case SNDCTL_DSP_GETFMTS: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETFMTS:\n")); - break; - case SNDCTL_DSP_SETFMT: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETFMT:\n")); - break; - case SNDCTL_DSP_POST: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_POST:\n")); - break; - case SNDCTL_DSP_GETTRIGGER: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETTRIGGER:\n")); - break; - case SNDCTL_DSP_SETTRIGGER: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETTRIGGER:\n")); - break; - case SNDCTL_DSP_GETOSPACE: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETOSPACE:\n")); - break; - case SNDCTL_DSP_GETISPACE: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETISPACE:\n")); - break; - case SNDCTL_DSP_NONBLOCK: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_NONBLOCK:\n")); - break; - case SNDCTL_DSP_GETODELAY: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETODELAY:\n")); - break; - case SNDCTL_DSP_GETIPTR: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETIPTR:\n")); - break; - case SNDCTL_DSP_GETOPTR: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETOPTR:\n")); - break; - case SNDCTL_DSP_GETBLKSIZE: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETBLKSIZE:\n")); - break; - case SNDCTL_DSP_SETFRAGMENT: - CS_DBGOUT(CS_IOCTL, 4, - printk("SNDCTL_DSP_SETFRAGMENT:\n")); - break; - case SNDCTL_DSP_SUBDIVIDE: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SUBDIVIDE:\n")); - break; - case SOUND_PCM_READ_RATE: - CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_RATE:\n")); - break; - case SOUND_PCM_READ_CHANNELS: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_PCM_READ_CHANNELS:\n")); - break; - case SOUND_PCM_READ_BITS: - CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_BITS:\n")); - break; - case SOUND_PCM_WRITE_FILTER: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_PCM_WRITE_FILTER:\n")); - break; - case SNDCTL_DSP_SETSYNCRO: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETSYNCRO:\n")); - break; - case SOUND_PCM_READ_FILTER: - CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_FILTER:\n")); - break; - case SOUND_MIXER_PRIVATE1: - CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE1:\n")); - break; - case SOUND_MIXER_PRIVATE2: - CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE2:\n")); - break; - case SOUND_MIXER_PRIVATE3: - CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE3:\n")); - break; - case SOUND_MIXER_PRIVATE4: - CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE4:\n")); - break; - case SOUND_MIXER_PRIVATE5: - CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE5:\n")); - break; - case SOUND_MIXER_INFO: - CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_INFO:\n")); - break; - case SOUND_OLD_MIXER_INFO: - CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_OLD_MIXER_INFO:\n")); - break; - - default: - switch (_IOC_NR(x)) { - case SOUND_MIXER_VOLUME: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_MIXER_VOLUME:\n")); - break; - case SOUND_MIXER_SPEAKER: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_MIXER_SPEAKER:\n")); - break; - case SOUND_MIXER_RECLEV: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_MIXER_RECLEV:\n")); - break; - case SOUND_MIXER_MIC: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_MIXER_MIC:\n")); - break; - case SOUND_MIXER_SYNTH: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_MIXER_SYNTH:\n")); - break; - case SOUND_MIXER_RECSRC: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_MIXER_RECSRC:\n")); - break; - case SOUND_MIXER_DEVMASK: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_MIXER_DEVMASK:\n")); - break; - case SOUND_MIXER_RECMASK: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_MIXER_RECMASK:\n")); - break; - case SOUND_MIXER_STEREODEVS: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_MIXER_STEREODEVS:\n")); - break; - case SOUND_MIXER_CAPS: - CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_CAPS:\n")); - break; - default: - i = _IOC_NR(x); - if (i >= SOUND_MIXER_NRDEVICES - || !(vidx = mixtable1[i])) { - CS_DBGOUT(CS_IOCTL, 4, printk - ("UNKNOWN IOCTL: 0x%.8x NR=%d\n", - x, i)); - } else { - CS_DBGOUT(CS_IOCTL, 4, printk - ("SOUND_MIXER_IOCTL AC9x: 0x%.8x NR=%d\n", - x, i)); - } - break; - } - } -} -#endif -static int prog_dmabuf_adc(struct cs4281_state *s); -static void prog_codec(struct cs4281_state *s, unsigned type); - -// --------------------------------------------------------------------- -// -// Hardware Interfaces For the CS4281 -// - - -//****************************************************************************** -// "delayus()-- Delay for the specified # of microseconds. -//****************************************************************************** -static void delayus(struct cs4281_state *s, u32 delay) -{ - u32 j; - if ((delay > 9999) && (s->pm.flags & CS4281_PM_IDLE)) { - j = (delay * HZ) / 1000000; /* calculate delay in jiffies */ - if (j < 1) - j = 1; /* minimum one jiffy. */ - current->state = TASK_UNINTERRUPTIBLE; - schedule_timeout(j); - } else - udelay(delay); - return; -} - - -//****************************************************************************** -// "cs4281_read_ac97" -- Reads a word from the specified location in the -// CS4281's address space(based on the BA0 register). -// -// 1. Write ACCAD = Command Address Register = 46Ch for AC97 register address -// 2. Write ACCDA = Command Data Register = 470h for data to write to AC97 register, -// 0h for reads. -// 3. Write ACCTL = Control Register = 460h for initiating the write -// 4. Read ACCTL = 460h, DCV should be reset by now and 460h = 17h -// 5. if DCV not cleared, break and return error -// 6. Read ACSTS = Status Register = 464h, check VSTS bit -//**************************************************************************** -static int cs4281_read_ac97(struct cs4281_state *card, u32 offset, - u32 * value) -{ - u32 count, status; - - // Make sure that there is not data sitting - // around from a previous uncompleted access. - // ACSDA = Status Data Register = 47Ch - status = readl(card->pBA0 + BA0_ACSDA); - - // Setup the AC97 control registers on the CS4281 to send the - // appropriate command to the AC97 to perform the read. - // ACCAD = Command Address Register = 46Ch - // ACCDA = Command Data Register = 470h - // ACCTL = Control Register = 460h - // bit DCV - will clear when process completed - // bit CRW - Read command - // bit VFRM - valid frame enabled - // bit ESYN - ASYNC generation enabled - - // Get the actual AC97 register from the offset - writel(offset - BA0_AC97_RESET, card->pBA0 + BA0_ACCAD); - writel(0, card->pBA0 + BA0_ACCDA); - writel(ACCTL_DCV | ACCTL_CRW | ACCTL_VFRM | ACCTL_ESYN, - card->pBA0 + BA0_ACCTL); - - // Wait for the read to occur. - for (count = 0; count < 10; count++) { - // First, we want to wait for a short time. - udelay(25); - - // Now, check to see if the read has completed. - // ACCTL = 460h, DCV should be reset by now and 460h = 17h - if (!(readl(card->pBA0 + BA0_ACCTL) & ACCTL_DCV)) - break; - } - - // Make sure the read completed. - if (readl(card->pBA0 + BA0_ACCTL) & ACCTL_DCV) - return 1; - - // Wait for the valid status bit to go active. - for (count = 0; count < 10; count++) { - // Read the AC97 status register. - // ACSTS = Status Register = 464h - status = readl(card->pBA0 + BA0_ACSTS); - - // See if we have valid status. - // VSTS - Valid Status - if (status & ACSTS_VSTS) - break; - // Wait for a short while. - udelay(25); - } - - // Make sure we got valid status. - if (!(status & ACSTS_VSTS)) - return 1; - - // Read the data returned from the AC97 register. - // ACSDA = Status Data Register = 474h - *value = readl(card->pBA0 + BA0_ACSDA); - - // Success. - return (0); -} - - -//**************************************************************************** -// -// "cs4281_write_ac97()"-- writes a word to the specified location in the -// CS461x's address space (based on the part's base address zero register). -// -// 1. Write ACCAD = Command Address Register = 46Ch for AC97 register address -// 2. Write ACCDA = Command Data Register = 470h for data to write to AC97 reg. -// 3. Write ACCTL = Control Register = 460h for initiating the write -// 4. Read ACCTL = 460h, DCV should be reset by now and 460h = 07h -// 5. if DCV not cleared, break and return error -// -//**************************************************************************** -static int cs4281_write_ac97(struct cs4281_state *card, u32 offset, - u32 value) -{ - u32 count, status=0; - - CS_DBGOUT(CS_FUNCTION, 2, - printk(KERN_INFO "cs4281: cs_4281_write_ac97()+ \n")); - - // Setup the AC97 control registers on the CS4281 to send the - // appropriate command to the AC97 to perform the read. - // ACCAD = Command Address Register = 46Ch - // ACCDA = Command Data Register = 470h - // ACCTL = Control Register = 460h - // set DCV - will clear when process completed - // reset CRW - Write command - // set VFRM - valid frame enabled - // set ESYN - ASYNC generation enabled - // set RSTN - ARST# inactive, AC97 codec not reset - - // Get the actual AC97 register from the offset - - writel(offset - BA0_AC97_RESET, card->pBA0 + BA0_ACCAD); - writel(value, card->pBA0 + BA0_ACCDA); - writel(ACCTL_DCV | ACCTL_VFRM | ACCTL_ESYN, - card->pBA0 + BA0_ACCTL); - - // Wait for the write to occur. - for (count = 0; count < 100; count++) { - // First, we want to wait for a short time. - udelay(25); - // Now, check to see if the write has completed. - // ACCTL = 460h, DCV should be reset by now and 460h = 07h - status = readl(card->pBA0 + BA0_ACCTL); - if (!(status & ACCTL_DCV)) - break; - } - - // Make sure the write completed. - if (status & ACCTL_DCV) { - CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO - "cs4281: cs_4281_write_ac97()- unable to write. ACCTL_DCV active\n")); - return 1; - } - CS_DBGOUT(CS_FUNCTION, 2, - printk(KERN_INFO "cs4281: cs_4281_write_ac97()- 0\n")); - // Success. - return 0; -} - - -//****************************************************************************** -// "Init4281()" -- Bring up the part. -//****************************************************************************** -static __devinit int cs4281_hw_init(struct cs4281_state *card) -{ - u32 ac97_slotid; - u32 temp1, temp2; - - CS_DBGOUT(CS_FUNCTION, 2, - printk(KERN_INFO "cs4281: cs4281_hw_init()+ \n")); -#ifndef NOT_CS4281_PM - if(!card) - return 1; -#endif - temp2 = readl(card->pBA0 + BA0_CFLR); - CS_DBGOUT(CS_INIT | CS_ERROR | CS_PARMS, 4, printk(KERN_INFO - "cs4281: cs4281_hw_init() CFLR 0x%x\n", temp2)); - if(temp2 != CS4281_CFLR_DEFAULT) - { - CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_INFO - "cs4281: cs4281_hw_init() CFLR invalid - resetting from 0x%x to 0x%x\n", - temp2,CS4281_CFLR_DEFAULT)); - writel(CS4281_CFLR_DEFAULT, card->pBA0 + BA0_CFLR); - temp2 = readl(card->pBA0 + BA0_CFLR); - if(temp2 != CS4281_CFLR_DEFAULT) - { - CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_INFO - "cs4281: cs4281_hw_init() Invalid hardware - unable to configure CFLR\n")); - return 1; - } - } - - //***************************************7 - // Set up the Sound System Configuration - //*************************************** - - // Set the 'Configuration Write Protect' register - // to 4281h. Allows vendor-defined configuration - // space between 0e4h and 0ffh to be written. - - writel(0x4281, card->pBA0 + BA0_CWPR); // (3e0h) - - // (0), Blast the clock control register to zero so that the - // PLL starts out in a known state, and blast the master serial - // port control register to zero so that the serial ports also - // start out in a known state. - - writel(0, card->pBA0 + BA0_CLKCR1); // (400h) - writel(0, card->pBA0 + BA0_SERMC); // (420h) - - - // (1), Make ESYN go to zero to turn off - // the Sync pulse on the AC97 link. - - writel(0, card->pBA0 + BA0_ACCTL); - udelay(50); - - - // (2) Drive the ARST# pin low for a minimum of 1uS (as defined in - // the AC97 spec) and then drive it high. This is done for non - // AC97 modes since there might be logic external to the CS461x - // that uses the ARST# line for a reset. - - writel(0, card->pBA0 + BA0_SPMC); // (3ech) - udelay(100); - writel(SPMC_RSTN, card->pBA0 + BA0_SPMC); - delayus(card,50000); // Wait 50 ms for ABITCLK to become stable. - - // (3) Turn on the Sound System Clocks. - writel(CLKCR1_PLLP, card->pBA0 + BA0_CLKCR1); // (400h) - delayus(card,50000); // Wait for the PLL to stabilize. - // Turn on clocking of the core (CLKCR1(400h) = 0x00000030) - writel(CLKCR1_PLLP | CLKCR1_SWCE, card->pBA0 + BA0_CLKCR1); - - // (4) Power on everything for now.. - writel(0x7E, card->pBA0 + BA0_SSPM); // (740h) - - // (5) Wait for clock stabilization. - for (temp1 = 0; temp1 < 1000; temp1++) { - udelay(1000); - if (readl(card->pBA0 + BA0_CLKCR1) & CLKCR1_DLLRDY) - break; - } - if (!(readl(card->pBA0 + BA0_CLKCR1) & CLKCR1_DLLRDY)) { - CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR - "cs4281: DLLRDY failed!\n")); - return -EIO; - } - // (6) Enable ASYNC generation. - writel(ACCTL_ESYN, card->pBA0 + BA0_ACCTL); // (460h) - - // Now wait 'for a short while' to allow the AC97 - // part to start generating bit clock. (so we don't - // Try to start the PLL without an input clock.) - delayus(card,50000); - - // Set the serial port timing configuration, so that the - // clock control circuit gets its clock from the right place. - writel(SERMC_PTC_AC97, card->pBA0 + BA0_SERMC); // (420h)=2. - - // (7) Wait for the codec ready signal from the AC97 codec. - - for (temp1 = 0; temp1 < 1000; temp1++) { - // Delay a mil to let things settle out and - // to prevent retrying the read too quickly. - udelay(1000); - if (readl(card->pBA0 + BA0_ACSTS) & ACSTS_CRDY) // If ready, (464h) - break; // exit the 'for' loop. - } - if (!(readl(card->pBA0 + BA0_ACSTS) & ACSTS_CRDY)) // If never came ready, - { - CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_ERR - "cs4281: ACSTS never came ready!\n")); - return -EIO; // exit initialization. - } - // (8) Assert the 'valid frame' signal so we can - // begin sending commands to the AC97 codec. - writel(ACCTL_VFRM | ACCTL_ESYN, card->pBA0 + BA0_ACCTL); // (460h) - - // (9), Wait until CODEC calibration is finished. - // Print an error message if it doesn't. - for (temp1 = 0; temp1 < 1000; temp1++) { - delayus(card,10000); - // Read the AC97 Powerdown Control/Status Register. - cs4281_read_ac97(card, BA0_AC97_POWERDOWN, &temp2); - if ((temp2 & 0x0000000F) == 0x0000000F) - break; - } - if ((temp2 & 0x0000000F) != 0x0000000F) { - CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_ERR - "cs4281: Codec failed to calibrate. Status = %.8x.\n", - temp2)); - return -EIO; - } - // (10), Set the serial port timing configuration, so that the - // clock control circuit gets its clock from the right place. - writel(SERMC_PTC_AC97, card->pBA0 + BA0_SERMC); // (420h)=2. - - - // (11) Wait until we've sampled input slots 3 & 4 as valid, meaning - // that the codec is pumping ADC data across the AC link. - for (temp1 = 0; temp1 < 1000; temp1++) { - // Delay a mil to let things settle out and - // to prevent retrying the read too quickly. - delayus(card,1000); //(test) - - // Read the input slot valid register; See - // if input slots 3 and 4 are valid yet. - if ( - (readl(card->pBA0 + BA0_ACISV) & - (ACISV_ISV3 | ACISV_ISV4)) == - (ACISV_ISV3 | ACISV_ISV4)) break; // Exit the 'for' if slots are valid. - } - // If we never got valid data, exit initialization. - if ((readl(card->pBA0 + BA0_ACISV) & (ACISV_ISV3 | ACISV_ISV4)) - != (ACISV_ISV3 | ACISV_ISV4)) { - CS_DBGOUT(CS_FUNCTION, 2, - printk(KERN_ERR - "cs4281: Never got valid data!\n")); - return -EIO; // If no valid data, exit initialization. - } - // (12), Start digital data transfer of audio data to the codec. - writel(ACOSV_SLV3 | ACOSV_SLV4, card->pBA0 + BA0_ACOSV); // (468h) - - - //************************************** - // Unmute the Master and Alternate - // (headphone) volumes. Set to max. - //************************************** - cs4281_write_ac97(card, BA0_AC97_HEADPHONE_VOLUME, 0); - cs4281_write_ac97(card, BA0_AC97_MASTER_VOLUME, 0); - - //****************************************** - // Power on the DAC(AddDACUser()from main()) - //****************************************** - cs4281_read_ac97(card, BA0_AC97_POWERDOWN, &temp1); - cs4281_write_ac97(card, BA0_AC97_POWERDOWN, temp1 &= 0xfdff); - - // Wait until we sample a DAC ready state. - for (temp2 = 0; temp2 < 32; temp2++) { - // Let's wait a mil to let things settle. - delayus(card,1000); - // Read the current state of the power control reg. - cs4281_read_ac97(card, BA0_AC97_POWERDOWN, &temp1); - // If the DAC ready state bit is set, stop waiting. - if (temp1 & 0x2) - break; - } - - //****************************************** - // Power on the ADC(AddADCUser()from main()) - //****************************************** - cs4281_read_ac97(card, BA0_AC97_POWERDOWN, &temp1); - cs4281_write_ac97(card, BA0_AC97_POWERDOWN, temp1 &= 0xfeff); - - // Wait until we sample ADC ready state. - for (temp2 = 0; temp2 < 32; temp2++) { - // Let's wait a mil to let things settle. - delayus(card,1000); - // Read the current state of the power control reg. - cs4281_read_ac97(card, BA0_AC97_POWERDOWN, &temp1); - // If the ADC ready state bit is set, stop waiting. - if (temp1 & 0x1) - break; - } - // Set up 4281 Register contents that - // don't change for boot duration. - - // For playback, we map AC97 slot 3 and 4(Left - // & Right PCM playback) to DMA Channel 0. - // Set the fifo to be 15 bytes at offset zero. - - ac97_slotid = 0x01000f00; // FCR0.RS[4:0]=1(=>slot4, right PCM playback). - // FCR0.LS[4:0]=0(=>slot3, left PCM playback). - // FCR0.SZ[6-0]=15; FCR0.OF[6-0]=0. - writel(ac97_slotid, card->pBA0 + BA0_FCR0); // (180h) - writel(ac97_slotid | FCRn_FEN, card->pBA0 + BA0_FCR0); // Turn on FIFO Enable. - - // For capture, we map AC97 slot 10 and 11(Left - // and Right PCM Record) to DMA Channel 1. - // Set the fifo to be 15 bytes at offset sixteen. - ac97_slotid = 0x0B0A0f10; // FCR1.RS[4:0]=11(=>slot11, right PCM record). - // FCR1.LS[4:0]=10(=>slot10, left PCM record). - // FCR1.SZ[6-0]=15; FCR1.OF[6-0]=16. - writel(ac97_slotid | FCRn_PSH, card->pBA0 + BA0_FCR1); // (184h) - writel(ac97_slotid | FCRn_FEN, card->pBA0 + BA0_FCR1); // Turn on FIFO Enable. - - // Map the Playback SRC to the same AC97 slots(3 & 4-- - // --Playback left & right)as DMA channel 0. - // Map the record SRC to the same AC97 slots(10 & 11-- - // -- Record left & right) as DMA channel 1. - - ac97_slotid = 0x0b0a0100; // SCRSA.PRSS[4:0]=1(=>slot4, right PCM playback). - // SCRSA.PLSS[4:0]=0(=>slot3, left PCM playback). - // SCRSA.CRSS[4:0]=11(=>slot11, right PCM record) - // SCRSA.CLSS[4:0]=10(=>slot10, left PCM record). - writel(ac97_slotid, card->pBA0 + BA0_SRCSA); // (75ch) - - // Set 'Half Terminal Count Interrupt Enable' and 'Terminal - // Count Interrupt Enable' in DMA Control Registers 0 & 1. - // Set 'MSK' flag to 1 to keep the DMA engines paused. - temp1 = (DCRn_HTCIE | DCRn_TCIE | DCRn_MSK); // (00030001h) - writel(temp1, card->pBA0 + BA0_DCR0); // (154h - writel(temp1, card->pBA0 + BA0_DCR1); // (15ch) - - // Set 'Auto-Initialize Control' to 'enabled'; For playback, - // set 'Transfer Type Control'(TR[1:0]) to 'read transfer', - // for record, set Transfer Type Control to 'write transfer'. - // All other bits set to zero; Some will be changed @ transfer start. - temp1 = (DMRn_DMA | DMRn_AUTO | DMRn_TR_READ); // (20000018h) - writel(temp1, card->pBA0 + BA0_DMR0); // (150h) - temp1 = (DMRn_DMA | DMRn_AUTO | DMRn_TR_WRITE); // (20000014h) - writel(temp1, card->pBA0 + BA0_DMR1); // (158h) - - // Enable DMA interrupts generally, and - // DMA0 & DMA1 interrupts specifically. - temp1 = readl(card->pBA0 + BA0_HIMR) & 0xfffbfcff; - writel(temp1, card->pBA0 + BA0_HIMR); - - CS_DBGOUT(CS_FUNCTION, 2, - printk(KERN_INFO "cs4281: cs4281_hw_init()- 0\n")); - return 0; -} - -#ifndef NOT_CS4281_PM -static void printpm(struct cs4281_state *s) -{ - CS_DBGOUT(CS_PM, 9, printk("pm struct:\n")); - CS_DBGOUT(CS_PM, 9, printk("flags:0x%x u32CLKCR1_SAVE: 0%x u32SSPMValue: 0x%x\n", - (unsigned)s->pm.flags,s->pm.u32CLKCR1_SAVE,s->pm.u32SSPMValue)); - CS_DBGOUT(CS_PM, 9, printk("u32PPLVCvalue: 0x%x u32PPRVCvalue: 0x%x\n", - s->pm.u32PPLVCvalue,s->pm.u32PPRVCvalue)); - CS_DBGOUT(CS_PM, 9, printk("u32FMLVCvalue: 0x%x u32FMRVCvalue: 0x%x\n", - s->pm.u32FMLVCvalue,s->pm.u32FMRVCvalue)); - CS_DBGOUT(CS_PM, 9, printk("u32GPIORvalue: 0x%x u32JSCTLvalue: 0x%x\n", - s->pm.u32GPIORvalue,s->pm.u32JSCTLvalue)); - CS_DBGOUT(CS_PM, 9, printk("u32SSCR: 0x%x u32SRCSA: 0x%x\n", - s->pm.u32SSCR,s->pm.u32SRCSA)); - CS_DBGOUT(CS_PM, 9, printk("u32DacASR: 0x%x u32AdcASR: 0x%x\n", - s->pm.u32DacASR,s->pm.u32AdcASR)); - CS_DBGOUT(CS_PM, 9, printk("u32DacSR: 0x%x u32AdcSR: 0x%x\n", - s->pm.u32DacSR,s->pm.u32AdcSR)); - CS_DBGOUT(CS_PM, 9, printk("u32MIDCR_Save: 0x%x\n", - s->pm.u32MIDCR_Save)); - -} -static void printpipe(struct cs4281_pipeline *pl) -{ - - CS_DBGOUT(CS_PM, 9, printk("pm struct:\n")); - CS_DBGOUT(CS_PM, 9, printk("flags:0x%x number: 0%x\n", - (unsigned)pl->flags,pl->number)); - CS_DBGOUT(CS_PM, 9, printk("u32DBAnValue: 0%x u32DBCnValue: 0x%x\n", - pl->u32DBAnValue,pl->u32DBCnValue)); - CS_DBGOUT(CS_PM, 9, printk("u32DMRnValue: 0x%x u32DCRnValue: 0x%x\n", - pl->u32DMRnValue,pl->u32DCRnValue)); - CS_DBGOUT(CS_PM, 9, printk("u32DBAnAddress: 0x%x u32DBCnAddress: 0x%x\n", - pl->u32DBAnAddress,pl->u32DBCnAddress)); - CS_DBGOUT(CS_PM, 9, printk("u32DCAnAddress: 0x%x u32DCCnAddress: 0x%x\n", - pl->u32DCCnAddress,pl->u32DCCnAddress)); - CS_DBGOUT(CS_PM, 9, printk("u32DMRnAddress: 0x%x u32DCRnAddress: 0x%x\n", - pl->u32DMRnAddress,pl->u32DCRnAddress)); - CS_DBGOUT(CS_PM, 9, printk("u32HDSRnAddress: 0x%x u32DBAn_Save: 0x%x\n", - pl->u32HDSRnAddress,pl->u32DBAn_Save)); - CS_DBGOUT(CS_PM, 9, printk("u32DBCn_Save: 0x%x u32DMRn_Save: 0x%x\n", - pl->u32DBCn_Save,pl->u32DMRn_Save)); - CS_DBGOUT(CS_PM, 9, printk("u32DCRn_Save: 0x%x u32DCCn_Save: 0x%x\n", - pl->u32DCRn_Save,pl->u32DCCn_Save)); - CS_DBGOUT(CS_PM, 9, printk("u32DCAn_Save: 0x%x\n", - pl->u32DCAn_Save)); - CS_DBGOUT(CS_PM, 9, printk("u32FCRn_Save: 0x%x u32FSICn_Save: 0x%x\n", - pl->u32FCRn_Save,pl->u32FSICn_Save)); - CS_DBGOUT(CS_PM, 9, printk("u32FCRnValue: 0x%x u32FSICnValue: 0x%x\n", - pl->u32FCRnValue,pl->u32FSICnValue)); - CS_DBGOUT(CS_PM, 9, printk("u32FCRnAddress: 0x%x u32FSICnAddress: 0x%x\n", - pl->u32FCRnAddress,pl->u32FSICnAddress)); - CS_DBGOUT(CS_PM, 9, printk("u32FPDRnValue: 0x%x u32FPDRnAddress: 0x%x\n", - pl->u32FPDRnValue,pl->u32FPDRnAddress)); -} -static void printpipelines(struct cs4281_state *s) -{ - int i; - for(i=0;i<CS4281_NUMBER_OF_PIPELINES;i++) - { - if(s->pl[i].flags & CS4281_PIPELINE_VALID) - { - printpipe(&s->pl[i]); - } - } -} -/**************************************************************************** -* -* Suspend - save the ac97 regs, mute the outputs and power down the part. -* -****************************************************************************/ -static void cs4281_ac97_suspend(struct cs4281_state *s) -{ - int Count,i; - - CS_DBGOUT(CS_PM, 9, printk("cs4281: cs4281_ac97_suspend()+\n")); -/* -* change the state, save the current hwptr, then stop the dac/adc -*/ - s-> |