diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig
index 31f52d3..f26a1bd 100644
--- a/sound/pci/Kconfig
+++ b/sound/pci/Kconfig
@@ -581,6 +581,14 @@ config SND_HDA_CODEC_SI3054
 	  Say Y here to include Silicon Labs 3054 HD-modem codec
 	  (and compatibles) support in snd-hda-intel driver.
 
+config SND_HDA_CODEC_CIRRUS
+	bool "Build Cirrus Logic HD-audio codec support"
+	depends on SND_HDA_INTEL
+	default y
+	help
+	  Say Y here to include Cirrus Logic 4207 HD-audio codec
+	  (and compatibles) support in snd-hda-intel driver.
+
 config SND_HDA_GENERIC
 	bool "Enable generic HD-audio codec parser"
 	depends on SND_HDA_INTEL
diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile
index ab0c726..bdd7bf3 100644
--- a/sound/pci/hda/Makefile
+++ b/sound/pci/hda/Makefile
@@ -14,5 +14,6 @@ snd-hda-intel-$(CONFIG_SND_HDA_CODEC_SI3054) += patch_si3054.o
 snd-hda-intel-$(CONFIG_SND_HDA_CODEC_ATIHDMI) += patch_atihdmi.o
 snd-hda-intel-$(CONFIG_SND_HDA_CODEC_CONEXANT) += patch_conexant.o
 snd-hda-intel-$(CONFIG_SND_HDA_CODEC_VIA) += patch_via.o
+snd-hda-intel-$(CONFIG_SND_HDA_CODEC_CIRRUS) += patch_cirrus.o
 
 obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-intel.o
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index d2e1093..dc88293 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -66,6 +66,7 @@ static struct hda_vendor_id hda_vendor_ids[] = {
 	{ 0x1854, "LG" },
 	{ 0x434d, "C-Media" },
 	{ 0x8384, "SigmaTel" },
+	{ 0x1013, "Cirrus Logic" },
 	{} /* terminator */
 };
 
@@ -94,6 +95,9 @@ static const struct hda_codec_preset *hda_preset_tables[] = {
 #ifdef CONFIG_SND_HDA_CODEC_VIA
 	snd_hda_preset_via,
 #endif
+#ifdef CONFIG_SND_HDA_CODEC_CIRRUS
+	snd_hda_preset_cirrus,
+#endif
 	NULL
 };
 
diff --git a/sound/pci/hda/hda_patch.h b/sound/pci/hda/hda_patch.h
index 2fdf235..3b786e6 100644
--- a/sound/pci/hda/hda_patch.h
+++ b/sound/pci/hda/hda_patch.h
@@ -18,3 +18,5 @@ extern struct hda_codec_preset snd_hda_preset_atihdmi[];
 extern struct hda_codec_preset snd_hda_preset_conexant[];
 /* VIA codecs */
 extern struct hda_codec_preset snd_hda_preset_via[];
