summaryrefslogtreecommitdiff
path: root/sound/hda/ext
diff options
context:
space:
mode:
authorAndré Fabian Silva Delgado <emulatorman@parabola.nu>2015-12-15 14:52:16 -0300
committerAndré Fabian Silva Delgado <emulatorman@parabola.nu>2015-12-15 14:52:16 -0300
commit8d91c1e411f55d7ea91b1183a2e9f8088fb4d5be (patch)
treee9891aa6c295060d065adffd610c4f49ecf884f3 /sound/hda/ext
parenta71852147516bc1cb5b0b3cbd13639bfd4022dc8 (diff)
Linux-libre 4.3.2-gnu
Diffstat (limited to 'sound/hda/ext')
-rw-r--r--sound/hda/ext/hdac_ext_bus.c99
-rw-r--r--sound/hda/ext/hdac_ext_controller.c30
-rw-r--r--sound/hda/ext/hdac_ext_stream.c62
3 files changed, 175 insertions, 16 deletions
diff --git a/sound/hda/ext/hdac_ext_bus.c b/sound/hda/ext/hdac_ext_bus.c
index 0aa5d9eb6..2433f7c81 100644
--- a/sound/hda/ext/hdac_ext_bus.c
+++ b/sound/hda/ext/hdac_ext_bus.c
@@ -19,6 +19,7 @@
#include <linux/module.h>
#include <linux/slab.h>
+#include <linux/io.h>
#include <sound/hdaudio_ext.h>
MODULE_DESCRIPTION("HDA extended core");
@@ -125,7 +126,7 @@ static void default_release(struct device *dev)
}
/**
- * snd_hdac_ext_device_init - initialize the HDA extended codec base device
+ * snd_hdac_ext_bus_device_init - initialize the HDA extended codec base device
* @ebus: hdac extended bus to attach to
* @addr: codec address
*
@@ -133,14 +134,16 @@ static void default_release(struct device *dev)
*/
int snd_hdac_ext_bus_device_init(struct hdac_ext_bus *ebus, int addr)
{
+ struct hdac_ext_device *edev;
struct hdac_device *hdev = NULL;
struct hdac_bus *bus = ebus_to_hbus(ebus);
char name[15];
int ret;
- hdev = kzalloc(sizeof(*hdev), GFP_KERNEL);
- if (!hdev)
+ edev = kzalloc(sizeof(*edev), GFP_KERNEL);
+ if (!edev)
return -ENOMEM;
+ hdev = &edev->hdac;
snprintf(name, sizeof(name), "ehdaudio%dD%d", ebus->idx, addr);
@@ -158,6 +161,7 @@ int snd_hdac_ext_bus_device_init(struct hdac_ext_bus *ebus, int addr)
snd_hdac_ext_bus_device_exit(hdev);
return ret;
}
+
return 0;
}
EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_device_init);
@@ -168,7 +172,94 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_device_init);
*/
void snd_hdac_ext_bus_device_exit(struct hdac_device *hdev)
{
+ struct hdac_ext_device *edev = to_ehdac_device(hdev);
+
snd_hdac_device_exit(hdev);
- kfree(hdev);
+ kfree(edev);
}
EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_device_exit);
+
+/**
+ * snd_hdac_ext_bus_device_remove - remove HD-audio extended codec base devices
+ *
+ * @ebus: HD-audio extended bus
+ */
+void snd_hdac_ext_bus_device_remove(struct hdac_ext_bus *ebus)
+{
+ struct hdac_device *codec, *__codec;
+ /*
+ * we need to remove all the codec devices objects created in the
+ * snd_hdac_ext_bus_device_init
+ */
+ list_for_each_entry_safe(codec, __codec, &ebus->bus.codec_list, list) {
+ snd_hdac_device_unregister(codec);
+ put_device(&codec->dev);
+ }
+}
+EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_device_remove);
+#define dev_to_hdac(dev) (container_of((dev), \
+ struct hdac_device, dev))
+
+static inline struct hdac_ext_driver *get_edrv(struct device *dev)
+{
+ struct hdac_driver *hdrv = drv_to_hdac_driver(dev->driver);
+ struct hdac_ext_driver *edrv = to_ehdac_driver(hdrv);
+
+ return edrv;
+}
+
+static inline struct hdac_ext_device *get_edev(struct device *dev)
+{
+ struct hdac_device *hdev = dev_to_hdac_dev(dev);
+ struct hdac_ext_device *edev = to_ehdac_device(hdev);
+
+ return edev;
+}
+
+static int hda_ext_drv_probe(struct device *dev)
+{
+ return (get_edrv(dev))->probe(get_edev(dev));
+}
+
+static int hdac_ext_drv_remove(struct device *dev)
+{
+ return (get_edrv(dev))->remove(get_edev(dev));
+}
+
+static void hdac_ext_drv_shutdown(struct device *dev)
+{
+ return (get_edrv(dev))->shutdown(get_edev(dev));
+}
+
+/**
+ * snd_hda_ext_driver_register - register a driver for ext hda devices
+ *
+ * @drv: ext hda driver structure
+ */
+int snd_hda_ext_driver_register(struct hdac_ext_driver *drv)
+{
+ drv->hdac.type = HDA_DEV_ASOC;
+ drv->hdac.driver.bus = &snd_hda_bus_type;
+ /* we use default match */
+
+ if (drv->probe)
+ drv->hdac.driver.probe = hda_ext_drv_probe;
+ if (drv->remove)
+ drv->hdac.driver.remove = hdac_ext_drv_remove;
+ if (drv->shutdown)
+ drv->hdac.driver.shutdown = hdac_ext_drv_shutdown;
+
+ return driver_register(&drv->hdac.driver);
+}
+EXPORT_SYMBOL_GPL(snd_hda_ext_driver_register);
+
+/**
+ * snd_hda_ext_driver_unregister - unregister a driver for ext hda devices
+ *
+ * @drv: ext hda driver structure
+ */
+void snd_hda_ext_driver_unregister(struct hdac_ext_driver *drv)
+{
+ driver_unregister(&drv->hdac.driver);
+}
+EXPORT_SYMBOL_GPL(snd_hda_ext_driver_unregister);
diff --git a/sound/hda/ext/hdac_ext_controller.c b/sound/hda/ext/hdac_ext_controller.c
index 358f16195..63215b172 100644
--- a/sound/hda/ext/hdac_ext_controller.c
+++ b/sound/hda/ext/hdac_ext_controller.c
@@ -177,8 +177,8 @@ int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_ext_bus *ebus)
hlink->bus = bus;
hlink->ml_addr = ebus->mlcap + AZX_ML_BASE +
(AZX_ML_INTERVAL * idx);
- hlink->lcaps = snd_hdac_chip_readl(bus, ML_LCAP);
- hlink->lsdiid = snd_hdac_chip_readw(bus, ML_LSDIID);
+ hlink->lcaps = readl(hlink->ml_addr + AZX_REG_ML_LCAP);
+ hlink->lsdiid = readw(hlink->ml_addr + AZX_REG_ML_LSDIID);
list_add_tail(&hlink->list, &ebus->hlink_list);
}
@@ -243,7 +243,7 @@ static int check_hdac_link_power_active(struct hdac_ext_link *link, bool enable)
timeout = 50;
do {
- val = snd_hdac_chip_readl(link->bus, ML_LCTL);
+ val = readl(link->ml_addr + AZX_REG_ML_LCTL);
if (enable) {
if (((val & mask) >> AZX_MLCTL_CPA))
return 0;
@@ -263,7 +263,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_chip_updatel(link->bus, ML_LCTL, 0, AZX_MLCTL_SPA);
+ snd_hdac_updatel(link->ml_addr, AZX_REG_ML_LCTL, 0, AZX_MLCTL_SPA);
return check_hdac_link_power_active(link, true);
}
@@ -275,8 +275,28 @@ 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_chip_updatel(link->bus, ML_LCTL, AZX_MLCTL_SPA, 0);
+ snd_hdac_updatel(link->ml_addr, AZX_REG_ML_LCTL, AZX_MLCTL_SPA, 0);
return check_hdac_link_power_active(link, false);
}
EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_down);
+
+/**
+ * snd_hdac_ext_bus_link_power_down_all -power down all hda link
+ * @ebus: HD-audio extended bus
+ */
+int snd_hdac_ext_bus_link_power_down_all(struct hdac_ext_bus *ebus)
+{
+ struct hdac_ext_link *hlink = NULL;
+ int ret;
+
+ list_for_each_entry(hlink, &ebus->hlink_list, list) {
+ snd_hdac_updatel(hlink->ml_addr, AZX_REG_ML_LCTL, AZX_MLCTL_SPA, 0);
+ ret = check_hdac_link_power_active(hlink, false);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_down_all);
diff --git a/sound/hda/ext/hdac_ext_stream.c b/sound/hda/ext/hdac_ext_stream.c
index 3de47dd1a..33ba77dd3 100644
--- a/sound/hda/ext/hdac_ext_stream.c
+++ b/sound/hda/ext/hdac_ext_stream.c
@@ -49,6 +49,16 @@ void snd_hdac_ext_stream_init(struct hdac_ext_bus *ebus,
AZX_PPLC_INTERVAL * idx;
}
+ if (ebus->spbcap) {
+ stream->spib_addr = ebus->spbcap + AZX_SPB_BASE +
+ AZX_SPB_INTERVAL * idx +
+ AZX_SPB_SPIB;
+
+ stream->fifo_addr = ebus->spbcap + AZX_SPB_BASE +
+ AZX_SPB_INTERVAL * idx +
+ AZX_SPB_MAXFIFO;
+ }
+
stream->decoupled = false;
snd_hdac_stream_init(bus, &stream->hstream, idx, direction, tag);
}
@@ -281,17 +291,12 @@ hdac_ext_host_stream_assign(struct hdac_ext_bus *ebus,
struct hdac_ext_stream *res = NULL;
struct hdac_stream *stream = NULL;
struct hdac_bus *hbus = &ebus->bus;
- int key;
if (!ebus->ppcap) {
dev_err(hbus->dev, "stream type not supported\n");
return NULL;
}
- /* make a non-zero unique key for the substream */
- key = (substream->pcm->device << 16) | (substream->number << 2) |
- (substream->stream + 1);
-
list_for_each_entry(stream, &hbus->stream_list, list) {
struct hdac_ext_stream *hstream = container_of(stream,
struct hdac_ext_stream,
@@ -310,7 +315,6 @@ hdac_ext_host_stream_assign(struct hdac_ext_bus *ebus,
spin_lock_irq(&hbus->reg_lock);
res->hstream.opened = 1;
res->hstream.running = 0;
- res->hstream.assigned_key = key;
res->hstream.substream = substream;
spin_unlock_irq(&hbus->reg_lock);
}
@@ -423,7 +427,7 @@ void snd_hdac_ext_stream_spbcap_enable(struct hdac_ext_bus *ebus,
mask |= (1 << index);
- register_mask = snd_hdac_chip_readl(bus, SPB_SPBFCCTL);
+ register_mask = readl(ebus->spbcap + AZX_REG_SPB_SPBFCCTL);
mask |= register_mask;
@@ -435,6 +439,50 @@ void snd_hdac_ext_stream_spbcap_enable(struct hdac_ext_bus *ebus,
EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_spbcap_enable);
/**
+ * snd_hdac_ext_stream_set_spib - sets the spib value of a stream
+ * @ebus: HD-audio ext core bus
+ * @stream: hdac_ext_stream
+ * @value: spib value to set
+ */
+int snd_hdac_ext_stream_set_spib(struct hdac_ext_bus *ebus,
+ struct hdac_ext_stream *stream, u32 value)
+{
+ struct hdac_bus *bus = &ebus->bus;
+
+ if (!ebus->spbcap) {
+ dev_err(bus->dev, "Address of SPB capability is NULL");
+ return -EINVAL;
+ }
+
+ writel(value, stream->spib_addr);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_set_spib);
+
+/**
+ * snd_hdac_ext_stream_get_spbmaxfifo - gets the spib value of a stream
+ * @ebus: HD-audio ext core bus
+ * @stream: hdac_ext_stream
+ *
+ * Return maxfifo for the stream
+ */
+int snd_hdac_ext_stream_get_spbmaxfifo(struct hdac_ext_bus *ebus,
+ struct hdac_ext_stream *stream)
+{
+ struct hdac_bus *bus = &ebus->bus;
+
+ if (!ebus->spbcap) {
+ dev_err(bus->dev, "Address of SPB capability is NULL");
+ return -EINVAL;
+ }
+
+ return readl(stream->fifo_addr);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_get_spbmaxfifo);
+
+
+/**
* snd_hdac_ext_stop_streams - stop all stream if running
* @ebus: HD-audio ext core bus
*/