summaryrefslogtreecommitdiff
path: root/sound/hda/ext
diff options
context:
space:
mode:
authorAndré Fabian Silva Delgado <emulatorman@parabola.nu>2016-09-11 04:34:46 -0300
committerAndré Fabian Silva Delgado <emulatorman@parabola.nu>2016-09-11 04:34:46 -0300
commit863981e96738983919de841ec669e157e6bdaeb0 (patch)
treed6d89a12e7eb8017837c057935a2271290907f76 /sound/hda/ext
parent8dec7c70575785729a6a9e6719a955e9c545bcab (diff)
Linux-libre 4.7.1-gnupck-4.7.1-gnu
Diffstat (limited to 'sound/hda/ext')
-rw-r--r--sound/hda/ext/hdac_ext_bus.c4
-rw-r--r--sound/hda/ext/hdac_ext_controller.c66
2 files changed, 70 insertions, 0 deletions
diff --git a/sound/hda/ext/hdac_ext_bus.c b/sound/hda/ext/hdac_ext_bus.c
index 2433f7c81..31b510c5c 100644
--- a/sound/hda/ext/hdac_ext_bus.c
+++ b/sound/hda/ext/hdac_ext_bus.c
@@ -105,6 +105,9 @@ int snd_hdac_ext_bus_init(struct hdac_ext_bus *ebus, struct device *dev,
INIT_LIST_HEAD(&ebus->hlink_list);
ebus->idx = idx++;
+ mutex_init(&ebus->lock);
+ ebus->cmd_dma_state = true;
+
return 0;
}
EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_init);
@@ -144,6 +147,7 @@ int snd_hdac_ext_bus_device_init(struct hdac_ext_bus *ebus, int addr)
if (!edev)
return -ENOMEM;
hdev = &edev->hdac;
+ edev->ebus = ebus;
snprintf(name, sizeof(name), "ehdaudio%dD%d", ebus->idx, addr);
diff --git a/sound/hda/ext/hdac_ext_controller.c b/sound/hda/ext/hdac_ext_controller.c
index 548cc1e41..860f8cad6 100644
--- a/sound/hda/ext/hdac_ext_controller.c
+++ b/sound/hda/ext/hdac_ext_controller.c
@@ -186,6 +186,9 @@ int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_ext_bus *ebus)
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);
}
@@ -327,3 +330,66 @@ int snd_hdac_ext_bus_link_power_down_all(struct hdac_ext_bus *ebus)
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);