All of lore.kernel.org
 help / color / mirror / Atom feed
From: Mike Frysinger <vapier-aBrp7R+bbdUdnm+yROfE0A@public.gmane.org>
To: alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw@public.gmane.org,
	Mark Brown
	<broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E@public.gmane.org>
Cc: uclinux-dist-devel-ZG0+EudsQA8dtHy/vicBwGD2FQJk+8+b@public.gmane.org,
	Cliff Cai <cliff.cai-OyLXuOCK7orQT0dZR+AlfA@public.gmane.org>
Subject: [PATCH 1/6] ASoC: add ADAU1361 codec driver
Date: Sat,  7 Aug 2010 16:28:20 -0400	[thread overview]
Message-ID: <1281212905-12957-1-git-send-email-vapier@gentoo.org> (raw)

From: Cliff Cai <cliff.cai-OyLXuOCK7orQT0dZR+AlfA@public.gmane.org>

Signed-off-by: Cliff Cai <cliff.cai-OyLXuOCK7orQT0dZR+AlfA@public.gmane.org>
Signed-off-by: Mike Frysinger <vapier-aBrp7R+bbdUdnm+yROfE0A@public.gmane.org>
---
 sound/soc/codecs/Kconfig    |    4 +
 sound/soc/codecs/Makefile   |    2 +
 sound/soc/codecs/adau1361.c |  992 +++++++++++++++++++++++++++++++++++++++++++
 sound/soc/codecs/adau1361.h |  264 ++++++++++++
 4 files changed, 1262 insertions(+), 0 deletions(-)
 create mode 100644 sound/soc/codecs/adau1361.c
 create mode 100644 sound/soc/codecs/adau1361.h

diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index ae01cba..f37d5f4 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -16,6 +16,7 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_AD193X if SND_SOC_I2C_AND_SPI
 	select SND_SOC_AD1980 if SND_SOC_AC97_BUS
 	select SND_SOC_AD73311 if I2C
+	select SND_SOC_ADAU1361 if I2C
 	select SND_SOC_ADAV80X if SND_SOC_I2C_AND_SPI
 	select SND_SOC_ADS117X
 	select SND_SOC_AK4104 if SPI_MASTER
@@ -104,6 +105,9 @@ config SND_SOC_AD1980
 config SND_SOC_AD73311
 	tristate
 	
+config SND_SOC_ADAU1361
+	tristate
+
 config SND_SOC_ADAV80X
 	tristate
 
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index f5b3d5b..d05b672 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -3,6 +3,7 @@ snd-soc-ad1836-objs := ad1836.o
 snd-soc-ad193x-objs := ad193x.o
 snd-soc-ad1980-objs := ad1980.o
 snd-soc-ad73311-objs := ad73311.o
+snd-soc-adau1361-objs := adau1361.o
 snd-soc-adav80x-objs := adav80x.o
 snd-soc-ads117x-objs := ads117x.o
 snd-soc-ak4104-objs := ak4104.o
@@ -70,6 +71,7 @@ obj-$(CONFIG_SND_SOC_AD1836)	+= snd-soc-ad1836.o
 obj-$(CONFIG_SND_SOC_AD193X)	+= snd-soc-ad193x.o
 obj-$(CONFIG_SND_SOC_AD1980)	+= snd-soc-ad1980.o
 obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o
+obj-$(CONFIG_SND_SOC_ADAU1361)	+= snd-soc-adau1361.o
 obj-$(CONFIG_SND_SOC_ADAV80X)	+= snd-soc-adav80x.o
 obj-$(CONFIG_SND_SOC_ADS117X)	+= snd-soc-ads117x.o
 obj-$(CONFIG_SND_SOC_AK4104)	+= snd-soc-ak4104.o
