summaryrefslogtreecommitdiffstats
path: root/sound/hda
diff options
context:
space:
mode:
Diffstat (limited to 'sound/hda')
-rw-r--r--sound/hda/ext/hdac_ext_bus.c53
-rw-r--r--sound/hda/ext/hdac_ext_controller.c16
-rw-r--r--sound/hda/ext/hdac_ext_stream.c34
-rw-r--r--sound/hda/hdac_stream.c100
4 files changed, 94 insertions, 109 deletions
diff --git a/sound/hda/ext/hdac_ext_bus.c b/sound/hda/ext/hdac_ext_bus.c
index 765c40a6ccba..6004ea1c373e 100644
--- a/sound/hda/ext/hdac_ext_bus.c
+++ b/sound/hda/ext/hdac_ext_bus.c
@@ -60,59 +60,6 @@ void snd_hdac_ext_bus_exit(struct hdac_bus *bus)
}
EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_exit);
-static void default_release(struct device *dev)
-{
- snd_hdac_ext_bus_device_exit(dev_to_hdac_dev(dev));
-}
-
-/**
- * snd_hdac_ext_bus_device_init - initialize the HDA extended codec base device
- * @bus: hdac bus to attach to
- * @addr: codec address
- * @hdev: hdac device to init
- * @type: codec type (HDAC_DEV_*) to use for this device
- *
- * Returns zero for success or a negative error code.
- */
-int snd_hdac_ext_bus_device_init(struct hdac_bus *bus, int addr,
- struct hdac_device *hdev, int type)
-{
- char name[15];
- int ret;
-
- hdev->bus = bus;
-
- snprintf(name, sizeof(name), "ehdaudio%dD%d", bus->idx, addr);
-
- ret = snd_hdac_device_init(hdev, bus, name, addr);
- if (ret < 0) {
- dev_err(bus->dev, "device init failed for hdac device\n");
- return ret;
- }
- hdev->type = type;
- hdev->dev.release = default_release;
-
- ret = snd_hdac_device_register(hdev);
- if (ret) {
- dev_err(bus->dev, "failed to register hdac device\n");
- snd_hdac_ext_bus_device_exit(hdev);
- return ret;
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_device_init);
-
-/**
- * snd_hdac_ext_bus_device_exit - clean up a HD-audio extended codec base device
- * @hdev: hdac device to clean up
- */
-void snd_hdac_ext_bus_device_exit(struct hdac_device *hdev)
-{
- snd_hdac_device_exit(hdev);
-}
-EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_device_exit);
-
/**
* snd_hdac_ext_bus_device_remove - remove HD-audio extended codec base devices
*
diff --git a/sound/hda/ext/hdac_ext_controller.c b/sound/hda/ext/hdac_ext_controller.c
index a42f66f561f5..80876b9a87f4 100644
--- a/sound/hda/ext/hdac_ext_controller.c
+++ b/sound/hda/ext/hdac_ext_controller.c
@@ -170,7 +170,7 @@ static int check_hdac_link_power_active(struct hdac_ext_link *link, bool enable)
{
int timeout;
u32 val;
- int mask = (1 << AZX_MLCTL_CPA_SHIFT);
+ int mask = (1 << AZX_ML_LCTL_CPA_SHIFT);
udelay(3);
timeout = 150;
@@ -178,10 +178,10 @@ static int check_hdac_link_power_active(struct hdac_ext_link *link, bool enable)
do {
val = readl(link->ml_addr + AZX_REG_ML_LCTL);
if (enable) {
- if (((val & mask) >> AZX_MLCTL_CPA_SHIFT))
+ if (((val & mask) >> AZX_ML_LCTL_CPA_SHIFT))
return 0;
} else {
- if (!((val & mask) >> AZX_MLCTL_CPA_SHIFT))
+ if (!((val & mask) >> AZX_ML_LCTL_CPA_SHIFT))
return 0;
}
udelay(3);
@@ -197,7 +197,7 @@ static int check_hdac_link_power_active(struct hdac_ext_link *link, bool enable)
int snd_hdac_ext_bus_link_power_up(struct hdac_ext_link *link)
{
snd_hdac_updatel(link->ml_addr, AZX_REG_ML_LCTL,
- AZX_MLCTL_SPA, AZX_MLCTL_SPA);
+ AZX_ML_LCTL_SPA, AZX_ML_LCTL_SPA);
return check_hdac_link_power_active(link, true);
}
@@ -209,7 +209,7 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_up);
*/
int snd_hdac_ext_bus_link_power_down(struct hdac_ext_link *link)
{
- snd_hdac_updatel(link->ml_addr, AZX_REG_ML_LCTL, AZX_MLCTL_SPA, 0);
+ snd_hdac_updatel(link->ml_addr, AZX_REG_ML_LCTL, AZX_ML_LCTL_SPA, 0);
return check_hdac_link_power_active(link, false);
}
@@ -226,7 +226,7 @@ int snd_hdac_ext_bus_link_power_up_all(struct hdac_bus *bus)
list_for_each_entry(hlink, &bus->hlink_list, list) {
snd_hdac_updatel(hlink->ml_addr, AZX_REG_ML_LCTL,
- AZX_MLCTL_SPA, AZX_MLCTL_SPA);
+ AZX_ML_LCTL_SPA, AZX_ML_LCTL_SPA);
ret = check_hdac_link_power_active(hlink, true);
if (ret < 0)
return ret;
@@ -247,7 +247,7 @@ int snd_hdac_ext_bus_link_power_down_all(struct hdac_bus *bus)
list_for_each_entry(hlink, &bus->hlink_list, list) {
snd_hdac_updatel(hlink->ml_addr, AZX_REG_ML_LCTL,
- AZX_MLCTL_SPA, 0);
+ AZX_ML_LCTL_SPA, 0);
ret = check_hdac_link_power_active(hlink, false);
if (ret < 0)
return ret;
@@ -281,7 +281,7 @@ int snd_hdac_ext_bus_link_get(struct hdac_bus *bus,
* clear the register to invalidate all the output streams
*/
snd_hdac_updatew(link->ml_addr, AZX_REG_ML_LOSIDV,
- ML_LOSIDV_STREAM_MASK, 0);
+ AZX_ML_LOSIDV_STREAM_MASK, 0);
/*
* wait for 521usec for codec to report status
* HDA spec section 4.3 - Codec Discovery
diff --git a/sound/hda/ext/hdac_ext_stream.c b/sound/hda/ext/hdac_ext_stream.c
index d2b5724b463f..70f3ad71aaf0 100644
--- a/sound/hda/ext/hdac_ext_stream.c
+++ b/sound/hda/ext/hdac_ext_stream.c
@@ -26,9 +26,9 @@
* initialize the stream, if ppcap is enabled then init those and then
* invoke hdac stream initialization routine
*/
-void snd_hdac_ext_stream_init(struct hdac_bus *bus,
- struct hdac_ext_stream *hext_stream,
- int idx, int direction, int tag)
+static void snd_hdac_ext_stream_init(struct hdac_bus *bus,
+ struct hdac_ext_stream *hext_stream,
+ int idx, int direction, int tag)
{
if (bus->ppcap) {
hext_stream->pphc_addr = bus->ppcap + AZX_PPHC_BASE +
@@ -56,7 +56,6 @@ void snd_hdac_ext_stream_init(struct hdac_bus *bus,
hext_stream->decoupled = false;
snd_hdac_stream_init(bus, &hext_stream->hstream, idx, direction, tag);
}
-EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_init);
/**
* snd_hdac_ext_stream_init_all - create and initialize the stream objects
@@ -88,11 +87,11 @@ int snd_hdac_ext_stream_init_all(struct hdac_bus *bus, int start_idx,
EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_init_all);
/**
- * snd_hdac_stream_free_all - free hdac extended stream objects
+ * snd_hdac_ext_stream_free_all - free hdac extended stream objects
*
* @bus: HD-audio core bus
*/
-void snd_hdac_stream_free_all(struct hdac_bus *bus)
+void snd_hdac_ext_stream_free_all(struct hdac_bus *bus)
{
struct hdac_stream *s, *_s;
struct hdac_ext_stream *hext_stream;
@@ -104,7 +103,7 @@ void snd_hdac_stream_free_all(struct hdac_bus *bus)
kfree(hext_stream);
}
}
-EXPORT_SYMBOL_GPL(snd_hdac_stream_free_all);
+EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_free_all);
void snd_hdac_ext_stream_decouple_locked(struct hdac_bus *bus,
struct hdac_ext_stream *hext_stream,
@@ -268,19 +267,15 @@ hdac_ext_link_stream_assign(struct hdac_bus *bus,
if (hstream->direction != substream->stream)
continue;
- /* check if decoupled stream and not in use is available */
- if (hext_stream->decoupled && !hext_stream->link_locked) {
- res = hext_stream;
- break;
- }
-
+ /* check if link stream is available */
if (!hext_stream->link_locked) {
- snd_hdac_ext_stream_decouple_locked(bus, hext_stream, true);
res = hext_stream;
break;
}
+
}
if (res) {
+ snd_hdac_ext_stream_decouple_locked(bus, res, true);
res->link_locked = 1;
res->link_substream = substream;
}
@@ -309,13 +304,12 @@ hdac_ext_host_stream_assign(struct hdac_bus *bus,
continue;
if (!hstream->opened) {
- if (!hext_stream->decoupled)
- snd_hdac_ext_stream_decouple_locked(bus, hext_stream, true);
res = hext_stream;
break;
}
}
if (res) {
+ snd_hdac_ext_stream_decouple_locked(bus, res, true);
res->hstream.opened = 1;
res->hstream.running = 0;
res->hstream.substream = substream;
@@ -388,15 +382,17 @@ void snd_hdac_ext_stream_release(struct hdac_ext_stream *hext_stream, int type)
case HDAC_EXT_STREAM_TYPE_HOST:
spin_lock_irq(&bus->reg_lock);
- if (hext_stream->decoupled && !hext_stream->link_locked)
+ /* couple link only if not in use */
+ if (!hext_stream->link_locked)
snd_hdac_ext_stream_decouple_locked(bus, hext_stream, false);
+ snd_hdac_stream_release_locked(&hext_stream->hstream);
spin_unlock_irq(&bus->reg_lock);
- snd_hdac_stream_release(&hext_stream->hstream);
break;
case HDAC_EXT_STREAM_TYPE_LINK:
spin_lock_irq(&bus->reg_lock);
- if (hext_stream->decoupled && !hext_stream->hstream.opened)
+ /* couple host only if not in use */
+ if (!hext_stream->hstream.opened)
snd_hdac_ext_stream_decouple_locked(bus, hext_stream, false);
hext_stream->link_locked = 0;
hext_stream->link_substream = NULL;
diff --git a/sound/hda/hdac_stream.c b/sound/hda/hdac_stream.c
index f3582012d22f..1b8be39c38a9 100644
--- a/sound/hda/hdac_stream.c
+++ b/sound/hda/hdac_stream.c
@@ -13,6 +13,39 @@
#include <sound/hda_register.h>
#include "trace.h"
+/*
+ * the hdac_stream library is intended to be used with the following
+ * transitions. The states are not formally defined in the code but loosely
+ * inspired by boolean variables. Note that the 'prepared' field is not used
+ * in this library but by the callers during the hw_params/prepare transitions
+ *
+ * |
+ * stream_init() |
+ * v
+ * +--+-------+
+ * | unused |
+ * +--+----+--+
+ * | ^
+ * stream_assign() | | stream_release()
+ * v |
+ * +--+----+--+
+ * | opened |
+ * +--+----+--+
+ * | ^
+ * stream_reset() | |
+ * stream_setup() | | stream_cleanup()
+ * v |
+ * +--+----+--+
+ * | prepared |
+ * +--+----+--+
+ * | ^
+ * stream_start() | | stream_stop()
+ * v |
+ * +--+----+--+
+ * | running |
+ * +----------+
+ */
+
/**
* snd_hdac_get_stream_stripe_ctl - get stripe control value
* @bus: HD-audio core bus
@@ -112,10 +145,10 @@ void snd_hdac_stream_start(struct hdac_stream *azx_dev, bool fresh_start)
EXPORT_SYMBOL_GPL(snd_hdac_stream_start);
/**
- * snd_hdac_stream_clear - stop a stream DMA
+ * snd_hdac_stream_clear - helper to clear stream registers and stop DMA transfers
* @azx_dev: HD-audio core stream to stop
*/
-void snd_hdac_stream_clear(struct hdac_stream *azx_dev)
+static void snd_hdac_stream_clear(struct hdac_stream *azx_dev)
{
snd_hdac_stream_updateb(azx_dev, SD_CTL,
SD_CTL_DMA_START | SD_INT_MASK, 0);
@@ -124,7 +157,6 @@ void snd_hdac_stream_clear(struct hdac_stream *azx_dev)
snd_hdac_stream_updateb(azx_dev, SD_CTL_3B, SD_CTL_STRIPE_MASK, 0);
azx_dev->running = false;
}
-EXPORT_SYMBOL_GPL(snd_hdac_stream_clear);
/**
* snd_hdac_stream_stop - stop a stream
@@ -143,16 +175,27 @@ void snd_hdac_stream_stop(struct hdac_stream *azx_dev)
EXPORT_SYMBOL_GPL(snd_hdac_stream_stop);
/**
+ * snd_hdac_stop_streams - stop all streams
+ * @bus: HD-audio core bus
+ */
+void snd_hdac_stop_streams(struct hdac_bus *bus)
+{
+ struct hdac_stream *stream;
+
+ list_for_each_entry(stream, &bus->stream_list, list)
+ snd_hdac_stream_stop(stream);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_stop_streams);
+
+/**
* snd_hdac_stop_streams_and_chip - stop all streams and chip if running
* @bus: HD-audio core bus
*/
void snd_hdac_stop_streams_and_chip(struct hdac_bus *bus)
{
- struct hdac_stream *stream;
if (bus->chip_init) {
- list_for_each_entry(stream, &bus->stream_list, list)
- snd_hdac_stream_stop(stream);
+ snd_hdac_stop_streams(bus);
snd_hdac_bus_stop_chip(bus);
}
}
@@ -165,7 +208,6 @@ EXPORT_SYMBOL_GPL(snd_hdac_stop_streams_and_chip);
void snd_hdac_stream_reset(struct hdac_stream *azx_dev)
{
unsigned char val;
- int timeout;
int dma_run_state;
snd_hdac_stream_clear(azx_dev);
@@ -173,30 +215,17 @@ void snd_hdac_stream_reset(struct hdac_stream *azx_dev)
dma_run_state = snd_hdac_stream_readb(azx_dev, SD_CTL) & SD_CTL_DMA_START;
snd_hdac_stream_updateb(azx_dev, SD_CTL, 0, SD_CTL_STREAM_RESET);
- udelay(3);
- timeout = 300;
- do {
- val = snd_hdac_stream_readb(azx_dev, SD_CTL) &
- SD_CTL_STREAM_RESET;
- if (val)
- break;
- } while (--timeout);
+
+ /* wait for hardware to report that the stream entered reset */
+ snd_hdac_stream_readb_poll(azx_dev, SD_CTL, val, (val & SD_CTL_STREAM_RESET), 3, 300);
if (azx_dev->bus->dma_stop_delay && dma_run_state)
udelay(azx_dev->bus->dma_stop_delay);
- val &= ~SD_CTL_STREAM_RESET;
- snd_hdac_stream_writeb(azx_dev, SD_CTL, val);
- udelay(3);
+ snd_hdac_stream_updateb(azx_dev, SD_CTL, SD_CTL_STREAM_RESET, 0);
- timeout = 300;
- /* waiting for hardware to report that the stream is out of reset */
- do {
- val = snd_hdac_stream_readb(azx_dev, SD_CTL) &
- SD_CTL_STREAM_RESET;
- if (!val)
- break;
- } while (--timeout);
+ /* wait for hardware to report that the stream is out of reset */
+ snd_hdac_stream_readb_poll(azx_dev, SD_CTL, val, !(val & SD_CTL_STREAM_RESET), 3, 300);
/* reset first position - may not be synced with hw at this time */
if (azx_dev->posbuf)
@@ -337,6 +366,21 @@ struct hdac_stream *snd_hdac_stream_assign(struct hdac_bus *bus,
EXPORT_SYMBOL_GPL(snd_hdac_stream_assign);
/**
+ * snd_hdac_stream_release_locked - release the assigned stream
+ * @azx_dev: HD-audio core stream to release
+ *
+ * Release the stream that has been assigned by snd_hdac_stream_assign().
+ * The bus->reg_lock needs to be taken at a higher level
+ */
+void snd_hdac_stream_release_locked(struct hdac_stream *azx_dev)
+{
+ azx_dev->opened = 0;
+ azx_dev->running = 0;
+ azx_dev->substream = NULL;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_stream_release_locked);
+
+/**
* snd_hdac_stream_release - release the assigned stream
* @azx_dev: HD-audio core stream to release
*
@@ -347,9 +391,7 @@ void snd_hdac_stream_release(struct hdac_stream *azx_dev)
struct hdac_bus *bus = azx_dev->bus;
spin_lock_irq(&bus->reg_lock);
- azx_dev->opened = 0;
- azx_dev->running = 0;
- azx_dev->substream = NULL;
+ snd_hdac_stream_release_locked(azx_dev);
spin_unlock_irq(&bus->reg_lock);
}
EXPORT_SYMBOL_GPL(snd_hdac_stream_release);