Creation of Cybook 2416 (actually Gen4) repository

This commit is contained in:
mlt
2009-12-18 17:10:00 +00:00
committed by godzil
commit 76f20f4d40
13791 changed files with 6812321 additions and 0 deletions

43
sound/soc/codecs/Kconfig Normal file
View File

@@ -0,0 +1,43 @@
config SND_SOC_AC97_CODEC
tristate
depends on SND_SOC
config SND_SOC_WM8580
tristate
depends on SND_SOC
config SND_SOC_WM8731
tristate
depends on SND_SOC
config SND_SOC_WM8750
tristate
depends on SND_SOC
config SND_SOC_WM8753
tristate
depends on SND_SOC
config SND_SOC_WM8772
tristate
depends on SND_SOC
config SND_SOC_WM8990
tristate
depends on SND_SOC
config SND_SOC_WM9712
tristate
depends on SND_SOC
config SND_SOC_WM9713
tristate
depends on SND_SOC
config SND_SOC_RT5627
tristate
depends on SND_SOC
config SND_SOC_RT5624
tristate
depends on SND_SOC

46
sound/soc/codecs/Makefile Normal file
View File

@@ -0,0 +1,46 @@
snd-soc-rt5627-objs := rt5627.o
snd-soc-rt5624-objs := rt5624.o
snd-soc-ac97-objs := ac97.o
snd-soc-wm8580-objs := wm8580.o
snd-soc-wm8731-objs := wm8731.o
snd-soc-wm8750-objs := wm8750.o
snd-soc-wm8753-objs := wm8753.o
snd-soc-wm8772-objs := wm8772.o
snd-soc-wm8900-objs := wm8900.o
snd-soc-wm8950-objs := wm8950.o
snd-soc-wm8951-objs := wm8951.o
snd-soc-wm8956-objs := wm8956.o
snd-soc-wm8960-objs := wm8960.o
snd-soc-wm8971-objs := wm8971.o
snd-soc-wm8974-objs := wm8974.o
snd-soc-wm8976-objs := wm8976.o
snd-soc-wm8978-objs := wm8978.o
snd-soc-wm8980-objs := wm8980.o
snd-soc-wm8990-objs := wm8990.o
snd-soc-wm8991-objs := wm8991.o
snd-soc-wm9712-objs := wm9712.o
snd-soc-wm9713-objs := wm9713.o
obj-$(CONFIG_SND_SOC_RT5627) += snd-soc-rt5627.o
obj-$(CONFIG_SND_SOC_RT5624) += snd-soc-rt5624.o
obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o
obj-$(CONFIG_SND_SOC_WM8580) += snd-soc-wm8580.o
obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o
obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o
obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o
obj-$(CONFIG_SND_SOC_WM8772) += snd-soc-wm8772.o
obj-$(CONFIG_SND_SOC_WM8950) += snd-soc-wm8950.o
obj-$(CONFIG_SND_SOC_WM8951) += snd-soc-wm8951.o
obj-$(CONFIG_SND_SOC_WM8956) += snd-soc-wm8956.o
obj-$(CONFIG_SND_SOC_WM8960) += snd-soc-wm8960.o
obj-$(CONFIG_SND_SOC_WM8971) += snd-soc-wm8971.o
obj-$(CONFIG_SND_SOC_WM8974) += snd-soc-wm8974.o
obj-$(CONFIG_SND_SOC_WM8976) += snd-soc-wm8976.o
obj-$(CONFIG_SND_SOC_WM8978) += snd-soc-wm8978.o
obj-$(CONFIG_SND_SOC_WM8980) += snd-soc-wm8980.o
obj-$(CONFIG_SND_SOC_WM8990) += snd-soc-wm8990.o
obj-$(CONFIG_SND_SOC_WM8991) += snd-soc-wm8991.o
obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o
obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o

158
sound/soc/codecs/ac97.c Normal file
View File

@@ -0,0 +1,158 @@
/*
* ac97.c -- ALSA Soc AC97 codec support
*
* Copyright 2005 Wolfson Microelectronics PLC.
* Author: Liam Girdwood
* liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.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.
*
* Revision history
* 17th Oct 2005 Initial version.
*
* Generic AC97 support.
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <sound/driver.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/ac97_codec.h>
#include <sound/initval.h>
#include <sound/soc.h>
#define AC97_VERSION "0.6"
static int ac97_prepare(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
struct snd_soc_codec *codec = socdev->codec;
int reg = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
AC97_PCM_FRONT_DAC_RATE : AC97_PCM_LR_ADC_RATE;
return snd_ac97_set_rate(codec->ac97, reg, runtime->rate);
}
#define STD_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
struct snd_soc_codec_dai ac97_dai = {
.name = "AC97 HiFi",
.type = SND_SOC_DAI_AC97,
.playback = {
.stream_name = "AC97 Playback",
.channels_min = 1,
.channels_max = 2,
.rates = STD_AC97_RATES,
.formats = SNDRV_PCM_FMTBIT_S16_LE,},
.capture = {
.stream_name = "AC97 Capture",
.channels_min = 1,
.channels_max = 2,
.rates = STD_AC97_RATES,
.formats = SNDRV_PCM_FMTBIT_S16_LE,},
.ops = {
.prepare = ac97_prepare,},
};
EXPORT_SYMBOL_GPL(ac97_dai);
static unsigned int ac97_read(struct snd_soc_codec *codec,
unsigned int reg)
{
return soc_ac97_ops.read(codec->ac97, reg);
}
static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int val)
{
soc_ac97_ops.write(codec->ac97, reg, val);
return 0;
}
static int ac97_soc_probe(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
struct snd_soc_codec *codec;
struct snd_ac97_bus *ac97_bus;
struct snd_ac97_template ac97_template;
int ret = 0;
printk(KERN_INFO "AC97 SoC Audio Codec %s\n", AC97_VERSION);
socdev->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
if (socdev->codec == NULL)
return -ENOMEM;
codec = socdev->codec;
mutex_init(&codec->mutex);
codec->name = "AC97";
codec->owner = THIS_MODULE;
codec->dai = &ac97_dai;
codec->num_dai = 1;
codec->write = ac97_write;
codec->read = ac97_read;
INIT_LIST_HEAD(&codec->dapm_widgets);
INIT_LIST_HEAD(&codec->dapm_paths);
/* register pcms */
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
if(ret < 0)
goto err;
/* add codec as bus device for standard ac97 */
ret = snd_ac97_bus(codec->card, 0, &soc_ac97_ops, NULL, &ac97_bus);
if(ret < 0)
goto bus_err;
memset(&ac97_template, 0, sizeof(struct snd_ac97_template));
ret = snd_ac97_mixer(ac97_bus, &ac97_template, &codec->ac97);
if(ret < 0)
goto bus_err;
ret = snd_soc_register_card(socdev);
if (ret < 0)
goto bus_err;
return 0;
bus_err:
snd_soc_free_pcms(socdev);
err:
kfree(socdev->codec->reg_cache);
kfree(socdev->codec);
socdev->codec = NULL;
return ret;
}
static int ac97_soc_remove(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
struct snd_soc_codec *codec = socdev->codec;
if(codec == NULL)
return 0;
snd_soc_free_pcms(socdev);
kfree(socdev->codec->reg_cache);
kfree(socdev->codec);
return 0;
}
struct snd_soc_codec_device soc_codec_dev_ac97= {
.probe = ac97_soc_probe,
.remove = ac97_soc_remove,
};
EXPORT_SYMBOL_GPL(soc_codec_dev_ac97);
MODULE_DESCRIPTION("Soc Generic AC97 driver");
MODULE_AUTHOR("Liam Girdwood");
MODULE_LICENSE("GPL");

19
sound/soc/codecs/ac97.h Normal file
View File

