return 0;
 }
 
+/*
+ * SPDIF sharing with analog output
+ */
+static int spdif_share_sw_get(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_multi_out *mout = snd_kcontrol_chip(kcontrol);
+       ucontrol->value.integer.value[0] = mout->share_spdif;
+       return 0;
+}
+
+static int spdif_share_sw_put(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_multi_out *mout = snd_kcontrol_chip(kcontrol);
+       mout->share_spdif = !!ucontrol->value.integer.value[0];
+       return 0;
+}
+
+static struct snd_kcontrol_new spdif_share_sw = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "IEC958 Default PCM Playback Switch",
+       .info = snd_ctl_boolean_mono_info,
+       .get = spdif_share_sw_get,
+       .put = spdif_share_sw_put,
+};
+
+int snd_hda_create_spdif_share_sw(struct hda_codec *codec,
+                                 struct hda_multi_out *mout)
+{
+       if (!mout->dig_out_nid)
+               return 0;
+       /* ATTENTION: here mout is passed as private_data, instead of codec */
+       return snd_ctl_add(codec->bus->card,
+                          snd_ctl_new1(&spdif_share_sw, mout));
+}
+
 /*
  * SPDIF input
  */
  */
 int snd_hda_multi_out_analog_open(struct hda_codec *codec,
                                  struct hda_multi_out *mout,
-                                 struct snd_pcm_substream *substream)
-{
-       substream->runtime->hw.channels_max = mout->max_channels;
+                                 struct snd_pcm_substream *substream,
+                                 struct hda_pcm_stream *hinfo)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       runtime->hw.channels_max = mout->max_channels;
+       if (mout->dig_out_nid) {
+               if (!mout->analog_rates) {
+                       mout->analog_rates = hinfo->rates;
+                       mout->analog_formats = hinfo->formats;
+                       mout->analog_maxbps = hinfo->maxbps;
+               } else {
+                       runtime->hw.rates = mout->analog_rates;
+                       runtime->hw.formats = mout->analog_formats;
+                       hinfo->maxbps = mout->analog_maxbps;
+               }
+               if (!mout->spdif_rates) {
+                       snd_hda_query_supported_pcm(codec, mout->dig_out_nid,
+                                                   &mout->spdif_rates,
+                                                   &mout->spdif_formats,
+                                                   &mout->spdif_maxbps);
+               }
+               mutex_lock(&codec->spdif_mutex);
+               if (mout->share_spdif) {
+                       runtime->hw.rates &= mout->spdif_rates;
+                       runtime->hw.formats &= mout->spdif_formats;
+                       if (mout->spdif_maxbps < hinfo->maxbps)
+                               hinfo->maxbps = mout->spdif_maxbps;
+               }
+       }
+       mutex_unlock(&codec->spdif_mutex);
        return snd_pcm_hw_constraint_step(substream->runtime, 0,
                                          SNDRV_PCM_HW_PARAM_CHANNELS, 2);
 }
        int i;
 
        mutex_lock(&codec->spdif_mutex);
-       if (mout->dig_out_nid && mout->dig_out_used != HDA_DIG_EXCLUSIVE) {
+       if (mout->dig_out_nid && mout->share_spdif &&
+           mout->dig_out_used != HDA_DIG_EXCLUSIVE) {
                if (chs == 2 &&
                    snd_hda_is_supported_format(codec, mout->dig_out_nid,
                                                format) &&
 
        int max_channels;       /* currently supported analog channels */
        int dig_out_used;       /* current usage of digital out (HDA_DIG_XXX) */
        int no_share_stream;    /* don't share a stream with multiple pins */
+       int share_spdif;        /* share SPDIF pin */
+       /* PCM information for both analog and SPDIF DACs */
+       unsigned int analog_rates;
+       unsigned int analog_maxbps;
+       u64 analog_formats;
+       unsigned int spdif_rates;
+       unsigned int spdif_maxbps;
+       u64 spdif_formats;
 };
 
+int snd_hda_create_spdif_share_sw(struct hda_codec *codec,
+                                 struct hda_multi_out *mout);
 int snd_hda_multi_out_dig_open(struct hda_codec *codec,
                               struct hda_multi_out *mout);
 int snd_hda_multi_out_dig_close(struct hda_codec *codec,
                                  struct snd_pcm_substream *substream);
 int snd_hda_multi_out_analog_open(struct hda_codec *codec,
                                  struct hda_multi_out *mout,
-                                 struct snd_pcm_substream *substream);
+                                 struct snd_pcm_substream *substream,
+                                 struct hda_pcm_stream *hinfo);
 int snd_hda_multi_out_analog_prepare(struct hda_codec *codec,
                                     struct hda_multi_out *mout,
                                     unsigned int stream_tag,
 
                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);
                                    struct snd_pcm_substream *substream)
 {
        struct ad198x_spec *spec = codec->spec;
-       return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
+       return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
+                                            hinfo);
 }
 
 static int ad198x_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
 
                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);
                                     struct snd_pcm_substream *substream)
 {
        struct cmi_spec *spec = codec->spec;
-       return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
+       return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
+                                            hinfo);
 }
 
 static int cmi9880_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
 
                                      struct snd_pcm_substream *substream)
 {
        struct conexant_spec *spec = codec->spec;
-       return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
+       return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
+                                            hinfo);
 }
 
 static int conexant_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
                                                    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);
 
                                                    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);
                                    struct snd_pcm_substream *substream)
 {
        struct alc_spec *spec = codec->spec;
-       return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
+       return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
+                                            hinfo);
 }
 
 static int alc880_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
 
                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);
                                      struct snd_pcm_substream *substream)
 {
        struct sigmatel_spec *spec = codec->spec;
-       return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
+       return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
+                                            hinfo);
 }
 
 static int stac92xx_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
 
                                 struct snd_pcm_substream *substream)
 {
        struct via_spec *spec = codec->spec;
-       return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
+       return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
+                                            hinfo);
 }
 
 static int via_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
                                                    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);