/*
* Copyright (c) by Jaroslav Kysela <perex@perex.cz>
* Routines for control of CS4235/4236B/4237B/4238B/4239 chips
*
* Note:
* -----
*
* Bugs:
* -----
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
/*
* Indirect control registers (CS4236B+)
*
* C0
* D8: WSS reset (all chips)
*
* C1 (all chips except CS4236)
* D7-D5: version
* D4-D0: chip id
* 11101 - CS4235
* 01011 - CS4236B
* 01000 - CS4237B
* 01001 - CS4238B
* 11110 - CS4239
*
* C2
* D7-D4: 3D Space (CS4235,CS4237B,CS4238B,CS4239)
* D3-D0: 3D Center (CS4237B); 3D Volume (CS4238B)
*
* C3
* D7: 3D Enable (CS4237B)
* D6: 3D Mono Enable (CS4237B)
* D5: 3D Serial Output (CS4237B,CS4238B)
* D4: 3D Enable (CS4235,CS4238B,CS4239)
*
* C4
* D7: consumer serial port enable (CS4237B,CS4238B)
* D6: channels status block reset (CS4237B,CS4238B)
* D5: user bit in sub-frame of digital audio data (CS4237B,CS4238B)
* D4: validity bit bit in sub-frame of digital audio data (CS4237B,CS4238B)
*
* C5 lower channel status (digital serial data description) (CS4237B,CS4238B)
* D7-D6: first two bits of category code
* D5: lock
* D4-D3: pre-emphasis (0 = none, 1 = 50/15us)
* D2: copy/copyright (0 = copy inhibited)
* D1: 0 = digital audio / 1 = non-digital audio
*
* C6 upper channel status (digital serial data description) (CS4237B,CS4238B)
* D7-D6: sample frequency (0 = 44.1kHz)
* D5: generation status (0 = no indication, 1 = original/commercially precaptureed data)
* D4-D0: category code (upper bits)
*
* C7 reserved (must write 0)
*
* C8 wavetable control
* D7: volume control interrupt enable (CS4235,CS4239)
* D6: hardware volume control format (CS4235,CS4239)
* D3: wavetable serial port enable (all chips)
* D2: DSP serial port switch (all chips)
* D1: disable MCLK (all chips)
* D0: force BRESET low (all chips)
*
*/
#include <asm/io.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/time.h>
#include <linux/wait.h>
#include <sound/core.h>
#include <sound/wss.h>
#include <sound/asoundef.h>
#include <sound/initval.h>
/*
*
*/
static unsigned char snd_cs4236_ext_map[18] = {
/* CS4236_LEFT_LINE */ 0xff,
/* CS4236_RIGHT_LINE */ 0xff,
/* CS4236_LEFT_MIC */ 0xdf,
/* CS4236_RIGHT_MIC */ 0xdf,
/* CS4236_LEFT_MIX_CTRL */ 0xe0 | 0x18,
/* CS4236_RIGHT_MIX_CTRL */ 0xe0,
/* CS4236_LEFT_FM */ 0xbf,
/* CS4236_RIGHT_FM */ 0xbf,
/* CS4236_LEFT_DSP */ 0xbf,
/* CS4236_RIGHT_DSP */ 0xbf,
/* CS4236_RIGHT_LOOPBACK */ 0xbf,
/* CS4236_DAC_MUTE */ 0xe0,
/* CS4236_ADC_RATE */ 0x01, /* 48kHz */
/* CS4236_DAC_RATE */ 0x01, /* 48kHz */
/* CS4236_LEFT_MASTER */ 0xbf,
/* CS4236_RIGHT_MASTER */ 0xbf,
/* CS4236_LEFT_WAVE */ 0xbf,
/* CS4236_RIGHT_WAVE */ 0xbf
};
/*
*
*/
static void snd_cs4236_ctrl_out(struct snd_wss *chip,
unsigned char reg, unsigned char val)
{
outb(reg, chip->cport + 3);
outb(chip->cimage[reg] = val, chip->cport + 4);
}
static unsigned char snd_cs4236_ctrl_in(struct snd_wss *chip, unsigned char reg)
{
outb(reg, chip->cport + 3);
return inb(chip->cport + 4);
}
/*
* PCM
*/
#define CLOCKS 8
static struct snd_ratnum clocks[CLOCKS] = {
{ .num = 16934400, .den_min = 353, .den_max = 353, .den_step = 1 },
{ .num = 16934400, .den_min = 529, .den_max = 529, .den_step = 1 },
{ .num = 16934400, .den_min = 617, .den_max = 617, .den_step = 1 },
{ .num = 16934400, .den_min = 1058, .den_max = 1058, .den_step = 1 },
{ .num = 16934400, .den_min = 1764, .den_max = 1764, .den_step = 1 },
{ .num = 16934400, .den_min = 2117, .den_max = 2117, .den_step = 1 },
{ .num = 16934400, .den_min = 2558, .den_max = 2558, .den_step = 1 },
{ .num = 16934400/16, .den_min = 21, .den_max = 192, .den_step = 1 }
};
static struct snd_pcm_hw_constraint_ratnums hw_constraints_clocks = {
.nrats = CLOCKS,
.rats = clocks,
};
static int snd_cs4236_xrate(struct snd_pcm_runtime *runtime)
{
return snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
&hw_constraints_clocks);
}
static unsigned char divisor_to_rate_register(unsigned int divisor)
{
switch (divisor) {
case 353: return