@@ -0,0 +1,19 @@
/*
* linux/sound/codecs/ac97.h -- ALSA SoC Layer
*
* Author: Liam Girdwood
* Created: Dec 1st 2005
* Copyright: Wolfson Microelectronics. PLC.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __LINUX_SND_SOC_AC97_H
#define __LINUX_SND_SOC_AC97_H
extern struct snd_soc_codec_device soc_codec_dev_ac97;
extern struct snd_soc_codec_dai ac97_dai;
#endif

3204
sound/soc/codecs/rt5624.c Normal file

File diff suppressed because it is too large Load Diff

609
sound/soc/codecs/rt5624.h Normal file
View File

@@ -0,0 +1,609 @@
/*
* rt5624.h -- audio driver for RT5624
*
* Copyright 2008 Realtek Microelectronics
*
* Author: flove <flove@realtek.com>
*
* Based on WM8753.h
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#ifndef _RT5624_H
#define _RT5624_H
//Index of Codec Register definition
#define RT5624_RESET 0X00 //RESET CODEC TO DEFAULT
#define RT5624_SPK_OUT_VOL 0X02 //SPEAKER OUT VOLUME
#define RT5624_HP_OUT_VOL 0X04 //HEADPHONE OUTPUT VOLUME
#define RT5624_PHONEIN_MONO_OUT_VOL 0X08 //PHONE INPUT/MONO OUTPUT VOLUME
#define RT5624_LINE_IN_VOL 0X0A //LINE IN VOLUME
#define RT5624_STEREO_DAC_VOL 0X0C //STEREO DAC VOLUME
#define RT5624_MIC_VOL 0X0E //MICROPHONE VOLUME
#define RT5624_MIC_ROUTING_CTRL 0X10 //MIC ROUTING CONTROL
#define RT5624_ADC_REC_GAIN 0X12 //ADC RECORD GAIN
#define RT5624_ADC_REC_MIXER 0X14 //ADC RECORD MIXER CONTROL
#define RT5624_VOICE_DAC_OUT_VOL 0X18 //VOICE DAC OUTPUT VOLUME
#define RT5624_OUTPUT_MIXER_CTRL 0X1C //OUTPUT MIXER CONTROL
#define RT5624_MIC_CTRL 0X22 //MICROPHONE CONTROL
#define RT5624_PD_CTRL_STAT 0X26 //POWER DOWN CONTROL/STATUS
#define RT5624_MAIN_SDP_CTRL 0X34 //MAIN SERIAL DATA PORT CONTROL(STEREO I2S)
#define RT5624_EXTEND_SDP_CTRL 0X36 //EXTEND SERIAL DATA PORT CONTROL(VOICE I2S/PCM)
#define RT5624_PWR_MANAG_ADD1 0X3A //POWER MANAGMENT ADDITION 1
#define RT5624_PWR_MANAG_ADD2 0X3C //POWER MANAGMENT ADDITION 2
#define RT5624_PWR_MANAG_ADD3 0X3E //POWER MANAGMENT ADDITION 3
#define RT5624_GEN_CTRL_REG1 0X40 //GENERAL PURPOSE CONTROL REGISTER 1
#define RT5624_GEN_CTRL_REG2 0X42 //GENERAL PURPOSE CONTROL REGISTER 2
#define RT5624_PLL_CTRL 0X44 //PLL CONTROL
#define RT5624_GPIO_PIN_CONFIG 0X4C //GPIO PIN CONFIGURATION
#define RT5624_GPIO_PIN_POLARITY 0X4E //GPIO PIN POLARITY
#define RT5624_GPIO_PIN_STICKY 0X50 //GPIO PIN STICKY
#define RT5624_GPIO_PIN_WAKEUP 0X52 //GPIO PIN WAKE UP
#define RT5624_GPIO_PIN_STATUS 0X54 //GPIO PIN STATUS
#define RT5624_GPIO_PIN_SHARING 0X56 //GPIO PIN SHARING
#define RT5624_OVER_TEMP_CURR_STATUS 0X58 //OVER TEMPERATURE AND CURRENT STATUS
#define RT5624_GPIO_OUT_CTRL 0X5C //GPIO OUTPUT PIN CONTRL
#define RT5624_MISC_CTRL 0X5E //MISC CONTROL
#define RT5624_STEREO_DAC_CLK_CTRL1 0X60 //STEREO DAC CLOCK CONTROL 1
#define RT5624_STEREO_DAC_CLK_CTRL2 0X62 //STEREO DAC CLOCK CONTROL 2
#define RT5624_VOICE_DAC_PCMCLK_CTRL1 0X64 //VOICE/PCM DAC CLOCK CONTROL 1
#define RT5624_VOICE_DAC_PCMCLK_CTRL2 0X66 //VOICE/PCM DAC CLOCK CONTROL 2
#define RT5624_PSEDUEO_SPATIAL_CTRL 0X68 //PSEDUEO STEREO /SPATIAL EFFECT BLOCK CONTROL
#define RT5624_INDEX_ADDRESS 0X6A //INDEX ADDRESS
#define RT5624_INDEX_DATA 0X6C //INDEX DATA
#define RT5624_EQ_STATUS 0X6E //EQ STATUS
#define RT5624_VENDOR_ID1 0x7C //VENDOR ID1
#define RT5624_VENDOR_ID2 0x7E //VENDOR ID2
//*************************************************************************************************
//Bit define of Codec Register
//*************************************************************************************************
//global definition
#define RT_L_MUTE (0x1<<15) //Mute Left Control
#define RT_L_ZC (0x1<<14) //Mute Left Zero-Cross Detector Control
#define RT_R_MUTE (0x1<<7) //Mute Right Control
#define RT_R_ZC (0x1<<6) //Mute Right Zero-Cross Detector Control
#define RT_M_HP_MIXER (0x1<<15) //Mute source to HP Mixer
#define RT_M_SPK_MIXER (0x1<<14) //Mute source to Speaker Mixer
#define RT_M_MONO_MIXER (0x1<<13) //Mute source to Mono Mixer
//Phone Input/MONO Output Volume(0x08)
#define M_PHONEIN_TO_HP_MIXER (0x1<<15) //Mute Phone In volume to HP mixer
#define M_PHONEIN_TO_SPK_MIXER (0x1<<14) //Mute Phone In volume to speaker mixer
#define M_MONO_OUT_VOL (0x1<<7) //Mute Mono output volume
//Mic Routing Control(0x10)
#define M_MIC1_TO_HP_MIXER (0x1<<15) //Mute MIC1 to HP mixer
#define M_MIC1_TO_SPK_MIXER (0x1<<14) //Mute MiC1 to SPK mixer
#define M_MIC1_TO_MONO_MIXER (0x1<<13) //Mute MIC1 to MONO mixer
#define MIC1_DIFF_INPUT_CTRL (0x1<<12) //MIC1 different input control
#define M_MIC2_TO_HP_MIXER (0x1<<7) //Mute MIC2 to HP mixer
#define M_MIC2_TO_SPK_MIXER (0x1<<6) //Mute MiC2 to SPK mixer
#define M_MIC2_TO_MONO_MIXER (0x1<<5) //Mute MIC2 to MONO mixer
#define MIC2_DIFF_INPUT_CTRL (0x1<<4) //MIC2 different input control
//ADC Record Gain(0x12)
#define M_ADC_L_TO_HP_MIXER (0x1<<15) //Mute left of ADC to HP Mixer
#define M_ADC_R_TO_HP_MIXER (0x1<<14) //Mute right of ADC to HP Mixer
#define M_ADC_L_TO_MONO_MIXER (0x1<<13) //Mute left of ADC to MONO Mixer
#define M_ADC_R_TO_MONO_MIXER (0x1<<12) //Mute right of ADC to MONO Mixer
#define ADC_L_GAIN_MASK (0x1f<<7) //ADC Record Gain Left channel Mask
#define ADC_L_ZC_DET (0x1<<6) //ADC Zero-Cross Detector Control
#define ADC_R_ZC_DET (0x1<<5) //ADC Zero-Cross Detector Control
#define ADC_R_GAIN_MASK (0x1f<<0) //ADC Record Gain Right channel Mask
//Voice DAC Output Volume(0x18)
#define M_V_DAC_TO_HP_MIXER (0x1<<15)
#define M_V_DAC_TO_SPK_MIXER (0x1<<14)
#define M_V_DAC_TO_MONO_MIXER (0x1<<13)
//Output Mixer Control(0x1C)
#define SPKL_INPUT_SEL_MASK (0x3<<14)
#define SPKL_INPUT_SEL_MONO (0x3<<14)
#define SPKL_INPUT_SEL_SPK (0x2<<14)
#define SPKL_INPUT_SEL_HPL (0x1<<14)
#define SPKL_INPUT_SEL_VMID (0x0<<14)
#define SPK_OUT_SEL_CLASS_D (0x1<<13)
#define SPK_OUT_SEL_CLASS_AB (0x0<<13)
#define SPKR_INPUT_SEL_MASK (0x3<<11)
#define SPKR_INPUT_SEL_MONO_MIXER (0x3<<11)
#define SPKR_INPUT_SEL_SPK_MIXER (0x2<<11)
#define SPKR_INPUT_SEL_HPR_MIXER (0x1<<11)
#define SPKR_INPUT_SEL_VMID (0x0<<11)
#define HPL_INPUT_SEL_HPL_MIXER (0x1<<9)
#define HPR_INPUT_SEL_HPR_MIXER (0x1<<8)
#define MONO_INPUT_SEL_MASK (0x3<<6)
#define MONO_INPUT_SEL_MONO_MIXER (0x3<<6)
#define MONO_INPUT_SEL_SPK_MIXER (0x2<<6)
#define MONO_INPUT_SEL_HP_MIXER (0x1<<6)
#define MONO_INPUT_SEL_VMID (0x0<<6)
//Micphone Control define(0x22)
#define MIC1 1
#define MIC2 2
#define MIC_BIAS_90_PRECNET_AVDD 1
#define MIC_BIAS_75_PRECNET_AVDD 2
#define MIC1_BOOST_CONTROL_MASK (0x3<<10)
#define MIC1_BOOST_CONTROL_BYPASS (0x0<<10)
#define MIC1_BOOST_CONTROL_20DB (0x1<<10)
#define MIC1_BOOST_CONTROL_30DB (0x2<<10)
#define MIC1_BOOST_CONTROL_40DB (0x3<<10)
#define MIC2_BOOST_CONTROL_MASK (0x3<<8)
#define MIC2_BOOST_CONTROL_BYPASS (0x0<<8)
#define MIC2_BOOST_CONTROL_20DB (0x1<<8)
#define MIC2_BOOST_CONTROL_30DB (0x2<<8)
#define MIC2_BOOST_CONTROL_40DB (0x3<<8)
#define MIC1_BIAS_VOLT_CTRL_MASK (0x1<<5)
#define MIC1_BIAS_VOLT_CTRL_90P (0x0<<5)
#define MIC1_BIAS_VOLT_CTRL_75P (0x1<<5)
#define MIC2_BIAS_VOLT_CTRL_MASK (0x1<<4)
#define MIC2_BIAS_VOLT_CTRL_90P (0x0<<4)
#define MIC2_BIAS_VOLT_CTRL_75P (0x1<<4)
//PowerDown control of register(0x26)
//power management bits
#define RT_PWR_PR7 (0x1<<15) //write this bit to power down the Speaker Amplifier
#define RT_PWR_PR6 (0x1<<14) //write this bit to power down the Headphone Out and MonoOut
#define RT_PWR_PR5 (0x1<<13) //write this bit to power down the internal clock(without PLL)
#define RT_PWR_PR3 (0x1<<11) //write this bit to power down the mixer(vref/vrefout out off)
#define RT_PWR_PR2 (0x1<<10) //write this bit to power down the mixer(vref/vrefout still on)
#define RT_PWR_PR1 (0x1<<9) //write this bit to power down the dac
#define RT_PWR_PR0 (0x1<<8) //write this bit to power down the adc
#define RT_PWR_REF (0x1<<3) //read only
#define RT_PWR_ANL (0x1<<2) //read only
#define RT_PWR_DAC (0x1<<1) //read only
#define RT_PWR_ADC (0x1) //read only
//Main Serial Data Port Control(0x34)
#define MAIN_I2S_MODE_SEL (0x1<<15) //0:Master mode 1:Slave mode
#define MAIN_I2S_SADLRCK_CTRL (0x1<<14) //0:Disable,ADC and DAC use the same fs,1:Enable
#define MAIN_I2S_BCLK_POLARITY (0x1<<12) //0:Normal 1:Invert
#define MAIN_I2S_DA_CLK_SOUR (0x1<<11) //0:from DA Filter,1:from DA Sigma Delta Clock Divider
//I2S DA SIGMA delta clock divider
#define MAIN_I2S_CLK_DIV_MASK (0x7<<8)
#define MAIN_I2S_CLK_DIV_2 (0x0<<8)
#define MAIN_I2S_CLK_DIV_4 (0x1<<8)
#define MAIN_I2S_CLK_DIV_8 (0x2<<8)
#define MAIN_I2S_CLK_DIV_16 (0x3<<8)
#define MAIN_I2S_CLK_DIV_32 (0x4<<8)
#define MAIN_I2S_CLK_DIV_64 (0x5<<8)
#define MAIN_I2S_PCM_MODE (0x1<<6) //PCM 0:mode A ,1:mode B
//Non PCM 0:Normal SADLRCK/SDALRCK,1:Invert SADLRCK/SDALRCK
//Data Length Slection
#define MAIN_I2S_DL_MASK (0x3<<2) //main i2s Data Length mask
#define MAIN_I2S_DL_16 (0x0<<2) //16 bits
#define MAIN_I2S_DL_20 (0x1<<2) //20 bits
#define MAIN_I2S_DL_24 (0x2<<2) //24 bits
#define MAIN_I2S_DL_32 (0x3<<2) //32 bits
//PCM Data Format Selection
#define MAIN_I2S_DF_MASK (0x3) //main i2s Data Format mask
#define MAIN_I2S_DF_I2S (0x0) //I2S FORMAT
#define MAIN_I2S_DF_RIGHT (0x1) //RIGHT JUSTIFIED format
#define MAIN_I2S_DF_LEFT (0x2) //LEFT JUSTIFIED format
#define MAIN_I2S_DF_PCM (0x3) //PCM format
//Extend Serial Data Port Control(0x36)
#define EXT_I2S_FUNC_ENABLE (0x1<<15) //Enable PCM interface on GPIO 1,3,4,5 0:GPIO function,1:Voice PCM interface
#define EXT_I2S_MODE_SEL (0x1<<14) //0:Master ,1:Slave
#define EXT_I2S_VOICE_ADC_EN (0x1<<8) //ADC_L=Stereo, ADC_R=Voice
#define EXT_I2S_BCLK_POLARITY (0x1<<7) //0:Normal 1:Invert
#define EXT_I2S_PCM_MODE (0x1<<6) //PCM 0:mode A ,1:mode B
//Non PCM 0:Normal SADLRCK/SDALRCK,1:Invert SADLRCK/SDALRCK
//Data Length Slection
#define EXT_I2S_DL_MASK (0x3<<2) //Extend i2s Data Length mask
#define EXT_I2S_DL_32 (0x3<<2) //32 bits
#define EXT_I2S_DL_24 (0x2<<2) //24 bits
#define EXT_I2S_DL_20 (0x1<<2) //20 bits
#define EXT_I2S_DL_16 (0x0<<2) //16 bits
//Voice Data Format
#define EXT_I2S_DF_MASK (0x3) //Extend i2s Data Format mask
#define EXT_I2S_DF_I2S (0x0) //I2S FORMAT
#define EXT_I2S_DF_RIGHT (0x1) //RIGHT JUSTIFIED format
#define EXT_I2S_DF_LEFT (0x2) //LEFT JUSTIFIED format
#define EXT_I2S_DF_PCM (0x3) //PCM format
//Power managment addition 1 (0x3A),0:Disable,1:Enable
#define PWR_HI_R_LOAD_MONO (0x1<<15)
#define PWR_HI_R_LOAD_HP (0x1<<14)
#define PWR_ZC_DET_PD (0x1<<13)
#define PWR_MAIN_I2S (0x1<<11)
#define PWR_MIC_BIAS1_DET (0x1<<5)
#define PWR_MIC_BIAS2_DET (0x1<<4)
#define PWR_MIC_BIAS1 (0x1<<3)
#define PWR_MIC_BIAS2 (0x1<<2)
#define PWR_MAIN_BIAS (0x1<<1)
#define PWR_DAC_REF (0x1)
//Power managment addition 2(0x3C),0:Disable,1:Enable
#define EN_THREMAL_SHUTDOWN (0x1<<15)
#define PWR_CLASS_AB (0x1<<14)
#define PWR_MIXER_VREF (0x1<<13)
#define PWR_PLL (0x1<<12)
#define PWR_VOICE_CLOCK (0x1<<10)
#define PWR_L_DAC_CLK (0x1<<9)
#define PWR_R_DAC_CLK (0x1<<8)
#define PWR_L_ADC_CLK_GAIN (0x1<<7)
#define PWR_R_ADC_CLK_GAIN (0x1<<6)
#define PWR_L_HP_MIXER (0x1<<5)
#define PWR_R_HP_MIXER (0x1<<4)
#define PWR_SPK_MIXER (0x1<<3)
#define PWR_MONO_MIXER (0x1<<2)
#define PWR_L_ADC_REC_MIXER (0x1<<1)
#define PWR_R_ADC_REC_MIXER (0x1)
//Power managment addition 3(0x3E),0:Disable,1:Enable
#define PWR_MONO_VOL (0x1<<14)
#define PWR_SPK_LN_OUT (0x1<<13)
#define PWR_SPK_RN_OUT (0x1<<12)
#define PWR_HP_L_OUT (0x1<<11)
#define PWR_HP_R_OUT (0x1<<10)
#define PWR_SPK_L_OUT (0x1<<9)
#define PWR_SPK_R_OUT (0x1<<8)
#define PWR_LINE_IN_L (0x1<<7)
#define PWR_LINE_IN_R (0x1<<6)
#define PWR_PHONE_MIXER (0x1<<5)
#define PWR_PHONE_VOL (0x1<<4)
#define PWR_MIC1_VOL_CTRL (0x1<<3)
#define PWR_MIC2_VOL_CTRL (0x1<<2)
#define PWR_MIC1_BOOST (0x1<<1)
#define PWR_MIC2_BOOST (0x1)
//General Purpose Control Register 1(0x40)
#define GP_CLK_FROM_PLL (0x1<<15) //Clock source from PLL output
#define GP_CLK_FROM_MCLK (0x0<<15) //Clock source from MCLK output
#define GP_HP_AMP_CTRL_MASK (0x3<<8)
#define GP_HP_AMP_CTRL_RATIO_100 (0x0<<8) //1.00 Vdd
#define GP_HP_AMP_CTRL_RATIO_125 (0x1<<8) //1.25 Vdd
#define GP_HP_AMP_CTRL_RATIO_150 (0x2<<8) //1.50 Vdd
#define GP_SPK_D_AMP_CTRL_MASK (0x3<<6)
#define GP_SPK_D_AMP_CTRL_RATIO_175 (0x0<<6) //1.75 Vdd
#define GP_SPK_D_AMP_CTRL_RATIO_150 (0x1<<6) //1.50 Vdd
#define GP_SPK_D_AMP_CTRL_RATIO_125 (0x2<<6) //1.25 Vdd
#define GP_SPK_D_AMP_CTRL_RATIO_100 (0x3<<6) //1.00 Vdd
#define GP_SPK_AB_AMP_CTRL_MASK (0x7<<3)
#define GP_SPK_AB_AMP_CTRL_RATIO_225 (0x0<<3) //2.25 Vdd
#define GP_SPK_AB_AMP_CTRL_RATIO_200 (0x1<<3) //2.00 Vdd
#define GP_SPK_AB_AMP_CTRL_RATIO_175 (0x2<<3) //1.75 Vdd
#define GP_SPK_AB_AMP_CTRL_RATIO_150 (0x3<<3) //1.50 Vdd
#define GP_SPK_AB_AMP_CTRL_RATIO_125 (0x4<<3) //1.25 Vdd
#define GP_SPK_AB_AMP_CTRL_RATIO_100 (0x5<<3) //1.00 Vdd
//General Purpose Control Register 2(0x42)
#define GP2_VOICE_TO_DIG_PATH_EN (0x1<<15)
#define GP2_CLASS_AB_SEL_DIFF (0x0<<13) //Differential Mode of Class AB
#define GP2_CLASS_D_SEL_SINGLE (0x1<<13) //Single End mode of Class AB
#define GP2_PLL_PRE_DIV_1 (0x0<<0) //PLL pre-Divider 1
#define GP2_PLL_PRE_DIV_2 (0x1<<0) //PLL pre-Divider 2
//PLL Control(0x44)
#define PLL_M_CODE_MASK 0xF //PLL M code mask
#define PLL_K_CODE_MASK (0x7<<4) //PLL K code mask
#define PLL_BYPASS_N (0x1<<7) //bypass PLL N code
#define PLL_N_CODE_MASK (0xFF<<8) //PLL N code mask
#define PLL_CTRL_M_VAL(m) ((m)&0xf)
#define PLL_CTRL_K_VAL(k) (((k)&0x7)<<4)
#define PLL_CTRL_N_VAL(n) (((n)&0xff)<<8)
//GPIO Pin Configuration(0x4C)
#define GPIO_1 (0x1<<1)
#define GPIO_2 (0x1<<2)
#define GPIO_3 (0x1<<3)
#define GPIO_4 (0x1<<4)
#define GPIO_5 (0x1<<5)
////INTERRUPT CONTROL(0x5E)
#define DISABLE_FAST_VREG (0x1<<15)
#define AVC_TARTGET_SEL_MASK (0x3<<12)
#define AVC_TARTGET_SEL_NONE (0x0<<12)
#define AVC_TARTGET_SEL_R (0x1<<12)
#define AVC_TARTGET_SEL_L (0x2<<12)
#define AVC_TARTGET_SEL_BOTH (0x3<<12)
//Stereo DAC Clock Control 1(0x60)
#define STEREO_SCLK_DIV1_MASK (0xF<<12)
#define STEREO_SCLK_DIV1_1 (0x0<<12)
#define STEREO_SCLK_DIV1_2 (0x1<<12)
#define STEREO_SCLK_DIV1_3 (0x2<<12)
#define STEREO_SCLK_DIV1_4 (0x3<<12)
#define STEREO_SCLK_DIV1_5 (0x4<<12)
#define STEREO_SCLK_DIV1_6 (0x5<<12)
#define STEREO_SCLK_DIV1_7 (0x6<<12)
#define STEREO_SCLK_DIV1_8 (0x7<<12)
#define STEREO_SCLK_DIV1_9 (0x8<<12)
#define STEREO_SCLK_DIV1_10 (0x9<<12)
#define STEREO_SCLK_DIV1_11 (0xA<<12)
#define STEREO_SCLK_DIV1_12 (0xB<<12)
#define STEREO_SCLK_DIV1_13 (0xC<<12)
#define STEREO_SCLK_DIV1_14 (0xD<<12)
#define STEREO_SCLK_DIV1_15 (0xE<<12)
#define STEREO_SCLK_DIV1_16 (0xF<<12)
#define STEREO_SCLK_DIV2_MASK (0x7<<8)
#define STEREO_SCLK_DIV2_2 (0x0<<8)
#define STEREO_SCLK_DIV2_4 (0x1<<8)
#define STEREO_SCLK_DIV2_8 (0x2<<8)
#define STEREO_SCLK_DIV2_16 (0x3<<8)
#define STEREO_SCLK_DIV2_32 (0x4<<8)
#define STEREO_AD_WCLK_DIV1_MASK (0xF<<4)
#define STEREO_AD_WCLK_DIV1_1 (0x0<<4)
#define STEREO_AD_WCLK_DIV1_2 (0x1<<4)
#define STEREO_AD_WCLK_DIV1_3 (0x2<<4)
#define STEREO_AD_WCLK_DIV1_4 (0x3<<4)
#define STEREO_AD_WCLK_DIV1_5 (0x4<<4)
#define STEREO_AD_WCLK_DIV1_6 (0x5<<4)
#define STEREO_AD_WCLK_DIV1_7 (0x6<<4)
#define STEREO_AD_WCLK_DIV1_8 (0x7<<4)
#define STEREO_AD_WCLK_DIV1_9 (0x8<<4)
#define STEREO_AD_WCLK_DIV1_10 (0x9<<4)
#define STEREO_AD_WCLK_DIV1_11 (0xA<<4)
#define STEREO_AD_WCLK_DIV1_12 (0xB<<4)
#define STEREO_AD_WCLK_DIV1_13 (0xC<<4)
#define STEREO_AD_WCLK_DIV1_14 (0xD<<4)
#define STEREO_AD_WCLK_DIV1_15 (0xE<<4)
#define STEREO_AD_WCLK_DIV1_16 (0xF<<4)
#define STEREO_AD_WCLK_DIV2_MASK (0x7<<1)
#define STEREO_AD_WCLK_DIV2_2 (0x0<<1)
#define STEREO_AD_WCLK_DIV2_4 (0x1<<1)
#define STEREO_AD_WCLK_DIV2_8 (0x2<<1)
#define STEREO_AD_WCLK_DIV2_16 (0x3<<1)
#define STEREO_AD_WCLK_DIV2_32 (0x4<<1)
#define STEREO_DA_WCLK_DIV_MASK (1)
#define STEREO_DA_WCLK_DIV_32 (0)
#define STEREO_DA_WCLK_DIV_64 (1)
//Stereo DAC Clock Control 2(0x62)
#define STEREO_DA_FILTER_DIV1_MASK (0xF<<12)
#define STEREO_DA_FILTER_DIV1_1 (0x0<<12)
#define STEREO_DA_FILTER_DIV1_2 (0x1<<12)
#define STEREO_DA_FILTER_DIV1_3 (0x2<<12)
#define STEREO_DA_FILTER_DIV1_4 (0x3<<12)
#define STEREO_DA_FILTER_DIV1_5 (0x4<<12)
#define STEREO_DA_FILTER_DIV1_6 (0x5<<12)
#define STEREO_DA_FILTER_DIV1_7 (0x6<<12)
#define STEREO_DA_FILTER_DIV1_8 (0x7<<12)
#define STEREO_DA_FILTER_DIV1_9 (0x8<<12)
#define STEREO_DA_FILTER_DIV1_10 (0x9<<12)
#define STEREO_DA_FILTER_DIV1_11 (0xA<<12)
#define STEREO_DA_FILTER_DIV1_12 (0xB<<12)
#define STEREO_DA_FILTER_DIV1_13 (0xC<<12)
#define STEREO_DA_FILTER_DIV1_14 (0xD<<12)
#define STEREO_DA_FILTER_DIV1_15 (0xE<<12)
#define STEREO_DA_FILTER_DIV1_16 (0xF<<12)
#define STEREO_DA_FILTER_DIV2_MASK (0x7<<9)
#define STEREO_DA_FILTER_DIV2_2 (0x0<<9)
#define STEREO_DA_FILTER_DIV2_4 (0x1<<9)
#define STEREO_DA_FILTER_DIV2_8 (0x2<<9)
#define STEREO_DA_FILTER_DIV2_16 (0x3<<9)
#define STEREO_DA_FILTER_DIV2_32 (0x4<<9)
#define STEREO_AD_FILTER_DIV1_MASK (0xF<<4)
#define STEREO_AD_FILTER_DIV1_1 (0x0<<4)
#define STEREO_AD_FILTER_DIV1_2 (0x1<<4)
#define STEREO_AD_FILTER_DIV1_3 (0x2<<4)
#define STEREO_AD_FILTER_DIV1_4 (0x3<<4)
#define STEREO_AD_FILTER_DIV1_5 (0x4<<4)
#define STEREO_AD_FILTER_DIV1_6 (0x5<<4)
#define STEREO_AD_FILTER_DIV1_7 (0x6<<4)
#define STEREO_AD_FILTER_DIV1_8 (0x7<<4)
#define STEREO_AD_FILTER_DIV1_9 (0x8<<4)
#define STEREO_AD_FILTER_DIV1_10 (0x9<<4)
#define STEREO_AD_FILTER_DIV1_11 (0xA<<4)
#define STEREO_AD_FILTER_DIV1_12 (0xB<<4)
#define STEREO_AD_FILTER_DIV1_13 (0xC<<4)
#define STEREO_AD_FILTER_DIV1_14 (0xD<<4)
#define STEREO_AD_FILTER_DIV1_15 (0xE<<4)
#define STEREO_AD_FILTER_DIV1_16 (0xF<<4)
#define STEREO_AD_FILTER_DIV2_MASK (0x7<<1)
#define STEREO_AD_FILTER_DIV2_2 (0x0<<1)
#define STEREO_AD_FILTER_DIV2_4 (0x1<<1)
#define STEREO_AD_FILTER_DIV2_8 (0x2<<1)
#define STEREO_AD_FILTER_DIV2_16 (0x3<<1)
#define STEREO_AD_FILTER_DIV2_32 (0x4<<1)
//Voice DAC PCM Clock Control 1(0x64)
#define VOICE_MCLK_SEL_MASK (0x1<<15)
#define VOICE_MCLK_SEL_MCLK_INPUT (0x0<<15)
#define VOICE_MCLK_SEL_PLL_OUTPUT (0x1<<15)
#define VOICE_SYSCLK_SEL_MASK (0x1<<14)
#define VOICE_SYSCLK_SEL_MCLK (0x0<<14)
#define VOICE_SYSCLK_SEL_EXTCLK (0x1<<14)
#define VOICE_WCLK_DIV_MASK (0x1<<13)
#define VOICE_WCLK_DIV_32 (0x0<<13)
#define VOICE_WCLK_DIV_64 (0x1<<13)
#define VOICE_EXTCLK_OUT_DIV_MASK (0x7<<8)
#define VOICE_EXTCLK_OUT_DIV_1 (0x0<<8)
#define VOICE_EXTCLK_OUT_DIV_2 (0x1<<8)
#define VOICE_EXTCLK_OUT_DIV_4 (0x2<<8)
#define VOICE_EXTCLK_OUT_DIV_8 (0x3<<8)
#define VOICE_EXTCLK_OUT_DIV_16 (0x4<<8)
#define VOICE_SCLK_DIV1_MASK (0xF<<4)
#define VOICE_SCLK_DIV1_1 (0x0<<4)
#define VOICE_SCLK_DIV1_2 (0x1<<4)
#define VOICE_SCLK_DIV1_3 (0x2<<4)
#define VOICE_SCLK_DIV1_4 (0x3<<4)
#define VOICE_SCLK_DIV1_5 (0x4<<4)
#define VOICE_SCLK_DIV1_6 (0x5<<4)
#define VOICE_SCLK_DIV1_7 (0x6<<4)
#define VOICE_SCLK_DIV1_8 (0x7<<4)
#define VOICE_SCLK_DIV1_9 (0x8<<4)
#define VOICE_SCLK_DIV1_10 (0x9<<4)
#define VOICE_SCLK_DIV1_11 (0xA<<4)
#define VOICE_SCLK_DIV1_12 (0xB<<4)
#define VOICE_SCLK_DIV1_13 (0xC<<4)
#define VOICE_SCLK_DIV1_14 (0xD<<4)
#define VOICE_SCLK_DIV1_15 (0xE<<4)
#define VOICE_SCLK_DIV1_16 (0xF<<4)
#define VOICE_SCLK_DIV2_MASK (0x7)
#define VOICE_SCLK_DIV2_2 (0x0)
#define VOICE_SCLK_DIV2_4 (0x1)
#define VOICE_SCLK_DIV2_8 (0x2)
#define VOICE_SCLK_DIV2_16 (0x3)
#define VOICE_SCLK_DIV2_32 (0x4)
//Voice DAC PCM Clock Control 2(0x66)
#define VOICE_CLK_FILTER_SLAVE_DIV_MASK (0x1<<15)
#define VOICE_CLK_FILTER_SLAVE_DIV_1 (0x0<<15)
#define VOICE_CLK_FILTER_SLAVE_DIV_2 (0x1<<15)
#define VOICE_FILTER_CLK_F_MASK (0x1<<14)
#define VOICE_FILTER_CLK_F_MCLK (0x0<<14)
#define VOICE_FILTER_CLK_F_VBCLK (0X1<<14)
#define VOICE_AD_DA_FILTER_SEL_MASK (0x1<<13)
#define VOICE_AD_DA_FILTER_SEL_128X (0x0<<13)
#define VOICE_AD_DA_FILTER_SEL_64X (0x1<<13)
#define VOICE_CLK_FILTER_DIV1_MASK (0xF<<4)
#define VOICE_CLK_FILTER_DIV1_1 (0x0<<4)
#define VOICE_CLK_FILTER_DIV1_2 (0x1<<4)
#define VOICE_CLK_FILTER_DIV1_3 (0x2<<4)
#define VOICE_CLK_FILTER_DIV1_4 (0x3<<4)
#define VOICE_CLK_FILTER_DIV1_5 (0x4<<4)
#define VOICE_CLK_FILTER_DIV1_6 (0x5<<4)
#define VOICE_CLK_FILTER_DIV1_7 (0x6<<4)
#define VOICE_CLK_FILTER_DIV1_8 (0x7<<4)
#define VOICE_CLK_FILTER_DIV1_9 (0x8<<4)
#define VOICE_CLK_FILTER_DIV1_10 (0x9<<4)
#define VOICE_CLK_FILTER_DIV1_11 (0xA<<4)
#define VOICE_CLK_FILTER_DIV1_12 (0xB<<4)
#define VOICE_CLK_FILTER_DIV1_13 (0xC<<4)
#define VOICE_CLK_FILTER_DIV1_14 (0xD<<4)
#define VOICE_CLK_FILTER_DIV1_15 (0xE<<4)
#define VOICE_CLK_FILTER_DIV1_16 (0xF<<4)
#define VOICE_CLK_FILTER_DIV2_MASK (0x7)
#define VOICE_CLK_FILTER_DIV2_2 (0x0)
#define VOICE_CLK_FILTER_DIV2_4 (0x1)
#define VOICE_CLK_FILTER_DIV2_8 (0x2)
#define VOICE_CLK_FILTER_DIV2_16 (0x3)
#define VOICE_CLK_FILTER_DIV2_32 (0x4)
//Psedueo Stereo & Spatial Effect Block Control(0x68)
#define SPATIAL_CTRL_EN (0x1<<15)
#define ALL_PASS_FILTER_EN (0x1<<14)
#define PSEUDO_STEREO_EN (0x1<<13)
#define STEREO_EXPENSION_EN (0x1<<12)
#define SPATIAL_GAIN_MASK (0x3<<6)
#define SPATIAL_GAIN_1_0 (0x0<<6)
#define SPATIAL_GAIN_1_5 (0x1<<6)
#define SPATIAL_GAIN_2_0 (0x2<<6)
#define SPATIAL_RATIO_MASK (0x3<<4)
#define SPATIAL_RATIO_0_0 (0x0<<4)
#define SPATIAL_RATIO_0_66 (0x1<<4)
#define SPATIAL_RATIO_1_0 (0x2<<4)
#define APF_MASK (0x3)
#define APF_FOR_48K (0x3)
#define APF_FOR_44_1K (0x2)
#define APF_FOR_32K (0x1)
struct rt5624_setup_data {
unsigned short i2c_address;
};
#define RT5624_PLL_FR_MCLK 0
//WaveOut channel for realtek codec
enum
{
RT_WAVOUT_SPK =(0x1<<0),
RT_WAVOUT_SPK_R =(0x1<<1),
RT_WAVOUT_SPK_L =(0x1<<2),
RT_WAVOUT_HP =(0x1<<3),
RT_WAVOUT_HP_R =(0x1<<4),
RT_WAVOUT_HP_L =(0x1<<5),
RT_WAVOUT_MONO =(0x1<<6),
RT_WAVOUT_AUXOUT =(0x1<<7),
RT_WAVOUT_AUXOUT_R =(0x1<<8),
RT_WAVOUT_AUXOUT_L =(0x1<<9),
RT_WAVOUT_LINEOUT =(0x1<<10),
RT_WAVOUT_LINEOUT_R =(0x1<<11),
RT_WAVOUT_LINEOUT_L =(0x1<<12),
RT_WAVOUT_DAC =(0x1<<13),
RT_WAVOUT_ALL_ON =(0x1<<14),
};
//WaveIn channel for realtek codec
enum
{
RT_WAVIN_R_MONO_MIXER =(0x1<<0),
RT_WAVIN_R_SPK_MIXER =(0x1<<1),
RT_WAVIN_R_HP_MIXER =(0x1<<2),
RT_WAVIN_R_PHONE =(0x1<<3),
RT_WAVIN_R_AUXIN =(0x1<<3),
RT_WAVIN_R_LINE_IN =(0x1<<4),
RT_WAVIN_R_MIC2 =(0x1<<5),
RT_WAVIN_R_MIC1 =(0x1<<6),
RT_WAVIN_L_MONO_MIXER =(0x1<<8),
RT_WAVIN_L_SPK_MIXER =(0x1<<9),
RT_WAVIN_L_HP_MIXER =(0x1<<10),
RT_WAVIN_L_PHONE =(0x1<<11),
RT_WAVIN_L_AUXIN =(0x1<<11),
RT_WAVIN_L_LINE_IN =(0x1<<12),
RT_WAVIN_L_MIC2 =(0x1<<13),
RT_WAVIN_L_MIC1 =(0x1<<14),
};
enum
{
POWER_STATE_D0=0,
POWER_STATE_D1,
POWER_STATE_D1_PLAYBACK,
POWER_STATE_D1_RECORD,
POWER_STATE_D2,
POWER_STATE_D2_PLAYBACK,
POWER_STATE_D2_RECORD,
POWER_STATE_D3,
POWER_STATE_D4
};
extern struct snd_soc_codec_dai rt5624_dai;
extern struct snd_soc_codec_device soc_codec_dev_rt5624;
#endif

1376
sound/soc/codecs/rt5627.c Normal file

File diff suppressed because it is too large Load Diff

316
sound/soc/codecs/rt5627.h Normal file
View File

@@ -0,0 +1,316 @@
/*
* rt5627.h -- audio driver for RT5627/RT5628
*
* Copyright 2008 Realtek Microelectronics
*
* Author: flove <flove@realtek.com>
*
* Based on WM8753.h
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#ifndef _RT5627_H
#define _RT5627_H
#define RT5627_RESET 0X00 //RESET CODEC TO DEFAULT
#define RT5627_SPK_OUT_VOL 0X02 //SPEAKER OUT VOLUME
#define RT5627_HP_OUT_VOL 0X04 //HEADPHONE OUTPUT VOLUME
#define RT5627_AUXIN_VOL 0X08 //AUXIN VOLUME
#define RT5627_LINE_IN_VOL 0X0A //LINE IN VOLUME
#define RT5627_STEREO_DAC_VOL 0X0C //STEREO DAC VOLUME
#define RT5627_SOFT_VOL_CTRL_TIME 0X16 //SOFT DELAY VOLUME CONTROL TIME
#define RT5627_OUTPUT_MIXER_CTRL 0X1C //OUTPUT MIXER CONTROL
#define RT5627_AUDIO_DATA_CTRL 0X34 //STEREO AUDIO DATA CONTROL
#define RT5627_DAC_CLK_CTRL 0X38 //STEREO DAC CLOCK CONTROL
#define RT5627_PWR_MANAG_ADD1 0X3A //POWER MANAGMENT ADDITION 1
#define RT5627_PWR_MANAG_ADD2 0X3C //POWER MANAGMENT ADDITION 2
#define RT5627_PWR_MANAG_ADD3 0X3E //POWER MANAGMENT ADDITION 3
#define RT5627_GEN_CTRL 0X40 //GENERAL PURPOSE CONTROL
#define RT5627_GLOBAL_CLK_CTRL 0X42 //GLOBAL CLOCK CONTROL
#define RT5627_PLL_CTRL 0X44 //PLL CONTROL
#define RT5627_GPIO_PIN_CONFIG 0X48 //GPIO PIN CONFIG
#define RT5627_GPIO_OUTPUT_PIN_CTRL 0X4A //GPIO CONTROL
#define RT5627_JACK_DET_CTRL 0X5A //JACK DETECT CONTROL
#define RT5627_MISC1_CTRL 0X5C //MISC1 CONTROL
#define RT5627_MISC2_CTRL 0X5E //MISC2 CONTROL
#define RT5627_AVC_CTRL 0X68 //AVC CONTROL
#define RT5627_HID_CTRL_INDEX 0X6A //PRIVATE REGISTER ADDRESS
#define RT5627_HID_CTRL_DATA 0X6C //PRIVATE REGISTER DATA
#define RT5627_VENDOR_ID1 0x7C //VENDOR ID1
#define RT5627_VENDOR_ID2 0x7E //VENDOR ID2
//global definition
#define RT_L_MUTE (0x1<<15) //MUTE LEFT CONTROL BIT
#define RT_R_MUTE (0x1<<7) //MUTE RIGHT CONTROL BIT
#define RT_M_HP_MIXER (0x1<<15) //Mute source to HP Mixer
#define RT_M_SPK_MIXER (0x1<<14) //Mute source to Speaker Mixer
#define RT_M_MONO_MIXER (0x1<<13) //Mute source to Mono Mixer
#define ALL_FIELD 0xffff
//Output Mixer Control(0x1C)
#define SPKOUT_N_SOUR_MASK (0x3<<14)
#define SPKOUT_N_SOUR_MUTE (0x3<<14)
#define SPKOUT_N_SOUR_LN (0x2<<14)
#define SPKOUT_N_SOUR_RP (0x1<<14)
#define SPKOUT_N_SOUR_RN (0x0<<14)
#define SPKOUT_INPUT_SEL_MASK (0x3<<10)
#define SPKOUT_INPUT_SEL_SPKMIXER (0x2<<10)
#define SPKOUT_INPUT_SEL_HPMIXER (0x1<<10)
#define SPKOUT_INPUT_SEL_VMID (0x0<<10)
#define HPL_INPUT_SEL_HPLMIXER (0x1<<9)
#define HPR_INPUT_SEL_HPRMIXER (0x1<<8)
#define AUXOUT_L_INPUT_SEL_MASK (0x1<<7)
#define AUXOUT_L_INPUT_SEL_HPLMIXER (0x1<<7)
#define AUXOUT_L_INPUT_SEL_SPKMIXER (0x0<<7)
#define AUXOUT_R_INPUT_SEL_MASK (0x1<<6)
#define AUXOUT_R_INPUT_SEL_HPLMIXER (0x1<<6)
#define AUXOUT_R_INPUT_SEL_SPKMIXER (0x0<<6)
#define SPK_VOL_DIFF_NEG_SIG_ENA (0x2<<2)
#define DAC_DIRECT_TO_HP (0x1<<1)
#define DAC_DIRECT_TO_AUXOUT (0x1)
//Audio Interface(0x34)
#define SDP_MASTER_MODE (0x0<<15)
#define SDP_SLAVE_MODE (0x1<<15)
#define MAIN_I2S_BCLK_POL_CTRL (0x1<<7) //0:Normal 1:Invert
#define DAC_DATA_L_R_SWAP (0x1<<4) //0:DAC data appear at left phase of LRCK
//1:DAC data appear at right phase of LRCK
//Data Length Slection
#define I2S_DL_MASK (0x3<<2) //main i2s Data Length mask
#define I2S_DL_16 (0x0<<2) //16 bits
#define I2S_DL_20 (0x1<<2) //20 bits
#define I2S_DL_24 (0x2<<2) //24 bits
//PCM Data Format Selection
#define I2S_DF_MASK (0x3) //IIS Data Format Mask
#define I2S_DF_I2S (0x0) //I2S FORMAT
#define I2S_DF_LEFT (0x1) //LEFT JUSTIFIED FORMAT
#define I2S_DF_PCM_A (0x2) //PCM MODE A
#define I2S_DF_PCM_B (0x3) //PCM MODE B
//Stereo AD/DA Clock Control(0x38h)
#define I2S_PRE_DIV_MASK (0x7<<13)
#define I2S_PRE_DIV_1 (0x0<<13) //DIV 1
#define I2S_PRE_DIV_2 (0x1<<13) //DIV 2
#define I2S_PRE_DIV_4 (0x2<<13) //DIV 4
#define I2S_PRE_DIV_8 (0x3<<13) //DIV 8
#define I2S_PRE_DIV_16 (0x4<<13) //DIV 16
#define I2S_PRE_DIV_32 (0x5<<13) //DIV 32
#define I2S_BCLK_SEL_64FS (0x0<<12) //32 BITS(64FS)
#define I2S_BCLK_SEL_32FS (0x1<<12) //16 BITS(32FS)
#define DAC_FILTER_CLK_SEL_256FS (0<<2) //256FS
#define DAC_FILTER_CLK_SEL_384FS (1<<2) //384FS
//Power managment addition 1 (0x3A),0:Disable,1:Enable
#define PWR_MAIN_I2S_EN (0x1<<15)
#define PWR_ZC_DET_PD_EN (0x1<<14)
#define PWR_SOFTGEN_EN (0x1<<8)
#define PWR_HP_AMP (0x1<<5)
#define PWR_HP_ENH_AMP (0x1<<4)
//Power managment addition 2(0x3C),0:Disable,1:Enable
#define PWR_CLASS_D (0x1<<14)
#define PWR_VREF (0x1<<13)
#define PWR_PLL (0x1<<12)
#define PWR_THERMAL_SD (0x1<<11)
#define PWR_DAC_REF_CIR (0x1<<10)
#define PWR_L_DAC_CLK (0x1<<9)
#define PWR_R_DAC_CLK (0x1<<8)
#define PWR_L_DAC_L_D_S (0x1<<7)
#define PWR_R_DAC_R_D_S (0x1<<6)
#define PWR_L_HP_MIXER (0x1<<5)
#define PWR_R_HP_MIXER (0x1<<4)
#define PWR_SPK_MIXER (0x1<<3)
//Power managment addition 3(0x3E),0:Disable,1:Enable
#define PWR_MAIN_BIAS (0x1<<15)
#define PWR_SPK_OUT (0x1<<12)
#define PWR_HP_L_OUT_VOL_AMP (0x1<<10)
#define PWR_HP_R_OUT_VOL_AMP (0x1<<9)
#define PWR_LINEIN_L_VOL (0x1<<7)
#define PWR_LINEIN_R_VOL (0x1<<6)
#define PWR_AUXIN_L_VOL (0x1<<5)
#define PWR_AUXIN_R_VOL (0x1<<4)
//Additional Control Register(0x40)
#define SPK_D_AMP_CTRL_MASK (0x7<<9)
#define SPK_D_AMP_CTRL_RATIO_225 (0x0<<9) //2.25 Vdd
#define SPK_D_AMP_CTRL_RATIO_200 (0x1<<9) //2.00 Vdd
#define SPK_D_AMP_CTRL_RATIO_175 (0x2<<9) //1.75 Vdd
#define SPK_D_AMP_CTRL_RATIO_150 (0x3<<9) //1.50 Vdd
#define SPK_D_AMP_CTRL_RATIO_125 (0x4<<9) //1.25 Vdd
#define SPK_D_AMP_CTRL_RATIO_100 (0x5<<9) //1.00 Vdd
#define STEREO_DAC_H_PASS_EN (0x1<<8) //enable HIGH PASS FILTER FOR DAC
//Global Clock Control Register(0x42)
#define SYSCLK_SOUR_SEL_MASK (0x1<<15)
#define SYSCLK_SOUR_SEL_MCLK (0x0<<15) //system Clock source from MCLK
#define SYSCLK_SOUR_SEL_PLL (0x1<<15) //system Clock source from PLL
#define PLLCLK_SOUR_SEL_MCLK (0x0<<14) //PLL clock source from MCLK
#define PLLCLK_SOUR_SEL_BITCLK (0x1<<14) //PLL clock source from BITCLK
#define PLLCLK_DIV_RATIO_MASK (0x3<<1)
#define PLLCLK_DIV_RATIO_DIV1 (0x0<<1) //DIV 1
#define PLLCLK_DIV_RATIO_DIV2 (0x1<<1) //DIV 2
#define PLLCLK_DIV_RATIO_DIV4 (0x2<<1) //DIV 4
#define PLLCLK_DIV_RATIO_DIV8 (0x3<<1) //DIV 8
#define PLLCLK_PRE_DIV1 (0x0) //DIV 1
#define PLLCLK_PRE_DIV2 (0x1) //DIV 2
//PLL Control(0x44)
#define PLL_CTRL_M_VAL(m) ((m)&0xf)
#define PLL_CTRL_K_VAL(k) (((k)&0x7)<<4)
#define PLL_CTRL_N_VAL(n) (((n)&0xff)<<8)
//GPIO CONTROL(0x4A)
#define GPIO_PIN_SEL_MASK (0x3<<14)
#define GPIO_PIN_SEL_LOG_OUT (0x0<<14)
#define GPIO_PIN_SEL_IRQ (0x1<<14)
#define GPIO_PIN_SEL_PLLOUT (0x3<<14)
#define GPIO_PIN_CON_MASK (0x1<<3)
#define GPIO_PIN_CON_OUTPUT (0x0<<3)
#define GPIO_PIN_CON_INPUT (0x1<<3)
#define GPIO_PIN_OUTPUT_SET_MASK (0x1<<2)
#define GPIO_PIN_OUTPUT_SET_LOW (0x0<<2)
#define GPIO_PIN_OUTPUT_SET_HIGH (0x1<<2)
#define GPIO_PIN_POLARITY_INV (0x1<<1)
//JACK DETECT CONTROL(0x5A)
#define JACK_DET_SEL_MASK (0x3<<14)
#define JACK_DET_SEL_OFF (0x0<<14) //Jack Detect Select none
#define JACK_DET_SEL_GPIO (0x1<<14) //Jack Detect Select GPIO
#define JACK_DET_SEL_JD1 (0x2<<14) //Jack Detect Select JD1,LineIn Left disable
#define JACK_DET_SEL_JD2 (0x3<<14) //Jack Detect Select JD2,LineIn Right Disable
#define JACK_DET_TRI_VREF (0x1<<13)
#define JACK_DET_POL_TRI_VREF (0x1<<12)
#define JACK_DET_TRI_HP (0x1<<11)
#define JACK_DET_POL_TRI_HP (0x1<<10)
#define JACK_DET_TRI_SPK (0x1<<9)
#define JACK_DET_POL_TRI_SPK (0x1<<8)
#define JACK_DET_POL (0x1<<3)
//MISC1 CONTROL(0x5C)
#define SPK_L_ZC_CTRL_EN (0x1<<15)
#define SPK_L_SV_CTRL_EN (0x1<<14)
#define SPK_R_ZC_CTRL_EN (0x1<<13)
#define SPK_R_SV_CTRL_EN (0x1<<12)
#define HP_L_ZC_CTRL_EN (0x1<<11)
#define HP_L_SV_CTRL_EN (0x1<<10)
#define HP_R_ZC_CTRL_EN (0x1<<9)
#define HP_R_SV_CTRL_EN (0x1<<8)
#define AUXOUT_L_ZC_CTRL_EN (0x1<<7)
#define AUXOUT_L_SV_CTRL_EN (0x1<<6)
#define AUXOUT_R_ZC_CTRL_EN (0x1<<5)
#define AUXOUT_R_SV_CTRL_EN (0x1<<4)
#define DAC_ZC_CTRL_EN (0x1<<3)
#define DAC_SV_CTRL_EN (0x1<<2)
////MISC2 CONTROL(0x5E)
#define DISABLE_FAST_VREG (0x1<<15)
#define THERMAL_SHUTDOWN_EN (0x1<<14)
#define HP_DEPOP_MODE2_EN (0x1<<9)
#define HP_DEPOP_MODE1_EN (0x1<<8)
#define HP_L_M_UM_DEPOP_EN (0x1<<7)
#define HP_R_M_UM_DEPOP_EN (0x1<<6)
#define M_UM_DEPOP_EN (0x1<<5)
#define M_DAC_L_INPUT (0x1<<3)
#define M_DAC_R_INPUT (0x1<<2)
//AVC Control(0x68)
#define AVC_ENABLE (0x1<<15)
#define AVC_TARTGET_SEL_MASK (0x1<<14)
#define AVC_TARTGET_SEL_R (0x1<<14)
#define AVC_TARTGET_SEL_L (0x0<<14)
//WaveOut channel for realtek codec
enum
{
RT_WAVOUT_SPK =(0x1<<0),
RT_WAVOUT_SPK_R =(0x1<<1),
RT_WAVOUT_SPK_L =(0x1<<2),
RT_WAVOUT_HP =(0x1<<3),
RT_WAVOUT_HP_R =(0x1<<4),
RT_WAVOUT_HP_L =(0x1<<5),
RT_WAVOUT_MONO =(0x1<<6),
RT_WAVOUT_AUXOUT =(0x1<<7),
RT_WAVOUT_AUXOUT_R =(0x1<<8),
RT_WAVOUT_AUXOUT_L =(0x1<<9),
RT_WAVOUT_LINEOUT =(0x1<<10),
RT_WAVOUT_LINEOUT_R =(0x1<<11),
RT_WAVOUT_LINEOUT_L =(0x1<<12),
RT_WAVOUT_DAC =(0x1<<13),
RT_WAVOUT_ALL_ON =(0x1<<14),
};
//WaveIn channel for realtek codec
enum
{
RT_WAVIN_R_MONO_MIXER =(0x1<<0),
RT_WAVIN_R_SPK_MIXER =(0x1<<1),
RT_WAVIN_R_HP_MIXER =(0x1<<2),
RT_WAVIN_R_PHONE =(0x1<<3),
RT_WAVIN_R_AUXIN =(0x1<<3),
RT_WAVIN_R_LINE_IN =(0x1<<4),
RT_WAVIN_R_MIC2 =(0x1<<5),
RT_WAVIN_R_MIC1 =(0x1<<6),
RT_WAVIN_L_MONO_MIXER =(0x1<<8),
RT_WAVIN_L_SPK_MIXER =(0x1<<9),
RT_WAVIN_L_HP_MIXER =(0x1<<10),
RT_WAVIN_L_PHONE =(0x1<<11),
RT_WAVIN_L_AUXIN =(0x1<<11),
RT_WAVIN_L_LINE_IN =(0x1<<12),
RT_WAVIN_L_MIC2 =(0x1<<13),
RT_WAVIN_L_MIC1 =(0x1<<14),
};
enum
{
POWER_STATE_D0=0,
POWER_STATE_D1,
POWER_STATE_D1_PLAYBACK,
POWER_STATE_D1_RECORD,
POWER_STATE_D2,
POWER_STATE_D2_PLAYBACK,
POWER_STATE_D2_RECORD,
POWER_STATE_D3,
POWER_STATE_D4
};
struct rt5627_setup_data {
unsigned short i2c_address;
};
#define RT5627_PLL_FR_MCLK 0
#define RT5627_PLL_FR_BCK 1
extern struct snd_soc_codec_dai rt5627_dai;
extern struct snd_soc_codec_device soc_codec_dev_rt5627;
#endif

1110
sound/soc/codecs/wm8580.c Normal file

File diff suppressed because it is too large Load Diff

166
sound/soc/codecs/wm8580.h Normal file
View File

@@ -0,0 +1,166 @@
/*
* wm8580.h -- audio driver for WM8580
*
* Copyright 2008 Samsung Electronics.
* Author: Ryu Euiyoul
* ryu.real@gmail.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.
*
*/
#ifndef _WM8580_H
#define _WM8580_H
#define WM8580_PLLA 1
#define WM8580_PLLB 2
#define WM8580_MCLK 1
#define WM8580_DAC_CLKSEL 2
#define WM8580_CLKOUTSRC 3
#define WM8580_CLKSRC_MCLK 1
#define WM8580_CLKSRC_PLLA 2
#define WM8580_CLKSRC_PLLB 3
#define WM8580_CLKSRC_OSC 4
#define WM8580_CLKSRC_NONE 5
/* WM8580 register space */
#define WM8580_PLLA1 0x00
#define WM8580_PLLA2 0x01
#define WM8580_PLLA3 0x02
#define WM8580_PLLA4 0x03
#define WM8580_PLLB1 0x04
#define WM8580_PLLB2 0x05
#define WM8580_PLLB3 0x06
#define WM8580_PLLB4 0x07
#define WM8580_CLKSEL 0x08
#define WM8580_PAIF1 0x09
#define WM8580_PAIF2 0x0A
#define WM8580_SAIF1 0x0B
#define WM8580_PAIF3 0x0C
#define WM8580_PAIF4 0x0D
#define WM8580_SAIF2 0x0E
#define WM8580_DAC_CONTROL1 0x0F
#define WM8580_DAC_CONTROL2 0x10
#define WM8580_DAC_CONTROL3 0x11
#define WM8580_DAC_CONTROL4 0x12
#define WM8580_DAC_CONTROL5 0x13
#define WM8580_DIGITAL_ATTENUATION_DACL1 0x14
#define WM8580_DIGITAL_ATTENUATION_DACR1 0x15
#define WM8580_DIGITAL_ATTENUATION_DACL2 0x16
#define WM8580_DIGITAL_ATTENUATION_DACR2 0x17
#define WM8580_DIGITAL_ATTENUATION_DACL3 0x18
#define WM8580_DIGITAL_ATTENUATION_DACR3 0x19
#define WM8580_MASTER_DIGITAL_ATTENUATION 0x1C
#define WM8580_ADC_CONTROL1 0x1D
#define WM8580_SPDTXCHAN0 0x1E
#define WM8580_SPDTXCHAN1 0x1F
#define WM8580_SPDTXCHAN2 0x20
#define WM8580_SPDTXCHAN3 0x21
#define WM8580_SPDTXCHAN4 0x22
#define WM8580_SPDTXCHAN5 0x23
#define WM8580_SPDMODE 0x24
#define WM8580_INTMASK 0x25
#define WM8580_GPO1 0x26
#define WM8580_GPO2 0x27
#define WM8580_GPO3 0x28
#define WM8580_GPO4 0x29
#define WM8580_GPO5 0x2A
#define WM8580_INTSTAT 0x2B
#define WM8580_SPDRXCHAN1 0x2C
#define WM8580_SPDRXCHAN2 0x2D
#define WM8580_SPDRXCHAN3 0x2E
#define WM8580_SPDRXCHAN4 0x2F
#define WM8580_SPDRXCHAN5 0x30
#define WM8580_SPDSTAT 0x31
#define WM8580_PWRDN1 0x32
#define WM8580_PWRDN2 0x33
#define WM8580_READBACK 0x34
#define WM8580_RESET 0x35
/* PLLB4 (register 7h) */
#define WM8580_PLLB4_MCLKOUTSRC_MASK 0x60
#define WM8580_PLLB4_MCLKOUTSRC_PLLA 0x20
#define WM8580_PLLB4_MCLKOUTSRC_PLLB 0x40
#define WM8580_PLLB4_MCLKOUTSRC_OSC 0x60
#define WM8580_PLLB4_CLKOUTSRC_MASK 0x180
#define WM8580_PLLB4_CLKOUTSRC_PLLACLK 0x080
#define WM8580_PLLB4_CLKOUTSRC_PLLBCLK 0x100
#define WM8580_PLLB4_CLKOUTSRC_OSCCLK 0x180
/* CLKSEL (register 8h) */
#define WM8580_CLKSEL_DAC_CLKSEL_MASK 0x03
#define WM8580_CLKSEL_DAC_CLKSEL_PLLA 0x01
#define WM8580_CLKSEL_DAC_CLKSEL_PLLB 0x02
/* AIF control 1 (registers 9h-bh) */
#define WM8580_AIF_RATE_MASK 0x7
#define WM8580_AIF_RATE_128 0x0
#define WM8580_AIF_RATE_192 0x1
#define WM8580_AIF_RATE_256 0x2
#define WM8580_AIF_RATE_384 0x3
#define WM8580_AIF_RATE_512 0x4
#define WM8580_AIF_RATE_768 0x5
#define WM8580_AIF_RATE_1152 0x6
#define WM8580_AIF_BCLKSEL_MASK 0x18
#define WM8580_AIF_BCLKSEL_64 0x00
#define WM8580_AIF_BCLKSEL_128 0x08
#define WM8580_AIF_BCLKSEL_256 0x10
#define WM8580_AIF_BCLKSEL_SYSCLK 0x18
#define WM8580_AIF_MS 0x20
#define WM8580_AIF_CLKSRC_MASK 0xc0
#define WM8580_AIF_CLKSRC_PLLA 0x40
#define WM8580_AIF_CLKSRC_PLLB 0x40
#define WM8580_AIF_CLKSRC_MCLK 0xc0
/* AIF control 2 (registers ch-eh) */
#define WM8580_AIF_FMT_MASK 0x03
#define WM8580_AIF_FMT_RIGHTJ 0x00
#define WM8580_AIF_FMT_LEFTJ 0x01
#define WM8580_AIF_FMT_I2S 0x02
#define WM8580_AIF_FMT_DSP 0x03
#define WM8580_AIF_LENGTH_MASK 0x0c
#define WM8580_AIF_LENGTH_16 0x00
#define WM8580_AIF_LENGTH_20 0x04
#define WM8580_AIF_LENGTH_24 0x08
#define WM8580_AIF_LENGTH_32 0x0c
#define WM8580_AIF_LRP 0x10
#define WM8580_AIF_BCP 0x20
/* Powerdown Register 1 (register 32h) */
#define WM8580_PWRDN1_PWDN 0x001
#define WM8580_PWRDN1_ALLDACPD 0x040
/* Powerdown Register 2 (register 33h) */
#define WM8580_PWRDN2_OSSCPD 0x001
#define WM8580_PWRDN2_PLLAPD 0x002
#define WM8580_PWRDN2_PLLBPD 0x004
#define WM8580_PWRDN2_SPDIFPD 0x008
#define WM8580_PWRDN2_SPDIFTXD 0x010
#define WM8580_PWRDN2_SPDIFRXD 0x020
extern struct snd_soc_codec_device soc_codec_dev_wm8580;
struct wm8580_setup_data {
unsigned short i2c_address;
};
#define WM8580_DAI_PAIFRX 0
#define WM8580_DAI_PAIFTX 1
#define WM8580_DAI_SAIF 2
extern struct snd_soc_codec_dai wm8580_dai[];
extern struct snd_soc_codec_device soc_codec_dev_wm8580;
#endif