+/* Cirrus Logic codecs */
+extern struct hda_codec_preset snd_hda_preset_cirrus[];
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
new file mode 100644
index 0000000..fe920f9
--- /dev/null
+++ b/sound/pci/hda/patch_cirrus.c
@@ -0,0 +1,668 @@
+/*
+ * Universal Interface for Intel High Definition Audio Codec
+ *
+ * HD audio interface patch for Cirrus Logic HD-audio codecs
+ *
+ * Copyright (c) 2008 Cirrus Logic Inc.
+ *
+ *
+ *  This driver is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This driver is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include "hda_codec.h"
+#include "hda_local.h"
+#include "hda_patch.h"
+
+/* Vendor Processing Widget */
+#define CS4207_VENDOR_NID	0x11
+
+/* Index registers */
+#define IDX_SPDIF_STAT		0x0000
+#define IDX_SPDIF_CTL		0x0001
+#define IDX_ADC_CFG		0x0002
+#define IDX_DAC_CFG		0x0003
+#define IDX_BEEP_CFG		0x0004
+/* 0x0008 - test reg key */
+/* 0x0009 - 0x0014 -> 12 test regs */
+/* 0x0015 - visibility reg */
+
+/* Unsolicitated Events */
+#define CS4207_HP_EVENT		0x01 /* NID 0x09 */
+#define CS4207_LINEOUT_EVENT	0x02 /* NID 0x0A */
+#define CS4207_LINEIN_EVENT	0x04 /* NID 0x0C */
+#define CS4207_MIC_EVENT	0x08 /* NID 0x0D */
+#define CS4207_SPDIFIN_EVENT	0x10 /* NID 0x0F */
+
+#define SPDIF_OUT1 0 /* NID 0x08 -> 0x10 */
+#define SPDIF_OUT2 1 /* NID 0x14 -> 0x15 */
+
+struct cs4207_spec {
+	struct hda_multi_out multiout;
+	struct hda_pcm pcm_rec[2];
+	
+	hda_nid_t *adc_nids;
+	int num_adcs;
+	hda_nid_t *dac_nids;
+	int num_dacs;
+
+	hda_nid_t dig_in_nid;
+	int hp_present;
+	/* capture sources */
+	unsigned int num_mux_defs;
+	const struct hda_input_mux *input_mux;
+	int cur_mux[2];
+};
+
+static struct hda_verb cs4207_basic_init[] = {
+	/* ADC1 - Line In (0x0C) */
+	{0x05, AC_VERB_SET_CONNECT_SEL, 0},
+	/* ADC2 - Mic In (0x0D) */
+	{0x06, AC_VERB_SET_CONNECT_SEL, 0},
+	/* Disable AUTOINC */
+	{0x11, AC_VERB_SET_PROC_STATE, 1},
+	{0x11, AC_VERB_SET_COEF_INDEX, IDX_DAC_CFG},
+	{0x11, AC_VERB_SET_PROC_COEF, 0x146A},
+
+	/* enable unsolicited event */
+	{0x09, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CS4207_HP_EVENT},
+
+	/* Disable SPDIF2 */
+	{0x14, AC_VERB_SET_DIGI_CONVERT_1, 0},
+	
+	{} /* terminator */
+};
+
+static hda_nid_t cs4207_dac_nids[] = { 0x02, 0x03, 0x04 };
+static hda_nid_t cs4207_adc_nids[] = { 0x05, 0x06 };
+static hda_nid_t cs4207_dig_out_nids[] = { 0x08, 0x14 };
+static int cs4207_default_spdif_out = SPDIF_OUT1;
+
+/*
+    Coefficient get/set functions - Vendor widget (0x11) 
+*/
+int cs4207_coef_get(struct hda_codec* codec, hda_nid_t nid, u16 index)
+{
+    /* set coeff index */
+    snd_hda_codec_write(codec, nid, 0,  AC_VERB_SET_COEF_INDEX, 
+			    (index & 0x1f));
+    /* read coeff */
+    return  snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PROC_COEF, 0) & 0xffff;
+}
+
+void cs4207_coef_set(struct hda_codec* codec, hda_nid_t nid, u16 index, u16 coeff)
+{
+    /* set coeff index */
+    snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX, 
+			    (index & 0x1f));
+    /* write coeff */
+    snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PROC_COEF, coeff);
+}
+
+
+/*
+ * Input selection
+ */
+static struct hda_input_mux cs4207_analog_capture_source = { 
+        .num_items = 2, 
+        .items = { 
+                { "Analog In", 0 },  /* ADC1-0x0C, ADC2-0x0D */
+                { "Digital Mic", 1 }, /* ADC1-0x12, ADC2-0x0E */
+        }, 
+};
+
+static int cs4207_mux_enum_info(struct snd_kcontrol *kcontrol, 
+                             struct snd_ctl_elem_info *uinfo) 
+{ 
+        struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 
+        struct cs4207_spec *spec = codec->spec; 
+        return snd_hda_input_mux_info(spec->input_mux, uinfo); 
+} 
+ 
+static int cs4207_mux_enum_get(struct snd_kcontrol *kcontrol, 
+                            struct snd_ctl_elem_value *ucontrol) 
+{ 
+        struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 
+        struct cs4207_spec *spec = codec->spec; 
+        unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 
+ 
+        ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx]; 
+        return 0; 
+} 
+ 
+static int cs4207_mux_enum_put(struct snd_kcontrol *kcontrol, 
+                            struct snd_ctl_elem_value *ucontrol) 
+{
+        struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 
+        struct cs4207_spec *spec = codec->spec; 
+        unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 
+
+        return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, 
+                        spec->adc_nids[adc_idx], &spec->cur_mux[adc_idx]); 
+}
+
+
+/*
+    Enumerated kcontrol.
+    Cirrus vendor processing widget (0x11) coefficients manipulation
+*/
+struct cs4207_enum {
+        unsigned short nid;
+        unsigned short index;
+        unsigned char shift;
+        unsigned int mask;
+        const char **texts;
+};
+
+int cs4207_index_enum_info(struct snd_kcontrol *kcontrol, 
+        struct snd_ctl_elem_info *uinfo) 
+{ 
+        struct cs4207_enum *e = (struct cs4207_enum *)kcontrol->private_value; 
+ 
+        uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 
+        uinfo->count = 1; 
+        uinfo->value.enumerated.items = e->mask; 
+ 
+        if (uinfo->value.enumerated.item > e->mask - 1) 
+                uinfo->value.enumerated.item = e->mask - 1; 
+        strcpy(uinfo->value.enumerated.name, 
+                e->texts[uinfo->value.enumerated.item]); 
+        return 0; 
+} 
+
+int cs4207_index_enum_get(struct snd_kcontrol *kcontrol, 
+        struct snd_ctl_elem_value *ucontrol) 
+{ 
+        struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 
+        struct cs4207_enum *e = (struct cs4207_enum *)kcontrol->private_value; 
+        unsigned short val, bitmask; 
+
+        for (bitmask = 1; bitmask < e->mask; bitmask <<= 1) ;
+
+        val = cs4207_coef_get(codec, e->nid, e->index);
+        ucontrol->value.enumerated.item[0] = (val >> e->shift) & (bitmask - 1); 
+ 
+        return 0; 
+} 
+
+int cs4207_index_enum_put(struct snd_kcontrol *kcontrol, 
+        struct snd_ctl_elem_value *ucontrol) 
+{ 
+        struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 
+        struct cs4207_enum *e = (struct cs4207_enum *)kcontrol->private_value; 
+        unsigned short val, coeff; 
+        unsigned short mask, bitmask; 
+
+        for (bitmask = 1; bitmask < e->mask; bitmask <<= 1);
+
+        if (ucontrol->value.enumerated.item[0] > e->mask - 1) 
+                return -EINVAL; 
+        val = ucontrol->value.enumerated.item[0] << e->shift;
+        mask = (bitmask - 1) << e->shift;
+
+	coeff = cs4207_coef_get(codec, e->nid, e->index);
+	coeff &= ~mask;
+	coeff |= (val & mask);
+	cs4207_coef_set(codec, e->nid, e->index, coeff);
+
+        return 0;
+} 
+
+
+#define CS4207_ENUM_SINGLE(xnid, xindex, xshift, xmask, xtexts) \
+{       .nid = xnid, .index = xindex, .shift = xshift,  \
+        .mask = xmask, .texts = xtexts }
+
+#define CS4207_ENUM(xname, xenum) \
+{       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,\
+        .info = cs4207_index_enum_info, \
+        .get = cs4207_index_enum_get, \
+	.put = cs4207_index_enum_put, \
+        .private_value = (unsigned long)&xenum \
+}
+
+static const char *cs4207_dac_szcmode[] = 
+	{"Immediate", "Zero Cross", "Soft Ramp", "Soft Ramp on Zero Cross"};
+static const char *cs4207_adc_szcmode[] = 
+	{"Immediate", "Digital Immediate, Analog Zero Cross", 
+	"Digital and Analog Soft Ramp", "Digital Soft Ramp, Analog Zero Cross"};
+static const char *cs4207_adc_pgamode[] = 
+	{"Differential", "Single-ended"};
+
+static const struct cs4207_enum cs4207_e[] = {
+/*0*/	CS4207_ENUM_SINGLE(CS4207_VENDOR_NID, IDX_DAC_CFG, 0, 4, cs4207_dac_szcmode), 
+	CS4207_ENUM_SINGLE(CS4207_VENDOR_NID, IDX_DAC_CFG, 2, 4, cs4207_dac_szcmode), 
+	CS4207_ENUM_SINGLE(CS4207_VENDOR_NID, IDX_DAC_CFG, 4, 4, cs4207_dac_szcmode), 
+	CS4207_ENUM_SINGLE(CS4207_VENDOR_NID, IDX_ADC_CFG, 0, 4, cs4207_adc_szcmode), 
+/*4*/	CS4207_ENUM_SINGLE(CS4207_VENDOR_NID, IDX_ADC_CFG, 2, 4, cs4207_adc_szcmode), 
+	CS4207_ENUM_SINGLE(CS4207_VENDOR_NID, IDX_ADC_CFG, 5, 2, cs4207_adc_pgamode), 
+	CS4207_ENUM_SINGLE(CS4207_VENDOR_NID, IDX_ADC_CFG, 6, 2, cs4207_adc_pgamode), 
+};
+
+
+static struct snd_kcontrol_new cs4207_mixer[] = { 
+        /* Output controls */ 
+        HDA_CODEC_VOLUME("Headphone Playback Volume", 0x02, 0x0, HDA_OUTPUT), 
+        HDA_CODEC_MUTE("Headphone Playback Switch", 0x02, 0x0, HDA_OUTPUT), 
+        HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x03, 0x0, HDA_OUTPUT), 
+        HDA_CODEC_MUTE("Line-Out Playback Switch", 0x03, 0x0, HDA_OUTPUT), 
+        HDA_CODEC_VOLUME("Speakers Playback Volume", 0x04, 0x0, HDA_OUTPUT), 
+        HDA_CODEC_MUTE("Speakers Playback Switch", 0x04, 0x0, HDA_OUTPUT), 
+
+	/* Input Controls */
+        HDA_CODEC_VOLUME("Mic Capture Volume", 0x06, 0, HDA_INPUT), 
+        HDA_CODEC_MUTE("Mic Capture Switch", 0x06, 0, HDA_INPUT), 
+        HDA_CODEC_VOLUME("Line Capture Volume", 0x05, 0, HDA_INPUT), 
+        HDA_CODEC_MUTE("Line Capture Switch", 0x05, 0, HDA_INPUT), 
+
+	/* Input Gain - 0,+10, +20 dB */
+	/*    Mute is ignored */
+        HDA_CODEC_VOLUME("Mic Input Capture Volume", 0x0D, 0, HDA_INPUT), 
+        HDA_CODEC_VOLUME("Line Input Capture Volume", 0x0C, 0, HDA_INPUT), 
+        HDA_CODEC_VOLUME("Digital Input 1 Capture Volume", 0x0E, 0, HDA_INPUT), 
+	/*
+	    Sets the soft ramp and
+	    zero crossing detection modes by which volume
+	    and muting changes will be implemented
+	*/
+	CS4207_ENUM("Headphone SZCMode Playback Switch", cs4207_e[0]),
+	CS4207_ENUM("Line-Out SZCMode Playback Switch", cs4207_e[1]),
+	CS4207_ENUM("Speakers SZCMode Playback Switch", cs4207_e[2]),
+	/*	
+	    Sets the mode by which
+	    analog PGA and digital volume, and muting
+	    changes will be implemented.
+	*/
+	CS4207_ENUM("Mic SZCMode Capture Switch", cs4207_e[3]),
+	CS4207_ENUM("Line-In SZCMode Capture Switch", cs4207_e[4]),
+	/*
+	    Sets the topology for the Line In, Mic In PGA
+	*/
+	CS4207_ENUM("Mic PGA Mode Capture Switch", cs4207_e[5]),
+	CS4207_ENUM("Line-In PGA Mode Capture Switch", cs4207_e[6]),
+
+        { } /* end */ 
+}; 
+
+
+/* SPDIF_TX2 - disabled/DMIC2 enabled - add DMIC2 widgets */
+static struct snd_kcontrol_new cs4207_mixer_dmic2[] = { 
+        HDA_CODEC_VOLUME("Digital Input 2 Capture Volume", 0x12, 0, HDA_INPUT), 
+        { 
+                .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 
+                .name = "Capture Source", 
+                .count = 2,
+                .info = cs4207_mux_enum_info, 
+                .get = cs4207_mux_enum_get, 
+                .put = cs4207_mux_enum_put, 
+        }, {}
+};
+
+/* SPDIF_TX2 - enabled/DMIC2 disabled */
+static struct snd_kcontrol_new cs4207_mixer_nodmic2[] = { 
+        { 
+                .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 
+                .name = "Capture Source", 
+                .count = 1,  
+                .info = cs4207_mux_enum_info, 
+                .get = cs4207_mux_enum_get, 
+                .put = cs4207_mux_enum_put, 
+        },{} 
+};
+
+/*
+ * Controls
+ */
+static int cs4207_build_controls(struct hda_codec *codec)
+{
+	struct cs4207_spec *spec = codec->spec;
+	int err;
+
+        err = snd_hda_add_new_ctls(codec, cs4207_mixer); 
+        if (err < 0) 
+                return err; 
+
+	/* Add DMIC2 widgets */
+	if (cs4207_default_spdif_out == SPDIF_OUT1) {
+    	    err = snd_hda_add_new_ctls(codec, cs4207_mixer_dmic2); 
+    	    if (err < 0) 
+                return err; 
+	} else  { /* SPDIF_OUT2 */
+    	    err = snd_hda_add_new_ctls(codec, cs4207_mixer_nodmic2); 
+    	    if (err < 0) 
+                return err; 
+
+	}
+
+        if (spec->multiout.dig_out_nid) {
+                err = snd_hda_create_spdif_out_ctls(codec,
+						spec->multiout.dig_out_nid);
+                if (err < 0)
+                        return err; 
+
+                err = snd_hda_create_spdif_share_sw(codec,
+                                                    &spec->multiout);
+                if (err < 0)
+                        return err;
+                spec->multiout.share_spdif = 1;
+
+        }
+        if (spec->dig_in_nid) {
+                err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); 
+                if (err < 0) 
+                        return err; 
+        }
+
+	return 0;
+}
+
+
+/* 
+ * Analog playback callbacks 
+ */ 
+static int cs4207_playback_pcm_open(struct hda_pcm_stream *hinfo, 
+                                     struct hda_codec *codec, 
+                                     struct snd_pcm_substream *substream) 
+{ 
+        struct cs4207_spec *spec = codec->spec; 
+        return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, 
+                                             hinfo); 
+} 
+ 
+static int cs4207_playback_pcm_prepare(struct hda_pcm_stream *hinfo, 
+                                        struct hda_codec *codec, 
+                                        unsigned int stream_tag, 
+                                        unsigned int format, 
+                                        struct snd_pcm_substream *substream) 
+{ 
+        struct cs4207_spec *spec = codec->spec; 
+        return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, 
+                                                format, substream); 
+} 
+ 
+static int cs4207_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, 
+                                       struct hda_codec *codec, 
+                                       struct snd_pcm_substream *substream) 
+{ 
+        struct cs4207_spec *spec = codec->spec; 
+        return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); 
+} 
+
+/* 
+ * Analog capture 
+ */ 
+static int cs4207_capture_pcm_prepare(struct hda_pcm_stream *hinfo, 
+                                      struct hda_codec *codec, 
+                                      unsigned int stream_tag, 
+                                      unsigned int format, 
+                                      struct snd_pcm_substream *substream) 
+{ 
+        struct cs4207_spec *spec = codec->spec; 
+ 
+        snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], 
+                                   stream_tag, 0, format); 
+        return 0; 
+} 
+ 
+static int cs4207_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, 
+                                      struct hda_codec *codec, 
+                                      struct snd_pcm_substream *substream) 
+{ 
+        struct cs4207_spec *spec = codec->spec; 
+ 
+        snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]); 
+        return 0; 
+} 
+
+
+
+/*
+ * Digital playback
+ */
+static int cs4207_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
+				     struct hda_codec *codec,
+				     struct snd_pcm_substream *substream)
+{
+	struct cs4207_spec *spec = codec->spec;
+	return snd_hda_multi_out_dig_open(codec, &spec->multiout);
+}
+
+static int cs4207_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
+				      struct hda_codec *codec,
+				      struct snd_pcm_substream *substream)
+{
+	struct cs4207_spec *spec = codec->spec;
+	return snd_hda_multi_out_dig_close(codec, &spec->multiout);
+}
+
+static int cs4207_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
+					    struct hda_codec *codec,
+					    unsigned int stream_tag,
+					    unsigned int format,
+					    struct snd_pcm_substream *substream)
+{
+	struct cs4207_spec *spec = codec->spec;
+	return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag,
+					     format, substream);
+}
+
+static struct hda_pcm_stream cs4207_pcm_analog_playback = { 
+        .substreams = 1, 
+        .channels_min = 2, 
+        .channels_max = 6, 
+        .nid = 0x03, /* NID to query formats and rates */ 
+        .ops = { 
+                .open = cs4207_playback_pcm_open, 
+                .prepare = cs4207_playback_pcm_prepare, 
+                .cleanup = cs4207_playback_pcm_cleanup 
+        }, 
+}; 
+ 
+static struct hda_pcm_stream cs4207_pcm_analog_capture = { 
+        .substreams = 2, 
+        .channels_min = 2, 
+        .channels_max = 4, 
+        .nid = 0x05, /* NID to query formats and rates */ 
+        .ops = { 
+                .prepare = cs4207_capture_pcm_prepare, 
+                .cleanup = cs4207_capture_pcm_cleanup 
+        }, 
+}; 
+
+
+static struct hda_pcm_stream cs4207_pcm_digital_playback = {
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 6,
+	.nid = 0x3, /* NID to query formats and rates and setup streams */
+	.ops = {
+		.open = cs4207_dig_playback_pcm_open,
+		.close = cs4207_dig_playback_pcm_close,
+		.prepare = cs4207_dig_playback_pcm_prepare
+	},
+};
+
+static struct hda_pcm_stream cs4207_pcm_digital_capture = { 
+        .substreams = 1, 
+        .channels_min = 2, 
+        .channels_max = 2, 
+	.nid = 0x05 /* ? */
+}; 
+
+
+static int cs4207_build_pcms(struct hda_codec *codec)
+{
+	struct cs4207_spec *spec = codec->spec;
+	struct hda_pcm *info = spec->pcm_rec;
+
+	codec->num_pcms = 1;
+	codec->pcm_info = info;
+
+        info->name = "CS4207 Analog";
+        info->stream[SNDRV_PCM_STREAM_PLAYBACK] = cs4207_pcm_analog_playback;
+        info->stream[SNDRV_PCM_STREAM_CAPTURE] = cs4207_pcm_analog_capture;
+        info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; 
+        info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adcs; 
+
+        if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
+                codec->num_pcms++;
+                info++;
+                info->name = "CS4207 Digital";
+                info->pcm_type = HDA_PCM_TYPE_SPDIF;
+                if (spec->multiout.dig_out_nid) {
+                        info->stream[SNDRV_PCM_STREAM_PLAYBACK] = cs4207_pcm_digital_playback;
+                        info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
+                }
+                if (spec->dig_in_nid) {
+                        info->stream[SNDRV_PCM_STREAM_CAPTURE] = cs4207_pcm_digital_capture;
+                        info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
+                }
+        }
+
+	return 0;
+}
+
+/* mute internal speaker if HP is plugged */ 
+static void cs4207_automute(struct hda_codec *codec)
+{
+        struct cs4207_spec *spec = codec->spec;
+        unsigned int bits;
+
+        spec->hp_present = snd_hda_codec_read(codec, 0x09, 0,
+                                 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+
+        bits = (spec->hp_present) ? HDA_AMP_MUTE : 0;
+	/* Mute Speakers (DAC3) */
+        snd_hda_codec_amp_stereo(codec, 0x04, HDA_OUTPUT, 0,
+                                 HDA_AMP_MUTE, bits);
+}
+
+/* Unsolicited events for jack sensing - remove ?*/
+static void cs4207_unsol_event(struct hda_codec *codec,
+                                   unsigned int res)
+{
+        res >>= 26;
+        switch (res) {
+    	    case CS4207_HP_EVENT:
+                cs4207_automute(codec);
+                break;
+	    /* Do something on these events ? */
+    	    case CS4207_LINEIN_EVENT:
+	    case CS4207_SPDIFIN_EVENT:
+	    case CS4207_MIC_EVENT:
+	    case CS4207_LINEOUT_EVENT:
+		break;
+        }
+}
+
+static int cs4207_init(struct hda_codec *codec)
+{
+	u16 coeff;
+	snd_hda_sequence_write(codec, cs4207_basic_init);
+	
+	/* SPDIF*/
+	coeff =  0;
+	coeff |= 0x0002; /* SRC_MUTE soft-mute on SPDIF (if no lock) */
+	coeff |= 0x0008; /* Replace with mute on error */
+	/* 
+	    RX to TX1 or TX2 Loopthru / SPDIF2 .
+	    SPDIF_OUT2 is shared with GPIO1 and DMIC_SDA2.
+	    Multiout uses single digital output
+	*/
+	if (cs4207_default_spdif_out == SPDIF_OUT2)
+	    coeff |= 0x4000;
+
+	cs4207_coef_set(codec, CS4207_VENDOR_NID, IDX_SPDIF_CTL, coeff);
+
+	/* ADC */
+	coeff = 0;
+	coeff |= 0x000a; /* ADC1/2 - Digital and Analog Soft Ramp */
+	coeff |= 0x0500; /* DMIC2 enable 2 channels, disable GPIO1 */
+	coeff |= 0x1800; /* DMIC1 enable 2 channels, disable GPIO0 
+			    No effect if SPDIF_OUT2 is slected in 
+			    IDX_SPDIF_CTL.
+			*/
+
+	cs4207_coef_set(codec, CS4207_VENDOR_NID, IDX_ADC_CFG, coeff);
+
+	/* DAC */
+	coeff =  0;
+	coeff |= 0x002a; /* DAC1/2/3 SZCMode Soft Ramp */
+	coeff |= 0x0040; /* Mute DACs on FIFO error */
+	coeff |= 0x1000; /* Enable DACs High Pass Filter */
+	coeff |= 0x0400; /* Disable Cefficient Auto increment */
+	cs4207_coef_set(codec, CS4207_VENDOR_NID, IDX_DAC_CFG, coeff);
+	
+	/* Beep */
+	coeff = 0x0007; /* Enable Beep thru DAC1/2/3 */
+	cs4207_coef_set(codec, CS4207_VENDOR_NID, IDX_BEEP_CFG, coeff);
+
+	if (codec->patch_ops.unsol_event) {
+	    cs4207_automute(codec);
+	}
+
+	return 0;
+}
+
+static void cs4207_free(struct hda_codec *codec)
+{
+	if (codec->spec)
+	    kfree(codec->spec);
+}
+
+static struct hda_codec_ops cs4207_patch_ops = {
+	.build_controls = cs4207_build_controls,
+	.build_pcms = cs4207_build_pcms,
+	.init = cs4207_init,
+	.free = cs4207_free,
+	.unsol_event = cs4207_unsol_event,
+};
+
+static int patch_cs4207(struct hda_codec *codec)
+{
+	struct cs4207_spec *spec;
+
+	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+	if (spec == NULL)
+		return -ENOMEM;
+
+	codec->spec = spec;
+
+	spec->multiout.dac_nids = cs4207_dac_nids;
+	spec->multiout.num_dacs =  ARRAY_SIZE(cs4207_dac_nids);	  /* 3 */
+	spec->multiout.max_channels = spec->multiout.num_dacs * 2;
+	/* NID for copying analog to digital */
+	spec->multiout.dig_out_nid = cs4207_dig_out_nids[cs4207_default_spdif_out]; 
+	spec->dig_in_nid = 0x7; /* SPDIF in*/
+	spec->adc_nids = cs4207_adc_nids;
+	spec->num_adcs = ARRAY_SIZE(cs4207_adc_nids);
+	spec->dac_nids = cs4207_dac_nids;
+	spec->num_dacs = ARRAY_SIZE(cs4207_dac_nids);
+	spec->input_mux = &cs4207_analog_capture_source;
+	codec->patch_ops = cs4207_patch_ops;
+
+	return 0;
+}
+
+/*
+ * patch entries
+ */
+struct hda_codec_preset snd_hda_preset_cirrus[] = {
+	{ .id = 0x10134207, .name = "CS4207", .patch = patch_cs4207 },
+	{} /* terminator */
+};
