* @gtscap: gts capabilities pointer
  * @drsmcap: dma resume capabilities pointer
  * @hlink_list: link list of HDA links
+ * @lock: lock for link mgmt
+ * @cmd_dma_state: state of cmd DMAs: CORB and RIRB
  */
 struct hdac_ext_bus {
        struct hdac_bus bus;
        void __iomem *drsmcap;
 
        struct list_head hlink_list;
+
+       struct mutex lock;
+       bool cmd_dma_state;
 };
 
 int snd_hdac_ext_bus_init(struct hdac_ext_bus *sbus, struct device *dev,
        void __iomem *ml_addr; /* link output stream reg pointer */
        u32 lcaps;   /* link capablities */
        u16 lsdiid;  /* link sdi identifier */
+
+       int ref_count;
+
        struct list_head list;
 };
 
 void snd_hdac_ext_link_clear_stream_id(struct hdac_ext_link *link,
                                 int stream);
 
+int snd_hdac_ext_bus_link_get(struct hdac_ext_bus *ebus,
+                               struct hdac_ext_link *link);
+int snd_hdac_ext_bus_link_put(struct hdac_ext_bus *ebus,
+                               struct hdac_ext_link *link);
+
 /* update register macro */
 #define snd_hdac_updatel(addr, reg, mask, val)         \
        writel(((readl(addr + reg) & ~(mask)) | (val)), \
 
                hlink->lcaps  = readl(hlink->ml_addr + AZX_REG_ML_LCAP);
                hlink->lsdiid = readw(hlink->ml_addr + AZX_REG_ML_LSDIID);
 
+               /* since link in On, update the ref */
+               hlink->ref_count = 1;
+
                list_add_tail(&hlink->list, &ebus->hlink_list);
        }
 
        return 0;
 }
 EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_down_all);
+
+int snd_hdac_ext_bus_link_get(struct hdac_ext_bus *ebus,
+                               struct hdac_ext_link *link)
+{
+       int ret = 0;
+
+       mutex_lock(&ebus->lock);
+
+       /*
+        * if we move from 0 to 1, count will be 1 so power up this link
+        * as well, also check the dma status and trigger that
+        */
+       if (++link->ref_count == 1) {
+               if (!ebus->cmd_dma_state) {
+                       snd_hdac_bus_init_cmd_io(&ebus->bus);
+                       ebus->cmd_dma_state = true;
+               }
+
+               ret = snd_hdac_ext_bus_link_power_up(link);
+       }
+
+       mutex_unlock(&ebus->lock);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_get);
+
+int snd_hdac_ext_bus_link_put(struct hdac_ext_bus *ebus,
+                               struct hdac_ext_link *link)
+{
+       int ret = 0;
+       struct hdac_ext_link *hlink;
+       bool link_up = false;
+
+       mutex_lock(&ebus->lock);
+
+       /*
+        * if we move from 1 to 0, count will be 0
+        * so power down this link as well
+        */
+       if (--link->ref_count == 0) {
+               ret = snd_hdac_ext_bus_link_power_down(link);
+
+               /*
+                * now check if all links are off, if so turn off
+                * cmd dma as well
+                */
+               list_for_each_entry(hlink, &ebus->hlink_list, list) {
+                       if (hlink->ref_count) {
+                               link_up = true;
+                               break;
+                       }
+               }
+
+               if (!link_up) {
+                       snd_hdac_bus_stop_cmd_io(&ebus->bus);
+                       ebus->cmd_dma_state = false;
+               }
+       }
+
+       mutex_unlock(&ebus->lock);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_put);