758
sound/soc/codecs/wm8731.c Normal file
View File

@@ -0,0 +1,758 @@
/*
* wm8731.c -- WM8731 ALSA SoC Audio driver
*
* Copyright 2005 Openedhand Ltd.
*
* Author: Richard Purdie <richard@openedhand.com>
*
* Based on wm8753.c by Liam Girdwood
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <sound/driver.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/initval.h>
#include "wm8731.h"
#define AUDIO_NAME "wm8731"
#define WM8731_VERSION "0.13"
/*
* Debug
*/
#define WM8731_DEBUG 0
#ifdef WM8731_DEBUG
#define dbg(format, arg...) \
printk(KERN_DEBUG AUDIO_NAME ": " format "\n" , ## arg)
#else
#define dbg(format, arg...) do {} while (0)
#endif
#define err(format, arg...) \
printk(KERN_ERR AUDIO_NAME ": " format "\n" , ## arg)
#define info(format, arg...) \
printk(KERN_INFO AUDIO_NAME ": " format "\n" , ## arg)
#define warn(format, arg...) \
printk(KERN_WARNING AUDIO_NAME ": " format "\n" , ## arg)
struct snd_soc_codec_device soc_codec_dev_wm8731;
/* codec private data */
struct wm8731_priv {
unsigned int sysclk;
};
/*
* wm8731 register cache
* We can't read the WM8731 register space when we are
* using 2 wire for device control, so we cache them instead.
* There is no point in caching the reset register
*/
static const u16 wm8731_reg[WM8731_CACHEREGNUM] = {
0x0097, 0x0097, 0x0079, 0x0079,
0x000a, 0x0008, 0x009f, 0x000a,
0x0000, 0x0000
};
/*
* read wm8731 register cache
*/
static inline unsigned int wm8731_read_reg_cache(struct snd_soc_codec *codec,
unsigned int reg)
{
u16 *cache = codec->reg_cache;
if (reg == WM8731_RESET)
return 0;
if (reg >= WM8731_CACHEREGNUM)
return -1;
return cache[reg];
}
/*
* write wm8731 register cache
*/
static inline void wm8731_write_reg_cache(struct snd_soc_codec *codec,
u16 reg, unsigned int value)
{
u16 *cache = codec->reg_cache;
if (reg >= WM8731_CACHEREGNUM)
return;
cache[reg] = value;
}
/*
* write to the WM8731 register space
*/
static int wm8731_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
u8 data[2];
/* data is
* D15..D9 WM8731 register offset
* D8...D0 register data
*/
data[0] = (reg << 1) | ((value >> 8) & 0x0001);
data[1] = value & 0x00ff;
wm8731_write_reg_cache (codec, reg, value);
if (codec->hw_write(codec->control_data, data, 2) == 2)
return 0;
else
return -EIO;
}
#define wm8731_reset(c) wm8731_write(c, WM8731_RESET, 0)
static const char *wm8731_input_select[] = {"Line In", "Mic"};
static const char *wm8731_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"};
static const struct soc_enum wm8731_enum[] = {
SOC_ENUM_SINGLE(WM8731_APANA, 2, 2, wm8731_input_select),
SOC_ENUM_SINGLE(WM8731_APDIGI, 1, 4, wm8731_deemph),
};
static const struct snd_kcontrol_new wm8731_snd_controls[] = {
SOC_DOUBLE_R("Master Playback Volume", WM8731_LOUT1V, WM8731_ROUT1V,
0, 127, 0),
SOC_DOUBLE_R("Master Playback ZC Switch", WM8731_LOUT1V, WM8731_ROUT1V,
7, 1, 0),
SOC_DOUBLE_R("Capture Volume", WM8731_LINVOL, WM8731_RINVOL, 0, 31, 0),
SOC_DOUBLE_R("Line Capture Switch", WM8731_LINVOL, WM8731_RINVOL, 7, 1, 1),
SOC_SINGLE("Mic Boost (+20dB)", WM8731_APANA, 0, 1, 0),
SOC_SINGLE("Capture Mic Switch", WM8731_APANA, 1, 1, 1),
SOC_SINGLE("Sidetone Playback Volume", WM8731_APANA, 6, 3, 1),
SOC_SINGLE("ADC High Pass Filter Switch", WM8731_APDIGI, 0, 1, 1),
SOC_SINGLE("Store DC Offset Switch", WM8731_APDIGI, 4, 1, 0),
SOC_ENUM("Playback De-emphasis", wm8731_enum[1]),
};
/* add non dapm controls */
static int wm8731_add_controls(struct snd_soc_codec *codec)
{
int err, i;
for (i = 0; i < ARRAY_SIZE(wm8731_snd_controls); i++) {
if ((err = snd_ctl_add(codec->card,
snd_soc_cnew(&wm8731_snd_controls[i],codec, NULL))) < 0)
return err;
}
return 0;
}
/* Output Mixer */
static const struct snd_kcontrol_new wm8731_output_mixer_controls[] = {
SOC_DAPM_SINGLE("Line Bypass Switch", WM8731_APANA, 3, 1, 0),
SOC_DAPM_SINGLE("Mic Sidetone Switch", WM8731_APANA, 5, 1, 0),
SOC_DAPM_SINGLE("HiFi Playback Switch", WM8731_APANA, 4, 1, 0),
};
/* Input mux */
static const struct snd_kcontrol_new wm8731_input_mux_controls =
SOC_DAPM_ENUM("Input Select", wm8731_enum[0]);
static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = {
SND_SOC_DAPM_MIXER("Output Mixer", WM8731_PWR, 4, 1,
&wm8731_output_mixer_controls[0],
ARRAY_SIZE(wm8731_output_mixer_controls)),
SND_SOC_DAPM_DAC("DAC", "HiFi Playback", WM8731_PWR, 3, 1),
SND_SOC_DAPM_OUTPUT("LOUT"),
SND_SOC_DAPM_OUTPUT("LHPOUT"),
SND_SOC_DAPM_OUTPUT("ROUT"),
SND_SOC_DAPM_OUTPUT("RHPOUT"),
SND_SOC_DAPM_ADC("ADC", "HiFi Capture", WM8731_PWR, 2, 1),
SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, &wm8731_input_mux_controls),
SND_SOC_DAPM_PGA("Line Input", WM8731_PWR, 0, 1, NULL, 0),
SND_SOC_DAPM_MICBIAS("Mic Bias", WM8731_PWR, 1, 1),
SND_SOC_DAPM_INPUT("MICIN"),
SND_SOC_DAPM_INPUT("RLINEIN"),
SND_SOC_DAPM_INPUT("LLINEIN"),
};
static const char *intercon[][3] = {
/* output mixer */
{"Output Mixer", "Line Bypass Switch", "Line Input"},
{"Output Mixer", "HiFi Playback Switch", "DAC"},
{"Output Mixer", "Mic Sidetone Switch", "Mic Bias"},
/* outputs */
{"RHPOUT", NULL, "Output Mixer"},
{"ROUT", NULL, "Output Mixer"},
{"LHPOUT", NULL, "Output Mixer"},
{"LOUT", NULL, "Output Mixer"},
/* input mux */
{"Input Mux", "Line In", "Line Input"},
{"Input Mux", "Mic", "Mic Bias"},
{"ADC", NULL, "Input Mux"},
/* inputs */
{"Line Input", NULL, "LLINEIN"},
{"Line Input", NULL, "RLINEIN"},
{"Mic Bias", NULL, "MICIN"},
/* terminator */
{NULL, NULL, NULL},
};
static int wm8731_add_widgets(struct snd_soc_codec *codec)
{
int i;
for(i = 0; i < ARRAY_SIZE(wm8731_dapm_widgets); i++) {
snd_soc_dapm_new_control(codec, &wm8731_dapm_widgets[i]);
}
/* set up audio path interconnects */
for(i = 0; intercon[i][0] != NULL; i++) {
snd_soc_dapm_connect_input(codec, intercon[i][0],
intercon[i][1], intercon[i][2]);
}
snd_soc_dapm_new_widgets(codec);
return 0;
}
struct _coeff_div {
u32 mclk;
u32 rate;
u16 fs;
u8 sr:4;
u8 bosr:1;
u8 usb:1;
};
/* codec mclk clock divider coefficients */
static const struct _coeff_div coeff_div[] = {
/* 48k */
{12288000, 48000, 256, 0x0, 0x0, 0x0},
{18432000, 48000, 384, 0x0, 0x1, 0x0},
{12000000, 48000, 250, 0x0, 0x0, 0x1},
/* 32k */
{12288000, 32000, 384, 0x6, 0x0, 0x0},
{18432000, 32000, 576, 0x6, 0x1, 0x0},
{12000000, 32000, 375, 0x6, 0x0, 0x1},
/* 8k */
{12288000, 8000, 1536, 0x3, 0x0, 0x0},
{18432000, 8000, 2304, 0x3, 0x1, 0x0},
{11289600, 8000, 1408, 0xb, 0x0, 0x0},
{16934400, 8000, 2112, 0xb, 0x1, 0x0},
{12000000, 8000, 1500, 0x3, 0x0, 0x1},
/* 96k */
{12288000, 96000, 128, 0x7, 0x0, 0x0},
{18432000, 96000, 192, 0x7, 0x1, 0x0},
{12000000, 96000, 125, 0x7, 0x0, 0x1},
/* 44.1k */
{11289600, 44100, 256, 0x8, 0x0, 0x0},
{16934400, 44100, 384, 0x8, 0x1, 0x0},
{12000000, 44100, 272, 0x8, 0x1, 0x1},
/* 88.2k */
{11289600, 88200, 128, 0xf, 0x0, 0x0},
{16934400, 88200, 192, 0xf, 0x1, 0x0},
{12000000, 88200, 136, 0xf, 0x1, 0x1},
};
static inline int get_coeff(int mclk, int rate)
{
int i;
for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
return i;
}
return 0;
}
static int wm8731_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
struct snd_soc_codec *codec = socdev->codec;
struct wm8731_priv *wm8731 = codec->private_data;
u16 iface = wm8731_read_reg_cache(codec, WM8731_IFACE) & 0xfff3;
int i = get_coeff(wm8731->sysclk, params_rate(params));
u16 srate = (coeff_div[i].sr << 2) |
(coeff_div[i].bosr << 1) | coeff_div[i].usb;
wm8731_write(codec, WM8731_SRATE, srate);
/* bit size */
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
break;
case SNDRV_PCM_FORMAT_S20_3LE:
iface |= 0x0004;
break;
case SNDRV_PCM_FORMAT_S24_LE:
iface |= 0x0008;
break;
}
wm8731_write(codec, WM8731_IFACE, iface);
return 0;
}
static int wm8731_pcm_prepare(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
struct snd_soc_codec *codec = socdev->codec;
/* set active */
wm8731_write(codec, WM8731_ACTIVE, 0x0001);
return 0;
}
static void wm8731_shutdown(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
struct snd_soc_codec *codec = socdev->codec;
/* deactivate */
if (!codec->active) {
udelay(50);
wm8731_write(codec, WM8731_ACTIVE, 0x0);
}
}
static int wm8731_mute(struct snd_soc_codec_dai *dai, int mute)
{
struct snd_soc_codec *codec = dai->codec;
u16 mute_reg = wm8731_read_reg_cache(codec, WM8731_APDIGI) & 0xfff7;
if (mute)
wm8731_write(codec, WM8731_APDIGI, mute_reg | 0x8);
else
wm8731_write(codec, WM8731_APDIGI, mute_reg);
return 0;
}
static int wm8731_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai,
int clk_id, unsigned int freq, int dir)
{
struct snd_soc_codec *codec = codec_dai->codec;
struct wm8731_priv *wm8731 = codec->private_data;
switch (freq) {
case 11289600:
case 12000000:
case 12288000:
case 16934400:
case 18432000:
wm8731->sysclk = freq;
return 0;
}
return -EINVAL;
}
static int wm8731_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,
unsigned int fmt)
{
struct snd_soc_codec *codec = codec_dai->codec;
u16 iface = 0;
/* set master/slave audio interface */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM:
iface |= 0x0040;
break;
case SND_SOC_DAIFMT_CBS_CFS:
break;
default:
return -EINVAL;
}
/* interface format */
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
iface |= 0x0002;
break;
case SND_SOC_DAIFMT_RIGHT_J:
break;
case SND_SOC_DAIFMT_LEFT_J:
iface |= 0x0001;
break;
case SND_SOC_DAIFMT_DSP_A:
iface |= 0x0003;
break;
case SND_SOC_DAIFMT_DSP_B:
iface |= 0x0013;
break;
default:
return -EINVAL;
}
/* clock inversion */
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF:
break;
case SND_SOC_DAIFMT_IB_IF:
iface |= 0x0090;
break;
case SND_SOC_DAIFMT_IB_NF:
iface |= 0x0080;
break;
case SND_SOC_DAIFMT_NB_IF:
iface |= 0x0010;
break;
default:
return -EINVAL;
}
/* set iface */
wm8731_write(codec, WM8731_IFACE, iface);
return 0;
}
static int wm8731_dapm_event(struct snd_soc_codec *codec, int event)
{
u16 reg = wm8731_read_reg_cache(codec, WM8731_PWR) & 0xff7f;
switch (event) {
case SNDRV_CTL_POWER_D0: /* full On */
/* vref/mid, osc on, dac unmute */
wm8731_write(codec, WM8731_PWR, reg);
break;
case SNDRV_CTL_POWER_D1: /* partial On */
case SNDRV_CTL_POWER_D2: /* partial On */
break;
case SNDRV_CTL_POWER_D3hot: /* Off, with power */
/* everything off except vref/vmid, */
wm8731_write(codec, WM8731_PWR, reg | 0x0040);
break;
case SNDRV_CTL_POWER_D3cold: /* Off, without power */
/* everything off, dac mute, inactive */
wm8731_write(codec, WM8731_ACTIVE, 0x0);
wm8731_write(codec, WM8731_PWR, 0xffff);
break;
}
codec->dapm_state = event;
return 0;
}
#define WM8731_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\
SNDRV_PCM_RATE_96000)
#define WM8731_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE)
struct snd_soc_codec_dai wm8731_dai = {
.name = "WM8731",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
.channels_max = 2,
.rates = WM8731_RATES,
.formats = WM8731_FORMATS,},
.capture = {
.stream_name = "Capture",
.channels_min = 1,
.channels_max = 2,
.rates = WM8731_RATES,
.formats = WM8731_FORMATS,},
.ops = {
.prepare = wm8731_pcm_prepare,
.hw_params = wm8731_hw_params,
.shutdown = wm8731_shutdown,
},
.dai_ops = {
.digital_mute = wm8731_mute,
.set_sysclk = wm8731_set_dai_sysclk,
.set_fmt = wm8731_set_dai_fmt,
}
};
EXPORT_SYMBOL_GPL(wm8731_dai);
static int wm8731_suspend(struct platform_device *pdev, pm_message_t state)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
struct snd_soc_codec *codec = socdev->codec;
wm8731_write(codec, WM8731_ACTIVE, 0x0);
wm8731_dapm_event(codec, SNDRV_CTL_POWER_D3cold);
return 0;
}
static int wm8731_resume(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
struct snd_soc_codec *codec = socdev->codec;
int i;
u8 data[2];
u16 *cache = codec->reg_cache;
/* Sync reg_cache with the hardware */
for (i = 0; i < ARRAY_SIZE(wm8731_reg); i++) {
data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
data[1] = cache[i] & 0x00ff;
codec->hw_write(codec->control_data, data, 2);
}
wm8731_dapm_event(codec, SNDRV_CTL_POWER_D3hot);
wm8731_dapm_event(codec, codec->suspend_dapm_state);
return 0;
}
/*
* initialise the WM8731 driver
* register the mixer and dsp interfaces with the kernel
*/
static int wm8731_init(struct snd_soc_device *socdev)
{
struct snd_soc_codec *codec = socdev->codec;
int reg, ret = 0;
codec->name = "WM8731";
codec->owner = THIS_MODULE;
codec->read = wm8731_read_reg_cache;
codec->write = wm8731_write;
codec->dapm_event = wm8731_dapm_event;
codec->dai = &wm8731_dai;
codec->num_dai = 1;
codec->reg_cache_size = sizeof(wm8731_reg);
codec->reg_cache = kmemdup(wm8731_reg, sizeof(wm8731_reg), GFP_KERNEL);
if (codec->reg_cache == NULL)
return -ENOMEM;
wm8731_reset(codec);
/* register pcms */
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
if (ret < 0) {
printk(KERN_ERR "wm8731: failed to create pcms\n");
goto pcm_err;
}
/* power on device */
wm8731_dapm_event(codec, SNDRV_CTL_POWER_D3hot);
/* set the update bits */
reg = wm8731_read_reg_cache(codec, WM8731_LOUT1V);
wm8731_write(codec, WM8731_LOUT1V, reg | 0x0100);
reg = wm8731_read_reg_cache(codec, WM8731_ROUT1V);
wm8731_write(codec, WM8731_ROUT1V, reg | 0x0100);
reg = wm8731_read_reg_cache(codec, WM8731_LINVOL);
wm8731_write(codec, WM8731_LINVOL, reg | 0x0100);
reg = wm8731_read_reg_cache(codec, WM8731_RINVOL);
wm8731_write(codec, WM8731_RINVOL, reg | 0x0100);
wm8731_add_controls(codec);
wm8731_add_widgets(codec);
ret = snd_soc_register_card(socdev);
if (ret < 0) {
printk(KERN_ERR "wm8731: failed to register card\n");
goto card_err;
}
return ret;
card_err:
snd_soc_free_pcms(socdev);
snd_soc_dapm_free(socdev);
pcm_err:
kfree(codec->reg_cache);
return ret;
}
static struct snd_soc_device *wm8731_socdev;
#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
/*
* WM8731 2 wire address is determined by GPIO5
* state during powerup.
* low = 0x1a
* high = 0x1b
*/
static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END };
/* Magic definition of all other variables and things */
I2C_CLIENT_INSMOD;
static struct i2c_driver wm8731_i2c_driver;
static struct i2c_client client_template;
/* If the i2c layer weren't so broken, we could pass this kind of data
around */
static int wm8731_codec_probe(struct i2c_adapter *adap, int addr, int kind)
{
struct snd_soc_device *socdev = wm8731_socdev;
struct wm8731_setup_data *setup = socdev->codec_data;
struct snd_soc_codec *codec = socdev->codec;
struct i2c_client *i2c;
int ret;
if (addr != setup->i2c_address)
return -ENODEV;
client_template.adapter = adap;
client_template.addr = addr;
i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
if (i2c == NULL) {
kfree(codec);
return -ENOMEM;
}
i2c_set_clientdata(i2c, codec);
codec->control_data = i2c;
ret = i2c_attach_client(i2c);
if (ret < 0) {
err("failed to attach codec at addr %x\n", addr);
goto err;
}
ret = wm8731_init(socdev);
if (ret < 0) {
err("failed to initialise WM8731\n");
goto err;
}
return ret;
err:
kfree(codec);
kfree(i2c);
return ret;
}
static int wm8731_i2c_detach(struct i2c_client *client)
{
struct snd_soc_codec* codec = i2c_get_clientdata(client);
i2c_detach_client(client);
kfree(codec->reg_cache);
kfree(client);
return 0;
}
static int wm8731_i2c_attach(struct i2c_adapter *adap)
{
return i2c_probe(adap, &addr_data, wm8731_codec_probe);
}
/* corgi i2c codec control layer */
static struct i2c_driver wm8731_i2c_driver = {
.driver = {
.name = "WM8731 I2C Codec",
.owner = THIS_MODULE,
},
.id = I2C_DRIVERID_WM8731,
.attach_adapter = wm8731_i2c_attach,
.detach_client = wm8731_i2c_detach,
.command = NULL,
};
static struct i2c_client client_template = {
.name = "WM8731",
.driver = &wm8731_i2c_driver,
};
#endif
static int wm8731_probe(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
struct wm8731_setup_data *setup;
struct snd_soc_codec *codec;
struct wm8731_priv *wm8731;
int ret = 0;
info("WM8731 Audio Codec %s", WM8731_VERSION);
setup = socdev->codec_data;
codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
if (codec == NULL)
return -ENOMEM;
wm8731 = kzalloc(sizeof(struct wm8731_priv), GFP_KERNEL);
if (wm8731 == NULL) {
kfree(codec);
return -ENOMEM;
}
codec->private_data = wm8731;
socdev->codec = codec;
mutex_init(&codec->mutex);
INIT_LIST_HEAD(&codec->dapm_widgets);
INIT_LIST_HEAD(&codec->dapm_paths);
wm8731_socdev = socdev;
#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
if (setup->i2c_address) {
normal_i2c[0] = setup->i2c_address;
codec->hw_write = (hw_write_t)i2c_master_send;
ret = i2c_add_driver(&wm8731_i2c_driver);
if (ret != 0)
printk(KERN_ERR "can't add i2c driver");
}
#else
/* Add other interfaces here */
#endif
return ret;
}
/* power down chip */
static int wm8731_remove(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
struct snd_soc_codec *codec = socdev->codec;
if (codec->control_data)
wm8731_dapm_event(codec, SNDRV_CTL_POWER_D3cold);
snd_soc_free_pcms(socdev);
snd_soc_dapm_free(socdev);
#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
i2c_del_driver(&wm8731_i2c_driver);
#endif
kfree(codec->private_data);
kfree(codec);
return 0;
}
struct snd_soc_codec_device soc_codec_dev_wm8731 = {
.probe = wm8731_probe,
.remove = wm8731_remove,
.suspend = wm8731_suspend,
.resume = wm8731_resume,
};
EXPORT_SYMBOL_GPL(soc_codec_dev_wm8731);
MODULE_DESCRIPTION("ASoC WM8731 driver");
MODULE_AUTHOR("Richard Purdie");
MODULE_LICENSE("GPL");

