#include "format.h"
 #include "clock.h"
 #include "stream.h"
+#include "power.h"
 
 /*
  * free a substream
                kfree(fp);
        }
        kfree(subs->rate_list.list);
+       kfree(subs->str_pd);
 }
 
 
 
 static void snd_usb_init_substream(struct snd_usb_stream *as,
                                   int stream,
-                                  struct audioformat *fp)
+                                  struct audioformat *fp,
+                                  struct snd_usb_power_domain *pd)
 {
        struct snd_usb_substream *subs = &as->substream[stream];
 
        if (fp->channels > subs->channels_max)
                subs->channels_max = fp->channels;
 
+       if (pd)
+               subs->str_pd = pd;
+
        snd_usb_preallocate_buffer(subs);
 }
 
  * fmt_list and will be freed on the chip instance release. do not free
  * fp or do remove it from the substream fmt_list to avoid double-free.
  */
-int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
-                            int stream,
-                            struct audioformat *fp)
+static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip,
+                                     int stream,
+                                     struct audioformat *fp,
+                                     struct snd_usb_power_domain *pd)
+
 {
        struct snd_usb_stream *as;
        struct snd_usb_substream *subs;
                err = snd_pcm_new_stream(as->pcm, stream, 1);
                if (err < 0)
                        return err;
-               snd_usb_init_substream(as, stream, fp);
+               snd_usb_init_substream(as, stream, fp, pd);
                return add_chmap(as->pcm, stream, subs);
        }
 
        else
                strcpy(pcm->name, "USB Audio");
 
-       snd_usb_init_substream(as, stream, fp);
+       snd_usb_init_substream(as, stream, fp, pd);
 
        /*
         * Keep using head insertion for M-Audio Audiophile USB (tm) which has a
        return add_chmap(pcm, stream, &as->substream[stream]);
 }
 
+int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
+                            int stream,
+                            struct audioformat *fp)
+{
+       return __snd_usb_add_audio_stream(chip, stream, fp, NULL);
+}
+
+static int snd_usb_add_audio_stream_v3(struct snd_usb_audio *chip,
+                                      int stream,
+                                      struct audioformat *fp,
+                                      struct snd_usb_power_domain *pd)
+{
+       return __snd_usb_add_audio_stream(chip, stream, fp, pd);
+}
+
 static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip,
                                         struct usb_host_interface *alts,
                                         int protocol, int iface_no)
 static struct audioformat *
 snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
                             struct usb_host_interface *alts,
+                            struct snd_usb_power_domain **pd_out,
                             int iface_no, int altset_idx,
                             int altno, int stream)
 {
        struct uac3_as_header_descriptor *as = NULL;
        struct uac3_hc_descriptor_header hc_header;
        struct snd_pcm_chmap_elem *chmap;
+       struct snd_usb_power_domain *pd;
        unsigned char badd_profile;
        u64 badd_formats = 0;
        unsigned int num_channels;
                fp->rate_max = UAC3_BADD_SAMPLING_RATE;
                fp->rates = SNDRV_PCM_RATE_CONTINUOUS;
 
+               pd = kzalloc(sizeof(pd), GFP_KERNEL);
+               if (!pd) {
+                       kfree(fp->rate_table);
+                       kfree(fp);
+                       return NULL;
+               }
+               pd->pd_id = (stream == SNDRV_PCM_STREAM_PLAYBACK) ?
+                                       UAC3_BADD_PD_ID10 : UAC3_BADD_PD_ID11;
+               pd->pd_d1d0_rec = UAC3_BADD_PD_RECOVER_D1D0;
+               pd->pd_d2d0_rec = UAC3_BADD_PD_RECOVER_D2D0;
+
        } else {
                fp->attributes = parse_uac_endpoint_attributes(chip, alts,
                                                               UAC_VERSION_3,
                                                               iface_no);
+
+               pd = snd_usb_find_power_domain(chip->ctrl_intf,
+                                              as->bTerminalLink);
+
                /* ok, let's parse further... */
                if (snd_usb_parse_audio_format_v3(chip, fp, as, stream) < 0) {
+                       kfree(pd);
                        kfree(fp->chmap);
                        kfree(fp->rate_table);
                        kfree(fp);
                }
        }
 
+       if (pd)
+               *pd_out = pd;
+
        return fp;
 }
 
        struct usb_interface_descriptor *altsd;
        int i, altno, err, stream;
        struct audioformat *fp = NULL;
+       struct snd_usb_power_domain *pd = NULL;
        int num, protocol;
 
        dev = chip->dev;
                        break;
                }
                case UAC_VERSION_3:
-                       fp = snd_usb_get_audioformat_uac3(chip, alts,
+                       fp = snd_usb_get_audioformat_uac3(chip, alts, &pd,
                                                iface_no, i, altno, stream);
                        break;
                }
                        return PTR_ERR(fp);
 
                dev_dbg(&dev->dev, "%u:%d: add audio endpoint %#x\n", iface_no, altno, fp->endpoint);
-               err = snd_usb_add_audio_stream(chip, stream, fp);
+               if (protocol == UAC_VERSION_3)
+                       err = snd_usb_add_audio_stream_v3(chip, stream, fp, pd);
+               else
+                       err = snd_usb_add_audio_stream(chip, stream, fp);
+
                if (err < 0) {
                        list_del(&fp->list); /* unlink for avoiding double-free */
+                       kfree(pd);
                        kfree(fp->rate_table);
                        kfree(fp->chmap);
                        kfree(fp);