From 972098c939e0476ae6dd6bbb84a6ffb5d2293083 Mon Sep 17 00:00:00 2001
From: Wang Xingchao <xingchao.wang@linux.intel.com>
Date: Fri, 3 May 2013 13:57:53 +0800
Subject: [RFC PATCH 1/4] Alsa: hda - add hdmi_i915 driver to fix dependency

This driver used to avoid dependency between ALSA and GFX.

Power well is a good starting point to test this driver.

In alsa side:
- A new hda_bus type is created to track all codecs.
- A new hdmi_i915 driver is registered on the bus too.
- The driver contains private APIs for gfx i915 module, will
add put/get_power_well() in next version.
- In codec driver, codec get its private data, which contains callbacks
about power well request/release.
- the hdmi_i915 has dependency on both CODEC_HDMI and DRM_I915 now, it's
intended to fix the dependency for Haswell platform only now.

Signed-off-by: Wang Xingchao <xingchao.wang@linux.intel.com>
---
 sound/Kconfig             |    7 +++++
 sound/Makefile            |    1 +
 sound/hda_bus.c           |   76 +++++++++++++++++++++++++++++++++++++++++++++
 sound/pci/hda/Kconfig     |    7 +++++
 sound/pci/hda/Makefile    |    4 +++
 sound/pci/hda/hda_codec.c |   16 +++++++++-
 sound/pci/hda/hda_codec.h |    8 +++++
 sound/pci/hda/hdmi_i915.c |   49 +++++++++++++++++++++++++++++
 8 files changed, 167 insertions(+), 1 deletion(-)
 create mode 100644 sound/hda_bus.c
 create mode 100644 sound/pci/hda/hdmi_i915.c

diff --git a/sound/Kconfig b/sound/Kconfig
index c710ce2..3aa927d 100644
--- a/sound/Kconfig
+++ b/sound/Kconfig
@@ -132,3 +132,10 @@ config AC97_BUS
 	  sound subsystem and other function drivers completely unrelated to
 	  sound although they're sharing the AC97 bus. Concerned drivers
 	  should "select" this.
+
+# HDA_BUS is used from both sound and drm_i915 
+config HDA_BUS
+	bool "Build HDMI/DisplayPort HD-audio codec support for i915 cards"
+	default y
+	help
+	  This is used to avoid dependency between drm i915 module and hdmi driver
diff --git a/sound/Makefile b/sound/Makefile
index ce9132b..79a5aa3 100644
--- a/sound/Makefile
+++ b/sound/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_SND_AOA) += aoa/
 
 # This one must be compilable even if sound is configured out
 obj-$(CONFIG_AC97_BUS) += ac97_bus.o
+obj-$(CONFIG_HDA_BUS) += hda_bus.o
 
 ifeq ($(CONFIG_SND),y)
   obj-y += last.o
diff --git a/sound/hda_bus.c b/sound/hda_bus.c
new file mode 100644
index 0000000..f8eb8bf
--- /dev/null
+++ b/sound/hda_bus.c
@@ -0,0 +1,76 @@
+/*
+ * Linux driver model hda bus interface
+ *
+ * Author: 	Wang xingchao	
+ * Created:	5/3, 2013	
+ * Copyright:	(C) Intel Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/string.h>
+
+/*
+ * Let drivers decide whether they want to support given codec from their
+ * probe method. Drivers have direct access to the struct snd_ac97
+ * structure and may  decide based on the id field amongst other things.
+ */
+static int hda_bus_match(struct device *dev, struct device_driver *drv)
+{
+	return 1;
+}
+
+#ifdef CONFIG_PM
+static int hda_bus_suspend(struct device *dev, pm_message_t state)
+{
+	int ret = 0;
+
+	if (dev->driver && dev->driver->suspend)
+		ret = dev->driver->suspend(dev, state);
+
+	return ret;
+}
+
+static int hda_bus_resume(struct device *dev)
+{
+	int ret = 0;
+
+	if (dev->driver && dev->driver->resume)
+		ret = dev->driver->resume(dev);
+
+	return ret;
+}
+#endif /* CONFIG_PM */
+
+struct bus_type hda_bus_type = {
+	.name		= "hda",
+	.match		= hda_bus_match,
+#ifdef CONFIG_PM
+	.suspend	= hda_bus_suspend,
+	.resume		= hda_bus_resume,
+#endif /* CONFIG_PM */
+};
+
+static int __init hda_bus_init(void)
+{
+	return bus_register(&hda_bus_type);
+}
+
+subsys_initcall(hda_bus_init);
+
+static void __exit hda_bus_exit(void)
+{
+	bus_unregister(&hda_bus_type);
+}
+
+module_exit(hda_bus_exit);
+
+EXPORT_SYMBOL(hda_bus_type);
+
+MODULE_LICENSE("GPL");
diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig
index 80a7d44..97cde17 100644
--- a/sound/pci/hda/Kconfig
+++ b/sound/pci/hda/Kconfig
@@ -254,4 +254,11 @@ config SND_HDA_POWER_SAVE_DEFAULT
 	  The default time-out value in seconds for HD-audio automatic
 	  power-save mode.  0 means to disable the power-save mode.
 