44
sound/soc/codecs/wm8731.h Normal file
View File

@@ -0,0 +1,44 @@
/*
* wm8731.h -- WM8731 Soc Audio driver
*
* Copyright 2005 Openedhand Ltd.
*
* Author: Richard Purdie <richard@openedhand.com>
*
* Based on wm8753.h
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _WM8731_H
#define _WM8731_H
/* WM8731 register space */
#define WM8731_LINVOL 0x00
#define WM8731_RINVOL 0x01
#define WM8731_LOUT1V 0x02
#define WM8731_ROUT1V 0x03
#define WM8731_APANA 0x04
#define WM8731_APDIGI 0x05
#define WM8731_PWR 0x06
#define WM8731_IFACE 0x07
#define WM8731_SRATE 0x08
#define WM8731_ACTIVE 0x09
#define WM8731_RESET 0x0f
#define WM8731_CACHEREGNUM 10
#define WM8731_SYSCLK 0
#define WM8731_DAI 0
struct wm8731_setup_data {
unsigned short i2c_address;
};
extern struct snd_soc_codec_dai wm8731_dai;
extern struct snd_soc_codec_device soc_codec_dev_wm8731;
#endif

1049
sound/soc/codecs/wm8750.c Normal file

File diff suppressed because it is too large Load Diff

67
sound/soc/codecs/wm8750.h Normal file
View File

@@ -0,0 +1,67 @@
/*
* Copyright 2005 Openedhand Ltd.
*
* Author: Richard Purdie <richard@openedhand.com>
*
* Based on WM8753.h
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#ifndef _WM8750_H
#define _WM8750_H
/* WM8750 register space */
#define WM8750_LINVOL 0x00
#define WM8750_RINVOL 0x01
#define WM8750_LOUT1V 0x02
#define WM8750_ROUT1V 0x03
#define WM8750_ADCDAC 0x05
#define WM8750_IFACE 0x07
#define WM8750_SRATE 0x08
#define WM8750_LDAC 0x0a
#define WM8750_RDAC 0x0b
#define WM8750_BASS 0x0c
#define WM8750_TREBLE 0x0d
#define WM8750_RESET 0x0f
#define WM8750_3D 0x10
#define WM8750_ALC1 0x11
#define WM8750_ALC2 0x12
#define WM8750_ALC3 0x13
#define WM8750_NGATE 0x14
#define WM8750_LADC 0x15
#define WM8750_RADC 0x16
#define WM8750_ADCTL1 0x17
#define WM8750_ADCTL2 0x18
#define WM8750_PWR1 0x19
#define WM8750_PWR2 0x1a
#define WM8750_ADCTL3 0x1b
#define WM8750_ADCIN 0x1f
#define WM8750_LADCIN 0x20
#define WM8750_RADCIN 0x21
#define WM8750_LOUTM1 0x22
#define WM8750_LOUTM2 0x23
#define WM8750_ROUTM1 0x24
#define WM8750_ROUTM2 0x25
#define WM8750_MOUTM1 0x26
#define WM8750_MOUTM2 0x27
#define WM8750_LOUT2V 0x28
#define WM8750_ROUT2V 0x29
#define WM8750_MOUTV 0x2a
#define WM8750_CACHE_REGNUM 0x2a
#define WM8750_SYSCLK 0
struct wm8750_setup_data {
unsigned short i2c_address;
};
extern struct snd_soc_codec_dai wm8750_dai;
extern struct snd_soc_codec_device soc_codec_dev_wm8750;
#endif

1859
sound/soc/codecs/wm8753.c Normal file

File diff suppressed because it is too large Load Diff

126
sound/soc/codecs/wm8753.h Normal file
View File

@@ -0,0 +1,126 @@
/*
* wm8753.h -- audio driver for WM8753
*
* Copyright 2003 Wolfson Microelectronics PLC.
* Author: Liam Girdwood
* liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.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.
*
*/
#ifndef _WM8753_H
#define _WM8753_H
/* WM8753 register space */
#define WM8753_DAC 0x01
#define WM8753_ADC 0x02
#define WM8753_PCM 0x03
#define WM8753_HIFI 0x04
#define WM8753_IOCTL 0x05
#define WM8753_SRATE1 0x06
#define WM8753_SRATE2 0x07
#define WM8753_LDAC 0x08
#define WM8753_RDAC 0x09
#define WM8753_BASS 0x0a
#define WM8753_TREBLE 0x0b
#define WM8753_ALC1 0x0c
#define WM8753_ALC2 0x0d
#define WM8753_ALC3 0x0e
#define WM8753_NGATE 0x0f
#define WM8753_LADC 0x10
#define WM8753_RADC 0x11
#define WM8753_ADCTL1 0x12
#define WM8753_3D 0x13
#define WM8753_PWR1 0x14
#define WM8753_PWR2 0x15
#define WM8753_PWR3 0x16
#define WM8753_PWR4 0x17
#define WM8753_ID 0x18
#define WM8753_INTPOL 0x19
#define WM8753_INTEN 0x1a
#define WM8753_GPIO1 0x1b
#define WM8753_GPIO2 0x1c
#define WM8753_RESET 0x1f
#define WM8753_RECMIX1 0x20
#define WM8753_RECMIX2 0x21
#define WM8753_LOUTM1 0x22
#define WM8753_LOUTM2 0x23
#define WM8753_ROUTM1 0x24
#define WM8753_ROUTM2 0x25
#define WM8753_MOUTM1 0x26
#define WM8753_MOUTM2 0x27
#define WM8753_LOUT1V 0x28
#define WM8753_ROUT1V 0x29
#define WM8753_LOUT2V 0x2a
#define WM8753_ROUT2V 0x2b
#define WM8753_MOUTV 0x2c
#define WM8753_OUTCTL 0x2d
#define WM8753_ADCIN 0x2e
#define WM8753_INCTL1 0x2f
#define WM8753_INCTL2 0x30
#define WM8753_LINVOL 0x31
#define WM8753_RINVOL 0x32
#define WM8753_MICBIAS 0x33
#define WM8753_CLOCK 0x34
#define WM8753_PLL1CTL1 0x35
#define WM8753_PLL1CTL2 0x36
#define WM8753_PLL1CTL3 0x37
#define WM8753_PLL1CTL4 0x38
#define WM8753_PLL2CTL1 0x39
#define WM8753_PLL2CTL2 0x3a
#define WM8753_PLL2CTL3 0x3b
#define WM8753_PLL2CTL4 0x3c
#define WM8753_BIASCTL 0x3d
#define WM8753_ADCTL2 0x3f
struct wm8753_setup_data {
unsigned short i2c_address;
};
#define WM8753_PLL1 0
#define WM8753_PLL2 1
/* clock inputs */
#define WM8753_MCLK 0
#define WM8753_PCMCLK 1
/* clock divider id's */
#define WM8753_PCMDIV 0
#define WM8753_BCLKDIV 1
#define WM8753_VXCLKDIV 2
/* PCM clock dividers */
#define WM8753_PCM_DIV_1 (0 << 6)
#define WM8753_PCM_DIV_3 (2 << 6)
#define WM8753_PCM_DIV_5_5 (3 << 6)
#define WM8753_PCM_DIV_2 (4 << 6)
#define WM8753_PCM_DIV_4 (5 << 6)
#define WM8753_PCM_DIV_6 (6 << 6)
#define WM8753_PCM_DIV_8 (7 << 6)
/* BCLK clock dividers */
#define WM8753_BCLK_DIV_1 (0 << 3)
#define WM8753_BCLK_DIV_2 (1 << 3)
#define WM8753_BCLK_DIV_4 (2 << 3)
#define WM8753_BCLK_DIV_8 (3 << 3)
#define WM8753_BCLK_DIV_16 (4 << 3)
/* VXCLK clock dividers */
#define WM8753_VXCLK_DIV_1 (0 << 6)
#define WM8753_VXCLK_DIV_2 (1 << 6)
#define WM8753_VXCLK_DIV_4 (2 << 6)
#define WM8753_VXCLK_DIV_8 (3 << 6)
#define WM8753_VXCLK_DIV_16 (4 << 6)
#define WM8753_DAI_HIFI 0
#define WM8753_DAI_VOICE 1
extern struct snd_soc_codec_dai wm8753_dai[2];
extern struct snd_soc_codec_device soc_codec_dev_wm8753;
#endif

807
sound/soc/codecs/wm8772.c Normal file
View File

