]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/commitdiff
drm/i915: setup bridge for HDMI LPE audio driver
authorJerome Anand <jerome.anand@intel.com>
Tue, 24 Jan 2017 22:57:49 +0000 (04:27 +0530)
committerTakashi Iwai <tiwai@suse.de>
Wed, 25 Jan 2017 13:21:47 +0000 (14:21 +0100)
Enable support for HDMI LPE audio mode on Baytrail and
Cherrytrail when HDaudio controller is not detected

Setup minimum required resources during i915_driver_load:
1. Create a platform device to share MMIO/IRQ resources
2. Make the platform device child of i915 device for runtime PM.
3. Create IRQ chip to forward HDMI LPE audio irqs.

HDMI LPE audio driver (a standalone sound driver) probes the
LPE audio device and creates a new sound card.

Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Signed-off-by: Jerome Anand <jerome.anand@intel.com>
Acked-by: Jani Nikula <jani.nikula@intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Documentation/gpu/i915.rst
drivers/gpu/drm/i915/Makefile
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/intel_audio.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_lpe_audio.c [new file with mode: 0644]
include/drm/intel_lpe_audio.h [new file with mode: 0644]

index 117d2ab7a5f73d0c28be683fefb66e3baca9b345..a671eee78945092039db8013db861574345e6836 100644 (file)
@@ -213,6 +213,15 @@ Video BIOS Table (VBT)
 .. kernel-doc:: drivers/gpu/drm/i915/intel_vbt_defs.h
    :internal:
 
+intel hdmi lpe audio support
+----------------------------
+
+.. kernel-doc:: drivers/gpu/drm/i915/intel_lpe_audio.c
+   :doc:  LPE Audio integration for HDMI or DP playback
+
+.. kernel-doc:: drivers/gpu/drm/i915/intel_lpe_audio.c
+   :internal:
+
 Memory Management and Command Submission
 ========================================
 
index 3dea46af9fe6785c5b5543a246b6ab43c9d39f6a..78711dddd9377730bc23323d840b81f8c5ae226c 100644 (file)
@@ -122,6 +122,9 @@ i915-y += intel_gvt.o
 include $(src)/gvt/Makefile
 endif
 
+# LPE Audio for VLV and CHT
+i915-y += intel_lpe_audio.o
+
 obj-$(CONFIG_DRM_I915) += i915.o
 
 CFLAGS_i915_trace_points.o := -I$(src)
index 445fec9c2841ad61282e538d4cfdbe1436e04fb3..9b8d81fa0441e8d0d7f54202a67d8369f29fc9a5 100644 (file)
@@ -1138,7 +1138,7 @@ static void i915_driver_register(struct drm_i915_private *dev_priv)
        if (IS_GEN5(dev_priv))
                intel_gpu_ips_init(dev_priv);
 