diff --git a/sound/soc/codecs/adau1361.c b/sound/soc/codecs/adau1361.c
new file mode 100644
index 0000000..ad78420
--- /dev/null
+++ b/sound/soc/codecs/adau1361.c
@@ -0,0 +1,992 @@
+/*
+ * Driver for ADAU1361 sound codec
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#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/workqueue.h>
+#include <linux/platform_device.h>
+#include <linux/sysfs.h>
+#include <linux/slab.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 "adau1361.h"
+
+#define AUDIO_NAME "adau1361"
+#define ADAU1361_VERSION "0.1"
+
+#define CAP_MIC  1
+#define CAP_LINE 2
+#define CAPTURE_SOURCE_NUMBER 2
+
+struct snd_soc_codec_device soc_codec_dev_adau1361;
+static struct snd_soc_codec *adau1361_codec;
+/* codec private data */
+struct adau1361_priv {
+	unsigned int sysclk;
+	unsigned int in_source;
+	unsigned int out_route;
+	unsigned int pll_out;
+	struct work_struct resume_work;
+	struct snd_soc_codec codec;
+	int dapm_state_suspend;
+	struct platform_device *pdev;
+	u8 pll_enable;
+	u8 adau1361_pll_reg[6];
+	u8 rate_index;
+	/* dapm */
+	u8 dapm_lineL;
+	u8 dapm_lineR;
+	u8 dapm_hpL;
+	u8 dapm_hpR;
+};
+
+/*
+ * write register cache
+ */
+static inline int adau1361_write_reg_cache(struct snd_soc_codec *codec,
+	unsigned int reg, unsigned int value)
+{
+	u8 *cache = codec->reg_cache;
+
+	if (reg < ADAU_FIRSTREG)
+		reg = reg + ADAU_FIRSTREG;
+
+	if ((reg < ADAU_FIRSTREG) || (reg > ADAU_LASTREG))
+		return -1;
+
+	cache[reg - ADAU_FIRSTREG] = value;
+
+	return 0;
+}
+
+/*
+ * read a multi-byte ADAU1361 register (6byte pll reg)
+ */
+static int adau1361_read_reg_block(struct snd_soc_codec *codec,
+	unsigned int reg, u8 len)
+{
+	u8 buf[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+	u8 addr[2];
+	unsigned int i;
+
+	if (reg < ADAU_FIRSTREG)
+		reg = reg + ADAU_FIRSTREG;
+
+	if ((reg < ADAU_FIRSTREG) || (reg > ADAU_LASTREG))
+		return -EIO;
+
+	addr[0] = (u8)(reg >> 8);
+	addr[1] = (u8)(reg & 0xFF);
+
+	/* write the 2byte read address */
+	if (codec->hw_write(codec->control_data, addr, 2) != 2) {
+		dev_err(codec->dev, "read_reg_byte:address write failed.");
+		return -EIO;
+	}
+
+	if (i2c_master_recv(codec->control_data, buf, len) != len)
+		return -EIO;
+
+	for (i = 0; i < len; i++)
+		adau1361_write_reg_cache(codec, reg+i, (unsigned int)buf[i]);
+
+	return 0;
+}
+
+/*
+ * write a multibyte ADAU1361 register (6byte pll reg)
+ */
+static int adau1361_write_reg_block(struct snd_soc_codec *codec,
+	unsigned int reg, u8 length, u8 *values)
+{
+	int count = length + 2; /*data plus 16bit register address*/
+	u8 buf[8] = {0, 0, 0, 0, 0, 0, 0, 0};
+
+	buf[0] = (u8)(reg >> 8);
+	buf[1] = (u8)(reg & 0xFF);
+
+	if (length > 0)
+		memcpy(&buf[2], values, length);
+
+	if (codec->hw_write(codec->control_data, buf, count) == count)
+		return 0;
+	else {
+		dev_err(codec->dev, "address block write failed.");
+		return -EIO;
+	}
+}
+
+/*
+ * adau1361 controls
+ */
+static int adau1361_mux_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct adau1361_priv *adau1361 = codec->private_data;
+
+	if (adau1361->in_source & CAP_MIC)
+		ucontrol->value.integer.value[0] = 0x0;
+	else
+		ucontrol->value.integer.value[0] = 0x1;
+
+	return 0;
+}
+
+static int adau1361_mux_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct adau1361_priv *adau1361 = codec->private_data;
+	int src = ucontrol->value.integer.value[0];
+	u8 regvalue = 0;
+
+	if (src == 0) {/* Select Mic */
+		adau1361->in_source = CAP_MIC;
+#ifdef ADAU1361_DIG_MIC
+		regvalue = (snd_soc_read(codec, ADAU_ADCCTL0) & 0xFB)|0x4;
+		snd_soc_write(codec, ADAU_ADCCTL0, regvalue);
+#else
+		snd_soc_write(codec, ADAU_RECMBIA, RECMBIA_DISABLE);
+		regvalue = (snd_soc_read(codec, ADAU_RECVLCL)
+				| RECVLC_ENABLE_MASK);
+		snd_soc_write(codec, ADAU_RECVLCL, regvalue);
+		regvalue = (snd_soc_read(codec, ADAU_RECVLCR)
+				| RECVLC_ENABLE_MASK);
+		snd_soc_write(codec, ADAU_RECVLCR, regvalue);
+		snd_soc_write(codec, ADAU_RECMLC1, RECMLC_MIC_0DB);
+		snd_soc_write(codec, ADAU_RECMRC1, RECMLC_MIC_0DB);
+#endif
+	} else if (src == 1) {/* Select Line */
+		adau1361->in_source = CAP_LINE;
+#ifdef ADAU1361_DIG_MIC
+		regvalue = (snd_soc_read(codec, ADAU_ADCCTL0) & 0xFB);
+		snd_soc_write(codec, ADAU_ADCCTL0, regvalue);
+#endif
+		snd_soc_write(codec, ADAU_RECMBIA, RECMBIA_DISABLE);
+		regvalue = (snd_soc_read(codec, ADAU_RECVLCL)
+				& RECVLC_DISABLE_MASK);
+		snd_soc_write(codec, ADAU_RECVLCL, regvalue);
+		regvalue = (snd_soc_read(codec, ADAU_RECVLCR)
+				& RECVLC_DISABLE_MASK);
+		snd_soc_write(codec, ADAU_RECVLCR, regvalue);
+		snd_soc_write(codec, ADAU_RECMLC1, RECMLC_LINE_0DB);
+		snd_soc_write(codec, ADAU_RECMRC1, RECMLC_LINE_0DB);
+	}
+
+	return 0;
+}
+
+static int adau1361_mic_boost_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct adau1361_priv *adau1361 = codec->private_data;
+
+	if (adau1361->in_source & CAP_MIC)
+		ucontrol->value.integer.value[0] =
+		(RECMLC_MIC_20DB ==
+			snd_soc_read(codec, ADAU_RECMLC1));
+	else
+		ucontrol->value.integer.value[0] = 0x0;
+
+	ucontrol->value.integer.value[1] = ucontrol->value.integer.value[0];
+
+	return 0;
+}
+
+static int adau1361_mic_boost_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct adau1361_priv *adau1361 = codec->private_data;
+	int val = ucontrol->value.integer.value[0];
+	u8 regvalue = 0;
+
+	if (adau1361->in_source & CAP_MIC) {
+		regvalue = (val) ? RECMLC_MIC_20DB : RECMLC_MIC_0DB;
+		if (snd_soc_read(codec, ADAU_RECMLC1) != regvalue) {
+			snd_soc_write(codec, ADAU_RECMLC1, regvalue);
+			snd_soc_write(codec, ADAU_RECMRC1, regvalue);
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+static const char *adau1361_input_select[] = {"Mic", "Line"};
+static const struct soc_enum adau1361_enums[] = {
+	SOC_ENUM_SINGLE(ADAU_RECMLC1, 0, 2, adau1361_input_select),
+};
+
+static const struct snd_kcontrol_new adau1361_snd_controls[] = {
+SOC_DOUBLE_R("Master Playback Volume", ADAU_DACCTL1,
+	ADAU_DACCTL2, 0, 255, 1),
+SOC_DOUBLE_R("Capture Volume", ADAU_ADCCTL1,
+	ADAU_ADCCTL2, 0, 255, 1),
+SOC_DOUBLE_R("Capture Switch", ADAU_RECMLC0,
+	ADAU_RECMRC0, 0, 1, 0),
+SOC_ENUM_EXT("Capture Source", adau1361_enums[0],
+	adau1361_mux_get, adau1361_mux_put),
+SOC_SINGLE_EXT("Mic Boost (+20dB)", ADAU_RECMLC1, 0, 1, 0,
+	adau1361_mic_boost_get, adau1361_mic_boost_put),
+SOC_DOUBLE_R("Headphone Playback Volume", ADAU_PLBHPVL,
+	ADAU_PLBHPVR, 2, 63, 0),
+SOC_DOUBLE_R("Line Playback Volume", ADAU_PLBLOVL,
+	ADAU_PLBLOVR, 2, 63, 0),
+};
+
+/*
+ * _DAPM_
+ */
+
+static int adau1361_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	u8 reg = 0;
+
+	if (mute) {
+		/* mute inputs */
+		reg = (snd_soc_read(codec, ADAU_RECMLC0) & 0xFE) | 0x0;
+		snd_soc_write(codec, ADAU_RECMLC0, reg);
+		reg = (snd_soc_read(codec, ADAU_RECMRC0) & 0xFE) | 0x0;
+		snd_soc_write(codec, ADAU_RECMRC0, reg);
+		/* mute outputs */
+		reg = (snd_soc_read(codec, ADAU_PLBMLC0) & 0xFE) | 0x1;
+		snd_soc_write(codec, ADAU_PLBMLC0, reg);
+		reg = (snd_soc_read(codec, ADAU_PLBMRC0) & 0xFE) | 0x1;
+		snd_soc_write(codec, ADAU_PLBMRC0, reg);
+
+	} else {
+		/* un-mute outputs, according to the spec,
+		   we should enable mixer3 and mixer4 here,
+		   but it seems that things are converse here.
+		 */
+		reg = (snd_soc_read(codec, ADAU_PLBMLC0) & 0xFE) | 0x0;
+		snd_soc_write(codec, ADAU_PLBMLC0, reg);
+		reg = (snd_soc_read(codec, ADAU_PLBMRC0) & 0xFE) | 0x0;
+		snd_soc_write(codec, ADAU_PLBMRC0, reg);
+		/* un-mute inputs */
+		reg = (snd_soc_read(codec, ADAU_RECMLC0) & 0xFE) | 0x1;
+		snd_soc_write(codec, ADAU_RECMLC0, reg);
+		reg = (snd_soc_read(codec, ADAU_RECMRC0) & 0xFE) | 0x1;
+		snd_soc_write(codec, ADAU_RECMRC0, reg);
+	}
+
+	return 0;
+}
+
+/* Left Mixer */
+static const struct snd_kcontrol_new adau1361_left_mixer_controls[] = {
+SOC_DAPM_SINGLE("LineLeft Bypass Switch", ADAU_PLBLOVL, 1, 1, 0),
+SOC_DAPM_SINGLE("HPLeft Bypass Switch", ADAU_PLBHPVL, 1, 1, 0),
+};
+
+/* Right mixer */
+static const struct snd_kcontrol_new adau1361_right_mixer_controls[] = {
+SOC_DAPM_SINGLE("LineRight Bypass Switch", ADAU_PLBLOVR, 1, 1, 0),
+SOC_DAPM_SINGLE("HPRight Bypass Switch", ADAU_PLBHPVR, 1, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget adau1361_dapm_widgets[] = {
+
+SND_SOC_DAPM_MIXER("Left Mixer", ADAU_PLBPWRM, 2, 1, \
+	&adau1361_left_mixer_controls[0], ARRAY_SIZE(adau1361_left_mixer_controls)),
+SND_SOC_DAPM_MIXER("Left Out", ADAU_PLBPWRM, 0, 0, NULL, 0),
+SND_SOC_DAPM_MIXER("Left Line Mixer", ADAU_PLBMLLO, 0, 0, NULL, 0),
+SND_SOC_DAPM_OUTPUT("LOUT"),
+SND_SOC_DAPM_OUTPUT("LHPOUT"),
+
+SND_SOC_DAPM_MIXER("Right Mixer", ADAU_PLBPWRM, 3, 1, \
+	&adau1361_right_mixer_controls[0], ARRAY_SIZE(adau1361_right_mixer_controls)),
+SND_SOC_DAPM_MIXER("Right Out", ADAU_PLBPWRM, 1, 0, NULL, 0),
+SND_SOC_DAPM_MIXER("Right Line Mixer", ADAU_PLBMRLO, 0, 0, NULL, 0),
+SND_SOC_DAPM_OUTPUT("ROUT"),
+SND_SOC_DAPM_OUTPUT("RHPOUT"),
+
+SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_MIXER("DAC Enable Left", ADAU_DACCTL0, 0, 0, NULL, 0),
+SND_SOC_DAPM_MIXER("DAC Enable Right", ADAU_DACCTL0, 1, 0, NULL, 0),
+SND_SOC_DAPM_MIXER("HP Bias Left", ADAU_PLBPWRM, 6, 1, NULL, 0),
+SND_SOC_DAPM_MIXER("HP Bias Right", ADAU_PLBLRMC, 0, 0, NULL, 0),
+
+SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_MIXER("ADC Left", ADAU_ADCCTL0, 0, 0, NULL, 0),
+SND_SOC_DAPM_MIXER("ADC Right", ADAU_ADCCTL0, 1, 0, NULL, 0),
+
+#if !defined(ADAU1361_DIG_MIC)
+SND_SOC_DAPM_MICBIAS("Mic Bias", ADAU_RECMBIA, 0, 0),
+SND_SOC_DAPM_MIXER("Left Mic Mixer", ADAU_RECVLCL, 0, 0, NULL, 0),
+SND_SOC_DAPM_MIXER("Right Mic Mixer", ADAU_RECVLCR, 0, 0, NULL, 0),
+#else
+SND_SOC_DAPM_MICBIAS("Mic Bias Left", SND_SOC_NOPM, 1, 0),
+SND_SOC_DAPM_MICBIAS("Mic Bias Right", SND_SOC_NOPM, 1, 0),
+SND_SOC_DAPM_MIXER("Left Mic Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_MIXER("Right Mic Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+#endif
+
+SND_SOC_DAPM_MIXER("Left Input", ADAU_RECPWRM, 1, 1, NULL, 0),
+SND_SOC_DAPM_MIXER("Right Input", ADAU_RECPWRM, 2, 1, NULL, 0),
+
+SND_SOC_DAPM_INPUT("LMICIN"),
+SND_SOC_DAPM_INPUT("RMICIN"),
+SND_SOC_DAPM_INPUT("LLINEIN"),
+SND_SOC_DAPM_INPUT("RLINEIN"),
+};
+
+static const struct snd_soc_dapm_route audio_conns[] = {
+	/* DAC */
+	{"DAC Enable Left", NULL, "DAC"},
+	{"DAC Enable Right", NULL, "DAC"},
+
+	/* mixers */
+	{"Left Mixer", NULL, "DAC Enable Left"},
+	{"Right Mixer", NULL, "DAC Enable Right"},
+
+	/* outputs */
+	{"Left Out", NULL, "Left Mixer"},
+	{"Right Out", NULL, "Right Mixer"},
+
+	/* line Out */
+	{"Left Line Mixer", NULL, "Left Out"},
+	{"Right Line Mixer", NULL, "Right Out"},
+	{"LOUT", "LineLeft Bypass Switch", "Left Line Mixer"},
+	{"ROUT", "LineRight Bypass Switch", "Right Line Mixer"},
+
+	/* headphone out */
+	{"HP Bias Left", NULL, "Left Out"},
+	{"HP Bias Right", NULL, "Right Out"},
+	{"LHPOUT", "HPLeft Bypass Switch", "HP Bias Left"},
+	{"RHPOUT", "HPRight Bypass Switch", "HP Bias Right"},
+
+	/* inputs */
+	{"Left Input", NULL, "LLINEIN"},
+	{"Right Input", NULL, "RLINEIN"},
+	{"ADC Left", NULL, "Left Input"},
+	{"ADC Right", NULL, "Right Input"},
+	{"ADC Left", NULL, "Left Mic Mixer"},
+	{"ADC Right", NULL, "Right Mic Mixer"},
+	{"ADC", NULL, "ADC Left"},
+	{"ADC", NULL, "ADC Right"},
+
+};
+
+static int adau1361_add_widgets(struct snd_soc_codec *codec)
+{
+	snd_soc_dapm_new_controls(codec, adau1361_dapm_widgets,
+				  ARRAY_SIZE(adau1361_dapm_widgets));
+
+	snd_soc_dapm_add_routes(codec, audio_conns, ARRAY_SIZE(audio_conns));
+
+	return 0;
+}
+
+/* PLL dividors */
+struct _pll_div {
+	u32 mclk;
+	u32 pll_freq;
+	u16 den;
+	u16 num;
+	u8  param;
+};
+
+static const struct _pll_div clock_dividers[] = {
+	{ 12000000, 45158400, 625, 477, /*44.1kHz*/
+		(PLLCTRL_INTPART_R3|PLLCTRL_INPUT_DIV1|PLLCTRL_TYPE_FRAC) },
+	{12000000, 49152000, 125, 12, /*48kHz*/
+		(PLLCTRL_INTPART_R4|PLLCTRL_INPUT_DIV1|PLLCTRL_TYPE_FRAC) },
+	{12288000, 45158400, 40, 27, /*44.1Khz*/
+		(PLLCTRL_INTPART_R3|PLLCTRL_INPUT_DIV1|PLLCTRL_TYPE_FRAC) },
+	{12288000, 49152000, 0, 0, /*48kHz*/
+		(PLLCTRL_INTPART_R4|PLLCTRL_INPUT_DIV1|PLLCTRL_TYPE_INT) },
+};
+
+static inline int get_pll_settings(int mclk, int pll_out)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(clock_dividers); i++) {
+		if (clock_dividers[i].mclk == mclk
+			&& clock_dividers[i].pll_freq == pll_out)
+			return i;
+	}
+	return 0;
+}
+
+static int adau1361_pll_init(struct snd_soc_codec *codec)
+{
+	struct adau1361_priv *adau1361 = codec->private_data;
+	u8 *pll_reg = adau1361->adau1361_pll_reg;
+	int ix = 0;
+
+	/* Init ADAU1361 clocking */
+	snd_soc_write(codec, ADAU_CLKCTRL,
+		(CLKCTRL_SRC_PLL | CLKCTRL_FRQ_1024 | CLKCTRL_DISABLE));
+
+	ix = get_pll_settings(adau1361->sysclk, adau1361->pll_out);
+
+	pll_reg[0] = (clock_dividers[ix].den >> 8);
+	pll_reg[1] = (clock_dividers[ix].den & 0xFF);
+	pll_reg[2] = (clock_dividers[ix].num >> 8);
+	pll_reg[3] = (clock_dividers[ix].num & 0xFF);
+	pll_reg[4] = clock_dividers[ix].param;
+	pll_reg[5] = PLLCTRL_DISABLE;
+	adau1361_write_reg_block(codec, ADAU_PLLCTRL, 6, pll_reg);
+
+	adau1361->pll_enable = 0;
+
+	return 0;
+}
+
+static int adau1361_pll_enable(struct snd_soc_codec *codec, int enable)
+{
+	struct adau1361_priv *adau1361 = codec->private_data;
+	u8 *pll_reg = adau1361->adau1361_pll_reg;
+	int counter = 0;
+
+	if (enable) {
+		pll_reg[5]  = PLLCTRL_ENABLE;
+		adau1361_write_reg_block(codec, ADAU_PLLCTRL, 6, pll_reg);
+
+		/* wait for PLL lock*/
+		do {
+			++counter;
+			schedule_timeout_interruptible(msecs_to_jiffies(1));
+			adau1361_read_reg_block(codec, ADAU_PLLCTRL, 6);
+		} while (0 == (snd_soc_read(codec, ADAU_PLLCTRL + 5) & 0x2)
+			&& counter < 20);
+		if (counter >= 20)
+			return -1;
+
+		adau1361->pll_enable = 1;
+
+		/* Init ADAU1361 clocking */
+		snd_soc_write(codec, ADAU_CLKCTRL,
+			(CLKCTRL_SRC_PLL | CLKCTRL_FRQ_1024 | CLKCTRL_ENABLE));
+	}
+
+	return 0;
+
+}
+
+static int adau1361_reg_init(struct snd_soc_codec *codec)
+{
+	struct adau1361_mode_register regdata;
+	struct adau1361_mode_register *registers = 0;
+	int i;
+#ifdef ADAU1361_DIG_MIC
+	int mode = 1;
+#else /* analog mic */
+	int mode = 0;
+#endif
+	adau1361_pll_init(codec);
+	adau1361_pll_enable(codec, 1);
+	/* Load deault regsiter settings */
+	for (i = 0; i < RESET_REGISTER_COUNT; ++i) {
+		regdata = adau1361_reset[i];
+		snd_soc_write(codec, regdata.regaddress, regdata.regvalue);
+	}
+	/* Load mode registers */
+	registers = adau1361_mode_registers[mode];
+	for (i = 0; i < MODE_REGISTER_COUNT; ++i) {
+		regdata = registers[i];
+		snd_soc_write(codec, regdata.regaddress, regdata.regvalue);
+	}
+	/* unmute outputs */
+	snd_soc_write(codec, ADAU_PLBHPVL, DAPM_HP_DEF);
+	snd_soc_write(codec, ADAU_PLBHPVR, DAPM_HP_DEF);
+	snd_soc_write(codec, ADAU_PLBLOVL, DAPM_LINE_DEF);
+	snd_soc_write(codec, ADAU_PLBLOVR, DAPM_LINE_DEF);
+
+	return 0;
+}
+
+struct _srate_set {
+	int fs;
+	u8 reg;
+};
+
+static const struct _srate_set srate_iface[] = {
+	{8000, 0x1},
+	{11025, 0x2},
+	{12000, 0x2},
+	{16000, 0x3},
+	{22050, 0x4},
+	{24000, 0x4},
+	{32000, 0x5},
+	{44100, 0x0},
+	{48000, 0x0},
+	{88200, 0x6},
+	{96000, 0x6},
+};
+
+static int adau1361_hw_params(struct snd_pcm_substream *substream,
+			      struct snd_pcm_hw_params *params,
+			      struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_codec *codec = socdev->card->codec;
+	struct adau1361_priv *adau1361 = codec->private_data;
+	int rate = params_rate(params);
+	int i;
+
+	/* initialize the PLL */
+	if (adau1361_pll_init(codec) != 0)
+		return -EINVAL;
+	for (i = 0; i < ARRAY_SIZE(srate_iface); i++) {
+		if (srate_iface[i].fs == rate) {
+			adau1361->rate_index = i;
+			break;
+		}
+	}
+	return 0;
+}
+
+static int adau1361_pcm_prepare(struct snd_pcm_substream *substream,
+				struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_codec *codec = socdev->card->codec;
+	struct adau1361_priv *adau1361 = codec->private_data;
+	u8 reg = 0;
+	int ret = 0;
+
+	reg = srate_iface[adau1361->rate_index].reg;
+	ret = adau1361_pll_enable(codec, 1);
+	if (ret)
+		dev_err(codec->dev, "Failed to initialize PLL");
+
+	reg = (snd_soc_read(codec, ADAU_CONVCT0) & 0xF8) | reg;
+	snd_soc_write(codec, ADAU_CONVCT0, reg);
+
+	return ret;
+}
+
+static void adau1361_shutdown(struct snd_pcm_substream *substream,
+			      struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_codec *codec = socdev->card->codec;
+	u8 reg;
+
+	if (!codec->active) {
+		reg = snd_soc_read(codec, ADAU_CLKCTRL);
+		snd_soc_write(codec, ADAU_CLKCTRL, reg & ~0x1);
+	}
+}
+
+static int adau1361_set_dai_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	u8 reg = 0;
+
+	/* set master/slave audio interface */
+	reg = (snd_soc_read(codec, ADAU_SPRTCT0) & 0xFE);
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:  /*master*/
+		reg |= 0x1;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS: /*slave*/
+		reg &= ~0x1;
+		break;
+	default:
+		return 0;
+	}
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		break;
+	/* TODO: support TDM */
+	default:
+		return 0;
+	}
+
+	/* clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	/* TODO: support signal inversions */
+	default:
+		return 0;
+	}
+
+	/* set I2S iface format*/
+	snd_soc_write(codec, ADAU_SPRTCT0, reg);
+	return 0;
+}
+
+/*
+ * Clock after PLL and dividers
+ */
+static int adau1361_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct adau1361_priv *adau1361 = codec->private_data;
+
+	switch (freq) {
+	case 12000000:
+		adau1361->sysclk = freq;
+		return 0;
+	case 12288000:
+		adau1361->sysclk = freq;
+		return 0;
+	}
+
+	/* supported 12MHz MCLK only for now */
+	return -EINVAL;
+}
+
+static int adau1361_set_dai_pll(struct snd_soc_dai *codec_dai,
+		int pll_id, int source, unsigned int freq_in, unsigned int freq_out)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct adau1361_priv *adau1361 = codec->private_data;
+
+	/* fixed MCLK only supported for now */
+	if (adau1361->sysclk != freq_in)
+		return -EINVAL;
+
+	/* Only update pll when freq changes */
+	if (adau1361->pll_enable && adau1361->pll_out == freq_out)
+		return 0;
+
+	switch (freq_out) {
+	case 45158400:
+		adau1361->pll_out = freq_out;
+		break;
+	case 49152000:
+		adau1361->pll_out = freq_out;
+		break;
+	default:
+		dev_err(codec->dev, "adau1361_set_dai_pll: undefined pll freq:%d", freq_out);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+
+static int adau1361_set_bias_level(struct snd_soc_codec *codec,
+				 enum snd_soc_bias_level level)
+{
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		snd_soc_write(codec, ADAU_CLKCTRL,
+			(CLKCTRL_SRC_PLL | CLKCTRL_FRQ_1024 | CLKCTRL_DISABLE));
+		break;
+	case SND_SOC_BIAS_OFF:
+		/* everything off, dac mute, inactive */
+		snd_soc_write(codec, ADAU_RECPWRM, RECPWRM_LOW_PWR);
+		snd_soc_write(codec, ADAU_PLBPWRM, PLBPWRM_LOW_PWR);
+		snd_soc_write(codec, ADAU_PLBCTRL, PLBCTRL_POP_OFF);
+		snd_soc_write(codec, ADAU_CLKCTRL,
+			(CLKCTRL_SRC_PLL | CLKCTRL_FRQ_1024 | CLKCTRL_DISABLE));
+		break;
+
+	}
+	codec->bias_level = level;
+	return 0;
+}
+
+#define ADAU1361_RATES (SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_22050 |\
+		SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_88200 |\
+		SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+		SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\
+		SNDRV_PCM_RATE_96000)
+
+#define ADAU1361_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+	SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_ops adau1361_dai_ops = {
+	.hw_params	= adau1361_hw_params,
+	.prepare	= adau1361_pcm_prepare,
+	.shutdown	= adau1361_shutdown,
+	.digital_mute	= adau1361_mute,
+	.set_fmt	= adau1361_set_dai_fmt,
+	.set_sysclk	= adau1361_set_dai_sysclk,
+	.set_pll	= adau1361_set_dai_pll,
+};
+
+struct snd_soc_dai adau1361_dai = {
+	.name = "ADAU1361",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = ADAU1361_RATES,
+		.formats = ADAU1361_FORMATS,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = ADAU1361_RATES,
+		.formats = ADAU1361_FORMATS,
+	},
+	.ops = &adau1361_dai_ops,
+};
+EXPORT_SYMBOL_GPL(adau1361_dai);
+
+static int adau1361_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->card->codec;
+
+	adau1361_set_bias_level(codec, SND_SOC_BIAS_OFF);
+	return 0;
+}
+
+static void adau1361_resume_wq_handler(struct work_struct *work)
+{
+	struct adau1361_priv *adau1361 = container_of(work, struct adau1361_priv, resume_work);
+	struct snd_soc_codec *codec = &adau1361->codec;
+	unsigned int i, v;
+
+	adau1361_pll_init(codec);
+	adau1361_pll_enable(codec, 1);
+
+	/* sync reg_cache with the hardware */
+	for (i = ADAU_FIRSTREG; i <= ADAU_LASTREG; ++i) {
+		/* skip over the 6byte PLL control register */
+		if (i >= ADAU_PLLCTRL && i < ADAU_MICCTRL)
+			continue;
+
+		v = snd_soc_read(codec, i);
+		if (snd_soc_write(codec, i, v) != 0) {
+			dev_err(codec->dev, "ERROR WRITING %.4X AT REG %x\n", v, i);
+			return;
+		}
+	}
+
+	snd_soc_write(codec, ADAU_PLBCTRL, PLBCTRL_POP_ON);
+	snd_soc_write(codec, ADAU_RECPWRM, RECPWRM_RUN_PWR);
+	snd_soc_write(codec, ADAU_PLBPWRM, PLBPWRM_RUN_PWR);
+
+	adau1361_set_bias_level(codec, SND_SOC_BIAS_ON);
+
+}
+
+static int adau1361_resume(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->card->codec;
+	struct adau1361_priv *adau1361 = codec->private_data;
+
+	adau1361->pdev = pdev;
+	schedule_work(&adau1361->resume_work);
+	return 0;
+}
+
+/*
+ * initialise the adau1361 driver
+ * register the mixer and dsp interfaces with the kernel
+ */
+static int adau1361_register(struct adau1361_priv *adau1361, enum snd_soc_control_type control)
+{
+	struct snd_soc_codec *codec = &adau1361->codec;
+	int ret = 0;
+
+	mutex_init(&codec->mutex);
+	INIT_LIST_HEAD(&codec->dapm_widgets);
+	INIT_LIST_HEAD(&codec->dapm_paths);
+	codec->name = "adau1361";
+	codec->owner = THIS_MODULE;
+	codec->set_bias_level = adau1361_set_bias_level;
+	codec->dai = &adau1361_dai;
+	codec->num_dai = 1;
+	codec->reg_cache_size = ADAU_NUMCACHEREG;
+	codec->reg_cache = kzalloc(ADAU_NUMCACHEREG, GFP_KERNEL);
+	if (codec->reg_cache == NULL)
+		return -ENOMEM;
+
+	ret = snd_soc_codec_set_cache_io(codec, 16, 8, control);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_register_codec(codec);
+	if (ret != 0) {
+		dev_err(codec->dev, "Failed to register codec: %d\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_register_dai(&adau1361_dai);
+	if (ret != 0) {
+		dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
+		snd_soc_unregister_codec(codec);
+		return ret;
+	}
+
+	return ret;
+}
+
+static void adau1361_unregister(struct adau1361_priv *adau1361)
+{
+	struct snd_soc_codec *codec = &adau1361->codec;
+
+	adau1361_set_bias_level(codec, SND_SOC_BIAS_OFF);
+	kfree(codec->reg_cache);
+	snd_soc_unregister_dai(&adau1361_dai);
+	snd_soc_unregister_codec(codec);
+	kfree(adau1361);
+	adau1361_codec = NULL;
+}
+
+static int adau1361_probe(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec;
+	struct adau1361_priv *adau1361;
+	int ret = 0;
+
+	socdev->card->codec = adau1361_codec;
+	codec = adau1361_codec;
+	adau1361 = codec->private_data;
+	adau1361->in_source = CAP_MIC; /*default is mic input*/
+	adau1361->sysclk = ADAU1361_MCLK_RATE;
+	adau1361->pll_out = ADAU1361_PLL_FREQ_48;
+	adau1361->dapm_lineL = DAPM_LINE_DEF;
+	adau1361->dapm_lineR = DAPM_LINE_DEF;
+	adau1361->dapm_hpL = DAPM_HP_DEF;
+	adau1361->dapm_hpR = DAPM_HP_DEF;
+	adau1361->pdev = pdev;
+
+	ret = adau1361_reg_init(codec);
+	if (ret < 0)
+		dev_err(codec->dev, "failed to initialize\n");
+	/* register pcms */
+	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+	if (ret < 0) {
+		dev_err(codec->dev, "failed to create pcms: %d\n", ret);
+		goto pcm_err;
+	}
+
+	snd_soc_add_controls(codec, adau1361_snd_controls,
+			     ARRAY_SIZE(adau1361_snd_controls));
+	adau1361_add_widgets(codec);
+pcm_err:
+	return ret;
+}
+
+/* remove everything here */
+static int adau1361_remove(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+
+	snd_soc_free_pcms(socdev);
+	snd_soc_dapm_free(socdev);
+
+	return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_adau1361 = {
+	.probe =	adau1361_probe,
+	.remove =	adau1361_remove,
+	.suspend =	adau1361_suspend,
+	.resume =	adau1361_resume,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_adau1361);
+
+
+static __devinit int adau1361_i2c_probe(struct i2c_client *i2c,
+			      const struct i2c_device_id *id)
+{
+	struct adau1361_priv *adau1361;
+	struct snd_soc_codec *codec;
+	int ret = 0;
+
+	adau1361 = kzalloc(sizeof(struct adau1361_priv), GFP_KERNEL);
+	if (adau1361 == NULL)
+		return -ENOMEM;
+	codec = &adau1361->codec;
+	codec->private_data = adau1361;
+	codec->hw_write = (hw_write_t)i2c_master_send;
+
+	i2c_set_clientdata(i2c, adau1361);
+	codec->control_data = i2c;
+
+	codec->dev = &i2c->dev;
+	adau1361_codec = codec;
+
+	INIT_WORK(&adau1361->resume_work, adau1361_resume_wq_handler);
+	ret = adau1361_register(adau1361, SND_SOC_I2C);
+	if (ret < 0)
+		dev_err(&i2c->dev, "failed to initialize\n");
+
+	return ret;
+}
+
+static __devexit int adau1361_i2c_remove(struct i2c_client *client)
+{
+	struct adau1361_priv *adau1361 = i2c_get_clientdata(client);
+	adau1361_unregister(adau1361);
+	return 0;
+}
+
+static const struct i2c_device_id adau1361_i2c_id[] = {
+	{ "adau1361", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, adau1361_i2c_id);
+
+/* corgi i2c codec control layer */
+static struct i2c_driver adau1361_i2c_driver = {
+	.driver = {
+		.name = "adau1361",
+		.owner = THIS_MODULE,
+	},
+	.probe    = adau1361_i2c_probe,
+	.remove   = __devexit_p(adau1361_i2c_remove),
+	.id_table = adau1361_i2c_id,
+};
+
+static int __init adau1361_modinit(void)
+{
+	int ret;
+
+	ret = i2c_add_driver(&adau1361_i2c_driver);
+	if (ret != 0) {
+		printk(KERN_ERR "Failed to register adau1361 I2C driver: %d\n",
+		       ret);
+	}
+
+	return ret;
+}
+module_init(adau1361_modinit);
+
+static void __exit adau1361_exit(void)
+{
+	i2c_del_driver(&adau1361_i2c_driver);
+}
+module_exit(adau1361_exit);
+
+MODULE_DESCRIPTION("ASoC ADAU1361 driver");
+MODULE_AUTHOR("Cliff Cai");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/adau1361.h b/sound/soc/codecs/adau1361.h
new file mode 100644
index 0000000..79cf576
--- /dev/null
+++ b/sound/soc/codecs/adau1361.h
@@ -0,0 +1,264 @@
+/*
+ * header file fortone adau1361 sound chip
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+
+#ifndef __ADAU1361_H__
+#define __ADAU1361_H__
+
+struct adau1361_setup_data {
+	unsigned short i2c_bus;
+	unsigned short i2c_address;
+};
+
+struct adau1361_mode_register {
+	u16  regaddress;
+	u16  regvalue;
+};
+
+#define RESET_REGISTER_COUNT 42
+#define MODE_REGISTER_COUNT 8
+
+#define MASTER_MODE 1
+#ifdef MASTER_MODE
+/* IIS mater mode*/
+#define ADAU_SRPT_CTRL0		0x01
+#else
+/* IIS slave mode*/
+#define ADAU_SRPT_CTRL0		0x00
+#endif
+
+/* adau1361_set_dai_sysclk clk_id */
+#define ADAU1361_MCLK_ID	0
+#define ADAU1361_BCLK_ID	0x33
+
+#define ADAU1361_MCLK_RATE	12288000
+
+#define ADAU1361_PLL_FREQ_441	45158400
+#define ADAU1361_PLL_FREQ_48	49152000
+
+
+/* ADAU1361 control registers */
+#define ADAU_FIRSTREG	0x4000
+
+#define ADAU_CLKCTRL	0x4000
+#define ADAU_PLLCTRL	0x4002
+#define ADAU_MICCTRL	0x4008
+#define ADAU_RECPWRM	0x4009
+#define ADAU_RECMLC0	0x400A
+#define ADAU_RECMLC1	0x400B
+#define ADAU_RECMRC0	0x400C
+#define ADAU_RECMRC1	0x400D
+#define ADAU_RECVLCL	0x400E
+#define ADAU_RECVLCR	0x400F
+
+#define ADAU_RECMBIA	0x4010
+#define ADAU_ALCCTR0	0x4011
+#define ADAU_ALCCTR1	0x4012
+#define ADAU_ALCCTR2	0x4013
+#define ADAU_ALCCTR3	0x4014
+#define ADAU_SPRTCT0	0x4015
+#define ADAU_SPRTCT1	0x4016
+#define ADAU_CONVCT0	0x4017
+#define ADAU_CONVCT1	0x4018
+#define ADAU_ADCCTL0	0x4019
+#define ADAU_ADCCTL1	0x401A
+#define ADAU_ADCCTL2	0x401B
+#define ADAU_PLBMLC0	0x401C
+#define ADAU_PLBMLC1	0x401D
+#define ADAU_PLBMRC0	0x401E
+#define ADAU_PLBMRC1	0x401F
+
+#define ADAU_PLBMLLO	0x4020
+#define ADAU_PLBMRLO	0x4021
+#define ADAU_PLBLRMC	0x4022
+#define ADAU_PLBHPVL	0x4023
+#define ADAU_PLBHPVR	0x4024
+#define ADAU_PLBLOVL	0x4025
+#define ADAU_PLBLOVR	0x4026
+#define ADAU_PLBMNOC	0x4027
+#define ADAU_PLBCTRL	0x4028
+#define ADAU_PLBPWRM	0x4029
+
+#define ADAU_DACCTL0	0x402A
+#define ADAU_DACCTL1	0x402B
+#define ADAU_DACCTL2	0x402C
+#define ADAU_SERPAD0	0x402D
+#define ADAU_COMPAD0	0x402F
+#define ADAU_COMPAD1	0x4030
+#define ADAU_MCLKPAD	0x4031
+
+#define ADAU_LASTREG	0x4031
+
+#define ADAU_NUMCACHEREG	44
+
+/* Register field definitions */
+/* Clock Control */
+#define CLKCTRL_SRC_MCLK	0x0
+#define CLKCTRL_SRC_PLL		0x8
+#define CLKCTRL_FRQ_256		0x0
+#define CLKCTRL_FRQ_512		0x2
+#define CLKCTRL_FRQ_768		0x4
+#define CLKCTRL_FRQ_1024	0x6
+#define CLKCTRL_DISABLE		0x0
+#define CLKCTRL_ENABLE		0x1
+
+/* PLL Control -- 6 bytes*/
+/*Bytes 5-6*/
+#define PLLCTRL_DEN_MSB		0x00
+#define PLLCTRL_DEN_LSB		0x00
+/*Bytes 3-4*/
+#define PLLCTRL_NUM_MSB		0x00
+#define PLLCTRL_NUM_LSB		0x00
+/*Byte 2*/
+#define PLLCTRL_INTPART_R2	0x10
+#define PLLCTRL_INTPART_R3	0x18
+#define PLLCTRL_INTPART_R4	0x20
+#define PLLCTRL_INTPART_R5	0x28
+#define PLLCTRL_INTPART_R6	0x30
+#define PLLCTRL_INTPART_R7	0x38
+#define PLLCTRL_INTPART_R8	0x40
+#define PLLCTRL_INPUT_DIV1	0x00
+#define PLLCTRL_INPUT_DIV2	0x02
+#define PLLCTRL_INPUT_DIV3	0x04
+#define PLLCTRL_INPUT_DIV4	0x06
+#define PLLCTRL_TYPE_INT	0x0
+#define PLLCTRL_TYPE_FRAC	0x1
+/*Byte 1*/
+#define PLLCTRL_DISABLE		0x0
+#define PLLCTRL_ENABLE		0x1
+
+/*ADC*/
+#define ADCCTL_DISABLE_MASK	0xFC
+#define ADCCTL_ENABLE_MASK	0x03
+
+/*MIC*/
+#define RECMBIA_DISABLE		0x00
+#define RECMBIA_ENABLE		0x01
+#define RECVLC_DISABLE_MASK	0xFC
+#define RECVLC_ENABLE_MASK	0x03
+
+#define RECMLC_MIC_0DB		0x08
+#define RECMLC_MIC_20DB		0x10
+#define RECMLC_LINE_0DB		0x05
+
+/* PWN MNGMNT */
+#define RECPWRM_LOW_PWR		0x0E
+#define PLBPWRM_LOW_PWR		0x5C
+#define PLBCTRL_POP_LPWR	0x10
+#define PLBCTRL_POP_OFF		0x06
+#define PLBCTRL_POP_ON		0x00
+#define RECPWRM_RUN_PWR		0x00
+#define PLBPWRM_RUN_PWR		0x03
+#define DAPM_LINE_DEF		0xE6
+#define DAPM_HP_DEF		0xE7
+#define PLB_MUTE_MASK		0x03
+
+#define ADAU1361_BITSFRAM_32	0x4000
+#define ADAU1361_BITSFRAM_48	0x8000
+
+/*playback output control*/
+#define ADAU1361_VOLUME_MASK 0xFC
+#define ADAU1361_VOLUME_BITS 0x2
+#define ADAU1361_MUTE_MASK 0x02
+#define ADAU1361_MUTE_BITS 0x1
+#define ADAU1361_ADVOL_MASK 0xff
+
+/*
+ * Reset Mode - ADC capture/DAC playback
+ * (AInput mixers 0db, AOuput mixers 0db, HP out ON)
+*/
+static struct adau1361_mode_register adau1361_reset[RESET_REGISTER_COUNT] = {
+	/* mute outputs */
+	{ADAU_PLBMNOC, 0xE5},
+	{ADAU_PLBHPVL, 0x01},
+	{ADAU_PLBHPVR, 0x01},
+	{ADAU_PLBLOVL, 0x00},
+	{ADAU_PLBLOVR, 0x00},
+	{ADAU_MICCTRL, 0x00},
+	{ADAU_RECPWRM, 0x00},
+	{ADAU_RECMLC0, 0x01},
+	{ADAU_RECMLC1, RECMLC_MIC_0DB},
+	{ADAU_RECMRC0, 0x01},
+	{ADAU_RECMRC1, RECMLC_MIC_0DB},
+	{ADAU_RECVLCL, 0x82},
+	{ADAU_RECVLCR, 0x82},
+	{ADAU_RECMBIA, RECMBIA_DISABLE},
+	{ADAU_ALCCTR0, 0x00},
+	{ADAU_ALCCTR1, 0x00},
+	{ADAU_ALCCTR2, 0x00},
+	{ADAU_ALCCTR3, 0x1F},
+	{ADAU_SPRTCT0, ADAU_SRPT_CTRL0},
+	{ADAU_SPRTCT1, 0x01}, /* 0x01 = 64bclocks frame */
+	{ADAU_CONVCT0, 0x00},
+	{ADAU_CONVCT1, 0x00},
+	{ADAU_ADCCTL0, 0x00},
+	{ADAU_ADCCTL1, 0x00},
+	{ADAU_ADCCTL2, 0x00},
+	{ADAU_PLBMLC0, 0x21},
+	{ADAU_PLBMLC1, 0x00},
+	{ADAU_PLBMRC0, 0x41},
+	{ADAU_PLBMRC1, 0x00},
+	{ADAU_PLBMLLO, 0x03},
+	{ADAU_PLBMRLO, 0x09},
+	{ADAU_PLBLRMC, 0x01},
+	{ADAU_PLBCTRL, 0x00},
+	{ADAU_PLBPWRM, 0x00},
+	{ADAU_DACCTL0, 0x03},
+	{ADAU_DACCTL1, 0x00},
+	{ADAU_DACCTL2, 0x00},
+	{ADAU_SERPAD0, 0xAA},
+	{ADAU_COMPAD0, 0xAA},
+	{ADAU_COMPAD1, 0x00},
+	{ADAU_MCLKPAD, 0x0A},
+};
+
+/*
+ * Default Mode
+ * Analog microphones, ADC capture/DAC playback
+ * (AInput mixers ON, AOuput mixers ON, HP out ON)
+*/
+static struct adau1361_mode_register adau1361_mode0[MODE_REGISTER_COUNT] = {
+	/* mute outputs */
+	{ADAU_PLBHPVL, 0x03},
+	{ADAU_PLBHPVR, 0x03},
+	{ADAU_PLBLOVL, 0x02},
+	{ADAU_PLBLOVR, 0x02},
+	{ADAU_PLBMNOC, 0xE5},
+	/*analog mic*/
+	{ADAU_RECVLCL, 0x42},
+	{ADAU_RECVLCR, 0x42},
+	{ADAU_MICCTRL, 0x00},
+};
+
+/*
+ * Digital Microphone mode,
+ * IIS Master, ADC capture/DAC playback
+ * (AInput mixers OFF, AOuput mixers ON, HP out ON)
+ */
+static struct adau1361_mode_register adau1361_mode1[MODE_REGISTER_COUNT] = {
+	/* mute outputs */
+	{ADAU_PLBHPVL, 0x03},
+	{ADAU_PLBHPVR, 0x03},
+	{ADAU_PLBLOVL, 0x02},
+	{ADAU_PLBLOVR, 0x02},
+	{ADAU_PLBMNOC, 0xE5},
+	/*digital mic*/
+	{ADAU_RECVLCL, 0x00},
+	{ADAU_RECVLCR, 0x00},
+	{ADAU_MICCTRL, 0x20},
+};
+
+static struct adau1361_mode_register *adau1361_mode_registers[] = {
+	adau1361_mode0,
+	adau1361_mode1,
+};
+
+extern struct snd_soc_dai adau1361_dai;
+extern struct snd_soc_codec_device soc_codec_dev_adau1361;
+
+#endif
-- 
1.7.2

             reply	other threads:[~2010-08-07 20:28 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-08-07 20:28 Mike Frysinger [this message]
     [not found] ` <1281212905-12957-1-git-send-email-vapier-aBrp7R+bbdUdnm+yROfE0A@public.gmane.org>
2010-08-07 20:28   ` [PATCH 2/6] ASoC: Blackfin: new machine driver for ADAU1361 codecs Mike Frysinger
2010-08-07 21:08     ` Mark Brown
2010-08-07 21:14       ` [Uclinux-dist-devel] " Mike Frysinger
2010-08-07 22:29         ` Mark Brown
2010-08-07 22:31           ` Mike Frysinger
2010-08-07 20:28   ` [PATCH 5/6] ASoC: new ADAU1761 codec driver Mike Frysinger
2010-08-07 22:16     ` Mark Brown
2010-08-07 22:29       ` [Uclinux-dist-devel] " Mike Frysinger
2010-08-07 22:36         ` Mark Brown
2010-08-07 22:41           ` Mike Frysinger
2010-08-07 23:10             ` Mark Brown
2010-08-07 20:28   ` [PATCH 6/6] ASoC: Blackfin: new machine driver for ADAU1761 codecs Mike Frysinger
2010-08-07 20:28 ` [PATCH 3/6] ASoC: new ADAU1381 codec driver Mike Frysinger
2010-08-07 21:43   ` Mark Brown
2010-08-07 20:28 ` [PATCH 4/6] ASoC: Blackfin: new machine driver for ADAU1381 codecs Mike Frysinger
2010-08-07 21:20 ` [PATCH 1/6] ASoC: add ADAU1361 codec driver Liam Girdwood
2010-08-07 22:06 ` Mark Brown

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1281212905-12957-1-git-send-email-vapier@gentoo.org \
    --to=vapier-abrp7r+bbdudnm+yrofe0a@public.gmane.org \
    --cc=alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw@public.gmane.org \
    --cc=broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E@public.gmane.org \
    --cc=cliff.cai-OyLXuOCK7orQT0dZR+AlfA@public.gmane.org \
    --cc=uclinux-dist-devel-ZG0+EudsQA8dtHy/vicBwGD2FQJk+8+b@public.gmane.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.