@@ -0,0 +1,807 @@
/*
* wm8772.c -- WM8772 ALSA Soc Audio driver
*
* Copyright 2005 Wolfson Microelectronics PLC.
* Author: Liam Girdwood
* liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.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.
*
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/i2c.h>
#include <sound/driver.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/initval.h>
#include "wm8772.h"
#define AUDIO_NAME "WM8772"
#define WM8772_VERSION "0.3"
/*
* wm8772 register cache
* We can't read the WM8772 register space when we
* are using 2 wire for device control, so we cache them instead.
*/
static const u16 wm8772_reg[] = {
0x00ff, 0x00ff, 0x0120, 0x0000, /* 0 */
0x00ff, 0x00ff, 0x00ff, 0x00ff, /* 4 */
0x00ff, 0x0000, 0x0080, 0x0040, /* 8 */
0x0000
};
#define WM8772_DAIFMT \
(SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_RIGHT_J | \
SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_IB_NF)
#define WM8772_DIR \
(SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE)
#define WM8772_PRATES \
(SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
#define WM8772_CRATES \
(SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
SNDRV_PCM_RATE_96000)
static struct snd_soc_dai_mode wm8772_modes[] = {
/* common codec frame and clock master modes */
/* 32k */
{
.fmt = WM8772_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
.pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
.pcmrate = SNDRV_PCM_RATE_32000,
.pcmdir = WM8772_DIR,
.flags = SND_SOC_DAI_BFS_RATE,
.fs = 768,
.bfs = 64,
},
{
.fmt = WM8772_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
.pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
.pcmrate = SNDRV_PCM_RATE_32000,
.pcmdir = WM8772_DIR,
.flags = SND_SOC_DAI_BFS_RATE,
.fs = 512,
.bfs = 64,
},
{
.fmt = WM8772_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
.pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
.pcmrate = SNDRV_PCM_RATE_32000,
.pcmdir = WM8772_DIR,
.flags = SND_SOC_DAI_BFS_RATE,
.fs = 384,
.bfs = 64,
},
{
.fmt = WM8772_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
.pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
.pcmrate = SNDRV_PCM_RATE_32000,
.pcmdir = WM8772_DIR,
.flags = SND_SOC_DAI_BFS_RATE,
.fs = 256,
.bfs = 64,
},
{
.fmt = WM8772_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
.pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
.pcmrate = SNDRV_PCM_RATE_32000,
.pcmdir = WM8772_DIR,
.flags = SND_SOC_DAI_BFS_RATE,
.fs = 192,
.bfs = 64,
},
{
.fmt = WM8772_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
.pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
.pcmrate = SNDRV_PCM_RATE_32000,
.pcmdir = WM8772_DIR,
.flags = SND_SOC_DAI_BFS_RATE,
.fs = 128,
.bfs = 64,
},
/* 44.1k */
{
.fmt = WM8772_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
.pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
.pcmrate = SNDRV_PCM_RATE_44100,
.pcmdir = WM8772_DIR,
.flags = SND_SOC_DAI_BFS_RATE,
.fs = 768,
.bfs = 64,
},
{
.fmt = WM8772_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
.pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
.pcmrate = SNDRV_PCM_RATE_44100,
.pcmdir = WM8772_DIR,
.flags = SND_SOC_DAI_BFS_RATE,
.fs = 512,
.bfs = 64,
},
{
.fmt = WM8772_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
.pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
.pcmrate = SNDRV_PCM_RATE_44100,
.pcmdir = WM8772_DIR,
.flags = SND_SOC_DAI_BFS_RATE,
.fs = 384,
.bfs = 64,
},
{
.fmt = WM8772_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
.pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
.pcmrate = SNDRV_PCM_RATE_44100,
.pcmdir = WM8772_DIR,
.flags = SND_SOC_DAI_BFS_RATE,
.fs = 256,
.bfs = 64,
},
{
.fmt = WM8772_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
.pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
.pcmrate = SNDRV_PCM_RATE_44100,
.pcmdir = WM8772_DIR,
.flags = SND_SOC_DAI_BFS_RATE,
.fs = 192,
.bfs = 64,
},
{
.fmt = WM8772_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
.pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
.pcmrate = SNDRV_PCM_RATE_44100,
.pcmdir = WM8772_DIR,
.flags = SND_SOC_DAI_BFS_RATE,
.fs = 128,
.bfs = 64,
},
/* 48k */
{
.fmt = WM8772_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
.pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
.pcmrate = SNDRV_PCM_RATE_48000,
.pcmdir = WM8772_DIR,
.flags = SND_SOC_DAI_BFS_RATE,
.fs = 768,
.bfs = 64,
},
{
.fmt = WM8772_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
.pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
.pcmrate = SNDRV_PCM_RATE_48000,
.pcmdir = WM8772_DIR,
.flags = SND_SOC_DAI_BFS_RATE,
.fs = 512,
.bfs = 64,
},
{
.fmt = WM8772_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
.pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
.pcmrate = SNDRV_PCM_RATE_48000,
.pcmdir = WM8772_DIR,
.flags = SND_SOC_DAI_BFS_RATE,
.fs = 384,
.bfs = 64,
},
{
.fmt = WM8772_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
.pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
.pcmrate = SNDRV_PCM_RATE_48000,
.pcmdir = WM8772_DIR,
.flags = SND_SOC_DAI_BFS_RATE,
.fs = 256,
.bfs = 64,
},
{
.fmt = WM8772_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
.pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
.pcmrate = SNDRV_PCM_RATE_48000,
.pcmdir = WM8772_DIR,
.flags = SND_SOC_DAI_BFS_RATE,
.fs = 192,
.bfs = 64,
},
{
.fmt = WM8772_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
.pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
.pcmrate = SNDRV_PCM_RATE_48000,
.pcmdir = WM8772_DIR,
.flags = SND_SOC_DAI_BFS_RATE,
.fs = 128,
.bfs = 64,
},
/* 96k */
{
.fmt = WM8772_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
.pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
.pcmrate = SNDRV_PCM_RATE_96000,
.pcmdir = WM8772_DIR,
.flags = SND_SOC_DAI_BFS_RATE,
.fs = 384,
.bfs = 64,
},
{
.fmt = WM8772_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
.pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
.pcmrate = SNDRV_PCM_RATE_96000,
.pcmdir = WM8772_DIR,
.flags = SND_SOC_DAI_BFS_RATE,
.fs = 256,
.bfs = 64,
},
{
.fmt = WM8772_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
.pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
.pcmrate = SNDRV_PCM_RATE_96000,
.pcmdir = WM8772_DIR,
.flags = SND_SOC_DAI_BFS_RATE,
.fs = 192,
.bfs = 64,
},
{
.fmt = WM8772_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
.pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
.pcmrate = SNDRV_PCM_RATE_96000,
.pcmdir = WM8772_DIR,
.pcmrate = SND_SOC_DAI_BFS_RATE,
.fs = 128,
.bfs = 64,
},
/* 192k */
{
.fmt = WM8772_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
.pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
.pcmrate = SNDRV_PCM_RATE_192000,
.pcmdir = SND_SOC_DAIDIR_PLAYBACK,
.flags = SND_SOC_DAI_BFS_RATE,
.fs = 192,
.bfs = 64,
},
{
.fmt = WM8772_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
.pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
.pcmrate = SNDRV_PCM_RATE_192000,
.pcmdir = SND_SOC_DAIDIR_PLAYBACK,
.flags = SND_SOC_DAI_BFS_RATE,
.fs = 128,
.bfs = 64,
},
/* slave mode */
{
.fmt = WM8772_DAIFMT,
.pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
.pcmrate = WM8772_PRATES,
.pcmdir = SND_SOC_DAIDIR_PLAYBACK,
.fs = SND_SOC_FS_ALL,
.bfs = SND_SOC_FSB_ALL,
},
{
.fmt = WM8772_DAIFMT,
.pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
.pcmrate = WM8772_CRATES,
.pcmdir = SND_SOC_DAIDIR_CAPTURE,
.fs = SND_SOC_FS_ALL,
.bfs = SND_SOC_FSB_ALL,
},
};
/*
* read wm8772 register cache
*/
static inline unsigned int wm8772_read_reg_cache(struct snd_soc_codec * codec,
unsigned int reg)
{
u16 *cache = codec->reg_cache;
if (reg > WM8772_CACHE_REGNUM)
return -1;
return cache[reg];
}
/*
* write wm8772 register cache
*/
static inline void wm8772_write_reg_cache(struct snd_soc_codec * codec,
unsigned int reg, unsigned int value)
{
u16 *cache = codec->reg_cache;
if (reg > WM8772_CACHE_REGNUM)
return;
cache[reg] = value;
}
static int wm8772_write(struct snd_soc_codec * codec, unsigned int reg,
unsigned int value)
{
u8 data[2];
/* data is
* D15..D9 WM8772 register offset
* D8...D0 register data
*/
data[0] = (reg << 1) | ((value >> 8) & 0x0001);
data[1] = value & 0x00ff;
wm8772_write_reg_cache (codec, reg, value);
if (codec->hw_write(codec->control_data, data, 2) == 2)
return 0;
else
return -1;
}
#define wm8772_reset(c) wm8772_write(c, WM8772_RESET, 0)
/*
* WM8772 Controls
*/
static const char *wm8772_zero_flag[] = {"All Ch", "Ch 1", "Ch 2", "Ch3"};
static const struct soc_enum wm8772_enum[] = {
SOC_ENUM_SINGLE(WM8772_DACCTRL, 0, 4, wm8772_zero_flag),
};
static const struct snd_kcontrol_new wm8772_snd_controls[] = {
SOC_SINGLE("Left1 Playback Volume", WM8772_LDAC1VOL, 0, 255, 0),
SOC_SINGLE("Left2 Playback Volume", WM8772_LDAC2VOL, 0, 255, 0),
SOC_SINGLE("Left3 Playback Volume", WM8772_LDAC3VOL, 0, 255, 0),
SOC_SINGLE("Right1 Playback Volume", WM8772_RDAC1VOL, 0, 255, 0),
SOC_SINGLE("Right1 Playback Volume", WM8772_RDAC2VOL, 0, 255, 0),
SOC_SINGLE("Right1 Playback Volume", WM8772_RDAC3VOL, 0, 255, 0),
SOC_SINGLE("Master Playback Volume", WM8772_MDACVOL, 0, 255, 0),
SOC_SINGLE("Playback Switch", WM8772_DACCH, 0, 1, 0),
SOC_SINGLE("Capture Switch", WM8772_ADCCTRL, 2, 1, 0),
SOC_SINGLE("Demp1 Playback Switch", WM8772_DACCTRL, 6, 1, 0),
SOC_SINGLE("Demp2 Playback Switch", WM8772_DACCTRL, 7, 1, 0),
SOC_SINGLE("Demp3 Playback Switch", WM8772_DACCTRL, 8, 1, 0),
SOC_SINGLE("Phase Invert 1 Switch", WM8772_IFACE, 6, 1, 0),
SOC_SINGLE("Phase Invert 2 Switch", WM8772_IFACE, 7, 1, 0),
SOC_SINGLE("Phase Invert 3 Switch", WM8772_IFACE, 8, 1, 0),
SOC_SINGLE("Playback ZC Switch", WM8772_DACCTRL, 0, 1, 0),
SOC_SINGLE("Capture High Pass Switch", WM8772_ADCCTRL, 3, 1, 0),
};
/* add non dapm controls */
static int wm8772_add_controls(struct snd_soc_codec *codec)
{
int err, i;
for (i = 0; i < ARRAY_SIZE(wm8772_snd_controls); i++) {
err = snd_ctl_add(codec->card,
snd_soc_cnew(&wm8772_snd_controls[i],codec, NULL));
if (err < 0)
return err;
}
return 0;
}
/* valid wm8772 mclk frequencies */
static const int freq_table[5][6] = {
{4096000, 6144000, 8192000, 12288000, 16384000, 24576000},
{5644800, 8467000, 11289600, 16934000, 22579200, 33868800},
{6144000, 9216000, 12288000, 18432000, 24576000, 36864000},
{12288000, 18432000, 24576000, 36864000, 0, 0},
{24576000, 36864000, 0, 0, 0},
};
static unsigned int check_freq(int rate, unsigned int freq)
{
int i;
for(i = 0; i < 6; i++) {
if(freq == freq_table[i][rate])
return freq;
}
return 0;
}
static unsigned int wm8772_config_sysclk(struct snd_soc_codec_dai *dai,
struct snd_soc_clock_info *info, unsigned int clk)
{
switch (info->rate){
case 32000:
dai->mclk = check_freq(0, clk);
break;
case 44100:
dai->mclk = check_freq(1, clk);
break;
case 48000:
dai->mclk = check_freq(2, clk);
break;
case 96000:
dai->mclk = check_freq(3, clk);
break;
case 192000:
dai->mclk = check_freq(4, clk);
break;
default:
dai->mclk = 0;
}
return dai->mclk;
}
static int wm8772_pcm_prepare(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
struct snd_soc_codec *codec = socdev->codec;
u16 diface = wm8772_read_reg_cache(codec, WM8772_IFACE) & 0xffc0;
u16 diface_ctrl = wm8772_read_reg_cache(codec, WM8772_DACRATE) & 0xfe1f;
u16 aiface = 0;
u16 aiface_ctrl = wm8772_read_reg_cache(codec, WM8772_ADCCTRL) & 0xfcff;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
/* set master/slave audio interface */
switch (rtd->codec_dai->dai_runtime.fmt & SND_SOC_DAIFMT_CLOCK_MASK) {
case SND_SOC_DAIFMT_CBM_CFM:
diface_ctrl |= 0x0010;
break;
case SND_SOC_DAIFMT_CBS_CFS:
break;
}
/* interface format */
switch (rtd->codec_dai->dai_runtime.fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
diface |= 0x0002;
break;
case SND_SOC_DAIFMT_RIGHT_J:
break;
case SND_SOC_DAIFMT_LEFT_J:
diface |= 0x0001;
break;
case SND_SOC_DAIFMT_DSP_A:
diface |= 0x0003;
break;
case SND_SOC_DAIFMT_DSP_B:
diface |= 0x0007;
break;
}
/* bit size */
switch (rtd->codec_dai->dai_runtime.pcmfmt) {
case SNDRV_PCM_FMTBIT_S16_LE:
break;
case SNDRV_PCM_FORMAT_S20_3LE:
diface |= 0x0010;
break;
case SNDRV_PCM_FORMAT_S24_3LE:
diface |= 0x0020;
break;
case SNDRV_PCM_FORMAT_S32_LE:
diface |= 0x0030;
break;
}
/* clock inversion */
switch (rtd->codec_dai->dai_runtime.fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF:
break;
case SND_SOC_DAIFMT_IB_NF:
diface |= 0x0008;
break;
}
/* set rate */
switch (rtd->codec_dai->dai_runtime.fs) {
case 768:
diface_ctrl |= (0x5 << 6);
break;
case 512:
diface_ctrl |= (0x4 << 6);
break;
case 384:
diface_ctrl |= (0x3 << 6);
break;
case 256:
diface_ctrl |= (0x2 << 6);
break;
case 192:
diface_ctrl |= (0x1 << 6);
break;
}
wm8772_write(codec, WM8772_DACRATE, diface_ctrl);
wm8772_write(codec, WM8772_IFACE, diface);
} else {
/* set master/slave audio interface */
switch (rtd->codec_dai->dai_runtime.fmt & SND_SOC_DAIFMT_CLOCK_MASK) {
case SND_SOC_DAIFMT_CBM_CFM:
aiface |= 0x0010;
break;
case SND_SOC_DAIFMT_CBS_CFS:
break;
}
/* interface format */
switch (rtd->codec_dai->dai_runtime.fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
aiface |= 0x0002;
break;
case SND_SOC_DAIFMT_RIGHT_J:
break;
case SND_SOC_DAIFMT_LEFT_J:
aiface |= 0x0001;
break;
case SND_SOC_DAIFMT_DSP_A:
aiface |= 0x0003;
break;
case SND_SOC_DAIFMT_DSP_B:
aiface |= 0x0003;
aiface_ctrl |= 0x0010;
break;
}
/* bit size */
switch (rtd->codec_dai->dai_runtime.pcmfmt) {
case SNDRV_PCM_FMTBIT_S16_LE:
break;
case SNDRV_PCM_FMTBIT_S20_3LE:
aiface |= 0x0004;
break;
case SNDRV_PCM_FMTBIT_S24_LE:
aiface |= 0x0008;
break;
case SNDRV_PCM_FMTBIT_S32_LE:
aiface |= 0x000c;
break;
}
/* clock inversion */
switch (rtd->codec_dai->dai_runtime.fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF:
break;
case SND_SOC_DAIFMT_IB_NF:
aiface_ctrl |= 0x0020;
break;
}
/* set rate */
switch (rtd->codec_dai->dai_runtime.fs) {
case 768:
aiface |= (0x5 << 5);
break;
case 512:
aiface |= (0x4 << 5);
break;
case 384:
aiface |= (0x3 << 5);
break;
case 256:
aiface |= (0x2 << 5);
break;
}
wm8772_write(codec, WM8772_ADCCTRL, aiface_ctrl);
wm8772_write(codec, WM8772_ADCRATE, aiface);
}
return 0;
}
static int wm8772_dapm_event(struct snd_soc_codec *codec, int event)
{
u16 master = wm8772_read_reg_cache(codec, WM8772_DACRATE) & 0xffe0;
switch (event) {
case SNDRV_CTL_POWER_D0: /* full On */
/* vref/mid, clk and osc on, dac unmute, active */
wm8772_write(codec, WM8772_DACRATE, master);
break;
case SNDRV_CTL_POWER_D1: /* partial On */
case SNDRV_CTL_POWER_D2: /* partial On */
break;
case SNDRV_CTL_POWER_D3hot: /* Off, with power */
/* everything off except vref/vmid, dac mute, inactive */
wm8772_write(codec, WM8772_DACRATE, master | 0x0f);
break;
case SNDRV_CTL_POWER_D3cold: /* Off, without power */
/* everything off, dac mute, inactive */
wm8772_write(codec, WM8772_DACRATE, master | 0x1f);
break;
}
codec->dapm_state = event;
return 0;
}
struct snd_soc_codec_dai wm8772_dai = {
.name = "WM8772",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
.channels_max = 6,
},
.capture = {
.stream_name = "Capture",
.channels_min = 1,
.channels_max = 2,
},
.config_sysclk = wm8772_config_sysclk,
.ops = {
.prepare = wm8772_pcm_prepare,
},
.caps = {
.num_modes = ARRAY_SIZE(wm8772_modes),
.mode = wm8772_modes,
},
};
EXPORT_SYMBOL_GPL(wm8772_dai);
static int wm8772_suspend(struct platform_device *pdev, pm_message_t state)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
struct snd_soc_codec *codec = socdev->codec;
wm8772_dapm_event(codec, SNDRV_CTL_POWER_D3cold);
return 0;
}
static int wm8772_resume(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
struct snd_soc_codec *codec = socdev->codec;
int i;
u8 data[2];
u16 *cache = codec->reg_cache;
/* Sync reg_cache with the hardware */
for (i = 0; i < ARRAY_SIZE(wm8772_reg); i++) {
data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
data[1] = cache[i] & 0x00ff;
codec->hw_write(codec->control_data, data, 2);
}
wm8772_dapm_event(codec, SNDRV_CTL_POWER_D3hot);
wm8772_dapm_event(codec, codec->suspend_dapm_state);
return 0;
}
/*
* initialise the WM8772 driver
* register the mixer and dsp interfaces with the kernel
*/
static int wm8772_init(struct snd_soc_device *socdev)
{
struct snd_soc_codec *codec = socdev->codec;
int reg, ret = 0;
codec->name = "WM8772";
codec->owner = THIS_MODULE;
codec->read = wm8772_read_reg_cache;
codec->write = wm8772_write;
codec->dapm_event = wm8772_dapm_event;
codec->dai = &wm8772_dai;
codec->num_dai = 1;
codec->reg_cache_size = ARRAY_SIZE(wm8772_reg);
codec->reg_cache =
kzalloc(sizeof(u16) * ARRAY_SIZE(wm8772_reg), GFP_KERNEL);
if (codec->reg_cache == NULL)
return -ENOMEM;
memcpy(codec->reg_cache, wm8772_reg,
sizeof(u16) * ARRAY_SIZE(wm8772_reg));
codec->reg_cache_size = sizeof(u16) * ARRAY_SIZE(wm8772_reg);
wm8772_reset(codec);
/* register pcms */
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
if(ret < 0) {
kfree(codec->reg_cache);
return ret;
}
/* power on device */
wm8772_dapm_event(codec, SNDRV_CTL_POWER_D3hot);
/* set the update bits */
reg = wm8772_read_reg_cache(codec, WM8772_MDACVOL);
wm8772_write(codec, WM8772_MDACVOL, reg | 0x0100);
reg = wm8772_read_reg_cache(codec, WM8772_LDAC1VOL);
wm8772_write(codec, WM8772_LDAC1VOL, reg | 0x0100);
reg = wm8772_read_reg_cache(codec, WM8772_LDAC2VOL);
wm8772_write(codec, WM8772_LDAC2VOL, reg | 0x0100);
reg = wm8772_read_reg_cache(codec, WM8772_LDAC3VOL);
wm8772_write(codec, WM8772_LDAC3VOL, reg | 0x0100);
reg = wm8772_read_reg_cache(codec, WM8772_RDAC1VOL);
wm8772_write(codec, WM8772_RDAC1VOL, reg | 0x0100);
reg = wm8772_read_reg_cache(codec, WM8772_RDAC2VOL);
wm8772_write(codec, WM8772_RDAC2VOL, reg | 0x0100);
reg = wm8772_read_reg_cache(codec, WM8772_RDAC3VOL);
wm8772_write(codec, WM8772_RDAC3VOL, reg | 0x0100);
wm8772_add_controls(codec);
ret = snd_soc_register_card(socdev);
if (ret < 0) {
snd_soc_free_pcms(socdev);
snd_soc_dapm_free(socdev);
}
return ret;
}
static struct snd_soc_device *wm8772_socdev;
static int wm8772_probe(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
struct wm8772_setup_data *setup;
struct snd_soc_codec *codec;
int ret = 0;
printk(KERN_INFO "WM8772 Audio Codec %s", WM8772_VERSION);
setup = socdev->codec_data;
codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
if (codec == NULL)
return -ENOMEM;
socdev->codec = codec;
mutex_init(&codec->mutex);
INIT_LIST_HEAD(&codec->dapm_widgets);
INIT_LIST_HEAD(&codec->dapm_paths);
wm8772_socdev = socdev;
/* Add other interfaces here */
#warning do SPI device probe here and then call wm8772_init()
return ret;
}
/* power down chip */
static int wm8772_remove(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
struct snd_soc_codec *codec = socdev->codec;
if (codec->control_data)
wm8772_dapm_event(codec, SNDRV_CTL_POWER_D3cold);
snd_soc_free_pcms(socdev);
kfree(codec);
return 0;
}
struct snd_soc_codec_device soc_codec_dev_wm8772 = {
.probe = wm8772_probe,
.remove = wm8772_remove,
.suspend = wm8772_suspend,
.resume = wm8772_resume,
};
EXPORT_SYMBOL_GPL(soc_codec_dev_wm8772);
MODULE_DESCRIPTION("ASoC WM8772 driver");
MODULE_AUTHOR("Liam Girdwood");
MODULE_LICENSE("GPL");

41
sound/soc/codecs/wm8772.h Normal file
View File

@@ -0,0 +1,41 @@
/*
* wm8772.h -- audio driver for WM8772
*
* Copyright 2005 Wolfson Microelectronics PLC.
* Author: Liam Girdwood
* liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.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.
*
*/
#ifndef _WM8772_H
#define _WM8772_H
/* WM8772 register space */
#define WM8772_LDAC1VOL 0x00
#define WM8772_RDAC1VOL 0x01
#define WM8772_DACCH 0x02
#define WM8772_IFACE 0x03
#define WM8772_LDAC2VOL 0x04
#define WM8772_RDAC2VOL 0x05
#define WM8772_LDAC3VOL 0x06
#define WM8772_RDAC3VOL 0x07
#define WM8772_MDACVOL 0x08
#define WM8772_DACCTRL 0x09
#define WM8772_DACRATE 0x0a
#define WM8772_ADCRATE 0x0b
#define WM8772_ADCCTRL 0x0c
#define WM8772_RESET 0x1f
#define WM8772_CACHE_REGNUM 10
extern struct snd_soc_codec_dai wm8772_dai;
extern struct snd_soc_codec_device soc_codec_dev_wm8772;
#endif

1657
sound/soc/codecs/wm8990.c Normal file

File diff suppressed because it is too large Load Diff

904
sound/soc/codecs/wm8990.h Normal file
View File