-       i915_audio_component_init(dev_priv);
+       intel_audio_init(dev_priv);
 
        /*
         * Some ports require correctly set-up hpd registers for detection to
@@ -1156,7 +1156,7 @@ static void i915_driver_register(struct drm_i915_private *dev_priv)
  */
 static void i915_driver_unregister(struct drm_i915_private *dev_priv)
 {
-       i915_audio_component_cleanup(dev_priv);
+       intel_audio_deinit(dev_priv);
 
        intel_gpu_ips_teardown();
        acpi_video_unregister();
index 243224aeabf82f111ab14c4d6995ce868c0d36c1..c55bf144c4e2e8309b5d1aa00f045e5da41354b5 100644 (file)
@@ -2136,6 +2136,12 @@ struct drm_i915_private {
        /* Used to save the pipe-to-encoder mapping for audio */
        struct intel_encoder *av_enc_map[I915_MAX_PIPES];
 
+       /* necessary resource sharing with HDMI LPE audio driver. */
+       struct {
+               struct platform_device *platdev;
+               int     irq;
+       } lpe_audio;
+
        /*
         * NOTE: This is the dri1/ums dungeon, don't add stuff here. Your patch
         * will be rejected. Instead look for a better place.
@@ -3390,6 +3396,11 @@ extern int i915_restore_state(struct drm_device *dev);
 void i915_setup_sysfs(struct drm_i915_private *dev_priv);
 void i915_teardown_sysfs(struct drm_i915_private *dev_priv);
 
+/* intel_lpe_audio.c */
+int  intel_lpe_audio_init(struct drm_i915_private *dev_priv);
+void intel_lpe_audio_teardown(struct drm_i915_private *dev_priv);
+void intel_lpe_audio_irq_handler(struct drm_i915_private *dev_priv);
+
 /* intel_i2c.c */
 extern int intel_setup_gmbus(struct drm_device *dev);
 extern void intel_teardown_gmbus(struct drm_device *dev);
index 07ca71cabb2bfe94a6c250cc538dce500157f404..f0880afbb87858db7198145f5fedc1bf3150e6a2 100644 (file)
@@ -1893,6 +1893,10 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
                 * signalled in iir */
                valleyview_pipestat_irq_ack(dev_priv, iir, pipe_stats);
 
+               if (iir & (I915_LPE_PIPE_A_INTERRUPT |
+                          I915_LPE_PIPE_B_INTERRUPT))
+                       intel_lpe_audio_irq_handler(dev_priv);
+
                /*
                 * VLV_IIR is single buffered, and reflects the level
                 * from PIPESTAT/PORT_HOTPLUG_STAT, hence clear it last.
@@ -1973,6 +1977,11 @@ static irqreturn_t cherryview_irq_handler(int irq, void *arg)
                 * signalled in iir */
                valleyview_pipestat_irq_ack(dev_priv, iir, pipe_stats);
 
+               if (iir & (I915_LPE_PIPE_A_INTERRUPT |
+                          I915_LPE_PIPE_B_INTERRUPT |
+                          I915_LPE_PIPE_C_INTERRUPT))
+                       intel_lpe_audio_irq_handler(dev_priv);
+
                /*
                 * VLV_IIR is single buffered, and reflects the level
                 * from PIPESTAT/PORT_HOTPLUG_STAT, hence clear it last.
@@ -2914,6 +2923,7 @@ static void vlv_display_irq_postinstall(struct drm_i915_private *dev_priv)
        u32 pipestat_mask;
        u32 enable_mask;
        enum pipe pipe;
+       u32 val;
 
        pipestat_mask = PLANE_FLIP_DONE_INT_STATUS_VLV |
                        PIPE_CRC_DONE_INTERRUPT_STATUS;
@@ -2930,6 +2940,12 @@ static void vlv_display_irq_postinstall(struct drm_i915_private *dev_priv)
 
        WARN_ON(dev_priv->irq_mask != ~0);
 
+       val = (I915_LPE_PIPE_A_INTERRUPT |
+               I915_LPE_PIPE_B_INTERRUPT |
+               I915_LPE_PIPE_C_INTERRUPT);
+
+       enable_mask |= val;
+
        dev_priv->irq_mask = ~enable_mask;
 
        GEN5_IRQ_INIT(VLV_, dev_priv->irq_mask, enable_mask);
index c70c07a7b5864955f251d25db496fd33f5a66812..a9ffc8df241b08550ecab9ca6b5f0860795f9df3 100644 (file)
@@ -2058,6 +2058,9 @@ enum skl_disp_power_wells {
 #define I915_ASLE_INTERRUPT                            (1<<0)
 #define I915_BSD_USER_INTERRUPT                                (1<<25)
 
+#define I915_HDMI_LPE_AUDIO_BASE       (VLV_DISPLAY_BASE + 0x65000)
+#define I915_HDMI_LPE_AUDIO_SIZE       0x1000
+
 #define GEN6_BSD_RNCID                 _MMIO(0x12198)
 
 #define GEN7_FF_THREAD_MODE            _MMIO(0x20a0)
index 49f10538d4aa1214b05670d33769be4e50ca88df..1e93263b4c871c5c150b67cf388fa3f25a3ccfa1 100644 (file)
@@ -931,3 +931,28 @@ void i915_audio_component_cleanup(struct drm_i915_private *dev_priv)
        component_del(dev_priv->drm.dev, &i915_audio_component_bind_ops);
        dev_priv->audio_component_registered = false;
 }
+
+/**
+ * intel_audio_init() - Initialize the audio driver either using
+ * component framework or using lpe audio bridge
+ * @dev_priv: the i915 drm device private data
+ *
+ */
+void intel_audio_init(struct drm_i915_private *dev_priv)
+{
+       if (intel_lpe_audio_init(dev_priv) < 0)
+               i915_audio_component_init(dev_priv);
+}
+
+/**
+ * intel_audio_deinit() - deinitialize the audio driver
+ * @dev_priv: the i915 drm device private data
+ *
+ */
+void intel_audio_deinit(struct drm_i915_private *dev_priv)
+{
+       if ((dev_priv)->lpe_audio.platdev != NULL)
+               intel_lpe_audio_teardown(dev_priv);
+       else
+               i915_audio_component_cleanup(dev_priv);
+}
index cd132c216a67decc86e4b1fbc22d544a8230b0ad..301c4be0544b48aca5cb783f96de1e6cdaf9c6e0 100644 (file)
@@ -1192,6 +1192,8 @@ void intel_audio_codec_enable(struct intel_encoder *encoder,
 void intel_audio_codec_disable(struct intel_encoder *encoder);
 void i915_audio_component_init(struct drm_i915_private *dev_priv);
 void i915_audio_component_cleanup(struct drm_i915_private *dev_priv);
+void intel_audio_init(struct drm_i915_private *dev_priv);
+void intel_audio_deinit(struct drm_i915_private *dev_priv);
 
 /* intel_display.c */
 enum transcoder intel_crtc_pch_transcoder(struct intel_crtc *crtc);
diff --git a/drivers/gpu/drm/i915/intel_lpe_audio.c b/drivers/gpu/drm/i915/intel_lpe_audio.c
new file mode 100644 (file)
index 0000000..7ce1b5b
--- /dev/null
@@ -0,0 +1,321 @@
+/*
+ * Copyright © 2016 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
+ *    Jerome Anand <jerome.anand@intel.com>
+ *    based on VED patches
+ *
+ */
+
+/**
+ * DOC: LPE Audio integration for HDMI or DP playback
+ *
+ * Motivation:
+ * Atom platforms (e.g. valleyview and cherryTrail) integrates a DMA-based
+ * interface as an alternative to the traditional HDaudio path. While this
+ * mode is unrelated to the LPE aka SST audio engine, the documentation refers
+ * to this mode as LPE so we keep this notation for the sake of consistency.
+ *
+ * The interface is handled by a separate standalone driver maintained in the
+ * ALSA subsystem for simplicity. To minimize the interaction between the two
+ * subsystems, a bridge is setup between the hdmi-lpe-audio and i915:
+ * 1. Create a platform device to share MMIO/IRQ resources
+ * 2. Make the platform device child of i915 device for runtime PM.
+ * 3. Create IRQ chip to forward the LPE audio irqs.
+ * the hdmi-lpe-audio driver probes the lpe audio device and creates a new
+ * sound card
+ *
+ * Threats:
+ * Due to the restriction in Linux platform device model, user need manually
+ * uninstall the hdmi-lpe-audio driver before uninstalling i915 module,
+ * otherwise we might run into use-after-free issues after i915 removes the
+ * platform device: even though hdmi-lpe-audio driver is released, the modules
+ * is still in "installed" status.
+ *
+ * Implementation:
+ * The MMIO/REG platform resources are created according to the registers
+ * specification.
+ * When forwarding LPE audio irqs, the flow control handler selection depends
+ * on the platform, for example on valleyview handle_simple_irq is enough.
+ *
+ */
+
+#include <linux/acpi.h>
+#include <linux/device.h>
+#include <linux/pci.h>
+
+#include "i915_drv.h"
+#include <linux/delay.h>
+#include <drm/intel_lpe_audio.h>
+
+#define HAS_LPE_AUDIO(dev_priv) ((dev_priv)->lpe_audio.platdev != NULL)
+
+static struct platform_device *
+lpe_audio_platdev_create(struct drm_i915_private *dev_priv)
+{
+       int ret;
+       struct drm_device *dev = &dev_priv->drm;
+       struct platform_device_info pinfo = {};
+       struct resource *rsc;
+       struct platform_device *platdev;
+       struct intel_hdmi_lpe_audio_pdata *pdata;
+
+       pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+       if (!pdata)
+               return ERR_PTR(-ENOMEM);
+
+       rsc = kcalloc(2, sizeof(*rsc), GFP_KERNEL);
+       if (!rsc) {
+               kfree(pdata);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       rsc[0].start    = rsc[0].end = dev_priv->lpe_audio.irq;
+       rsc[0].flags    = IORESOURCE_IRQ;
+       rsc[0].name     = "hdmi-lpe-audio-irq";
+
+       rsc[1].start    = pci_resource_start(dev->pdev, 0) +
+               I915_HDMI_LPE_AUDIO_BASE;
+       rsc[1].end      = pci_resource_start(dev->pdev, 0) +
+               I915_HDMI_LPE_AUDIO_BASE + I915_HDMI_LPE_AUDIO_SIZE - 1;
+       rsc[1].flags    = IORESOURCE_MEM;
+       rsc[1].name     = "hdmi-lpe-audio-mmio";
+
+       pinfo.parent = dev->dev;
+       pinfo.name = "hdmi-lpe-audio";
+       pinfo.id = -1;
+       pinfo.res = rsc;
+       pinfo.num_res = 2;
+       pinfo.data = pdata;
+       pinfo.size_data = sizeof(*pdata);
+       pinfo.dma_mask = DMA_BIT_MASK(32);
+
+       spin_lock_init(&pdata->lpe_audio_slock);
+
+       platdev = platform_device_register_full(&pinfo);
+       if (IS_ERR(platdev)) {
+               ret = PTR_ERR(platdev);
+               DRM_ERROR("Failed to allocate LPE audio platform device\n");
+               goto err;
+       }
+
+       kfree(rsc);
+
+       return platdev;
+
+err:
+       kfree(rsc);
+       kfree(pdata);
+       return ERR_PTR(ret);
+}
+
+static void lpe_audio_platdev_destroy(struct drm_i915_private *dev_priv)
+{
+       platform_device_unregister(dev_priv->lpe_audio.platdev);
+       kfree(dev_priv->lpe_audio.platdev->dev.dma_mask);
+}
+
+static void lpe_audio_irq_unmask(struct irq_data *d)
+{
+       struct drm_i915_private *dev_priv = d->chip_data;
+       unsigned long irqflags;
+       u32 val = (I915_LPE_PIPE_A_INTERRUPT |
+               I915_LPE_PIPE_B_INTERRUPT);
+
+       if (IS_CHERRYVIEW(dev_priv))
+               val |= I915_LPE_PIPE_C_INTERRUPT;
+
+       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+
+       dev_priv->irq_mask &= ~val;
+       I915_WRITE(VLV_IIR, val);
+       I915_WRITE(VLV_IIR, val);
+       I915_WRITE(VLV_IMR, dev_priv->irq_mask);
+       POSTING_READ(VLV_IMR);
+
+       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+}
+
+static void lpe_audio_irq_mask(struct irq_data *d)
+{
+       struct drm_i915_private *dev_priv = d->chip_data;
+       unsigned long irqflags;
+       u32 val = (I915_LPE_PIPE_A_INTERRUPT |
+               I915_LPE_PIPE_B_INTERRUPT);
+
+       if (IS_CHERRYVIEW(dev_priv))
+               val |= I915_LPE_PIPE_C_INTERRUPT;
+
+       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+
+       dev_priv->irq_mask |= val;
+       I915_WRITE(VLV_IMR, dev_priv->irq_mask);
+       I915_WRITE(VLV_IIR, val);
+       I915_WRITE(VLV_IIR, val);
+       POSTING_READ(VLV_IIR);
+
+       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+}
+
+static struct irq_chip lpe_audio_irqchip = {
+       .name = "hdmi_lpe_audio_irqchip",
+       .irq_mask = lpe_audio_irq_mask,
+       .irq_unmask = lpe_audio_irq_unmask,
+};
+
+static int lpe_audio_irq_init(struct drm_i915_private *dev_priv)
+{
+       int irq = dev_priv->lpe_audio.irq;
+
+       WARN_ON(!intel_irqs_enabled(dev_priv));
+       irq_set_chip_and_handler_name(irq,
+                               &lpe_audio_irqchip,
+                               handle_simple_irq,
+                               "hdmi_lpe_audio_irq_handler");
+
+       return irq_set_chip_data(irq, dev_priv);
+}
+
+static bool lpe_audio_detect(struct drm_i915_private *dev_priv)
+{
+       int lpe_present = false;
+
+       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
+               static const struct pci_device_id atom_hdaudio_ids[] = {
+                       /* Baytrail */
+                       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0f04)},
+                       /* Braswell */
+                       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2284)},
+                       {}
+               };
+
+               if (!pci_dev_present(atom_hdaudio_ids)) {
+                       DRM_INFO("%s\n", "HDaudio controller not detected, using LPE audio instead\n");
+                       lpe_present = true;
+               }
+       }
+       return lpe_present;
+}
+
+static int lpe_audio_setup(struct drm_i915_private *dev_priv)
+{
+       int ret;
+
+       dev_priv->lpe_audio.irq = irq_alloc_desc(0);
+       if (dev_priv->lpe_audio.irq < 0) {
+               DRM_ERROR("Failed to allocate IRQ desc: %d\n",
+                       dev_priv->lpe_audio.irq);
+               ret = dev_priv->lpe_audio.irq;
+               goto err;
+       }
+
+       DRM_DEBUG("irq = %d\n", dev_priv->lpe_audio.irq);
+
+       ret = lpe_audio_irq_init(dev_priv);
+
+       if (ret) {
+               DRM_ERROR("Failed to initialize irqchip for lpe audio: %d\n",
+                       ret);
+               goto err_free_irq;
+       }
+
+       dev_priv->lpe_audio.platdev = lpe_audio_platdev_create(dev_priv);
+
+       if (IS_ERR(dev_priv->lpe_audio.platdev)) {
+               ret = PTR_ERR(dev_priv->lpe_audio.platdev);
+               DRM_ERROR("Failed to create lpe audio platform device: %d\n",
+                       ret);
+               goto err_free_irq;
+       }
+
+       return 0;
+err_free_irq:
+       irq_free_desc(dev_priv->lpe_audio.irq);
+err:
+       dev_priv->lpe_audio.irq = -1;
+       dev_priv->lpe_audio.platdev = NULL;
+       return ret;
+}
+
+/**
+ * intel_lpe_audio_irq_handler() - forwards the LPE audio irq
+ * @dev_priv: the i915 drm device private data
+ *
+ * the LPE Audio irq is forwarded to the irq handler registered by LPE audio
+ * driver.
+ */
+void intel_lpe_audio_irq_handler(struct drm_i915_private *dev_priv)
+{
+       int ret;
+
+       if (!HAS_LPE_AUDIO(dev_priv))
+               return;
+
+       ret = generic_handle_irq(dev_priv->lpe_audio.irq);
+       if (ret)
+               DRM_ERROR_RATELIMITED("error handling LPE audio irq: %d\n",
+                               ret);
+}
+
+/**
+ * intel_lpe_audio_init() - detect and setup the bridge between HDMI LPE Audio
+ * driver and i915
+ * @dev_priv: the i915 drm device private data
+ *
+ * Return: 0 if successful. non-zero if detection or
+ * llocation/initialization fails
+ */
+int intel_lpe_audio_init(struct drm_i915_private *dev_priv)
+{
+       int ret = -ENODEV;
+
+       if (lpe_audio_detect(dev_priv)) {
+               ret = lpe_audio_setup(dev_priv);
+               if (ret < 0)
+                       DRM_ERROR("failed to setup LPE Audio bridge\n");
+       }
+       return ret;
+}
+
+/**
+ * intel_lpe_audio_teardown() - destroy the bridge between HDMI LPE
+ * audio driver and i915
+ * @dev_priv: the i915 drm device private data
+ *
+ * release all the resources for LPE audio <-> i915 bridge.
+ */
+void intel_lpe_audio_teardown(struct drm_i915_private *dev_priv)
+{
+       struct irq_desc *desc;
+
+       if (!HAS_LPE_AUDIO(dev_priv))
+               return;
+
+       desc = irq_to_desc(dev_priv->lpe_audio.irq);
+
+       lpe_audio_irq_mask(&desc->irq_data);
+
+       lpe_audio_platdev_destroy(dev_priv);
+
+       irq_free_desc(dev_priv->lpe_audio.irq);
+}
diff --git a/include/drm/intel_lpe_audio.h b/include/drm/intel_lpe_audio.h
new file mode 100644 (file)
index 0000000..952de05
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright © 2016 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef _INTEL_LPE_AUDIO_H_
+#define _INTEL_LPE_AUDIO_H_
+
+#include <linux/types.h>
+#include <linux/spinlock_types.h>
+
+#define HDMI_MAX_ELD_BYTES     128
+
+struct intel_hdmi_lpe_audio_eld {
+       int port_id;
+       unsigned char eld_data[HDMI_MAX_ELD_BYTES];
+};
+
+struct intel_hdmi_lpe_audio_pdata {
+       bool notify_pending;
+       int tmds_clock_speed;
+       bool hdmi_connected;
+       struct intel_hdmi_lpe_audio_eld eld;
+       void (*notify_audio_lpe)(void *audio_ptr);
+       spinlock_t lpe_audio_slock;
+};
+
+#endif /* _I915_LPE_AUDIO_H_ */