+config SND_HDA_CODEC_HDMI_I915
+	bool "avoid haswell hdmi and drm i915 dependency"
+	depends on SND_HDA_CODEC_HDMI && DRM_I915
+	default y
+	help 
+	  This driver avoid dependency between drm i915 and hda driver
+
 endif
diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile
index 24a2514..90aba6d 100644
--- a/sound/pci/hda/Makefile
+++ b/sound/pci/hda/Makefile
@@ -21,6 +21,7 @@ snd-hda-codec-ca0132-objs :=	patch_ca0132.o
 snd-hda-codec-conexant-objs :=	patch_conexant.o
 snd-hda-codec-via-objs :=	patch_via.o
 snd-hda-codec-hdmi-objs :=	patch_hdmi.o hda_eld.o
+snd-hda-codec-hdmi-i915-objs :=	hdmi_i915.o
 
 # common driver
 obj-$(CONFIG_SND_HDA_INTEL) := snd-hda-codec.o
@@ -59,6 +60,9 @@ endif
 ifdef CONFIG_SND_HDA_CODEC_HDMI
 obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-hdmi.o
 endif
+ifdef CONFIG_SND_HDA_CODEC_HDMI_I915
+obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-hdmi-i915.o
+endif
 
 # this must be the last entry after codec drivers;
 # otherwise the codec patches won't be hooked before the PCI probe
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index ecdf30e..04a8ba4 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -787,8 +787,20 @@ static int snd_hda_bus_dev_register(struct snd_device *device)
 	list_for_each_entry(codec, &bus->codec_list, list) {
 		snd_hda_hwdep_add_sysfs(codec);
 		snd_hda_hwdep_add_power_sysfs(codec);
+
+        	codec->dev.bus = &hda_bus_type;
+        	codec->dev.parent = codec->bus->card->dev;
+        	codec->dev.release = codec_device_release;
+        	dev_set_name(&codec->dev, "%d-%d:%s",
+        		     codec->bus->card->number, codec->addr,
+        		     codec->chip_name);
+        	if ((err = device_register(&codec->dev)) < 0) {
+        		snd_printk(KERN_ERR "Can't register hda bus\n");
+        		codec->dev.bus = NULL;
+        		return err;
+        	}
 	}
-	return 0;
+    	return 0;
 }
 #else
 #define snd_hda_bus_dev_register	NULL
@@ -5503,6 +5515,7 @@ int snd_hda_suspend(struct hda_bus *bus)
 		cancel_delayed_work_sync(&codec->jackpoll_work);
 		if (hda_codec_is_power_on(codec))
 			hda_call_codec_suspend(codec, false);
+		//TODO: Get codec private i915 data and release power well
 	}
 	return 0;
 }
@@ -5519,6 +5532,7 @@ int snd_hda_resume(struct hda_bus *bus)
 	struct hda_codec *codec;
 
 	list_for_each_entry(codec, &bus->codec_list, list) {
+		//TODO: Get codec private i915 data and request power well
 		hda_call_codec_resume(codec);
 	}
 	return 0;
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index 23ca172..fc6088b 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -920,6 +920,11 @@ struct hda_codec {
 
 	/* additional init verbs */
 	struct snd_array verbs;
+
+	/* device node for hda bus */
+	//TODO: Add hdmi_i915_private pointer
+	struct hdmi_i915_private *i915_data; 
+	struct device dev;
 };
 
 /* direction */
@@ -1195,6 +1200,9 @@ snd_hda_codec_load_dsp_cleanup(struct hda_codec *codec,
 				struct snd_dma_buffer *dmab) {}
 #endif
 
+/* HDA display audio device driver access */
+extern struct bus_type hda_bus_type;
+
 /*
  * Codec modularization
  */
diff --git a/sound/pci/hda/hdmi_i915.c b/sound/pci/hda/hdmi_i915.c
new file mode 100644
index 0000000..ca0916e
--- /dev/null
+++ b/sound/pci/hda/hdmi_i915.c
@@ -0,0 +1,49 @@
+/*
+ * hdmi_i915.c  --  Haswell driver for Display audio and gfx i915 module
+ *
+ * Copyright Intel. Inc 
+ * Author: Wang xingchao <xingchao.wang@intel.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+//TODO:
+//1. Add i915 private APIs here
+//2. register the private data to device side(hda_codec)
+
+struct hdmi_i915_private {
+	//place callbacks here
+};
+
+static struct device_driver hdmi_i915_driver = {
+	.name =		"hdmi-i915",
+	.bus =		&hda_bus_type,
+	.owner =	THIS_MODULE,
+#if 0
+	.probe =	wm97xx_probe,
+	.remove =	wm97xx_remove,
+	.suspend =	wm97xx_suspend,
+	.resume =	wm97xx_resume,
+#endif
+};
+
+static int __init hdmi_i915_init(void)
+{
+	return driver_register(&hdmi_i915_driver);
+}
+
+static void __exit hdmi_i915_exit(void)
+{
+	driver_unregister(&hdmi_i915_driver);
+}
+
+module_init(hdmi_i915_init);
+module_exit(hdmi_i915_exit);
+
+/* Module information */
+MODULE_AUTHOR("Wang xingchao <xingchao.wang@intel.com>");
+MODULE_DESCRIPTION("Haswell Display audio dependency driver");
+MODULE_LICENSE("GPL");
-- 
1.7.9.5