@@ -0,0 +1,904 @@
/*
* wm8753.h -- audio driver for WM8753
*
* Copyright 2007 Wolfson Microelectronics PLC.
* Author: Graeme Gregory
* graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.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.
*
*/
#ifndef __WM8990REGISTERDEFS_H__
#define __WM8990REGISTERDEFS_H__
/*
* Register values.
*/
#define WM8990_RESET 0x00
#define WM8990_POWER_MANAGEMENT_1 0x01
#define WM8990_POWER_MANAGEMENT_2 0x02
#define WM8990_POWER_MANAGEMENT_3 0x03
#define WM8990_AUDIO_INTERFACE_1 0x04
#define WM8990_AUDIO_INTERFACE_2 0x05
#define WM8990_CLOCKING_1 0x06
#define WM8990_CLOCKING_2 0x07
#define WM8990_AUDIO_INTERFACE_3 0x08
#define WM8990_AUDIO_INTERFACE_4 0x09
#define WM8990_DAC_CTRL 0x0A
#define WM8990_LEFT_DAC_DIGITAL_VOLUME 0x0B
#define WM8990_RIGHT_DAC_DIGITAL_VOLUME 0x0C
#define WM8990_DIGITAL_SIDE_TONE 0x0D
#define WM8990_ADC_CTRL 0x0E
#define WM8990_LEFT_ADC_DIGITAL_VOLUME 0x0F
#define WM8990_RIGHT_ADC_DIGITAL_VOLUME 0x10
#define WM8990_GPIO_CTRL_1 0x12
#define WM8990_GPIO1_GPIO2 0x13
#define WM8990_GPIO3_GPIO4 0x14
#define WM8990_GPIO5_GPIO6 0x15
#define WM8990_GPIOCTRL_2 0x16
#define WM8990_GPIO_POL 0x17
#define WM8990_LEFT_LINE_INPUT_1_2_VOLUME 0x18
#define WM8990_LEFT_LINE_INPUT_3_4_VOLUME 0x19
#define WM8990_RIGHT_LINE_INPUT_1_2_VOLUME 0x1A
#define WM8990_RIGHT_LINE_INPUT_3_4_VOLUME 0x1B
#define WM8990_LEFT_OUTPUT_VOLUME 0x1C
#define WM8990_RIGHT_OUTPUT_VOLUME 0x1D
#define WM8990_LINE_OUTPUTS_VOLUME 0x1E
#define WM8990_OUT3_4_VOLUME 0x1F
#define WM8990_LEFT_OPGA_VOLUME 0x20
#define WM8990_RIGHT_OPGA_VOLUME 0x21
#define WM8990_SPEAKER_VOLUME 0x22
#define WM8990_CLASSD1 0x23
#define WM8990_CLASSD3 0x25
#define WM8990_INPUT_MIXER1 0x27
#define WM8990_INPUT_MIXER2 0x28
#define WM8990_INPUT_MIXER3 0x29
#define WM8990_INPUT_MIXER4 0x2A
#define WM8990_INPUT_MIXER5 0x2B
#define WM8990_INPUT_MIXER6 0x2C
#define WM8990_OUTPUT_MIXER1 0x2D
#define WM8990_OUTPUT_MIXER2 0x2E
#define WM8990_OUTPUT_MIXER3 0x2F
#define WM8990_OUTPUT_MIXER4 0x30
#define WM8990_OUTPUT_MIXER5 0x31
#define WM8990_OUTPUT_MIXER6 0x32
#define WM8990_OUT3_4_MIXER 0x33
#define WM8990_LINE_MIXER1 0x34
#define WM8990_LINE_MIXER2 0x35
#define WM8990_SPEAKER_MIXER 0x36
#define WM8990_ADDITIONAL_CONTROL 0x37
#define WM8990_ANTIPOP1 0x38
#define WM8990_ANTIPOP2 0x39
#define WM8990_MICBIAS 0x3A
#define WM8990_PLL1 0x3C
#define WM8990_PLL2 0x3D
#define WM8990_PLL3 0x3E
#define WM8990_INTDRIVBITS 0x3F
#define WM8990_REGISTER_COUNT 60
#define WM8990_MAX_REGISTER 0x3F
/*
* Field Definitions.
*/
/*
* R0 (0x00) - Reset
*/
#define WM8990_SW_RESET_CHIP_ID_MASK 0xFFFF /* SW_RESET_CHIP_ID - [15:0] */
/*
* R1 (0x01) - Power Management (1)
*/
#define WM8990_SPK_ENA 0x1000 /* SPK_ENA */
#define WM8990_SPK_ENA_BIT 12
#define WM8990_OUT3_ENA 0x0800 /* OUT3_ENA */
#define WM8990_OUT3_ENA_BIT 11
#define WM8990_OUT4_ENA 0x0400 /* OUT4_ENA */
#define WM8990_OUT4_ENA_BIT 10
#define WM8990_LOUT_ENA 0x0200 /* LOUT_ENA */
#define WM8990_LOUT_ENA_BIT 9
#define WM8990_ROUT_ENA 0x0100 /* ROUT_ENA */
#define WM8990_ROUT_ENA_BIT 8
#define WM8990_MICBIAS_ENA 0x0010 /* MICBIAS_ENA */
#define WM8990_MICBIAS_ENA_BIT 4
#define WM8990_VMID_MODE_MASK 0x0006 /* VMID_MODE - [2:1] */
#define WM8990_VREF_ENA 0x0001 /* VREF_ENA */
#define WM8990_VREF_ENA_BIT 0
/*
* R2 (0x02) - Power Management (2)
*/
#define WM8990_PLL_ENA 0x8000 /* PLL_ENA */
#define WM8990_PLL_ENA_BIT 15
#define WM8990_TSHUT_ENA 0x4000 /* TSHUT_ENA */
#define WM8990_TSHUT_ENA_BIT 14
#define WM8990_TSHUT_OPDIS 0x2000 /* TSHUT_OPDIS */
#define WM8990_TSHUT_OPDIS_BIT 13
#define WM8990_OPCLK_ENA 0x0800 /* OPCLK_ENA */
#define WM8990_OPCLK_ENA_BIT 11
#define WM8990_AINL_ENA 0x0200 /* AINL_ENA */
#define WM8990_AINL_ENA_BIT 9
#define WM8990_AINR_ENA 0x0100 /* AINR_ENA */
#define WM8990_AINR_ENA_BIT 8
#define WM8990_LIN34_ENA 0x0080 /* LIN34_ENA */
#define WM8990_LIN34_ENA_BIT 7
#define WM8990_LIN12_ENA 0x0040 /* LIN12_ENA */
#define WM8990_LIN12_ENA_BIT 6
#define WM8990_RIN34_ENA 0x0020 /* RIN34_ENA */
#define WM8990_RIN34_ENA_BIT 5
#define WM8990_RIN12_ENA 0x0010 /* RIN12_ENA */
#define WM8990_RIN12_ENA_BIT 4
#define WM8990_ADCL_ENA 0x0002 /* ADCL_ENA */
#define WM8990_ADCL_ENA_BIT 1
#define WM8990_ADCR_ENA 0x0001 /* ADCR_ENA */
#define WM8990_ADCR_ENA_BIT 0
/*
* R3 (0x03) - Power Management (3)
*/
#define WM8990_LON_ENA 0x2000 /* LON_ENA */
#define WM8990_LON_ENA_BIT 13
#define WM8990_LOP_ENA 0x1000 /* LOP_ENA */
#define WM8990_LOP_ENA_BIT 12
#define WM8990_RON_ENA 0x0800 /* RON_ENA */
#define WM8990_RON_ENA_BIT 11
#define WM8990_ROP_ENA 0x0400 /* ROP_ENA */
#define WM8990_ROP_ENA_BIT 10
#define WM8990_LOPGA_ENA 0x0080 /* LOPGA_ENA */
#define WM8990_LOPGA_ENA_BIT 7
#define WM8990_ROPGA_ENA 0x0040 /* ROPGA_ENA */
#define WM8990_ROPGA_ENA_BIT 6
#define WM8990_LOMIX_ENA 0x0020 /* LOMIX_ENA */
#define WM8990_LOMIX_ENA_BIT 5
#define WM8990_ROMIX_ENA 0x0010 /* ROMIX_ENA */
#define WM8990_ROMIX_ENA_BIT 4
#define WM8990_DACL_ENA 0x0002 /* DACL_ENA */
#define WM8990_DACL_ENA_BIT 1
#define WM8990_DACR_ENA 0x0001 /* DACR_ENA */
#define WM8990_DACR_ENA_BIT 0
/*
* R4 (0x04) - Audio Interface (1)
*/
#define WM8990_AIFADCL_SRC 0x8000 /* AIFADCL_SRC */
#define WM8990_AIFADCR_SRC 0x4000 /* AIFADCR_SRC */
#define WM8990_AIFADC_TDM 0x2000 /* AIFADC_TDM */
#define WM8990_AIFADC_TDM_CHAN 0x1000 /* AIFADC_TDM_CHAN */
#define WM8990_AIF_BCLK_INV 0x0100 /* AIF_BCLK_INV */
#define WM8990_AIF_LRCLK_INV 0x0080 /* AIF_LRCLK_INV */
#define WM8990_AIF_WL_MASK 0x0060 /* AIF_WL - [6:5] */
#define WM8990_AIF_WL_16BITS (0 << 5)
#define WM8990_AIF_WL_20BITS (1 << 5)
#define WM8990_AIF_WL_24BITS (2 << 5)
#define WM8990_AIF_WL_32BITS (3 << 5)
#define WM8990_AIF_FMT_MASK 0x0018 /* AIF_FMT - [4:3] */
#define WM8990_AIF_TMF_RIGHTJ (0 << 3)
#define WM8990_AIF_TMF_LEFTJ (1 << 3)
#define WM8990_AIF_TMF_I2S (2 << 3)
#define WM8990_AIF_TMF_DSP (3 << 3)
/*
* R5 (0x05) - Audio Interface (2)
*/
#define WM8990_DACL_SRC 0x8000 /* DACL_SRC */
#define WM8990_DACR_SRC 0x4000 /* DACR_SRC */
#define WM8990_AIFDAC_TDM 0x2000 /* AIFDAC_TDM */
#define WM8990_AIFDAC_TDM_CHAN 0x1000 /* AIFDAC_TDM_CHAN */
#define WM8990_DAC_BOOST_MASK 0x0C00 /* DAC_BOOST - [11:10] */
#define WM8990_DAC_COMP 0x0010 /* DAC_COMP */
#define WM8990_DAC_COMPMODE 0x0008 /* DAC_COMPMODE */
#define WM8990_ADC_COMP 0x0004 /* ADC_COMP */
#define WM8990_ADC_COMPMODE 0x0002 /* ADC_COMPMODE */
#define WM8990_LOOPBACK 0x0001 /* LOOPBACK */
/*
* R6 (0x06) - Clocking (1)
*/
#define WM8990_TOCLK_RATE 0x8000 /* TOCLK_RATE */
#define WM8990_TOCLK_ENA 0x4000 /* TOCLK_ENA */
#define WM8990_OPCLKDIV_MASK 0x1E00 /* OPCLKDIV - [12:9] */
#define WM8990_DCLKDIV_MASK 0x01C0 /* DCLKDIV - [8:6] */
#define WM8990_BCLK_DIV_MASK 0x001E /* BCLK_DIV - [4:1] */
#define WM8990_BCLK_DIV_1 (0x0 << 1)
#define WM8990_BCLK_DIV_1_5 (0x1 << 1)
#define WM8990_BCLK_DIV_2 (0x2 << 1)
#define WM8990_BCLK_DIV_3 (0x3 << 1)
#define WM8990_BCLK_DIV_4 (0x4 << 1)
#define WM8990_BCLK_DIV_5_5 (0x5 << 1)
#define WM8990_BCLK_DIV_6 (0x6 << 1)
#define WM8990_BCLK_DIV_8 (0x7 << 1)
#define WM8990_BCLK_DIV_11 (0x8 << 1)
#define WM8990_BCLK_DIV_12 (0x9 << 1)
#define WM8990_BCLK_DIV_16 (0xA << 1)
#define WM8990_BCLK_DIV_22 (0xB << 1)
#define WM8990_BCLK_DIV_24 (0xC << 1)
#define WM8990_BCLK_DIV_32 (0xD << 1)
#define WM8990_BCLK_DIV_44 (0xE << 1)
#define WM8990_BCLK_DIV_48 (0xF << 1)
/*
* R7 (0x07) - Clocking (2)
*/
#define WM8990_MCLK_SRC 0x8000 /* MCLK_SRC */
#define WM8990_SYSCLK_SRC 0x4000 /* SYSCLK_SRC */
#define WM8990_CLK_FORCE 0x2000 /* CLK_FORCE */
#define WM8990_MCLK_DIV_MASK 0x1800 /* MCLK_DIV - [12:11] */
#define WM8990_MCLK_DIV_1 ( 0 << 11)
#define WM8990_MCLK_DIV_2 ( 2 << 11)
#define WM8990_MCLK_INV 0x0400 /* MCLK_INV */
#define WM8990_ADC_CLKDIV_MASK 0x00E0 /* ADC_CLKDIV - [7:5] */
#define WM8990_ADC_CLKDIV_1 ( 0 << 5)
#define WM8990_ADC_CLKDIV_1_5 ( 1 << 5)
#define WM8990_ADC_CLKDIV_2 ( 2 << 5)
#define WM8990_ADC_CLKDIV_3 ( 3 << 5)
#define WM8990_ADC_CLKDIV_4 ( 4 << 5)
#define WM8990_ADC_CLKDIV_5_5 ( 5 << 5)
#define WM8990_ADC_CLKDIV_6 ( 6 << 5)
#define WM8990_DAC_CLKDIV_MASK 0x001C /* DAC_CLKDIV - [4:2] */
#define WM8990_DAC_CLKDIV_1 ( 0 << 2)
#define WM8990_DAC_CLKDIV_1_5 ( 1 << 2)
#define WM8990_DAC_CLKDIV_2 ( 2 << 2)
#define WM8990_DAC_CLKDIV_3 ( 3 << 2)
#define WM8990_DAC_CLKDIV_4 ( 4 << 2)
#define WM8990_DAC_CLKDIV_5_5 ( 5 << 2)
#define WM8990_DAC_CLKDIV_6 ( 6 << 2)
/*
* R8 (0x08) - Audio Interface (3)
*/
#define WM8990_AIF_MSTR1 0x8000 /* AIF_MSTR1 */
#define WM8990_AIF_MSTR2 0x4000 /* AIF_MSTR2 */
#define WM8990_AIF_SEL 0x2000 /* AIF_SEL */
#define WM8990_ADCLRC_DIR 0x0800 /* ADCLRC_DIR */
#define WM8990_ADCLRC_RATE_MASK 0x07FF /* ADCLRC_RATE - [10:0] */
/*
* R9 (0x09) - Audio Interface (4)
*/
#define WM8990_ALRCGPIO1 0x8000 /* ALRCGPIO1 */
#define WM8990_ALRCBGPIO6 0x4000 /* ALRCBGPIO6 */
#define WM8990_AIF_TRIS 0x2000 /* AIF_TRIS */
#define WM8990_DACLRC_DIR 0x0800 /* DACLRC_DIR */
#define WM8990_DACLRC_RATE_MASK 0x07FF /* DACLRC_RATE - [10:0] */
/*
* R10 (0x0A) - DAC CTRL
*/
#define WM8990_AIF_LRCLKRATE 0x0400 /* AIF_LRCLKRATE */
#define WM8990_DAC_MONO 0x0200 /* DAC_MONO */
#define WM8990_DAC_SB_FILT 0x0100 /* DAC_SB_FILT */
#define WM8990_DAC_MUTERATE 0x0080 /* DAC_MUTERATE */
#define WM8990_DAC_MUTEMODE 0x0040 /* DAC_MUTEMODE */
#define WM8990_DEEMP_MASK 0x0030 /* DEEMP - [5:4] */
#define WM8990_DAC_MUTE 0x0004 /* DAC_MUTE */
#define WM8990_DACL_DATINV 0x0002 /* DACL_DATINV */
#define WM8990_DACR_DATINV 0x0001 /* DACR_DATINV */
/*
* R11 (0x0B) - Left DAC Digital Volume
*/
#define WM8990_DAC_VU 0x0100 /* DAC_VU */
#define WM8990_DACL_VOL_MASK 0x00FF /* DACL_VOL - [7:0] */
#define WM8990_DACL_VOL_SHIFT 0
/*
* R12 (0x0C) - Right DAC Digital Volume
*/
#define WM8990_DAC_VU 0x0100 /* DAC_VU */
#define WM8990_DACR_VOL_MASK 0x00FF /* DACR_VOL - [7:0] */
#define WM8990_DACR_VOL_SHIFT 0
/*
* R13 (0x0D) - Digital Side Tone
*/
#define WM8990_ADCL_DAC_SVOL_MASK 0x0F /* ADCL_DAC_SVOL - [12:9] */
#define WM8990_ADCL_DAC_SVOL_SHIFT 9
#define WM8990_ADCR_DAC_SVOL_MASK 0x0F /* ADCR_DAC_SVOL - [8:5] */
#define WM8990_ADCR_DAC_SVOL_SHIFT 5
#define WM8990_ADC_TO_DACL_MASK 0x03 /* ADC_TO_DACL - [3:2] */
#define WM8990_ADC_TO_DACL_SHIFT 2
#define WM8990_ADC_TO_DACR_MASK 0x03 /* ADC_TO_DACR - [1:0] */
#define WM8990_ADC_TO_DACR_SHIFT 0
/*
* R14 (0x0E) - ADC CTRL
*/
#define WM8990_ADC_HPF_ENA 0x0100 /* ADC_HPF_ENA */
#define WM8990_ADC_HPF_ENA_BIT 8
#define WM8990_ADC_HPF_CUT_MASK 0x03 /* ADC_HPF_CUT - [6:5] */
#define WM8990_ADC_HPF_CUT_SHIFT 5
#define WM8990_ADCL_DATINV 0x0002 /* ADCL_DATINV */
#define WM8990_ADCL_DATINV_BIT 1
#define WM8990_ADCR_DATINV 0x0001 /* ADCR_DATINV */
#define WM8990_ADCR_DATINV_BIT 0
/*
* R15 (0x0F) - Left ADC Digital Volume
*/
#define WM8990_ADC_VU 0x0100 /* ADC_VU */
#define WM8990_ADCL_VOL_MASK 0x00FF /* ADCL_VOL - [7:0] */
#define WM8990_ADCL_VOL_SHIFT 0
/*
* R16 (0x10) - Right ADC Digital Volume
*/
#define WM8990_ADC_VU 0x0100 /* ADC_VU */
#define WM8990_ADCR_VOL_MASK 0x00FF /* ADCR_VOL - [7:0] */
#define WM8990_ADCR_VOL_SHIFT 0
/*
* R18 (0x12) - GPIO CTRL 1
*/
#define WM8990_IRQ 0x1000 /* IRQ */
#define WM8990_TEMPOK 0x0800 /* TEMPOK */
#define WM8990_MICSHRT 0x0400 /* MICSHRT */
#define WM8990_MICDET 0x0200 /* MICDET */
#define WM8990_PLL_LCK 0x0100 /* PLL_LCK */
#define WM8990_GPI8_STATUS 0x0080 /* GPI8_STATUS */
#define WM8990_GPI7_STATUS 0x0040 /* GPI7_STATUS */
#define WM8990_GPIO6_STATUS 0x0020 /* GPIO6_STATUS */
#define WM8990_GPIO5_STATUS 0x0010 /* GPIO5_STATUS */
#define WM8990_GPIO4_STATUS 0x0008 /* GPIO4_STATUS */
#define WM8990_GPIO3_STATUS 0x0004 /* GPIO3_STATUS */
#define WM8990_GPIO2_STATUS 0x0002 /* GPIO2_STATUS */
#define WM8990_GPIO1_STATUS 0x0001 /* GPIO1_STATUS */
/*
* R19 (0x13) - GPIO1 & GPIO2
*/
#define WM8990_GPIO2_DEB_ENA 0x8000 /* GPIO2_DEB_ENA */
#define WM8990_GPIO2_IRQ_ENA 0x4000 /* GPIO2_IRQ_ENA */
#define WM8990_GPIO2_PU 0x2000 /* GPIO2_PU */
#define WM8990_GPIO2_PD 0x1000 /* GPIO2_PD */
#define WM8990_GPIO2_SEL_MASK 0x0F00 /* GPIO2_SEL - [11:8] */
#define WM8990_GPIO1_DEB_ENA 0x0080 /* GPIO1_DEB_ENA */
#define WM8990_GPIO1_IRQ_ENA 0x0040 /* GPIO1_IRQ_ENA */
#define WM8990_GPIO1_PU 0x0020 /* GPIO1_PU */
#define WM8990_GPIO1_PD 0x0010 /* GPIO1_PD */
#define WM8990_GPIO1_SEL_MASK 0x000F /* GPIO1_SEL - [3:0] */
/*
* R20 (0x14) - GPIO3 & GPIO4
*/
#define WM8990_GPIO4_DEB_ENA 0x8000 /* GPIO4_DEB_ENA */
#define WM8990_GPIO4_IRQ_ENA 0x4000 /* GPIO4_IRQ_ENA */
#define WM8990_GPIO4_PU 0x2000 /* GPIO4_PU */
#define WM8990_GPIO4_PD 0x1000 /* GPIO4_PD */
#define WM8990_GPIO4_SEL_MASK 0x0F00 /* GPIO4_SEL - [11:8] */
#define WM8990_GPIO3_DEB_ENA 0x0080 /* GPIO3_DEB_ENA */
#define WM8990_GPIO3_IRQ_ENA 0x0040 /* GPIO3_IRQ_ENA */
#define WM8990_GPIO3_PU 0x0020 /* GPIO3_PU */
#define WM8990_GPIO3_PD 0x0010 /* GPIO3_PD */
#define WM8990_GPIO3_SEL_MASK 0x000F /* GPIO3_SEL - [3:0] */
/*
* R21 (0x15) - GPIO5 & GPIO6
*/
#define WM8990_GPIO6_DEB_ENA 0x8000 /* GPIO6_DEB_ENA */
#define WM8990_GPIO6_IRQ_ENA 0x4000 /* GPIO6_IRQ_ENA */
#define WM8990_GPIO6_PU 0x2000 /* GPIO6_PU */
#define WM8990_GPIO6_PD 0x1000 /* GPIO6_PD */
#define WM8990_GPIO6_SEL_MASK 0x0F00 /* GPIO6_SEL - [11:8] */
#define WM8990_GPIO5_DEB_ENA 0x0080 /* GPIO5_DEB_ENA */
#define WM8990_GPIO5_IRQ_ENA 0x0040 /* GPIO5_IRQ_ENA */
#define WM8990_GPIO5_PU 0x0020 /* GPIO5_PU */
#define WM8990_GPIO5_PD 0x0010 /* GPIO5_PD */
#define WM8990_GPIO5_SEL_MASK 0x000F /* GPIO5_SEL - [3:0] */
/*
* R22 (0x16) - GPIOCTRL 2
*/
#define WM8990_RD_3W_ENA 0x8000 /* RD_3W_ENA */
#define WM8990_MODE_3W4W 0x4000 /* MODE_3W4W */
#define WM8990_TEMPOK_IRQ_ENA 0x0800 /* TEMPOK_IRQ_ENA */
#define WM8990_MICSHRT_IRQ_ENA 0x0400 /* MICSHRT_IRQ_ENA */
#define WM8990_MICDET_IRQ_ENA 0x0200 /* MICDET_IRQ_ENA */
#define WM8990_PLL_LCK_IRQ_ENA 0x0100 /* PLL_LCK_IRQ_ENA */
#define WM8990_GPI8_DEB_ENA 0x0080 /* GPI8_DEB_ENA */
#define WM8990_GPI8_IRQ_ENA 0x0040 /* GPI8_IRQ_ENA */
#define WM8990_GPI8_ENA 0x0010 /* GPI8_ENA */
#define WM8990_GPI7_DEB_ENA 0x0008 /* GPI7_DEB_ENA */
#define WM8990_GPI7_IRQ_ENA 0x0004 /* GPI7_IRQ_ENA */
#define WM8990_GPI7_ENA 0x0001 /* GPI7_ENA */
/*
* R23 (0x17) - GPIO_POL
*/
#define WM8990_IRQ_INV 0x1000 /* IRQ_INV */
#define WM8990_TEMPOK_POL 0x0800 /* TEMPOK_POL */
#define WM8990_MICSHRT_POL 0x0400 /* MICSHRT_POL */
#define WM8990_MICDET_POL 0x0200 /* MICDET_POL */
#define WM8990_PLL_LCK_POL 0x0100 /* PLL_LCK_POL */
#define WM8990_GPI8_POL 0x0080 /* GPI8_POL */
#define WM8990_GPI7_POL 0x0040 /* GPI7_POL */
#define WM8990_GPIO6_POL 0x0020 /* GPIO6_POL */
#define WM8990_GPIO5_POL 0x0010 /* GPIO5_POL */
#define WM8990_GPIO4_POL 0x0008 /* GPIO4_POL */
#define WM8990_GPIO3_POL 0x0004 /* GPIO3_POL */
#define WM8990_GPIO2_POL 0x0002 /* GPIO2_POL */
#define WM8990_GPIO1_POL 0x0001 /* GPIO1_POL */
/*
* R24 (0x18) - Left Line Input 1&2 Volume
*/
#define WM8990_IPVU 0x0100 /* IPVU */
#define WM8990_LI12MUTE 0x0080 /* LI12MUTE */
#define WM8990_LI12MUTE_BIT 7
#define WM8990_LI12ZC 0x0040 /* LI12ZC */
#define WM8990_LI12ZC_BIT 6
#define WM8990_LIN12VOL_MASK 0x001F /* LIN12VOL - [4:0] */
#define WM8990_LIN12VOL_SHIFT 0
/*
* R25 (0x19) - Left Line Input 3&4 Volume
*/
#define WM8990_IPVU 0x0100 /* IPVU */
#define WM8990_LI34MUTE 0x0080 /* LI34MUTE */
#define WM8990_LI34MUTE_BIT 7
#define WM8990_LI34ZC 0x0040 /* LI34ZC */
#define WM8990_LI34ZC_BIT 6
#define WM8990_LIN34VOL_MASK 0x001F /* LIN34VOL - [4:0] */
#define WM8990_LIN34VOL_SHIFT 0
/*
* R26 (0x1A) - Right Line Input 1&2 Volume
*/
#define WM8990_IPVU 0x0100 /* IPVU */
#define WM8990_RI12MUTE 0x0080 /* RI12MUTE */
#define WM8990_RI12MUTE_BIT 7
#define WM8990_RI12ZC 0x0040 /* RI12ZC */
#define WM8990_RI12ZC_BIT 6
#define WM8990_RIN12VOL_MASK 0x001F /* RIN12VOL - [4:0] */
#define WM8990_RIN12VOL_SHIFT 0
/*
* R27 (0x1B) - Right Line Input 3&4 Volume
*/
#define WM8990_IPVU 0x0100 /* IPVU */
#define WM8990_RI34MUTE 0x0080 /* RI34MUTE */
#define WM8990_RI34MUTE_BIT 7
#define WM8990_RI34ZC 0x0040 /* RI34ZC */
#define WM8990_RI34ZC_BIT 6
#define WM8990_RIN34VOL_MASK 0x001F /* RIN34VOL - [4:0] */
#define WM8990_RIN34VOL_SHIFT 0
/*
* R28 (0x1C) - Left Output Volume
*/
#define WM8990_OPVU 0x0100 /* OPVU */
#define WM8990_LOZC 0x0080 /* LOZC */
#define WM8990_LOZC_BIT 7
#define WM8990_LOUTVOL_MASK 0x007F /* LOUTVOL - [6:0] */
#define WM8990_LOUTVOL_SHIFT 0
/*
* R29 (0x1D) - Right Output Volume
*/
#define WM8990_OPVU 0x0100 /* OPVU */
#define WM8990_ROZC 0x0080 /* ROZC */
#define WM8990_ROZC_BIT 7
#define WM8990_ROUTVOL_MASK 0x007F /* ROUTVOL - [6:0] */
#define WM8990_ROUTVOL_SHIFT 0
/*
* R30 (0x1E) - Line Outputs Volume
*/
#define WM8990_LONMUTE 0x0040 /* LONMUTE */
#define WM8990_LONMUTE_BIT 6
#define WM8990_LOPMUTE 0x0020 /* LOPMUTE */
#define WM8990_LOPMUTE_BIT 5
#define WM8990_LOATTN 0x0010 /* LOATTN */
#define WM8990_LOATTN_BIT 4
#define WM8990_RONMUTE 0x0004 /* RONMUTE */
#define WM8990_RONMUTE_BIT 2
#define WM8990_ROPMUTE 0x0002 /* ROPMUTE */
#define WM8990_ROPMUTE_BIT 1
#define WM8990_ROATTN 0x0001 /* ROATTN */
#define WM8990_ROATTN_BIT 0
/*
* R31 (0x1F) - Out3/4 Volume
*/
#define WM8990_OUT3MUTE 0x0020 /* OUT3MUTE */
#define WM8990_OUT3MUTE_BIT 5
#define WM8990_OUT3ATTN 0x0010 /* OUT3ATTN */
#define WM8990_OUT3ATTN_BIT 4
#define WM8990_OUT4MUTE 0x0002 /* OUT4MUTE */
#define WM8990_OUT4MUTE_BIT 1
#define WM8990_OUT4ATTN 0x0001 /* OUT4ATTN */
#define WM8990_OUT4ATTN_BIT 0
/*
* R32 (0x20) - Left OPGA Volume
*/
#define WM8990_OPVU 0x0100 /* OPVU */
#define WM8990_LOPGAZC 0x0080 /* LOPGAZC */
#define WM8990_LOPGAZC_BIT 7
#define WM8990_LOPGAVOL_MASK 0x007F /* LOPGAVOL - [6:0] */
#define WM8990_LOPGAVOL_SHIFT 0
/*
* R33 (0x21) - Right OPGA Volume
*/
#define WM8990_OPVU 0x0100 /* OPVU */
#define WM8990_ROPGAZC 0x0080 /* ROPGAZC */
#define WM8990_ROPGAZC_BIT 7
#define WM8990_ROPGAVOL_MASK 0x007F /* ROPGAVOL - [6:0] */
#define WM8990_ROPGAVOL_SHIFT 0
/*
* R34 (0x22) - Speaker Volume
*/
#define WM8990_SPKVOL_MASK 0x0003 /* SPKVOL - [1:0] */
#define WM8990_SPKVOL_SHIFT 0
/*
* R35 (0x23) - ClassD1
*/
#define WM8990_CDMODE 0x0100 /* CDMODE */
#define WM8990_CDMODE_BIT 8
/*
* R37 (0x25) - ClassD3
*/
#define WM8990_DCGAIN_MASK 0x0007 /* DCGAIN - [5:3] */
#define WM8990_DCGAIN_SHIFT 3
#define WM8990_ACGAIN_MASK 0x0007 /* ACGAIN - [2:0] */
#define WM8990_ACGAIN_SHIFT 0
/*
* R39 (0x27) - Input Mixer1
*/
#define WM8990_AINLMODE_MASK 0x000C /* AINLMODE - [3:2] */
#define WM8990_AINLMODE_SHIFT 2
#define WM8990_AINRMODE_MASK 0x0003 /* AINRMODE - [1:0] */
#define WM8990_AINRMODE_SHIFT 0
/*
* R40 (0x28) - Input Mixer2
*/
#define WM8990_LMP4 0x0080 /* LMP4 */
#define WM8990_LMP4_BIT 7 /* LMP4 */
#define WM8990_LMN3 0x0040 /* LMN3 */
#define WM8990_LMN3_BIT 6 /* LMN3 */
#define WM8990_LMP2 0x0020 /* LMP2 */
#define WM8990_LMP2_BIT 5 /* LMP2 */
#define WM8990_LMN1 0x0010 /* LMN1 */
#define WM8990_LMN1_BIT 4 /* LMN1 */
#define WM8990_RMP4 0x0008 /* RMP4 */
#define WM8990_RMP4_BIT 3 /* RMP4 */
#define WM8990_RMN3 0x0004 /* RMN3 */
#define WM8990_RMN3_BIT 2 /* RMN3 */
#define WM8990_RMP2 0x0002 /* RMP2 */
#define WM8990_RMP2_BIT 1 /* RMP2 */
#define WM8990_RMN1 0x0001 /* RMN1 */
#define WM8990_RMN1_BIT 0 /* RMN1 */
/*
* R41 (0x29) - Input Mixer3
*/
#define WM8990_L34MNB 0x0100 /* L34MNB */
#define WM8990_L34MNB_BIT 8
#define WM8990_L34MNBST 0x0080 /* L34MNBST */
#define WM8990_L34MNBST_BIT 7
#define WM8990_L12MNB 0x0020 /* L12MNB */
#define WM8990_L12MNB_BIT 5
#define WM8990_L12MNBST 0x0010 /* L12MNBST */
#define WM8990_L12MNBST_BIT 4
#define WM8990_LDBVOL_MASK 0x0007 /* LDBVOL - [2:0] */
#define WM8990_LDBVOL_SHIFT 0
/*
* R42 (0x2A) - Input Mixer4
*/
#define WM8990_R34MNB 0x0100 /* R34MNB */
#define WM8990_R34MNB_BIT 8
#define WM8990_R34MNBST 0x0080 /* R34MNBST */
#define WM8990_R34MNBST_BIT 7
#define WM8990_R12MNB 0x0020 /* R12MNB */
#define WM8990_R12MNB_BIT 5
#define WM8990_R12MNBST 0x0010 /* R12MNBST */
#define WM8990_R12MNBST_BIT 4
#define WM8990_RDBVOL_MASK 0x0007 /* RDBVOL - [2:0] */
#define WM8990_RDBVOL_SHIFT 0
/*
* R43 (0x2B) - Input Mixer5
*/
#define WM8990_LI2BVOL_MASK 0x07 /* LI2BVOL - [8:6] */
#define WM8990_LI2BVOL_SHIFT 6
#define WM8990_LR4BVOL_MASK 0x07 /* LR4BVOL - [5:3] */
#define WM8990_LR4BVOL_SHIFT 3
#define WM8990_LL4BVOL_MASK 0x07 /* LL4BVOL - [2:0] */
#define WM8990_LL4BVOL_SHIFT 0
/*
* R44 (0x2C) - Input Mixer6
*/
#define WM8990_RI2BVOL_MASK 0x07 /* RI2BVOL - [8:6] */
#define WM8990_RI2BVOL_SHIFT 6
#define WM8990_RL4BVOL_MASK 0x07 /* RL4BVOL - [5:3] */
#define WM8990_RL4BVOL_SHIFT 3
#define WM8990_RR4BVOL_MASK 0x07 /* RR4BVOL - [2:0] */
#define WM8990_RR4BVOL_SHIFT 0
/*
* R45 (0x2D) - Output Mixer1
*/
#define WM8990_LRBLO 0x0080 /* LRBLO */
#define WM8990_LRBLO_BIT 7
#define WM8990_LLBLO 0x0040 /* LLBLO */
#define WM8990_LLBLO_BIT 6
#define WM8990_LRI3LO 0x0020 /* LRI3LO */
#define WM8990_LRI3LO_BIT 5
#define WM8990_LLI3LO 0x0010 /* LLI3LO */
#define WM8990_LLI3LO_BIT 4
#define WM8990_LR12LO 0x0008 /* LR12LO */
#define WM8990_LR12LO_BIT 3
#define WM8990_LL12LO 0x0004 /* LL12LO */
#define WM8990_LL12LO_BIT 2
#define WM8990_LDLO 0x0001 /* LDLO */
#define WM8990_LDLO_BIT 0
/*
* R46 (0x2E) - Output Mixer2
*/
#define WM8990_RLBRO 0x0080 /* RLBRO */
#define WM8990_RLBRO_BIT 7
#define WM8990_RRBRO 0x0040 /* RRBRO */
#define WM8990_RRBRO_BIT 6
#define WM8990_RLI3RO 0x0020 /* RLI3RO */
#define WM8990_RLI3RO_BIT 5
#define WM8990_RRI3RO 0x0010 /* RRI3RO */
#define WM8990_RRI3RO_BIT 4
#define WM8990_RL12RO 0x0008 /* RL12RO */
#define WM8990_RL12RO_BIT 3
#define WM8990_RR12RO 0x0004 /* RR12RO */
#define WM8990_RR12RO_BIT 2
#define WM8990_RDRO 0x0001 /* RDRO */
#define WM8990_RDRO_BIT 0
/*
* R47 (0x2F) - Output Mixer3
*/
#define WM8990_LLI3LOVOL_MASK 0x07 /* LLI3LOVOL - [8:6] */
#define WM8990_LLI3LOVOL_SHIFT 6
#define WM8990_LR12LOVOL_MASK 0x07 /* LR12LOVOL - [5:3] */
#define WM8990_LR12LOVOL_SHIFT 3
#define WM8990_LL12LOVOL_MASK 0x07 /* LL12LOVOL - [2:0] */
#define WM8990_LL12LOVOL_SHIFT 0
/*
* R48 (0x30) - Output Mixer4
*/
#define WM8990_RRI3ROVOL_MASK 0x07 /* RRI3ROVOL - [8:6] */
#define WM8990_RRI3ROVOL_SHIFT 6
#define WM8990_RL12ROVOL_MASK 0x07 /* RL12ROVOL - [5:3] */
#define WM8990_RL12ROVOL_SHIFT 3
#define WM8990_RR12ROVOL_MASK 0x07 /* RR12ROVOL - [2:0] */
#define WM8990_RR12ROVOL_SHIFT 0
/*
* R49 (0x31) - Output Mixer5
*/
#define WM8990_LRI3LOVOL_MASK 0x07 /* LRI3LOVOL - [8:6] */
#define WM8990_LRI3LOVOL_SHIFT 6
#define WM8990_LRBLOVOL_MASK 0x07 /* LRBLOVOL - [5:3] */
#define WM8990_LRBLOVOL_SHIFT 3
#define WM8990_LLBLOVOL_MASK 0x07 /* LLBLOVOL - [2:0] */
#define WM8990_LLBLOVOL_SHIFT 0
/*
* R50 (0x32) - Output Mixer6
*/
#define WM8990_RLI3ROVOL_MASK 0x07 /* RLI3ROVOL - [8:6] */
#define WM8990_RLI3ROVOL_SHIFT 6
#define WM8990_RLBROVOL_MASK 0x07 /* RLBROVOL - [5:3] */
#define WM8990_RLBROVOL_SHIFT 3
#define WM8990_RRBROVOL_MASK 0x07 /* RRBROVOL - [2:0] */
#define WM8990_RRBROVOL_SHIFT 0
/*
* R51 (0x33) - Out3/4 Mixer
*/
#define WM8990_VSEL_MASK 0x0180 /* VSEL - [8:7] */
#define WM8990_LI4O3 0x0020 /* LI4O3 */
#define WM8990_LI4O3_BIT 5
#define WM8990_LPGAO3 0x0010 /* LPGAO3 */
#define WM8990_LPGAO3_BIT 4
#define WM8990_RI4O4 0x0002 /* RI4O4 */
#define WM8990_RI4O4_BIT 1
#define WM8990_RPGAO4 0x0001 /* RPGAO4 */
#define WM8990_RPGAO4_BIT 0
/*
* R52 (0x34) - Line Mixer1
*/
#define WM8990_LLOPGALON 0x0040 /* LLOPGALON */
#define WM8990_LLOPGALON_BIT 6
#define WM8990_LROPGALON 0x0020 /* LROPGALON */
#define WM8990_LROPGALON_BIT 5
#define WM8990_LOPLON 0x0010 /* LOPLON */
#define WM8990_LOPLON_BIT 4
#define WM8990_LR12LOP 0x0004 /* LR12LOP */
#define WM8990_LR12LOP_BIT 2
#define WM8990_LL12LOP 0x0002 /* LL12LOP */
#define WM8990_LL12LOP_BIT 1
#define WM8990_LLOPGALOP 0x0001 /* LLOPGALOP */
#define WM8990_LLOPGALOP_BIT 0
/*
* R53 (0x35) - Line Mixer2
*/
#define WM8990_RROPGARON 0x0040 /* RROPGARON */
#define WM8990_RROPGARON_BIT 6
#define WM8990_RLOPGARON 0x0020 /* RLOPGARON */
#define WM8990_RLOPGARON_BIT 5
#define WM8990_ROPRON 0x0010 /* ROPRON */
#define WM8990_ROPRON_BIT 4
#define WM8990_RL12ROP 0x0004 /* RL12ROP */
#define WM8990_RL12ROP_BIT 2
#define WM8990_RR12ROP 0x0002 /* RR12ROP */
#define WM8990_RR12ROP_BIT 1
#define WM8990_RROPGAROP 0x0001 /* RROPGAROP */
#define WM8990_RROPGAROP_BIT 0
/*
* R54 (0x36) - Speaker Mixer
*/
#define WM8990_LB2SPK 0x0080 /* LB2SPK */
#define WM8990_LB2SPK_BIT 7
#define WM8990_RB2SPK 0x0040 /* RB2SPK */
#define WM8990_RB2SPK_BIT 6
#define WM8990_LI2SPK 0x0020 /* LI2SPK */
#define WM8990_LI2SPK_BIT 5
#define WM8990_RI2SPK 0x0010 /* RI2SPK */
#define WM8990_RI2SPK_BIT 4
#define WM8990_LOPGASPK 0x0008 /* LOPGASPK */
#define WM8990_LOPGASPK_BIT 3
#define WM8990_ROPGASPK 0x0004 /* ROPGASPK */
#define WM8990_ROPGASPK_BIT 2
#define WM8990_LDSPK 0x0002 /* LDSPK */
#define WM8990_LDSPK_BIT 1
#define WM8990_RDSPK 0x0001 /* RDSPK */
#define WM8990_RDSPK_BIT 0
/*
* R55 (0x37) - Additional Control
*/
#define WM8990_VROI 0x0001 /* VROI */
/*
* R56 (0x38) - AntiPOP1
*/
#define WM8990_DIS_LLINE 0x0020 /* DIS_LLINE */
#define WM8990_DIS_RLINE 0x0010 /* DIS_RLINE */
#define WM8990_DIS_OUT3 0x0008 /* DIS_OUT3 */
#define WM8990_DIS_OUT4 0x0004 /* DIS_OUT4 */
#define WM8990_DIS_LOUT 0x0002 /* DIS_LOUT */
#define WM8990_DIS_ROUT 0x0001 /* DIS_ROUT */
/*
* R57 (0x39) - AntiPOP2
*/
#define WM8990_SOFTST 0x0040 /* SOFTST */
#define WM8990_BUFIOEN 0x0008 /* BUFIOEN */
#define WM8990_BUFDCOPEN 0x0004 /* BUFDCOPEN */
#define WM8990_POBCTRL 0x0002 /* POBCTRL */
#define WM8990_VMIDTOG 0x0001 /* VMIDTOG */
/*
* R58 (0x3A) - MICBIAS
*/
#define WM8990_MCDSCTH_MASK 0x00C0 /* MCDSCTH - [7:6] */
#define WM8990_MCDTHR_MASK 0x0038 /* MCDTHR - [5:3] */
#define WM8990_MCD 0x0004 /* MCD */
#define WM8990_MBSEL 0x0001 /* MBSEL */
/*
* R60 (0x3C) - PLL1
*/
#define WM8990_SDM 0x0080 /* SDM */
#define WM8990_PRESCALE 0x0040 /* PRESCALE */
#define WM8990_PLLN_MASK 0x000F /* PLLN - [3:0] */
/*
* R61 (0x3D) - PLL2
*/
#define WM8990_PLLK1_MASK 0x00FF /* PLLK1 - [7:0] */
/*
* R62 (0x3E) - PLL3
*/
#define WM8990_PLLK2_MASK 0x00FF /* PLLK2 - [7:0] */
/*
* R63 (0x3F) - Internal Driver Bits
*/
#define WM8990_INMIXL_PWR_BIT 0
#define WM8990_AINLMUX_PWR_BIT 1
#define WM8990_INMIXR_PWR_BIT 2
#define WM8990_AINRMUX_PWR_BIT 3
/*
* Default values.
*/
#define WM8990_REGISTER_DEFAULTS \
{ \
/*0x8990,*/ /* R0 - Reset */ \
0x0000, /* R1 - Power Management (1) */ \
0x6000, /* R2 - Power Management (2) */ \
0x0000, /* R3 - Power Management (3) */ \
0x4050, /* R4 - Audio Interface (1) */ \
0x4000, /* R5 - Audio Interface (2) */ \
0x01C8, /* R6 - Clocking (1) */ \
0x0000, /* R7 - Clocking (2) */ \
0x0040, /* R8 - Audio Interface (3) */ \
0x0040, /* R9 - Audio Interface (4) */ \
0x0004, /* R10 - DAC CTRL */ \
0x00C0, /* R11 - Left DAC Digital Volume */ \
0x00C0, /* R12 - Right DAC Digital Volume */ \
0x0000, /* R13 - Digital Side Tone */ \
0x0100, /* R14 - ADC CTRL */ \
0x00C0, /* R15 - Left ADC Digital Volume */ \
0x00C0, /* R16 - Right ADC Digital Volume */ \
0x0000, /* R17 */ \
0x0000, /* R18 - GPIO CTRL 1 */ \
0x1000, /* R19 - GPIO1 & GPIO2 */ \
0x1010, /* R20 - GPIO3 & GPIO4 */ \
0x1010, /* R21 - GPIO5 & GPIO6 */ \
0x8000, /* R22 - GPIOCTRL 2 */ \
0x0800, /* R23 - GPIO_POL */ \
0x008B, /* R24 - Left Line Input 1&2 Volume */ \
0x008B, /* R25 - Left Line Input 3&4 Volume */ \
0x008B, /* R26 - Right Line Input 1&2 Volume */ \
0x008B, /* R27 - Right Line Input 3&4 Volume */ \
0x0000, /* R28 - Left Output Volume */ \
0x0000, /* R29 - Right Output Volume */ \
0x0066, /* R30 - Line Outputs Volume */ \
0x0022, /* R31 - Out3/4 Volume */ \
0x0079, /* R32 - Left OPGA Volume */ \
0x0079, /* R33 - Right OPGA Volume */ \
0x0003, /* R34 - Speaker Volume */ \
0x0003, /* R35 - ClassD1 */ \
0x0000, /* R36 */ \
0x0100, /* R37 - ClassD3 */ \
0x0000, /* R38 */ \
0x0000, /* R39 - Input Mixer1 */ \
0x0000, /* R40 - Input Mixer2 */ \
0x0000, /* R41 - Input Mixer3 */ \
0x0000, /* R42 - Input Mixer4 */ \
0x0000, /* R43 - Input Mixer5 */ \
0x0000, /* R44 - Input Mixer6 */ \
0x0000, /* R45 - Output Mixer1 */ \
0x0000, /* R46 - Output Mixer2 */ \
0x0000, /* R47 - Output Mixer3 */ \
0x0000, /* R48 - Output Mixer4 */ \
0x0000, /* R49 - Output Mixer5 */ \
0x0000, /* R50 - Output Mixer6 */ \
0x0180, /* R51 - Out3/4 Mixer */ \
0x0000, /* R52 - Line Mixer1 */ \
0x0000, /* R53 - Line Mixer2 */ \
0x0000, /* R54 - Speaker Mixer */ \
0x0000, /* R55 - Additional Control */ \
0x0000, /* R56 - AntiPOP1 */ \
0x0000, /* R57 - AntiPOP2 */ \
0x0000, /* R58 - MICBIAS */ \
0x0000, /* R59 */ \
0x0008, /* R60 - PLL1 */ \
0x0031, /* R61 - PLL2 */ \
0x0026, /* R62 - PLL3 */ \
}
struct wm8990_setup_data {
unsigned short i2c_address;
};
#define WM8990_MCLK_DIV 0
#define WM8990_DACCLK_DIV 1
#define WM8990_ADCCLK_DIV 2
#define WM8990_BCLK_DIV 3
#define WM8990_MCLK 0
extern struct snd_soc_codec_dai wm8990_dai;
extern struct snd_soc_codec_device soc_codec_dev_wm8990;
#endif /* __WM8990REGISTERDEFS_H__ */
/*------------------------------ END OF FILE ---------------------------------*/

