/*
* ac97_codec.c: Generic AC97 mixer/modem module
*
* Derived from ac97 mixer in maestro and trident driver.
*
* Copyright 2000 Silicon Integrated System Corporation
*
* 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.
*
**************************************************************************
*
* The Intel Audio Codec '97 specification is available at:
* http://download.intel.com/support/motherboards/desktop/sb/ac97_r23.pdf
*
**************************************************************************
*
* History
* May 02, 2003 Liam Girdwood <lrg@slimlogic.co.uk>
* Removed non existent WM9700
* Added support for WM9705, WM9708, WM9709, WM9710, WM9711
* WM9712 and WM9717
* Mar 28, 2002 Randolph Bentson <bentson@holmsjoen.com>
* corrections to support WM9707 in ViewPad 1000
* v0.4 Mar 15 2000 Ollie Lho
* dual codecs support verified with 4 channels output
* v0.3 Feb 22 2000 Ollie Lho
* bug fix for record mask setting
* v0.2 Feb 10 2000 Ollie Lho
* add ac97_read_proc for /proc/driver/{vendor}/ac97
* v0.1 Jan 14 2000 Ollie Lho <ollie@sis.com.tw>
* Isolated from trident.c to support multiple ac97 codec
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/ac97_codec.h>
#include <asm/uaccess.h>
#include <linux/mutex.h>
#define CODEC_ID_BUFSZ 14
static int ac97_read_mixer(struct ac97_codec *codec, int oss_channel);
static void ac97_write_mixer(struct ac97_codec *codec, int oss_channel,
unsigned int left, unsigned int right);
static void ac97_set_mixer(struct ac97_codec *codec, unsigned int oss_mixer, unsigned int val );
static int ac97_recmask_io(struct ac97_codec *codec, int rw, int mask);
static int ac97_mixer_ioctl(struct ac97_codec *codec, unsigned int cmd, unsigned long arg);
static int ac97_init_mixer(struct ac97_codec *codec);
static int wolfson_init03(struct ac97_codec * codec);
static int wolfson_init04(struct ac97_codec * codec);
static int wolfson_init05(struct ac97_codec * codec);
static int wolfson_init11(struct ac97_codec * codec);
static int wolfson_init13(struct ac97_codec * codec);
static int tritech_init(struct ac97_codec * codec);
static int tritech_maestro_init(struct ac97_codec * codec);
static int sigmatel_9708_init(struct ac97_codec *codec);
static int sigmatel_9721_init(struct ac97_codec *codec);
static int sigmatel_9744_init(struct ac97_codec *codec);
static int ad1886_init(struct ac97_codec *codec);
static int eapd_control(struct ac97_codec *codec, int);
static int crystal_digital_control(struct ac97_codec *codec, int slots, int rate, int mode);
static int cmedia_init(struct ac97_codec * codec);
static int cmedia_digital_control(struct ac97_codec *codec, int slots, int rate, int mode);
static int generic_digital_control(struct ac97_codec *codec, int slots, int rate, int mode);
/*
* AC97 operations.
*
* If you are adding a codec then you should be able to use
* eapd_ops - any codec that supports EAPD amp control (most)
* null_ops - any ancient codec that supports nothing
*
* The three functions are
* init - used for non AC97 standard initialisation
* amplifier - used to do amplifier control (1=on 0=off)
* digital - switch to digital modes (0 = analog)
*
* Not all codecs support all features, not al