772
sound/soc/codecs/wm9712.c Normal file
View File

@@ -0,0 +1,772 @@
/*
* wm9712.c -- ALSA Soc WM9712 codec support
*
* Copyright 2006 Wolfson Microelectronics PLC.
* Author: Liam Girdwood
* liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.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.
*
* Revision history
* 4th Feb 2006 Initial version.
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <sound/driver.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/ac97_codec.h>
#include <sound/initval.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#define WM9712_VERSION "0.4"
static unsigned int ac97_read(struct snd_soc_codec *codec,
unsigned int reg);
static int ac97_write(struct snd_soc_codec *codec,
unsigned int reg, unsigned int val);
/*
* WM9712 register cache
*/
static const u16 wm9712_reg[] = {
0x6174, 0x8000, 0x8000, 0x8000, // 6
0x0f0f, 0xaaa0, 0xc008, 0x6808, // e
0xe808, 0xaaa0, 0xad00, 0x8000, // 16
0xe808, 0x3000, 0x8000, 0x0000, // 1e
0x0000, 0x0000, 0x0000, 0x000f, // 26
0x0405, 0x0410, 0xbb80, 0xbb80, // 2e
0x0000, 0xbb80, 0x0000, 0x0000, // 36
0x0000, 0x2000, 0x0000, 0x0000, // 3e
0x0000, 0x0000, 0x0000, 0x0000, // 46
0x0000, 0x0000, 0xf83e, 0xffff, // 4e
0x0000, 0x0000, 0x0000, 0xf83e, // 56
0x0008, 0x0000, 0x0000, 0x0000, // 5e
0xb032, 0x3e00, 0x0000, 0x0000, // 66
0x0000, 0x0000, 0x0000, 0x0000, // 6e
0x0000, 0x0000, 0x0000, 0x0006, // 76
0x0001, 0x0000, 0x574d, 0x4c12, // 7e
0x0000, 0x0000 // virtual hp mixers
};
/* virtual HP mixers regs */
#define HPL_MIXER 0x80
#define HPR_MIXER 0x82
static const char *wm9712_alc_select[] = {"None", "Left", "Right", "Stereo"};
static const char *wm9712_alc_mux[] = {"Stereo", "Left", "Right", "None"};
static const char *wm9712_out3_src[] = {"Left", "VREF", "Left + Right",
"Mono"};
static const char *wm9712_spk_src[] = {"Speaker Mix", "Headphone Mix"};
static const char *wm9712_rec_adc[] = {"Stereo", "Left", "Right", "Mute"};
static const char *wm9712_base[] = {"Linear Control", "Adaptive Boost"};
static const char *wm9712_rec_gain[] = {"+1.5dB Steps", "+0.75dB Steps"};
static const char *wm9712_mic[] = {"Mic 1", "Differential", "Mic 2",
"Stereo"};
static const char *wm9712_rec_sel[] = {"Mic", "NC", "NC", "Speaker Mixer",
"Line", "Headphone Mixer", "Phone Mixer", "Phone"};
static const char *wm9712_ng_type[] = {"Constant Gain", "Mute"};
static const char *wm9712_diff_sel[] = {"Mic", "Line"};
static const struct soc_enum wm9712_enum[] = {
SOC_ENUM_SINGLE(AC97_PCI_SVID, 14, 4, wm9712_alc_select),
SOC_ENUM_SINGLE(AC97_VIDEO, 12, 4, wm9712_alc_mux),
SOC_ENUM_SINGLE(AC97_AUX, 9, 4, wm9712_out3_src),
SOC_ENUM_SINGLE(AC97_AUX, 8, 2, wm9712_spk_src),
SOC_ENUM_SINGLE(AC97_REC_SEL, 12, 4, wm9712_rec_adc),
SOC_ENUM_SINGLE(AC97_MASTER_TONE, 15, 2, wm9712_base),
SOC_ENUM_DOUBLE(AC97_REC_GAIN, 14, 6, 2, wm9712_rec_gain),
SOC_ENUM_SINGLE(AC97_MIC, 5, 4, wm9712_mic),
SOC_ENUM_SINGLE(AC97_REC_SEL, 8, 8, wm9712_rec_sel),
SOC_ENUM_SINGLE(AC97_REC_SEL, 0, 8, wm9712_rec_sel),
SOC_ENUM_SINGLE(AC97_PCI_SVID, 5, 2, wm9712_ng_type),
SOC_ENUM_SINGLE(0x5c, 8, 2, wm9712_diff_sel),
};
static const struct snd_kcontrol_new wm9712_snd_ac97_controls[] = {
SOC_DOUBLE("Speaker Playback Volume", AC97_MASTER, 8, 0, 31, 1),
SOC_SINGLE("Speaker Playback Switch", AC97_MASTER, 15, 1, 1),
SOC_DOUBLE("Headphone Playback Volume", AC97_HEADPHONE, 8, 0, 31, 1),
SOC_SINGLE("Headphone Playback Switch", AC97_HEADPHONE,15, 1, 1),
SOC_DOUBLE("PCM Playback Volume", AC97_PCM, 8, 0, 31, 1),
SOC_SINGLE("Speaker Playback ZC Switch", AC97_MASTER, 7, 1, 0),
SOC_SINGLE("Speaker Playback Invert Switch", AC97_MASTER, 6, 1, 0),
SOC_SINGLE("Headphone Playback ZC Switch", AC97_HEADPHONE, 7, 1, 0),
SOC_SINGLE("Mono Playback ZC Switch", AC97_MASTER_MONO, 7, 1, 0),
SOC_SINGLE("Mono Playback Volume", AC97_MASTER_MONO, 0, 31, 0),
SOC_SINGLE("ALC Target Volume", AC97_CODEC_CLASS_REV, 12, 15, 0),
SOC_SINGLE("ALC Hold Time", AC97_CODEC_CLASS_REV, 8, 15, 0),
SOC_SINGLE("ALC Decay Time", AC97_CODEC_CLASS_REV, 4, 15, 0),
SOC_SINGLE("ALC Attack Time", AC97_CODEC_CLASS_REV, 0, 15, 0),
SOC_ENUM("ALC Function", wm9712_enum[0]),
SOC_SINGLE("ALC Max Volume", AC97_PCI_SVID, 11, 7, 0),
SOC_SINGLE("ALC ZC Timeout", AC97_PCI_SVID, 9, 3, 1),
SOC_SINGLE("ALC ZC Switch", AC97_PCI_SVID, 8, 1, 0),
SOC_SINGLE("ALC NG Switch", AC97_PCI_SVID, 7, 1, 0),
SOC_ENUM("ALC NG Type", wm9712_enum[10]),
SOC_SINGLE("ALC NG Threshold", AC97_PCI_SVID, 0, 31, 1),
SOC_SINGLE("Mic Headphone Volume", AC97_VIDEO, 12, 7, 1),
SOC_SINGLE("ALC Headphone Volume", AC97_VIDEO, 7, 7, 1),
SOC_SINGLE("Out3 Switch", AC97_AUX, 15, 1, 1),
SOC_SINGLE("Out3 ZC Switch", AC97_AUX, 7, 1, 1),
SOC_SINGLE("Out3 Volume", AC97_AUX, 0, 31, 1),
SOC_SINGLE("PCBeep Bypass Headphone Volume", AC97_PC_BEEP, 12, 7, 1),
SOC_SINGLE("PCBeep Bypass Speaker Volume", AC97_PC_BEEP, 8, 7, 1),
SOC_SINGLE("PCBeep Bypass Phone Volume", AC97_PC_BEEP, 4, 7, 1),
SOC_SINGLE("Aux Playback Headphone Volume", AC97_CD, 12, 7, 1),
SOC_SINGLE("Aux Playback Speaker Volume", AC97_CD, 8, 7, 1),
SOC_SINGLE("Aux Playback Phone Volume", AC97_CD, 4, 7, 1),
SOC_SINGLE("Phone Volume", AC97_PHONE, 0, 15, 0),
SOC_DOUBLE("Line Capture Volume", AC97_LINE, 8, 0, 31, 1),
SOC_SINGLE("Capture 20dB Boost Switch", AC97_REC_SEL, 14, 1, 0),
SOC_SINGLE("Capture to Phone 20dB Boost Switch", AC97_REC_SEL, 11, 1, 1),
SOC_SINGLE("3D Upper Cut-off Switch", AC97_3D_CONTROL, 5, 1, 1),
SOC_SINGLE("3D Lower Cut-off Switch", AC97_3D_CONTROL, 4, 1, 1),
SOC_SINGLE("3D Playback Volume", AC97_3D_CONTROL, 0, 15, 0),
SOC_ENUM("Bass Control", wm9712_enum[5]),
SOC_SINGLE("Bass Cut-off Switch", AC97_MASTER_TONE, 12, 1, 1),
SOC_SINGLE("Tone Cut-off Switch", AC97_MASTER_TONE, 4, 1, 1),
SOC_SINGLE("Playback Attenuate (-6dB) Switch", AC97_MASTER_TONE, 6, 1, 0),
SOC_SINGLE("Bass Volume", AC97_MASTER_TONE, 8, 15, 0),
SOC_SINGLE("Treble Volume", AC97_MASTER_TONE, 0, 15, 0),
SOC_SINGLE("Capture ADC Switch", AC97_REC_GAIN, 15, 1, 1),
SOC_ENUM("Capture Volume Steps", wm9712_enum[6]),
SOC_DOUBLE("Capture Volume", AC97_REC_GAIN, 8, 0, 63, 1),
SOC_SINGLE("Capture ZC Switch", AC97_REC_GAIN, 7, 1, 0),
SOC_SINGLE("Mic 1 Volume", AC97_MIC, 8, 31, 1),
SOC_SINGLE("Mic 2 Volume", AC97_MIC, 0, 31, 1),
SOC_SINGLE("Mic 20dB Boost Switch", AC97_MIC, 7, 1, 0),
};
/* add non dapm controls */
static int wm9712_add_controls(struct snd_soc_codec *codec)
{
int err, i;
for (i = 0; i < ARRAY_SIZE(wm9712_snd_ac97_controls); i++) {
err = snd_ctl_add(codec->card,
snd_soc_cnew(&wm9712_snd_ac97_controls[i],codec, NULL));
if (err < 0)
return err;
}
return 0;
}
/* We have to create a fake left and right HP mixers because
* the codec only has a single control that is shared by both channels.
* This makes it impossible to determine the audio path.
*/
static int mixer_event (struct snd_soc_dapm_widget *w, int event)
{
u16 l, r, beep, line, phone, mic, pcm, aux;
l = ac97_read(w->codec, HPL_MIXER);
r = ac97_read(w->codec, HPR_MIXER);
beep = ac97_read(w->codec, AC97_PC_BEEP);
mic = ac97_read(w->codec, AC97_VIDEO);
phone = ac97_read(w->codec, AC97_PHONE);
line = ac97_read(w->codec, AC97_LINE);
pcm = ac97_read(w->codec, AC97_PCM);
aux = ac97_read(w->codec, AC97_CD);
if (l & 0x1 || r & 0x1)
ac97_write(w->codec, AC97_VIDEO, mic & 0x7fff);
else
ac97_write(w->codec, AC97_VIDEO, mic | 0x8000);
if (l & 0x2 || r & 0x2)
ac97_write(w->codec, AC97_PCM, pcm & 0x7fff);
else
ac97_write(w->codec, AC97_PCM, pcm | 0x8000);
if (l & 0x4 || r & 0x4)
ac97_write(w->codec, AC97_LINE, line & 0x7fff);
else
ac97_write(w->codec, AC97_LINE, line | 0x8000);
if (l & 0x8 || r & 0x8)
ac97_write(w->codec, AC97_PHONE, phone & 0x7fff);
else
ac97_write(w->codec, AC97_PHONE, phone | 0x8000);
if (l & 0x10 || r & 0x10)
ac97_write(w->codec, AC97_CD, aux & 0x7fff);
else
ac97_write(w->codec, AC97_CD, aux | 0x8000);
if (l & 0x20 || r & 0x20)
ac97_write(w->codec, AC97_PC_BEEP, beep & 0x7fff);
else
ac97_write(w->codec, AC97_PC_BEEP, beep | 0x8000);
return 0;
}
/* Left Headphone Mixers */
static const struct snd_kcontrol_new wm9712_hpl_mixer_controls[] = {
SOC_DAPM_SINGLE("PCBeep Bypass Switch", HPL_MIXER, 5, 1, 0),
SOC_DAPM_SINGLE("Aux Playback Switch", HPL_MIXER, 4, 1, 0),
SOC_DAPM_SINGLE("Phone Bypass Switch", HPL_MIXER, 3, 1, 0),
SOC_DAPM_SINGLE("Line Bypass Switch", HPL_MIXER, 2, 1, 0),
SOC_DAPM_SINGLE("PCM Playback Switch", HPL_MIXER, 1, 1, 0),
SOC_DAPM_SINGLE("Mic Sidetone Switch", HPL_MIXER, 0, 1, 0),
};
/* Right Headphone Mixers */
static const struct snd_kcontrol_new wm9712_hpr_mixer_controls[] = {
SOC_DAPM_SINGLE("PCBeep Bypass Switch", HPR_MIXER, 5, 1, 0),
SOC_DAPM_SINGLE("Aux Playback Switch", HPR_MIXER, 4, 1, 0),
SOC_DAPM_SINGLE("Phone Bypass Switch", HPR_MIXER, 3, 1, 0),
SOC_DAPM_SINGLE("Line Bypass Switch", HPR_MIXER, 2, 1, 0),
SOC_DAPM_SINGLE("PCM Playback Switch", HPR_MIXER, 1, 1, 0),
SOC_DAPM_SINGLE("Mic Sidetone Switch", HPR_MIXER, 0, 1, 0),
};
/* Speaker Mixer */
static const struct snd_kcontrol_new wm9712_speaker_mixer_controls[] = {
SOC_DAPM_SINGLE("PCBeep Bypass Switch", AC97_PC_BEEP, 11, 1, 1),
SOC_DAPM_SINGLE("Aux Playback Switch", AC97_CD, 11, 1, 1),
SOC_DAPM_SINGLE("Phone Bypass Switch", AC97_PHONE, 14, 1, 1),
SOC_DAPM_SINGLE("Line Bypass Switch", AC97_LINE, 14, 1, 1),
SOC_DAPM_SINGLE("PCM Playback Switch", AC97_PCM, 14, 1, 1),
};
/* Phone Mixer */
static const struct snd_kcontrol_new wm9712_phone_mixer_controls[] = {
SOC_DAPM_SINGLE("PCBeep Bypass Switch", AC97_PC_BEEP, 7, 1, 1),
SOC_DAPM_SINGLE("Aux Playback Switch", AC97_CD, 7, 1, 1),
SOC_DAPM_SINGLE("Line Bypass Switch", AC97_LINE, 13, 1, 1),
SOC_DAPM_SINGLE("PCM Playback Switch", AC97_PCM, 13, 1, 1),
SOC_DAPM_SINGLE("Mic 1 Sidetone Switch", AC97_MIC, 14, 1, 1),
SOC_DAPM_SINGLE("Mic 2 Sidetone Switch", AC97_MIC, 13, 1, 1),
};
/* ALC headphone mux */
static const struct snd_kcontrol_new wm9712_alc_mux_controls =
SOC_DAPM_ENUM("Route", wm9712_enum[1]);
/* out 3 mux */
static const struct snd_kcontrol_new wm9712_out3_mux_controls =
SOC_DAPM_ENUM("Route", wm9712_enum[2]);
/* spk mux */
static const struct snd_kcontrol_new wm9712_spk_mux_controls =
SOC_DAPM_ENUM("Route", wm9712_enum[3]);
/* Capture to Phone mux */
static const struct snd_kcontrol_new wm9712_capture_phone_mux_controls =
SOC_DAPM_ENUM("Route", wm9712_enum[4]);
/* Capture left select */
static const struct snd_kcontrol_new wm9712_capture_selectl_controls =
SOC_DAPM_ENUM("Route", wm9712_enum[8]);
/* Capture right select */
static const struct snd_kcontrol_new wm9712_capture_selectr_controls =
SOC_DAPM_ENUM("Route", wm9712_enum[9]);
/* Mic select */
static const struct snd_kcontrol_new wm9712_mic_src_controls =
SOC_DAPM_ENUM("Route", wm9712_enum[7]);
/* diff select */
static const struct snd_kcontrol_new wm9712_diff_sel_controls =
SOC_DAPM_ENUM("Route", wm9712_enum[11]);
static const struct snd_soc_dapm_widget wm9712_dapm_widgets[] = {
SND_SOC_DAPM_MUX("ALC Sidetone Mux", SND_SOC_NOPM, 0, 0,
&wm9712_alc_mux_controls),
SND_SOC_DAPM_MUX("Out3 Mux", SND_SOC_NOPM, 0, 0,
&wm9712_out3_mux_controls),
SND_SOC_DAPM_MUX("Speaker Mux", SND_SOC_NOPM, 0, 0,
&wm9712_spk_mux_controls),
SND_SOC_DAPM_MUX("Capture Phone Mux", SND_SOC_NOPM, 0, 0,
&wm9712_capture_phone_mux_controls),
SND_SOC_DAPM_MUX("Left Capture Select", SND_SOC_NOPM, 0, 0,
&wm9712_capture_selectl_controls),
SND_SOC_DAPM_MUX("Right Capture Select", SND_SOC_NOPM, 0, 0,
&wm9712_capture_selectr_controls),
SND_SOC_DAPM_MUX("Mic Select Source", SND_SOC_NOPM, 0, 0,
&wm9712_mic_src_controls),
SND_SOC_DAPM_MUX("Differential Source", SND_SOC_NOPM, 0, 0,
&wm9712_diff_sel_controls),
SND_SOC_DAPM_MIXER("AC97 Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_MIXER_E("Left HP Mixer", AC97_INT_PAGING, 9, 1,
&wm9712_hpl_mixer_controls[0], ARRAY_SIZE(wm9712_hpl_mixer_controls),
mixer_event, SND_SOC_DAPM_POST_REG),
SND_SOC_DAPM_MIXER_E("Right HP Mixer", AC97_INT_PAGING, 8, 1,
&wm9712_hpr_mixer_controls[0], ARRAY_SIZE(wm9712_hpr_mixer_controls),
mixer_event, SND_SOC_DAPM_POST_REG),
SND_SOC_DAPM_MIXER("Phone Mixer", AC97_INT_PAGING, 6, 1,
&wm9712_phone_mixer_controls[0], ARRAY_SIZE(wm9712_phone_mixer_controls)),
SND_SOC_DAPM_MIXER("Speaker Mixer", AC97_INT_PAGING, 7, 1,
&wm9712_speaker_mixer_controls[0],
ARRAY_SIZE(wm9712_speaker_mixer_controls)),
SND_SOC_DAPM_MIXER("Mono Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_DAC("Left DAC", "Left HiFi Playback", AC97_INT_PAGING, 14, 1),
SND_SOC_DAPM_DAC("Right DAC", "Right HiFi Playback", AC97_INT_PAGING, 13, 1),
SND_SOC_DAPM_DAC("Aux DAC", "Aux Playback", SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_ADC("Left ADC", "Left HiFi Capture", AC97_INT_PAGING, 12, 1),
SND_SOC_DAPM_ADC("Right ADC", "Right HiFi Capture", AC97_INT_PAGING, 11, 1),
SND_SOC_DAPM_PGA("Headphone PGA", AC97_INT_PAGING, 4, 1, NULL, 0),
SND_SOC_DAPM_PGA("Speaker PGA", AC97_INT_PAGING, 3, 1, NULL, 0),
SND_SOC_DAPM_PGA("Out 3 PGA", AC97_INT_PAGING, 5, 1, NULL, 0),
SND_SOC_DAPM_PGA("Line PGA", AC97_INT_PAGING, 2, 1, NULL, 0),
SND_SOC_DAPM_PGA("Phone PGA", AC97_INT_PAGING, 1, 1, NULL, 0),
SND_SOC_DAPM_PGA("Mic PGA", AC97_INT_PAGING, 0, 1, NULL, 0),
SND_SOC_DAPM_MICBIAS("Mic Bias", AC97_INT_PAGING, 10, 1),
SND_SOC_DAPM_OUTPUT("MONOOUT"),
SND_SOC_DAPM_OUTPUT("HPOUTL"),
SND_SOC_DAPM_OUTPUT("HPOUTR"),
SND_SOC_DAPM_OUTPUT("LOUT2"),
SND_SOC_DAPM_OUTPUT("ROUT2"),
SND_SOC_DAPM_OUTPUT("OUT3"),
SND_SOC_DAPM_INPUT("LINEINL"),
SND_SOC_DAPM_INPUT("LINEINR"),
SND_SOC_DAPM_INPUT("PHONE"),
SND_SOC_DAPM_INPUT("PCBEEP"),
SND_SOC_DAPM_INPUT("MIC1"),
SND_SOC_DAPM_INPUT("MIC2"),
};
static const char *audio_map[][3] = {
/* virtual mixer - mixes left & right channels for spk and mono */
{"AC97 Mixer", NULL, "Left DAC"},
{"AC97 Mixer", NULL, "Right DAC"},
/* Left HP mixer */
{"Left HP Mixer", "PCBeep Bypass Switch", "PCBEEP"},
{"Left HP Mixer", "Aux Playback Switch", "Aux DAC"},
{"Left HP Mixer", "Phone Bypass Switch", "Phone PGA"},
{"Left HP Mixer", "Line Bypass Switch", "Line PGA"},
{"Left HP Mixer", "PCM Playback Switch", "Left DAC"},
{"Left HP Mixer", "Mic Sidetone Switch", "Mic PGA"},
{"Left HP Mixer", NULL, "ALC Sidetone Mux"},
//{"Right HP Mixer", NULL, "HP Mixer"},
/* Right HP mixer */
{"Right HP Mixer", "PCBeep Bypass Switch", "PCBEEP"},
{"Right HP Mixer", "Aux Playback Switch", "Aux DAC"},
{"Right HP Mixer", "Phone Bypass Switch", "Phone PGA"},
{"Right HP Mixer", "Line Bypass Switch", "Line PGA"},
{"Right HP Mixer", "PCM Playback Switch", "Right DAC"},
{"Right HP Mixer", "Mic Sidetone Switch", "Mic PGA"},
{"Right HP Mixer", NULL, "ALC Sidetone Mux"},
/* speaker mixer */
{"Speaker Mixer", "PCBeep Bypass Switch", "PCBEEP"},
{"Speaker Mixer", "Line Bypass Switch", "Line PGA"},
{"Speaker Mixer", "PCM Playback Switch", "AC97 Mixer"},
{"Speaker Mixer", "Phone Bypass Switch", "Phone PGA"},
{"Speaker Mixer", "Aux Playback Switch", "Aux DAC"},
/* Phone mixer */
{"Phone Mixer", "PCBeep Bypass Switch", "PCBEEP"},
{"Phone Mixer", "Line Bypass Switch", "Line PGA"},
{"Phone Mixer", "Aux Playback Switch", "Aux DAC"},
{"Phone Mixer", "PCM Playback Switch", "AC97 Mixer"},
{"Phone Mixer", "Mic 1 Sidetone Switch", "Mic PGA"},
{"Phone Mixer", "Mic 2 Sidetone Switch", "Mic PGA"},
/* inputs */
{"Line PGA", NULL, "LINEINL"},
{"Line PGA", NULL, "LINEINR"},
{"Phone PGA", NULL, "PHONE"},
{"Mic PGA", NULL, "MIC1"},
{"Mic PGA", NULL, "MIC2"},
/* left capture selector */
{"Left Capture Select", "Mic", "MIC1"},
{"Left Capture Select", "Speaker Mixer", "Speaker Mixer"},
{"Left Capture Select", "Line", "LINEINL"},
{"Left Capture Select", "Headphone Mixer", "Left HP Mixer"},
{"Left Capture Select", "Phone Mixer", "Phone Mixer"},
{"Left Capture Select", "Phone", "PHONE"},
/* right capture selector */
{"Right Capture Select", "Mic", "MIC2"},
{"Right Capture Select", "Speaker Mixer", "Speaker Mixer"},
{"Right Capture Select", "Line", "LINEINR"},
{"Right Capture Select", "Headphone Mixer", "Right HP Mixer"},
{"Right Capture Select", "Phone Mixer", "Phone Mixer"},
{"Right Capture Select", "Phone", "PHONE"},
/* ALC Sidetone */
{"ALC Sidetone Mux", "Stereo", "Left Capture Select"},
{"ALC Sidetone Mux", "Stereo", "Right Capture Select"},
{"ALC Sidetone Mux", "Left", "Left Capture Select"},
{"ALC Sidetone Mux", "Right", "Right Capture Select"},
/* ADC's */
{"Left ADC", NULL, "Left Capture Select"},
{"Right ADC", NULL, "Right Capture Select"},
/* outputs */
{"MONOOUT", NULL, "Phone Mixer"},
{"HPOUTL", NULL, "Headphone PGA"},
{"Headphone PGA", NULL, "Left HP Mixer"},
{"HPOUTR", NULL, "Headphone PGA"},
{"Headphone PGA", NULL, "Right HP Mixer"},
/* mono hp mixer */
{"Mono HP Mixer", NULL, "Left HP Mixer"},
{"Mono HP Mixer", NULL, "Right HP Mixer"},
/* Out3 Mux */
{"Out3 Mux", "Left", "Left HP Mixer"},
{"Out3 Mux", "Mono", "Phone Mixer"},
{"Out3 Mux", "Left + Right", "Mono HP Mixer"},
{"Out 3 PGA", NULL, "Out3 Mux"},
{"OUT3", NULL, "Out 3 PGA"},
/* speaker Mux */
{"Speaker Mux", "Speaker Mix", "Speaker Mixer"},
{"Speaker Mux", "Headphone Mix", "Mono HP Mixer"},
{"Speaker PGA", NULL, "Speaker Mux"},
{"LOUT2", NULL, "Speaker PGA"},
{"ROUT2", NULL, "Speaker PGA"},
{NULL, NULL, NULL},
};
static int wm9712_add_widgets(struct snd_soc_codec *codec)
{
int i;
for(i = 0; i < ARRAY_SIZE(wm9712_dapm_widgets); i++) {
snd_soc_dapm_new_control(codec, &wm9712_dapm_widgets[i]);
}
/* set up audio path audio_mapnects */
for(i = 0; audio_map[i][0] != NULL; i++) {
snd_soc_dapm_connect_input(codec, audio_map[i][0],
audio_map[i][1], audio_map[i][2]);
}
snd_soc_dapm_new_widgets(codec);
return 0;
}
static unsigned int ac97_read(struct snd_soc_codec *codec,
unsigned int reg)
{
u16 *cache = codec->reg_cache;
if (reg == AC97_RESET || reg == AC97_GPIO_STATUS ||
reg == AC97_VENDOR_ID1 || reg == AC97_VENDOR_ID2 ||
reg == AC97_REC_GAIN)
return soc_ac97_ops.read(codec->ac97, reg);
else {
reg = reg >> 1;
if (reg > (ARRAY_SIZE(wm9712_reg)))
return -EIO;
return cache[reg];
}
}
static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int val)
{
u16 *cache = codec->reg_cache;
soc_ac97_ops.write(codec->ac97, reg, val);
reg = reg >> 1;
if (reg <= (ARRAY_SIZE(wm9712_reg)))
cache[reg] = val;
return 0;
}
static int ac97_prepare(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
struct snd_soc_codec *codec = socdev->codec;
int reg;
u16 vra;
vra = ac97_read(codec, AC97_EXTENDED_STATUS);
ac97_write(codec, AC97_EXTENDED_STATUS, vra | 0x1);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
reg = AC97_PCM_FRONT_DAC_RATE;
else
reg = AC97_PCM_LR_ADC_RATE;
return ac97_write(codec, reg, runtime->rate);
}
static int ac97_aux_prepare(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
struct snd_soc_codec *codec = socdev->codec;
u16 vra, xsle;
vra = ac97_read(codec, AC97_EXTENDED_STATUS);
ac97_write(codec, AC97_EXTENDED_STATUS, vra | 0x1);
xsle = ac97_read(codec, AC97_PCI_SID);
ac97_write(codec, AC97_PCI_SID, xsle | 0x8000);
if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
return -ENODEV;
return ac97_write(codec, AC97_PCM_SURR_DAC_RATE, runtime->rate);
}
#define WM9712_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
struct snd_soc_codec_dai wm9712_dai[] = {
{
.name = "AC97 HiFi",
.type = SND_SOC_DAI_AC97_BUS,
.playback = {
.stream_name = "HiFi Playback",
.channels_min = 1,
.channels_max = 2,
.rates = WM9712_AC97_RATES,
.formats = SNDRV_PCM_FMTBIT_S16_LE,},
.capture = {
.stream_name = "HiFi Capture",
.channels_min = 1,
.channels_max = 2,
.rates = WM9712_AC97_RATES,
.formats = SNDRV_PCM_FMTBIT_S16_LE,},
.ops = {
.prepare = ac97_prepare,},
},
{
.name = "AC97 Aux",
.playback = {
.stream_name = "Aux Playback",
.channels_min = 1,
.channels_max = 1,
.rates = WM9712_AC97_RATES,
.formats = SNDRV_PCM_FMTBIT_S16_LE,},
.ops = {
.prepare = ac97_aux_prepare,},
}
};
EXPORT_SYMBOL_GPL(wm9712_dai);
static int wm9712_dapm_event(struct snd_soc_codec *codec, int event)
{
u16 reg;
switch (event) {
case SNDRV_CTL_POWER_D0: /* full On */
/* liam - maybe enable thermal shutdown */
reg = ac97_read(codec, AC97_EXTENDED_MID) & 0xdfff;
ac97_write(codec, AC97_EXTENDED_MID, reg);
break;
case SNDRV_CTL_POWER_D1: /* partial On */
case SNDRV_CTL_POWER_D2: /* partial On */
break;
case SNDRV_CTL_POWER_D3hot: /* Off, with power */
/* enable master bias and vmid */
reg = ac97_read(codec, AC97_EXTENDED_MID) & 0xbbff;
ac97_write(codec, AC97_EXTENDED_MID, reg);
ac97_write(codec, AC97_POWERDOWN, 0x0000);
break;
case SNDRV_CTL_POWER_D3cold: /* Off, without power */
/* disable everything including AC link */
ac97_write(codec, AC97_EXTENDED_MID, 0xffff);
ac97_write(codec, AC97_EXTENDED_MSTATUS, 0xffff);
ac97_write(codec, AC97_POWERDOWN, 0xffff);
break;
}
codec->dapm_state = event;
return 0;
}
static int wm9712_reset(struct snd_soc_codec *codec, int try_warm)
{
if (try_warm && soc_ac97_ops.warm_reset) {
soc_ac97_ops.warm_reset(codec->ac97);
if (!(ac97_read(codec, 0) & 0x8000))
return 1;
}
soc_ac97_ops.reset(codec->ac97);
if (ac97_read(codec, 0) & 0x8000)
goto err;
return 0;
err:
printk(KERN_ERR "WM9712 AC97 reset failed\n");
return -EIO;
}
static int wm9712_soc_suspend(struct platform_device *pdev,
pm_message_t state)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
struct snd_soc_codec *codec = socdev->codec;
wm9712_dapm_event(codec, SNDRV_CTL_POWER_D3cold);
return 0;
}
static int wm9712_soc_resume(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
struct snd_soc_codec *codec = socdev->codec;
int i, ret;
u16 *cache = codec->reg_cache;
ret = wm9712_reset(codec, 1);
if (ret < 0){
printk(KERN_ERR "could not reset AC97 codec\n");
return ret;
}
wm9712_dapm_event(codec, SNDRV_CTL_POWER_D3hot);
if (ret == 0) {
/* Sync reg_cache with the hardware after cold reset */
for (i = 2; i < ARRAY_SIZE(wm9712_reg) << 1; i+=2) {
if (i == AC97_INT_PAGING || i == AC97_POWERDOWN ||
(i > 0x58 && i != 0x5c))
continue;
soc_ac97_ops.write(codec->ac97, i, cache[i>>1]);
}
}
if (codec->suspend_dapm_state == SNDRV_CTL_POWER_D0)
wm9712_dapm_event(codec, SNDRV_CTL_POWER_D0);
return ret;
}
static int wm9712_soc_probe(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
struct snd_soc_codec *codec;
int ret = 0;
printk(KERN_INFO "WM9711/WM9712 SoC Audio Codec %s\n", WM9712_VERSION);
socdev->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
if (socdev->codec == NULL)
return -ENOMEM;
codec = socdev->codec;
mutex_init(&codec->mutex);
codec->reg_cache = kmemdup(wm9712_reg, sizeof(wm9712_reg), GFP_KERNEL);
if (codec->reg_cache == NULL) {
ret = -ENOMEM;
goto cache_err;
}
codec->reg_cache_size = sizeof(wm9712_reg);
codec->reg_cache_step = 2;
codec->name = "WM9712";
codec->owner = THIS_MODULE;
codec->dai = wm9712_dai;
codec->num_dai = ARRAY_SIZE(wm9712_dai);
codec->write = ac97_write;
codec->read = ac97_read;
codec->dapm_event = wm9712_dapm_event;
INIT_LIST_HEAD(&codec->dapm_widgets);
INIT_LIST_HEAD(&codec->dapm_paths);
ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
if (ret < 0) {
printk(KERN_ERR "wm9712: failed to register AC97 codec\n");
goto codec_err;
}
/* register pcms */
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
if (ret < 0)
goto pcm_err;
ret = wm9712_reset(codec, 0);
if (ret < 0) {
printk(KERN_ERR "AC97 link error\n");
goto reset_err;
}
/* set alc mux to none */
ac97_write(codec, AC97_VIDEO, ac97_read(codec, AC97_VIDEO) | 0x3000);
wm9712_dapm_event(codec, SNDRV_CTL_POWER_D3hot);
wm9712_add_controls(codec);
wm9712_add_widgets(codec);
ret = snd_soc_register_card(socdev);
if (ret < 0) {
printk(KERN_ERR "wm9712: failed to register card\n");
goto reset_err;
}
return 0;
reset_err:
snd_soc_free_pcms(socdev);
pcm_err:
snd_soc_free_ac97_codec(codec);
codec_err:
kfree(codec->reg_cache);
cache_err:
kfree(socdev->codec);
socdev->codec = NULL;
return ret;
}
static int wm9712_soc_remove(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
struct snd_soc_codec *codec = socdev->codec;
if (codec == NULL)
return 0;
snd_soc_dapm_free(socdev);
snd_soc_free_pcms(socdev);
snd_soc_free_ac97_codec(codec);
kfree(codec->reg_cache);
kfree(codec);
return 0;
}
struct snd_soc_codec_device soc_codec_dev_wm9712 = {
.probe = wm9712_soc_probe,
.remove = wm9712_soc_remove,
.suspend = wm9712_soc_suspend,
.resume = wm9712_soc_resume,
};
EXPORT_SYMBOL_GPL(soc_codec_dev_wm9712);
MODULE_DESCRIPTION("ASoC WM9711/WM9712 driver");
MODULE_AUTHOR("Liam Girdwood");
MODULE_LICENSE("GPL");

14
sound/soc/codecs/wm9712.h Normal file
View File

@@ -0,0 +1,14 @@
/*
* wm9712.h -- WM9712 Soc Audio driver
*/
#ifndef _WM9712_H
#define _WM9712_H
#define WM9712_DAI_AC97_HIFI 0
#define WM9712_DAI_AC97_AUX 1
extern struct snd_soc_codec_dai wm9712_dai[2];
extern struct snd_soc_codec_device soc_codec_dev_wm9712;
#endif

1224
sound/soc/codecs/wm9713.c Normal file

File diff suppressed because it is too large Load Diff

51
sound/soc/codecs/wm9713.h Normal file
View File

@@ -0,0 +1,51 @@
/*
* wm9713.h -- WM9713 Soc Audio driver
*/
#ifndef _WM9713_H
#define _WM9713_H
/* clock inputs */
#define WM9713_CLKA_PIN 0
#define WM9713_CLKB_PIN 1
/* clock divider ID's */
#define WM9713_PCMCLK_DIV 0
#define WM9713_CLKA_MULT 1
#define WM9713_CLKB_MULT 2
#define WM9713_HIFI_DIV 3
#define WM9713_PCMBCLK_DIV 4
/* PCM clk div */
#define WM9713_PCMDIV(x) ((x - 1) << 8)
/* HiFi Div */
#define WM9713_HIFIDIV(x) ((x - 1) << 12)
/* MCLK clock mulitipliers */
#define WM9713_CLKA_X1 (0 << 1)
#define WM9713_CLKA_X2 (1 << 1)
#define WM9713_CLKB_X1 (0 << 2)
#define WM9713_CLKB_X2 (1 << 2)
/* MCLK clock MUX */
#define WM9713_CLK_MUX_A (0 << 0)
#define WM9713_CLK_MUX_B (1 << 0)
/* Voice DAI BCLK divider */
#define WM9713_PCMBCLK_DIV_1 (0 << 9)
#define WM9713_PCMBCLK_DIV_2 (1 << 9)
#define WM9713_PCMBCLK_DIV_4 (2 << 9)
#define WM9713_PCMBCLK_DIV_8 (3 << 9)
#define WM9713_PCMBCLK_DIV_16 (4 << 9)
#define WM9713_DAI_AC97_HIFI 0
#define WM9713_DAI_AC97_AUX 1
#define WM9713_DAI_PCM_VOICE 2
extern struct snd_soc_codec_device soc_codec_dev_wm9713;
extern struct snd_soc_codec_dai wm9713_dai[3];
int wm9713_reset(struct snd_soc_codec *codec, int try_warm);
#endif