summary refs log tree commit diff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-12-11 12:46:32 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2014-12-11 12:46:32 -0800
commit413fd0e3fbf52873f2310eb75bfa6c7b72847277 (patch)
treebb83812cf8dbeaf47a39a09f023deae3b65526ab
parent6b9e2cea428cf7af93a84bcb865e478d8bf1c165 (diff)
parent3315764efceaccfb02c7d4c99ef8eed6716cd861 (diff)
downloadlinux-413fd0e3fbf52873f2310eb75bfa6c7b72847277.tar.gz
Merge tag 'fbdev-3.19' of git://git.kernel.org/pub/scm/linux/kernel/git/tomba/linux
Pull fbdev updates from Tomi Valkeinen:
 - support for mx6sl and mx6sx
 - OMAP HDMI audio rewrite to make it finally work
 - OMAP video PLL work to prepare for new DRA7xx SoCs
 - simplefb DT related improvements

* tag 'fbdev-3.19' of git://git.kernel.org/pub/scm/linux/kernel/git/tomba/linux: (81 commits)
  video: uvesafb: Deletion of an unnecessary check before the function call "platform_device_put"
  video: fbdev-VIA: Deletion of an unnecessary check before the function call "framebuffer_release"
  video: fbdev-MMP: Deletion of an unnecessary check before the function call "mmp_unregister_path"
  video: mx3fb: Deletion of an unnecessary check before the function call "backlight_device_unregister"
  video: fbdev-OMAP2: Deletion of unnecessary checks before the function call "i2c_put_adapter"
  video: fbdev-SIS: Deletion of unnecessary checks before the function call "pci_dev_put"
  video: smscufx: Deletion of unnecessary checks before the function call "vfree"
  video: udlfb: Deletion of unnecessary checks before the function call "vfree"
  video: uvesafb: Deletion of an unnecessary check before the function call "uvesafb_free"
  video: fbdev-LCDC: Deletion of an unnecessary check before the function call "vfree"
  video: fbdev: arkfb: suppress build warning
  video: fbdev: s3fb: suppress build warning
  video: fbdev: vt8623fb: suppress build warning
  OMAPDSS: hdmi5: Fix bit field for IEC958_AES2_CON_SOURCE
  OMAPDSS: hdmi: Remove __exit qualifier from hdmi_uninit_output()
  OMAPDSS: hdmi5: Change hdmi_wp idlemode to to no_idle for audio playback
  OMAPDSS: Remove all references to obsolete HDMI audio callbacks
  ASoC: omap: Remove obsolete HDMI audio code and Kconfig options
  OMAPDSS: hdmi5: Register ASoC platform device for omap hdmi audio
  OMAPDSS: hdmi5: Remove callbacks for the old ASoC DAI driver
  ...
-rw-r--r--Documentation/devicetree/bindings/video/simple-framebuffer-sunxi.txt33
-rw-r--r--Documentation/devicetree/bindings/video/simple-framebuffer.txt68
-rw-r--r--MAINTAINERS8
-rw-r--r--drivers/video/console/fbcon.c2
-rw-r--r--drivers/video/fbdev/Kconfig2
-rw-r--r--drivers/video/fbdev/amba-clcd.c1
-rw-r--r--drivers/video/fbdev/arkfb.c2
-rw-r--r--drivers/video/fbdev/mmp/core.c6
-rw-r--r--drivers/video/fbdev/mmp/hw/mmp_ctrl.c3
-rw-r--r--drivers/video/fbdev/mx3fb.c3
-rw-r--r--drivers/video/fbdev/mxsfb.c19
-rw-r--r--drivers/video/fbdev/omap2/displays-new/connector-dvi.c9
-rw-r--r--drivers/video/fbdev/omap2/displays-new/connector-hdmi.c99
-rw-r--r--drivers/video/fbdev/omap2/displays-new/encoder-tfp410.c1
-rw-r--r--drivers/video/fbdev/omap2/displays-new/encoder-tpd12s015.c57
-rw-r--r--drivers/video/fbdev/omap2/dss/Kconfig7
-rw-r--r--drivers/video/fbdev/omap2/dss/Makefile2
-rw-r--r--drivers/video/fbdev/omap2/dss/dispc.c20
-rw-r--r--drivers/video/fbdev/omap2/dss/dpi.c327
-rw-r--r--drivers/video/fbdev/omap2/dss/dsi.c659
-rw-r--r--drivers/video/fbdev/omap2/dss/dss-of.c58
-rw-r--r--drivers/video/fbdev/omap2/dss/dss.c123
-rw-r--r--drivers/video/fbdev/omap2/dss/dss.h225
-rw-r--r--drivers/video/fbdev/omap2/dss/dss_features.c42
-rw-r--r--drivers/video/fbdev/omap2/dss/dss_features.h12
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi.h71
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi4.c338
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi4_core.c14
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi4_core.h4
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi5.c338
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi5_core.c11
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi5_core.h2
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi_common.c2
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi_phy.c31
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi_pll.c313
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi_wp.c16
-rw-r--r--drivers/video/fbdev/omap2/dss/output.c19
-rw-r--r--drivers/video/fbdev/omap2/dss/pll.c378
-rw-r--r--drivers/video/fbdev/omap2/dss/sdi.c2
-rw-r--r--drivers/video/fbdev/s3fb.c2
-rw-r--r--drivers/video/fbdev/sh_mobile_lcdcfb.c3
-rw-r--r--drivers/video/fbdev/simplefb.c162
-rw-r--r--drivers/video/fbdev/sis/sis_main.c14
-rw-r--r--drivers/video/fbdev/sm501fb.c1
-rw-r--r--drivers/video/fbdev/smscufx.c6
-rw-r--r--drivers/video/fbdev/udlfb.c9
-rw-r--r--drivers/video/fbdev/uvesafb.c6
-rw-r--r--drivers/video/fbdev/via/viafbdev.c3
-rw-r--r--drivers/video/fbdev/vt8623fb.c2
-rw-r--r--include/linux/of.h3
-rw-r--r--include/sound/omap-hdmi-audio.h43
-rw-r--r--include/video/omapdss.h45
-rw-r--r--sound/soc/omap/Kconfig26
-rw-r--r--sound/soc/omap/Makefile6
-rw-r--r--sound/soc/omap/omap-hdmi-audio.c407
-rw-r--r--sound/soc/omap/omap-hdmi-card.c87
-rw-r--r--sound/soc/omap/omap-hdmi.c364
-rw-r--r--sound/soc/omap/omap-hdmi.h38
58 files changed, 2398 insertions, 2156 deletions
diff --git a/Documentation/devicetree/bindings/video/simple-framebuffer-sunxi.txt b/Documentation/devicetree/bindings/video/simple-framebuffer-sunxi.txt
new file mode 100644
index 000000000000..c46ba641a1df
--- /dev/null
+++ b/Documentation/devicetree/bindings/video/simple-framebuffer-sunxi.txt
@@ -0,0 +1,33 @@
+Sunxi specific Simple Framebuffer bindings
+
+This binding documents sunxi specific extensions to the simple-framebuffer
+bindings. The sunxi simplefb u-boot code relies on the devicetree containing
+pre-populated simplefb nodes.
+
+These extensions are intended so that u-boot can select the right node based
+on which pipeline is being used. As such they are solely intended for
+firmware / bootloader use, and the OS should ignore them.
+
+Required properties:
+- compatible: "allwinner,simple-framebuffer"
+- allwinner,pipeline, one of:
+  "de_be0-lcd0"
+  "de_be1-lcd1"
+  "de_be0-lcd0-hdmi"
+  "de_be1-lcd1-hdmi"
+
+Example:
+
+chosen {
+	#address-cells = <1>;
+	#size-cells = <1>;
+	ranges;
+
+	framebuffer@0 {
+		compatible = "allwinner,simple-framebuffer", "simple-framebuffer";
+		allwinner,pipeline = "de_be0-lcd0-hdmi";
+		clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 43>,
+			 <&ahb_gates 44>;
+		status = "disabled";
+	};
+};
diff --git a/Documentation/devicetree/bindings/video/simple-framebuffer.txt b/Documentation/devicetree/bindings/video/simple-framebuffer.txt
index 70c26f3a5b9a..4474ef6e0b95 100644
--- a/Documentation/devicetree/bindings/video/simple-framebuffer.txt
+++ b/Documentation/devicetree/bindings/video/simple-framebuffer.txt
@@ -1,8 +1,40 @@
 Simple Framebuffer
 
-A simple frame-buffer describes a raw memory region that may be rendered to,
-with the assumption that the display hardware has already been set up to scan
-out from that buffer.
+A simple frame-buffer describes a frame-buffer setup by firmware or
+the bootloader, with the assumption that the display hardware has already
+been set up to scan out from the memory pointed to by the reg property.
+
+Since simplefb nodes represent runtime information they must be sub-nodes of
+the chosen node (*). Simplefb nodes must be named "framebuffer@<address>".
+
+If the devicetree contains nodes for the display hardware used by a simplefb,
+then the simplefb node must contain a property called "display", which
+contains a phandle pointing to the primary display hw node, so that the OS
+knows which simplefb to disable when handing over control to a driver for the
+real hardware. The bindings for the hw nodes must specify which node is
+considered the primary node.
+
+It is advised to add display# aliases to help the OS determine how to number
+things. If display# aliases are used, then if the simplefb node contains a
+"display" property then the /aliases/display# path must point to the display
+hw node the "display" property points to, otherwise it must point directly
+to the simplefb node.
+
+If a simplefb node represents the preferred console for user interaction,
+then the chosen node's stdout-path property should point to it, or to the
+primary display hw node, as with display# aliases. If display aliases are
+used then it should be set to the alias instead.
+
+It is advised that devicetree files contain pre-filled, disabled framebuffer
+nodes, so that the firmware only needs to update the mode information and
+enable them. This way if e.g. later on support for more display clocks get
+added, the simplefb nodes will already contain this info and the firmware
+does not need to be updated.
+
+If pre-filled framebuffer nodes are used, the firmware may need extra
+information to find the right node. In that case an extra platform specific
+compatible and platform specific properties should be used and documented,
+see e.g. simple-framebuffer-sunxi.txt .
 
 Required properties:
 - compatible: "simple-framebuffer"
@@ -14,13 +46,41 @@ Required properties:
   - r5g6b5 (16-bit pixels, d[15:11]=r, d[10:5]=g, d[4:0]=b).
   - a8b8g8r8 (32-bit pixels, d[31:24]=a, d[23:16]=b, d[15:8]=g, d[7:0]=r).
 
+Optional properties:
+- clocks : List of clocks used by the framebuffer. Clocks listed here
+           are expected to already be configured correctly. The OS must
+           ensure these clocks are not modified or disabled while the
+           simple framebuffer remains active.
+- display : phandle pointing to the primary display hardware node
+
 Example:
 
-	framebuffer {
+aliases {
+	display0 = &lcdc0;
+}
+
+chosen {
+	framebuffer0: framebuffer@1d385000 {
 		compatible = "simple-framebuffer";
 		reg = <0x1d385000 (1600 * 1200 * 2)>;
 		width = <1600>;
 		height = <1200>;
 		stride = <(1600 * 2)>;
 		format = "r5g6b5";
+		clocks = <&ahb_gates 36>, <&ahb_gates 43>, <&ahb_gates 44>;
+		display = <&lcdc0>;
+	};
+	stdout-path = "display0";
+};
+
+soc@01c00000 {
+	lcdc0: lcdc@1c0c000 {
+		compatible = "allwinner,sun4i-a10-lcdc";
+		...
 	};
+};
+
+
+*) Older devicetree files may have a compatible = "simple-framebuffer" node
+in a different place, operating systems must first enumerate any compatible
+nodes found under chosen and then check for other compatible nodes.
diff --git a/MAINTAINERS b/MAINTAINERS
index 1a4165094482..7bff8087fce7 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8586,6 +8586,14 @@ F:	drivers/media/usb/siano/
 F:	drivers/media/usb/siano/
 F:	drivers/media/mmc/siano/
 
+SIMPLEFB FB DRIVER
+M:	Hans de Goede <hdegoede@redhat.com>
+L:	linux-fbdev@vger.kernel.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/video/simple-framebuffer.txt
+F:	drivers/video/fbdev/simplefb.c
+F:	include/linux/platform_data/simplefb.h
+
 SH_VEU V4L2 MEM2MEM DRIVER
 L:	linux-media@vger.kernel.org
 S:	Orphan
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index eb976ee3a02f..ea437245562e 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -3624,7 +3624,7 @@ static int __init fb_console_init(void)
 	return 0;
 }
 
-module_init(fb_console_init);
+fs_initcall(fb_console_init);
 
 #ifdef MODULE
 
diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig
index c78bfd1d1b34..4916c97216f8 100644
--- a/drivers/video/fbdev/Kconfig
+++ b/drivers/video/fbdev/Kconfig
@@ -2408,7 +2408,7 @@ config FB_JZ4740
 
 config FB_MXS
 	tristate "MXS LCD framebuffer support"
-	depends on FB && ARCH_MXS
+	depends on FB && (ARCH_MXS || ARCH_MXC)
 	select FB_CFB_FILLRECT
 	select FB_CFB_COPYAREA
 	select FB_CFB_IMAGEBLIT
diff --git a/drivers/video/fbdev/amba-clcd.c b/drivers/video/fbdev/amba-clcd.c
index 6ad23bd3523a..32c0b6b28097 100644
--- a/drivers/video/fbdev/amba-clcd.c
+++ b/drivers/video/fbdev/amba-clcd.c
@@ -27,7 +27,6 @@
 #include <linux/bitops.h>
 #include <linux/clk.h>
 #include <linux/hardirq.h>
-#include <linux/dma-mapping.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_graph.h>
diff --git a/drivers/video/fbdev/arkfb.c b/drivers/video/fbdev/arkfb.c
index adc4ea2cc5a0..b305a1e7cc76 100644
--- a/drivers/video/fbdev/arkfb.c
+++ b/drivers/video/fbdev/arkfb.c
@@ -1016,7 +1016,7 @@ static int ark_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
 
 	pcibios_bus_to_resource(dev->bus, &vga_res, &bus_reg);
 
-	par->state.vgabase = (void __iomem *) vga_res.start;
+	par->state.vgabase = (void __iomem *) (unsigned long) vga_res.start;
 
 	/* FIXME get memsize */
 	regval = vga_rseq(par->state.vgabase, 0x10);
diff --git a/drivers/video/fbdev/mmp/core.c b/drivers/video/fbdev/mmp/core.c
index b563b920f159..a0f496049db7 100644
--- a/drivers/video/fbdev/mmp/core.c
+++ b/drivers/video/fbdev/mmp/core.c
@@ -223,10 +223,10 @@ struct mmp_path *mmp_register_path(struct mmp_path_info *info)
 EXPORT_SYMBOL_GPL(mmp_register_path);
 
 /*
- * mmp_unregister_path - unregister and destory path
- * @p: path to be destoried.
+ * mmp_unregister_path - unregister and destroy path
+ * @p: path to be destroyed.
  *
- * this function registers path and destorys it.
+ * this function registers path and destroys it.
  */
 void mmp_unregister_path(struct mmp_path *path)
 {
diff --git a/drivers/video/fbdev/mmp/hw/mmp_ctrl.c b/drivers/video/fbdev/mmp/hw/mmp_ctrl.c
index 8621a9f2bdcc..3c12bd83b561 100644
--- a/drivers/video/fbdev/mmp/hw/mmp_ctrl.c
+++ b/drivers/video/fbdev/mmp/hw/mmp_ctrl.c
@@ -441,8 +441,7 @@ static void path_deinit(struct mmphw_path_plat *path_plat)
 	if (!path_plat)
 		return;
 
-	if (path_plat->path)
-		mmp_unregister_path(path_plat->path);
+	mmp_unregister_path(path_plat->path);
 }
 
 static int mmphw_probe(struct platform_device *pdev)
diff --git a/drivers/video/fbdev/mx3fb.c b/drivers/video/fbdev/mx3fb.c
index 23ec781e9a61..f23fca0be9d7 100644
--- a/drivers/video/fbdev/mx3fb.c
+++ b/drivers/video/fbdev/mx3fb.c
@@ -334,8 +334,7 @@ static void mx3fb_init_backlight(struct mx3fb_data *fbd)
 
 static void mx3fb_exit_backlight(struct mx3fb_data *fbd)
 {
-	if (fbd->bl)
-		backlight_device_unregister(fbd->bl);
+	backlight_device_unregister(fbd->bl);
 }
 
 static void mx3fb_dma_done(void *);
diff --git a/drivers/video/fbdev/mxsfb.c b/drivers/video/fbdev/mxsfb.c
index accf48a2cce4..f8ac4a452f26 100644
--- a/drivers/video/fbdev/mxsfb.c
+++ b/drivers/video/fbdev/mxsfb.c
@@ -172,6 +172,8 @@ struct mxsfb_info {
 	struct fb_info fb_info;
 	struct platform_device *pdev;
 	struct clk *clk;
+	struct clk *clk_axi;
+	struct clk *clk_disp_axi;
 	void __iomem *base;	/* registers */
 	unsigned allocated_size;
 	int enabled;
@@ -331,6 +333,11 @@ static void mxsfb_enable_controller(struct fb_info *fb_info)
 		}
 	}
 
+	if (host->clk_axi)
+		clk_prepare_enable(host->clk_axi);
+
+	if (host->clk_disp_axi)
+		clk_prepare_enable(host->clk_disp_axi);
 	clk_prepare_enable(host->clk);
 	clk_set_rate(host->clk, PICOS2KHZ(fb_info->var.pixclock) * 1000U);
 
@@ -374,6 +381,10 @@ static void mxsfb_disable_controller(struct fb_info *fb_info)
 	writel(reg & ~VDCTRL4_SYNC_SIGNALS_ON, host->base + LCDC_VDCTRL4);
 
 	clk_disable_unprepare(host->clk);
+	if (host->clk_disp_axi)
+		clk_disable_unprepare(host->clk_disp_axi);
+	if (host->clk_axi)
+		clk_disable_unprepare(host->clk_axi);
 
 	host->enabled = 0;
 
@@ -867,6 +878,14 @@ static int mxsfb_probe(struct platform_device *pdev)
 		goto fb_release;
 	}
 
+	host->clk_axi = devm_clk_get(&host->pdev->dev, "axi");
+	if (IS_ERR(host->clk_axi))
+		host->clk_axi = NULL;
+
+	host->clk_disp_axi = devm_clk_get(&host->pdev->dev, "disp_axi");
+	if (IS_ERR(host->clk_disp_axi))
+		host->clk_disp_axi = NULL;
+
 	host->reg_lcd = devm_regulator_get(&pdev->dev, "lcd");
 	if (IS_ERR(host->reg_lcd))
 		host->reg_lcd = NULL;
diff --git a/drivers/video/fbdev/omap2/displays-new/connector-dvi.c b/drivers/video/fbdev/omap2/displays-new/connector-dvi.c
index 2dfb6e5ff0cc..3d38e478bc64 100644
--- a/drivers/video/fbdev/omap2/displays-new/connector-dvi.c
+++ b/drivers/video/fbdev/omap2/displays-new/connector-dvi.c
@@ -262,8 +262,7 @@ static int dvic_probe_pdata(struct platform_device *pdev)
 
 	in = omap_dss_find_output(pdata->source);
 	if (in == NULL) {
-		if (ddata->i2c_adapter)
-			i2c_put_adapter(ddata->i2c_adapter);
+		i2c_put_adapter(ddata->i2c_adapter);
 
 		dev_err(&pdev->dev, "Failed to find video source\n");
 		return -EPROBE_DEFER;
@@ -352,8 +351,7 @@ static int dvic_probe(struct platform_device *pdev)
 err_reg:
 	omap_dss_put_device(ddata->in);
 
-	if (ddata->i2c_adapter)
-		i2c_put_adapter(ddata->i2c_adapter);
+	i2c_put_adapter(ddata->i2c_adapter);
 
 	return r;
 }
@@ -371,8 +369,7 @@ static int __exit dvic_remove(struct platform_device *pdev)
 
 	omap_dss_put_device(in);
 
-	if (ddata->i2c_adapter)
-		i2c_put_adapter(ddata->i2c_adapter);
+	i2c_put_adapter(ddata->i2c_adapter);
 
 	return 0;
 }
diff --git a/drivers/video/fbdev/omap2/displays-new/connector-hdmi.c b/drivers/video/fbdev/omap2/displays-new/connector-hdmi.c
index 7b25967a91eb..219f14f59672 100644
--- a/drivers/video/fbdev/omap2/displays-new/connector-hdmi.c
+++ b/drivers/video/fbdev/omap2/displays-new/connector-hdmi.c
@@ -170,98 +170,6 @@ static bool hdmic_detect(struct omap_dss_device *dssdev)
 		return in->ops.hdmi->detect(in);
 }
 
-static int hdmic_audio_enable(struct omap_dss_device *dssdev)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-	int r;
-
-	/* enable audio only if the display is active */
-	if (!omapdss_device_is_enabled(dssdev))
-		return -EPERM;
-
-	r = in->ops.hdmi->audio_enable(in);
-	if (r)
-		return r;
-
-	dssdev->audio_state = OMAP_DSS_AUDIO_ENABLED;
-
-	return 0;
-}
-
-static void hdmic_audio_disable(struct omap_dss_device *dssdev)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	in->ops.hdmi->audio_disable(in);
-
-	dssdev->audio_state = OMAP_DSS_AUDIO_DISABLED;
-}
-
-static int hdmic_audio_start(struct omap_dss_device *dssdev)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-	int r;
-
-	/*
-	 * No need to check the panel state. It was checked when trasitioning
-	 * to AUDIO_ENABLED.
-	 */
-	if (dssdev->audio_state != OMAP_DSS_AUDIO_ENABLED)
-		return -EPERM;
-
-	r = in->ops.hdmi->audio_start(in);
-	if (r)
-		return r;
-
-	dssdev->audio_state = OMAP_DSS_AUDIO_PLAYING;
-
-	return 0;
-}
-
-static void hdmic_audio_stop(struct omap_dss_device *dssdev)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	in->ops.hdmi->audio_stop(in);
-
-	dssdev->audio_state = OMAP_DSS_AUDIO_ENABLED;
-}
-
-static bool hdmic_audio_supported(struct omap_dss_device *dssdev)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	if (!omapdss_device_is_enabled(dssdev))
-		return false;
-
-	return in->ops.hdmi->audio_supported(in);
-}
-
-static int hdmic_audio_config(struct omap_dss_device *dssdev,
-		struct omap_dss_audio *audio)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-	int r;
-
-	/* config audio only if the display is active */
-	if (!omapdss_device_is_enabled(dssdev))
-		return -EPERM;
-
-	r = in->ops.hdmi->audio_config(in, audio);
-	if (r)
-		return r;
-
-	dssdev->audio_state = OMAP_DSS_AUDIO_CONFIGURED;
-
-	return 0;
-}
-
 static int hdmic_set_hdmi_mode(struct omap_dss_device *dssdev, bool hdmi_mode)
 {
 	struct panel_drv_data *ddata = to_panel_data(dssdev);
@@ -296,13 +204,6 @@ static struct omap_dss_driver hdmic_driver = {
 	.detect			= hdmic_detect,
 	.set_hdmi_mode		= hdmic_set_hdmi_mode,
 	.set_hdmi_infoframe	= hdmic_set_infoframe,
-
-	.audio_enable		= hdmic_audio_enable,
-	.audio_disable		= hdmic_audio_disable,
-	.audio_start		= hdmic_audio_start,
-	.audio_stop		= hdmic_audio_stop,
-	.audio_supported	= hdmic_audio_supported,
-	.audio_config		= hdmic_audio_config,
 };
 
 static int hdmic_probe_pdata(struct platform_device *pdev)
diff --git a/drivers/video/fbdev/omap2/displays-new/encoder-tfp410.c b/drivers/video/fbdev/omap2/displays-new/encoder-tfp410.c
index 47ee7cdee1c5..e349064ed615 100644
--- a/drivers/video/fbdev/omap2/displays-new/encoder-tfp410.c
+++ b/drivers/video/fbdev/omap2/displays-new/encoder-tfp410.c
@@ -249,6 +249,7 @@ static int tfp410_probe(struct platform_device *pdev)
 	dssdev->output_type = OMAP_DISPLAY_TYPE_DVI;
 	dssdev->owner = THIS_MODULE;
 	dssdev->phy.dpi.data_lines = ddata->data_lines;
+	dssdev->port_num = 1;
 
 	r = omapdss_register_output(dssdev);
 	if (r) {
diff --git a/drivers/video/fbdev/omap2/displays-new/encoder-tpd12s015.c b/drivers/video/fbdev/omap2/displays-new/encoder-tpd12s015.c
index c4abd56dd846..c7a3ce2c5120 100644
--- a/drivers/video/fbdev/omap2/displays-new/encoder-tpd12s015.c
+++ b/drivers/video/fbdev/omap2/displays-new/encoder-tpd12s015.c
@@ -193,55 +193,6 @@ static bool tpd_detect(struct omap_dss_device *dssdev)
 	return gpio_get_value_cansleep(ddata->hpd_gpio);
 }
 
-static int tpd_audio_enable(struct omap_dss_device *dssdev)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	return in->ops.hdmi->audio_enable(in);
-}
-
-static void tpd_audio_disable(struct omap_dss_device *dssdev)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	in->ops.hdmi->audio_disable(in);
-}
-
-static int tpd_audio_start(struct omap_dss_device *dssdev)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	return in->ops.hdmi->audio_start(in);
-}
-
-static void tpd_audio_stop(struct omap_dss_device *dssdev)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	in->ops.hdmi->audio_stop(in);
-}
-
-static bool tpd_audio_supported(struct omap_dss_device *dssdev)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	return in->ops.hdmi->audio_supported(in);
-}
-
-static int tpd_audio_config(struct omap_dss_device *dssdev,
-		struct omap_dss_audio *audio)
-{
-	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
-
-	return in->ops.hdmi->audio_config(in, audio);
-}
-
 static int tpd_set_infoframe(struct omap_dss_device *dssdev,
 		const struct hdmi_avi_infoframe *avi)
 {
@@ -275,13 +226,6 @@ static const struct omapdss_hdmi_ops tpd_hdmi_ops = {
 	.detect			= tpd_detect,
 	.set_infoframe		= tpd_set_infoframe,
 	.set_hdmi_mode		= tpd_set_hdmi_mode,
-
-	.audio_enable		= tpd_audio_enable,
-	.audio_disable		= tpd_audio_disable,
-	.audio_start		= tpd_audio_start,
-	.audio_stop		= tpd_audio_stop,
-	.audio_supported	= tpd_audio_supported,
-	.audio_config		= tpd_audio_config,
 };
 
 static int tpd_probe_pdata(struct platform_device *pdev)
@@ -409,6 +353,7 @@ static int tpd_probe(struct platform_device *pdev)
 	dssdev->type = OMAP_DISPLAY_TYPE_HDMI;
 	dssdev->output_type = OMAP_DISPLAY_TYPE_HDMI;
 	dssdev->owner = THIS_MODULE;
+	dssdev->port_num = 1;
 
 	in = ddata->in;
 
diff --git a/drivers/video/fbdev/omap2/dss/Kconfig b/drivers/video/fbdev/omap2/dss/Kconfig
index 3d5eb6c36c22..d1fa730c7d54 100644
--- a/drivers/video/fbdev/omap2/dss/Kconfig
+++ b/drivers/video/fbdev/omap2/dss/Kconfig
@@ -74,9 +74,6 @@ config OMAP4_DSS_HDMI
 	help
 	  HDMI support for OMAP4 based SoCs.
 
-config OMAP4_DSS_HDMI_AUDIO
-	bool
-
 config OMAP5_DSS_HDMI
 	bool "HDMI support for OMAP5"
 	default n
@@ -86,10 +83,6 @@ config OMAP5_DSS_HDMI
 	  Definition Multimedia Interface. See http://www.hdmi.org/ for HDMI
 	  specification.
 
-config OMAP5_DSS_HDMI_AUDIO
-	depends on OMAP5_DSS_HDMI
-	bool
-
 config OMAP2_DSS_SDI
 	bool "SDI support"
         default n
diff --git a/drivers/video/fbdev/omap2/dss/Makefile b/drivers/video/fbdev/omap2/dss/Makefile
index 245f933060ee..2ea9d382354c 100644
--- a/drivers/video/fbdev/omap2/dss/Makefile
+++ b/drivers/video/fbdev/omap2/dss/Makefile
@@ -2,7 +2,7 @@ obj-$(CONFIG_OMAP2_DSS_INIT) += omapdss-boot-init.o
 obj-$(CONFIG_OMAP2_DSS) += omapdss.o
 # Core DSS files
 omapdss-y := core.o dss.o dss_features.o dispc.o dispc_coefs.o display.o \
-	output.o dss-of.o
+	output.o dss-of.o pll.o
 # DSS compat layer files
 omapdss-y += manager.o manager-sysfs.o overlay.o overlay-sysfs.o apply.o \
 	dispc-compat.o display-sysfs.o
diff --git a/drivers/video/fbdev/omap2/dss/dispc.c b/drivers/video/fbdev/omap2/dss/dispc.c
index 0e9a74bb9fc2..0729c08ac75a 100644
--- a/drivers/video/fbdev/omap2/dss/dispc.c
+++ b/drivers/video/fbdev/omap2/dss/dispc.c
@@ -3028,7 +3028,7 @@ static void dispc_mgr_get_lcd_divisor(enum omap_channel channel, int *lck_div,
 
 unsigned long dispc_fclk_rate(void)
 {
-	struct platform_device *dsidev;
+	struct dss_pll *pll;
 	unsigned long r = 0;
 
 	switch (dss_get_dispc_clk_source()) {
@@ -3036,12 +3036,12 @@ unsigned long dispc_fclk_rate(void)
 		r = dss_get_dispc_clk_rate();
 		break;
 	case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
-		dsidev = dsi_get_dsidev_from_id(0);
-		r = dsi_get_pll_hsdiv_dispc_rate(dsidev);
+		pll = dss_pll_find("dsi0");
+		r = pll->cinfo.clkout[0];
 		break;
 	case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
-		dsidev = dsi_get_dsidev_from_id(1);
-		r = dsi_get_pll_hsdiv_dispc_rate(dsidev);
+		pll = dss_pll_find("dsi1");
+		r = pll->cinfo.clkout[0];
 		break;
 	default:
 		BUG();
@@ -3053,7 +3053,7 @@ unsigned long dispc_fclk_rate(void)
 
 unsigned long dispc_mgr_lclk_rate(enum omap_channel channel)
 {
-	struct platform_device *dsidev;
+	struct dss_pll *pll;
 	int lcd;
 	unsigned long r;
 	u32 l;
@@ -3068,12 +3068,12 @@ unsigned long dispc_mgr_lclk_rate(enum omap_channel channel)
 			r = dss_get_dispc_clk_rate();
 			break;
 		case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
-			dsidev = dsi_get_dsidev_from_id(0);
-			r = dsi_get_pll_hsdiv_dispc_rate(dsidev);
+			pll = dss_pll_find("dsi0");
+			r = pll->cinfo.clkout[0];
 			break;
 		case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
-			dsidev = dsi_get_dsidev_from_id(1);
-			r = dsi_get_pll_hsdiv_dispc_rate(dsidev);
+			pll = dss_pll_find("dsi1");
+			r = pll->cinfo.clkout[0];
 			break;
 		default:
 			BUG();
diff --git a/drivers/video/fbdev/omap2/dss/dpi.c b/drivers/video/fbdev/omap2/dss/dpi.c
index 4a3363dae74a..2edf5caa002f 100644
--- a/drivers/video/fbdev/omap2/dss/dpi.c
+++ b/drivers/video/fbdev/omap2/dss/dpi.c
@@ -31,17 +31,20 @@
 #include <linux/regulator/consumer.h>
 #include <linux/string.h>
 #include <linux/of.h>
+#include <linux/clk.h>
 
 #include <video/omapdss.h>
 
 #include "dss.h"
 #include "dss_features.h"
 
-static struct {
+#define HSDIV_DISPC	0
+
+struct dpi_data {
 	struct platform_device *pdev;
 
 	struct regulator *vdds_dsi_reg;
-	struct platform_device *dsidev;
+	struct dss_pll *pll;
 
 	struct mutex lock;
 
@@ -52,9 +55,20 @@ static struct {
 	struct omap_dss_device output;
 
 	bool port_initialized;
-} dpi;
+};
+
+static struct dpi_data *dpi_get_data_from_dssdev(struct omap_dss_device *dssdev)
+{
+	return container_of(dssdev, struct dpi_data, output);
+}
+
+/* only used in non-DT mode */
+static struct dpi_data *dpi_get_data_from_pdev(struct platform_device *pdev)
+{
+	return dev_get_drvdata(&pdev->dev);
+}
 
-static struct platform_device *dpi_get_dsidev(enum omap_channel channel)
+static struct dss_pll *dpi_get_pll(enum omap_channel channel)
 {
 	/*
 	 * XXX we can't currently use DSI PLL for DPI with OMAP3, as the DSI PLL
@@ -75,9 +89,9 @@ static struct platform_device *dpi_get_dsidev(enum omap_channel channel)
 	case OMAPDSS_VER_OMAP4:
 		switch (channel) {
 		case OMAP_DSS_CHANNEL_LCD:
-			return dsi_get_dsidev_from_id(0);
+			return dss_pll_find("dsi0");
 		case OMAP_DSS_CHANNEL_LCD2:
-			return dsi_get_dsidev_from_id(1);
+			return dss_pll_find("dsi1");
 		default:
 			return NULL;
 		}
@@ -85,9 +99,9 @@ static struct platform_device *dpi_get_dsidev(enum omap_channel channel)
 	case OMAPDSS_VER_OMAP5:
 		switch (channel) {
 		case OMAP_DSS_CHANNEL_LCD:
-			return dsi_get_dsidev_from_id(0);
+			return dss_pll_find("dsi0");
 		case OMAP_DSS_CHANNEL_LCD3:
-			return dsi_get_dsidev_from_id(1);
+			return dss_pll_find("dsi1");
 		default:
 			return NULL;
 		}
@@ -114,7 +128,7 @@ static enum omap_dss_clk_source dpi_get_alt_clk_src(enum omap_channel channel)
 }
 
 struct dpi_clk_calc_ctx {
-	struct platform_device *dsidev;
+	struct dss_pll *pll;
 
 	/* inputs */
 
@@ -122,7 +136,7 @@ struct dpi_clk_calc_ctx {
 
 	/* outputs */
 
-	struct dsi_clock_info dsi_cinfo;
+	struct dss_pll_clock_info dsi_cinfo;
 	unsigned long fck;
 	struct dispc_clock_info dispc_cinfo;
 };
@@ -154,7 +168,7 @@ static bool dpi_calc_dispc_cb(int lckd, int pckd, unsigned long lck,
 }
 
 
-static bool dpi_calc_hsdiv_cb(int regm_dispc, unsigned long dispc,
+static bool dpi_calc_hsdiv_cb(int m_dispc, unsigned long dispc,
 		void *data)
 {
 	struct dpi_clk_calc_ctx *ctx = data;
@@ -164,30 +178,31 @@ static bool dpi_calc_hsdiv_cb(int regm_dispc, unsigned long dispc,
 	 * shifted. So skip all odd dividers when the pixel clock is on the
 	 * higher side.
 	 */
-	if (regm_dispc > 1 && regm_dispc % 2 != 0 && ctx->pck_min >= 100000000)
+	if (m_dispc > 1 && m_dispc % 2 != 0 && ctx->pck_min >= 100000000)
 		return false;
 
-	ctx->dsi_cinfo.regm_dispc = regm_dispc;
-	ctx->dsi_cinfo.dsi_pll_hsdiv_dispc_clk = dispc;
+	ctx->dsi_cinfo.mX[HSDIV_DISPC] = m_dispc;
+	ctx->dsi_cinfo.clkout[HSDIV_DISPC] = dispc;
 
 	return dispc_div_calc(dispc, ctx->pck_min, ctx->pck_max,
 			dpi_calc_dispc_cb, ctx);
 }
 
 
-static bool dpi_calc_pll_cb(int regn, int regm, unsigned long fint,
-		unsigned long pll,
+static bool dpi_calc_pll_cb(int n, int m, unsigned long fint,
+		unsigned long clkdco,
 		void *data)
 {
 	struct dpi_clk_calc_ctx *ctx = data;
 
-	ctx->dsi_cinfo.regn = regn;
-	ctx->dsi_cinfo.regm = regm;
+	ctx->dsi_cinfo.n = n;
+	ctx->dsi_cinfo.m = m;
 	ctx->dsi_cinfo.fint = fint;
-	ctx->dsi_cinfo.clkin4ddr = pll;
+	ctx->dsi_cinfo.clkdco = clkdco;
 
-	return dsi_hsdiv_calc(ctx->dsidev, pll, ctx->pck_min,
-			dpi_calc_hsdiv_cb, ctx);
+	return dss_pll_hsdiv_calc(ctx->pll, clkdco,
+		ctx->pck_min, dss_feat_get_param_max(FEAT_PARAM_DSS_FCK),
+		dpi_calc_hsdiv_cb, ctx);
 }
 
 static bool dpi_calc_dss_cb(unsigned long fck, void *data)
@@ -200,23 +215,23 @@ static bool dpi_calc_dss_cb(unsigned long fck, void *data)
 			dpi_calc_dispc_cb, ctx);
 }
 
-static bool dpi_dsi_clk_calc(unsigned long pck, struct dpi_clk_calc_ctx *ctx)
+static bool dpi_dsi_clk_calc(struct dpi_data *dpi, unsigned long pck,
+		struct dpi_clk_calc_ctx *ctx)
 {
 	unsigned long clkin;
 	unsigned long pll_min, pll_max;
 
-	clkin = dsi_get_pll_clkin(dpi.dsidev);
-
 	memset(ctx, 0, sizeof(*ctx));
-	ctx->dsidev = dpi.dsidev;
+	ctx->pll = dpi->pll;
 	ctx->pck_min = pck - 1000;
 	ctx->pck_max = pck + 1000;
-	ctx->dsi_cinfo.clkin = clkin;
 
 	pll_min = 0;
 	pll_max = 0;
 
-	return dsi_pll_calc(dpi.dsidev, clkin,
+	clkin = clk_get_rate(ctx->pll->clkin);
+
+	return dss_pll_calc(ctx->pll, clkin,
 			pll_min, pll_max,
 			dpi_calc_pll_cb, ctx);
 }
@@ -252,7 +267,7 @@ static bool dpi_dss_clk_calc(unsigned long pck, struct dpi_clk_calc_ctx *ctx)
 
 
 
-static int dpi_set_dsi_clk(enum omap_channel channel,
+static int dpi_set_dsi_clk(struct dpi_data *dpi, enum omap_channel channel,
 		unsigned long pck_req, unsigned long *fck, int *lck_div,
 		int *pck_div)
 {
@@ -260,28 +275,28 @@ static int dpi_set_dsi_clk(enum omap_channel channel,
 	int r;
 	bool ok;
 
-	ok = dpi_dsi_clk_calc(pck_req, &ctx);
+	ok = dpi_dsi_clk_calc(dpi, pck_req, &ctx);
 	if (!ok)
 		return -EINVAL;
 
-	r = dsi_pll_set_clock_div(dpi.dsidev, &ctx.dsi_cinfo);
+	r = dss_pll_set_config(dpi->pll, &ctx.dsi_cinfo);
 	if (r)
 		return r;
 
 	dss_select_lcd_clk_source(channel,
 			dpi_get_alt_clk_src(channel));
 
-	dpi.mgr_config.clock_info = ctx.dispc_cinfo;
+	dpi->mgr_config.clock_info = ctx.dispc_cinfo;
 
-	*fck = ctx.dsi_cinfo.dsi_pll_hsdiv_dispc_clk;
+	*fck = ctx.dsi_cinfo.clkout[HSDIV_DISPC];
 	*lck_div = ctx.dispc_cinfo.lck_div;
 	*pck_div = ctx.dispc_cinfo.pck_div;
 
 	return 0;
 }
 
-static int dpi_set_dispc_clk(unsigned long pck_req, unsigned long *fck,
-		int *lck_div, int *pck_div)
+static int dpi_set_dispc_clk(struct dpi_data *dpi, unsigned long pck_req,
+		unsigned long *fck, int *lck_div, int *pck_div)
 {
 	struct dpi_clk_calc_ctx ctx;
 	int r;
@@ -295,7 +310,7 @@ static int dpi_set_dispc_clk(unsigned long pck_req, unsigned long *fck,
 	if (r)
 		return r;
 
-	dpi.mgr_config.clock_info = ctx.dispc_cinfo;
+	dpi->mgr_config.clock_info = ctx.dispc_cinfo;
 
 	*fck = ctx.fck;
 	*lck_div = ctx.dispc_cinfo.lck_div;
@@ -304,19 +319,21 @@ static int dpi_set_dispc_clk(unsigned long pck_req, unsigned long *fck,
 	return 0;
 }
 
-static int dpi_set_mode(struct omap_overlay_manager *mgr)
+static int dpi_set_mode(struct dpi_data *dpi)
 {
-	struct omap_video_timings *t = &dpi.timings;
+	struct omap_dss_device *out = &dpi->output;
+	struct omap_overlay_manager *mgr = out->manager;
+	struct omap_video_timings *t = &dpi->timings;
 	int lck_div = 0, pck_div = 0;
 	unsigned long fck = 0;
 	unsigned long pck;
 	int r = 0;
 
-	if (dpi.dsidev)
-		r = dpi_set_dsi_clk(mgr->id, t->pixelclock, &fck,
+	if (dpi->pll)
+		r = dpi_set_dsi_clk(dpi, mgr->id, t->pixelclock, &fck,
 				&lck_div, &pck_div);
 	else
-		r = dpi_set_dispc_clk(t->pixelclock, &fck,
+		r = dpi_set_dispc_clk(dpi, t->pixelclock, &fck,
 				&lck_div, &pck_div);
 	if (r)
 		return r;
@@ -335,28 +352,32 @@ static int dpi_set_mode(struct omap_overlay_manager *mgr)
 	return 0;
 }
 
-static void dpi_config_lcd_manager(struct omap_overlay_manager *mgr)
+static void dpi_config_lcd_manager(struct dpi_data *dpi)
 {
-	dpi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;
+	struct omap_dss_device *out = &dpi->output;
+	struct omap_overlay_manager *mgr = out->manager;
+
+	dpi->mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;
 
-	dpi.mgr_config.stallmode = false;
-	dpi.mgr_config.fifohandcheck = false;
+	dpi->mgr_config.stallmode = false;
+	dpi->mgr_config.fifohandcheck = false;
 
-	dpi.mgr_config.video_port_width = dpi.data_lines;
+	dpi->mgr_config.video_port_width = dpi->data_lines;
 
-	dpi.mgr_config.lcden_sig_polarity = 0;
+	dpi->mgr_config.lcden_sig_polarity = 0;
 
-	dss_mgr_set_lcd_config(mgr, &dpi.mgr_config);
+	dss_mgr_set_lcd_config(mgr, &dpi->mgr_config);
 }
 
 static int dpi_display_enable(struct omap_dss_device *dssdev)
 {
-	struct omap_dss_device *out = &dpi.output;
+	struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
+	struct omap_dss_device *out = &dpi->output;
 	int r;
 
-	mutex_lock(&dpi.lock);
+	mutex_lock(&dpi->lock);
 
-	if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) && !dpi.vdds_dsi_reg) {
+	if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) && !dpi->vdds_dsi_reg) {
 		DSSERR("no VDSS_DSI regulator\n");
 		r = -ENODEV;
 		goto err_no_reg;
@@ -369,7 +390,7 @@ static int dpi_display_enable(struct omap_dss_device *dssdev)
 	}
 
 	if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) {
-		r = regulator_enable(dpi.vdds_dsi_reg);
+		r = regulator_enable(dpi->vdds_dsi_reg);
 		if (r)
 			goto err_reg_enable;
 	}
@@ -378,25 +399,21 @@ static int dpi_display_enable(struct omap_dss_device *dssdev)
 	if (r)
 		goto err_get_dispc;
 
-	r = dss_dpi_select_source(out->manager->id);
+	r = dss_dpi_select_source(out->port_num, out->manager->id);
 	if (r)
 		goto err_src_sel;
 
-	if (dpi.dsidev) {
-		r = dsi_runtime_get(dpi.dsidev);
-		if (r)
-			goto err_get_dsi;
-
-		r = dsi_pll_init(dpi.dsidev, 0, 1);
+	if (dpi->pll) {
+		r = dss_pll_enable(dpi->pll);
 		if (r)
 			goto err_dsi_pll_init;
 	}
 
-	r = dpi_set_mode(out->manager);
+	r = dpi_set_mode(dpi);
 	if (r)
 		goto err_set_mode;
 
-	dpi_config_lcd_manager(out->manager);
+	dpi_config_lcd_manager(dpi);
 
 	mdelay(2);
 
@@ -404,78 +421,80 @@ static int dpi_display_enable(struct omap_dss_device *dssdev)
 	if (r)
 		goto err_mgr_enable;
 
-	mutex_unlock(&dpi.lock);
+	mutex_unlock(&dpi->lock);
 
 	return 0;
 
 err_mgr_enable:
 err_set_mode:
-	if (dpi.dsidev)
-		dsi_pll_uninit(dpi.dsidev, true);
+	if (dpi->pll)
+		dss_pll_disable(dpi->pll);
 err_dsi_pll_init:
-	if (dpi.dsidev)
-		dsi_runtime_put(dpi.dsidev);
-err_get_dsi:
 err_src_sel:
 	dispc_runtime_put();
 err_get_dispc:
 	if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
-		regulator_disable(dpi.vdds_dsi_reg);
+		regulator_disable(dpi->vdds_dsi_reg);
 err_reg_enable:
 err_no_out_mgr:
 err_no_reg:
-	mutex_unlock(&dpi.lock);
+	mutex_unlock(&dpi->lock);
 	return r;
 }
 
 static void dpi_display_disable(struct omap_dss_device *dssdev)
 {
-	struct omap_overlay_manager *mgr = dpi.output.manager;
+	struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
+	struct omap_overlay_manager *mgr = dpi->output.manager;
 
-	mutex_lock(&dpi.lock);
+	mutex_lock(&dpi->lock);
 
 	dss_mgr_disable(mgr);
 
-	if (dpi.dsidev) {
+	if (dpi->pll) {
 		dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK);
-		dsi_pll_uninit(dpi.dsidev, true);
-		dsi_runtime_put(dpi.dsidev);
+		dss_pll_disable(dpi->pll);
 	}
 
 	dispc_runtime_put();
 
 	if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
-		regulator_disable(dpi.vdds_dsi_reg);
+		regulator_disable(dpi->vdds_dsi_reg);
 
-	mutex_unlock(&dpi.lock);
+	mutex_unlock(&dpi->lock);
 }
 
 static void dpi_set_timings(struct omap_dss_device *dssdev,
 		struct omap_video_timings *timings)
 {
+	struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
+
 	DSSDBG("dpi_set_timings\n");
 
-	mutex_lock(&dpi.lock);
+	mutex_lock(&dpi->lock);
 
-	dpi.timings = *timings;
+	dpi->timings = *timings;
 
-	mutex_unlock(&dpi.lock);
+	mutex_unlock(&dpi->lock);
 }
 
 static void dpi_get_timings(struct omap_dss_device *dssdev,
 		struct omap_video_timings *timings)
 {
-	mutex_lock(&dpi.lock);
+	struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
+
+	mutex_lock(&dpi->lock);
 
-	*timings = dpi.timings;
+	*timings = dpi->timings;
 
-	mutex_unlock(&dpi.lock);
+	mutex_unlock(&dpi->lock);
 }
 
 static int dpi_check_timings(struct omap_dss_device *dssdev,
 			struct omap_video_timings *timings)
 {
-	struct omap_overlay_manager *mgr = dpi.output.manager;
+	struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
+	struct omap_overlay_manager *mgr = dpi->output.manager;
 	int lck_div, pck_div;
 	unsigned long fck;
 	unsigned long pck;
@@ -488,12 +507,12 @@ static int dpi_check_timings(struct omap_dss_device *dssdev,
 	if (timings->pixelclock == 0)
 		return -EINVAL;
 
-	if (dpi.dsidev) {
-		ok = dpi_dsi_clk_calc(timings->pixelclock, &ctx);
+	if (dpi->pll) {
+		ok = dpi_dsi_clk_calc(dpi, timings->pixelclock, &ctx);
 		if (!ok)
 			return -EINVAL;
 
-		fck = ctx.dsi_cinfo.dsi_pll_hsdiv_dispc_clk;
+		fck = ctx.dsi_cinfo.clkout[HSDIV_DISPC];
 	} else {
 		ok = dpi_dss_clk_calc(timings->pixelclock, &ctx);
 		if (!ok)
@@ -514,74 +533,69 @@ static int dpi_check_timings(struct omap_dss_device *dssdev,
 
 static void dpi_set_data_lines(struct omap_dss_device *dssdev, int data_lines)
 {
-	mutex_lock(&dpi.lock);
+	struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
 
-	dpi.data_lines = data_lines;
+	mutex_lock(&dpi->lock);
 
-	mutex_unlock(&dpi.lock);
+	dpi->data_lines = data_lines;
+
+	mutex_unlock(&dpi->lock);
 }
 
-static int dpi_verify_dsi_pll(struct platform_device *dsidev)
+static int dpi_verify_dsi_pll(struct dss_pll *pll)
 {
 	int r;
 
 	/* do initial setup with the PLL to see if it is operational */
 
-	r = dsi_runtime_get(dsidev);
+	r = dss_pll_enable(pll);
 	if (r)
 		return r;
 
-	r = dsi_pll_init(dsidev, 0, 1);
-	if (r) {
-		dsi_runtime_put(dsidev);
-		return r;
-	}
-
-	dsi_pll_uninit(dsidev, true);
-	dsi_runtime_put(dsidev);
+	dss_pll_disable(pll);
 
 	return 0;
 }
 
-static int dpi_init_regulator(void)
+static int dpi_init_regulator(struct dpi_data *dpi)
 {
 	struct regulator *vdds_dsi;
 
 	if (!dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
 		return 0;
 
-	if (dpi.vdds_dsi_reg)
+	if (dpi->vdds_dsi_reg)
 		return 0;
 
-	vdds_dsi = devm_regulator_get(&dpi.pdev->dev, "vdds_dsi");
+	vdds_dsi = devm_regulator_get(&dpi->pdev->dev, "vdds_dsi");
 	if (IS_ERR(vdds_dsi)) {
 		if (PTR_ERR(vdds_dsi) != -EPROBE_DEFER)
 			DSSERR("can't get VDDS_DSI regulator\n");
 		return PTR_ERR(vdds_dsi);
 	}
 
-	dpi.vdds_dsi_reg = vdds_dsi;
+	dpi->vdds_dsi_reg = vdds_dsi;
 
 	return 0;
 }
 
-static void dpi_init_pll(void)
+static void dpi_init_pll(struct dpi_data *dpi)
 {
-	struct platform_device *dsidev;
+	struct dss_pll *pll;
 
-	if (dpi.dsidev)
+	if (dpi->pll)
 		return;
 
-	dsidev = dpi_get_dsidev(dpi.output.dispc_channel);
-	if (!dsidev)
+	pll = dpi_get_pll(dpi->output.dispc_channel);
+	if (!pll)
 		return;
 
-	if (dpi_verify_dsi_pll(dsidev)) {
+	if (dpi_verify_dsi_pll(pll)) {
 		DSSWARN("DSI PLL not operational\n");
 		return;
 	}
 
-	dpi.dsidev = dsidev;
+	dpi->pll = pll;
 }
 
 /*
@@ -590,7 +604,7 @@ static void dpi_init_pll(void)
  * the channel in some more dynamic manner, or get the channel as a user
  * parameter.
  */
-static enum omap_channel dpi_get_channel(void)
+static enum omap_channel dpi_get_channel(int port_num)
 {
 	switch (omapdss_get_version()) {
 	case OMAPDSS_VER_OMAP24xx:
@@ -618,14 +632,15 @@ static enum omap_channel dpi_get_channel(void)
 static int dpi_connect(struct omap_dss_device *dssdev,
 		struct omap_dss_device *dst)
 {
+	struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
 	struct omap_overlay_manager *mgr;
 	int r;
 
-	r = dpi_init_regulator();
+	r = dpi_init_regulator(dpi);
 	if (r)
 		return r;
 
-	dpi_init_pll();
+	dpi_init_pll(dpi);
 
 	mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel);
 	if (!mgr)
@@ -676,13 +691,14 @@ static const struct omapdss_dpi_ops dpi_ops = {
 
 static void dpi_init_output(struct platform_device *pdev)
 {
-	struct omap_dss_device *out = &dpi.output;
+	struct dpi_data *dpi = dpi_get_data_from_pdev(pdev);
+	struct omap_dss_device *out = &dpi->output;
 
 	out->dev = &pdev->dev;
 	out->id = OMAP_DSS_OUTPUT_DPI;
 	out->output_type = OMAP_DISPLAY_TYPE_DPI;
 	out->name = "dpi.0";
-	out->dispc_channel = dpi_get_channel();
+	out->dispc_channel = dpi_get_channel(0);
 	out->ops.dpi = &dpi_ops;
 	out->owner = THIS_MODULE;
 
@@ -691,16 +707,69 @@ static void dpi_init_output(struct platform_device *pdev)
 
 static void __exit dpi_uninit_output(struct platform_device *pdev)
 {
-	struct omap_dss_device *out = &dpi.output;
+	struct dpi_data *dpi = dpi_get_data_from_pdev(pdev);
+	struct omap_dss_device *out = &dpi->output;
+
+	omapdss_unregister_output(out);
+}
+
+static void dpi_init_output_port(struct platform_device *pdev,
+	struct device_node *port)
+{
+	struct dpi_data *dpi = port->data;
+	struct omap_dss_device *out = &dpi->output;
+	int r;
+	u32 port_num;
+
+	r = of_property_read_u32(port, "reg", &port_num);
+	if (r)
+		port_num = 0;
+
+	switch (port_num) {
+	case 2:
+		out->name = "dpi.2";
+		break;
+	case 1:
+		out->name = "dpi.1";
+		break;
+	case 0:
+	default:
+		out->name = "dpi.0";
+		break;
+	}
+
+	out->dev = &pdev->dev;
+	out->id = OMAP_DSS_OUTPUT_DPI;
+	out->output_type = OMAP_DISPLAY_TYPE_DPI;
+	out->dispc_channel = dpi_get_channel(port_num);
+	out->port_num = port_num;
+	out->ops.dpi = &dpi_ops;
+	out->owner = THIS_MODULE;
+
+	omapdss_register_output(out);
+}
+
+static void __exit dpi_uninit_output_port(struct device_node *port)
+{
+	struct dpi_data *dpi = port->data;
+	struct omap_dss_device *out = &dpi->output;
 
 	omapdss_unregister_output(out);
 }
 
 static int omap_dpi_probe(struct platform_device *pdev)
 {
-	dpi.pdev = pdev;
+	struct dpi_data *dpi;
+
+	dpi = devm_kzalloc(&pdev->dev, sizeof(*dpi), GFP_KERNEL);
+	if (!dpi)
+		return -ENOMEM;
 
-	mutex_init(&dpi.lock);
+	dpi->pdev = pdev;
+
+	dev_set_drvdata(&pdev->dev, dpi);
+
+	mutex_init(&dpi->lock);
 
 	dpi_init_output(pdev);
 
@@ -736,10 +805,15 @@ void __exit dpi_uninit_platform_driver(void)
 
 int __init dpi_init_port(struct platform_device *pdev, struct device_node *port)
 {
+	struct dpi_data *dpi;
 	struct device_node *ep;
 	u32 datalines;
 	int r;
 
+	dpi = devm_kzalloc(&pdev->dev, sizeof(*dpi), GFP_KERNEL);
+	if (!dpi)
+		return -ENOMEM;
+
 	ep = omapdss_of_get_next_endpoint(port, NULL);
 	if (!ep)
 		return 0;
@@ -750,17 +824,18 @@ int __init dpi_init_port(struct platform_device *pdev, struct device_node *port)
 		goto err_datalines;
 	}
 
-	dpi.data_lines = datalines;
+	dpi->data_lines = datalines;
 
 	of_node_put(ep);
 
-	dpi.pdev = pdev;
+	dpi->pdev = pdev;
+	port->data = dpi;
 
-	mutex_init(&dpi.lock);
+	mutex_init(&dpi->lock);
 
-	dpi_init_output(pdev);
+	dpi_init_output_port(pdev, port);
 
-	dpi.port_initialized = true;
+	dpi->port_initialized = true;
 
 	return 0;
 
@@ -770,10 +845,12 @@ err_datalines:
 	return r;
 }
 
-void __exit dpi_uninit_port(void)
+void __exit dpi_uninit_port(struct device_node *port)
 {
-	if (!dpi.port_initialized)
+	struct dpi_data *dpi = port->data;
+
+	if (!dpi->port_initialized)
 		return;
 
-	dpi_uninit_output(dpi.pdev);
+	dpi_uninit_output_port(port);
 }
diff --git a/drivers/video/fbdev/omap2/dss/dsi.c b/drivers/video/fbdev/omap2/dss/dsi.c
index 0793bc67a275..73af35159468 100644
--- a/drivers/video/fbdev/omap2/dss/dsi.c
+++ b/drivers/video/fbdev/omap2/dss/dsi.c
@@ -219,6 +219,10 @@ static void dsi_display_uninit_dispc(struct platform_device *dsidev,
 
 static int dsi_vc_send_null(struct omap_dss_device *dssdev, int channel);
 
+/* DSI PLL HSDIV indices */
+#define HSDIV_DISPC	0
+#define HSDIV_DSI	1
+
 #define DSI_MAX_NR_ISRS                2
 #define DSI_MAX_NR_LANES	5
 
@@ -271,6 +275,7 @@ struct dsi_isr_tables {
 
 struct dsi_clk_calc_ctx {
 	struct platform_device *dsidev;
+	struct dss_pll *pll;
 
 	/* inputs */
 
@@ -280,13 +285,18 @@ struct dsi_clk_calc_ctx {
 
 	/* outputs */
 
-	struct dsi_clock_info dsi_cinfo;
+	struct dss_pll_clock_info dsi_cinfo;
 	struct dispc_clock_info dispc_cinfo;
 
 	struct omap_video_timings dispc_vm;
 	struct omap_dss_dsi_videomode_timings dsi_vm;
 };
 
+struct dsi_lp_clock_info {
+	unsigned long lp_clk;
+	u16 lp_clk_div;
+};
+
 struct dsi_data {
 	struct platform_device *pdev;
 	void __iomem *proto_base;
@@ -300,12 +310,14 @@ struct dsi_data {
 	bool is_enabled;
 
 	struct clk *dss_clk;
-	struct clk *sys_clk;
 
 	struct dispc_clock_info user_dispc_cinfo;
-	struct dsi_clock_info user_dsi_cinfo;
+	struct dss_pll_clock_info user_dsi_cinfo;
+
+	struct dsi_lp_clock_info user_lp_cinfo;
+	struct dsi_lp_clock_info current_lp_cinfo;
 
-	struct dsi_clock_info current_cinfo;
+	struct dss_pll pll;
 
 	bool vdds_dsi_enabled;
 	struct regulator *vdds_dsi_reg;
@@ -321,8 +333,6 @@ struct dsi_data {
 	struct mutex lock;
 	struct semaphore bus_lock;
 
-	unsigned pll_locked;
-
 	spinlock_t irq_lock;
 	struct dsi_isr_tables isr_tables;
 	/* space for a copy used by the interrupt handler */
@@ -347,7 +357,7 @@ struct dsi_data {
 
 	unsigned long cache_req_pck;
 	unsigned long cache_clk_freq;
-	struct dsi_clock_info cache_cinfo;
+	struct dss_pll_clock_info cache_cinfo;
 
 	u32		errors;
 	spinlock_t	errors_lock;
@@ -362,11 +372,6 @@ struct dsi_data {
 	spinlock_t irq_stats_lock;
 	struct dsi_irq_stats irq_stats;
 #endif
-	/* DSI PLL Parameter Ranges */
-	unsigned long regm_max, regn_max;
-	unsigned long  regm_dispc_max, regm_dsi_max;
-	unsigned long  fint_min, fint_max;
-	unsigned long lpdiv_max;
 
 	unsigned num_lanes_supported;
 	unsigned line_buffer_size;
@@ -412,7 +417,7 @@ static inline struct platform_device *dsi_get_dsidev_from_dssdev(struct omap_dss
 	return to_platform_device(dssdev->dev);
 }
 
-struct platform_device *dsi_get_dsidev_from_id(int module)
+static struct platform_device *dsi_get_dsidev_from_id(int module)
 {
 	struct omap_dss_device *out;
 	enum omap_dss_output_id	id;
@@ -1134,7 +1139,7 @@ static u32 dsi_get_errors(struct platform_device *dsidev)
 	return e;
 }
 
-int dsi_runtime_get(struct platform_device *dsidev)
+static int dsi_runtime_get(struct platform_device *dsidev)
 {
 	int r;
 	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
@@ -1146,7 +1151,7 @@ int dsi_runtime_get(struct platform_device *dsidev)
 	return r < 0 ? r : 0;
 }
 
-void dsi_runtime_put(struct platform_device *dsidev)
+static void dsi_runtime_put(struct platform_device *dsidev)
 {
 	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 	int r;
@@ -1188,23 +1193,6 @@ static int dsi_regulator_init(struct platform_device *dsidev)
 	return 0;
 }
 
-/* source clock for DSI PLL. this could also be PCLKFREE */
-static inline void dsi_enable_pll_clock(struct platform_device *dsidev,
-		bool enable)
-{
-	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
-
-	if (enable)
-		clk_prepare_enable(dsi->sys_clk);
-	else
-		clk_disable_unprepare(dsi->sys_clk);
-
-	if (enable && dsi->pll_locked) {
-		if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 1, 1) != 1)
-			DSSERR("cannot lock PLL when enabling clocks\n");
-	}
-}
-
 static void _dsi_print_reset_status(struct platform_device *dsidev)
 {
 	u32 l;
@@ -1256,25 +1244,25 @@ static inline int dsi_if_enable(struct platform_device *dsidev, bool enable)
 	return 0;
 }
 
-unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev)
+static unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev)
 {
 	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 
-	return dsi->current_cinfo.dsi_pll_hsdiv_dispc_clk;
+	return dsi->pll.cinfo.clkout[HSDIV_DISPC];
 }
 
 static unsigned long dsi_get_pll_hsdiv_dsi_rate(struct platform_device *dsidev)
 {
 	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 
-	return dsi->current_cinfo.dsi_pll_hsdiv_dsi_clk;
+	return dsi->pll.cinfo.clkout[HSDIV_DSI];
 }
 
 static unsigned long dsi_get_txbyteclkhs(struct platform_device *dsidev)
 {
 	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 
-	return dsi->current_cinfo.clkin4ddr / 16;
+	return dsi->pll.cinfo.clkdco / 16;
 }
 
 static unsigned long dsi_fclk_rate(struct platform_device *dsidev)
@@ -1293,10 +1281,10 @@ static unsigned long dsi_fclk_rate(struct platform_device *dsidev)
 	return r;
 }
 
-static int dsi_lp_clock_calc(struct dsi_clock_info *cinfo,
-		unsigned long lp_clk_min, unsigned long lp_clk_max)
+static int dsi_lp_clock_calc(unsigned long dsi_fclk,
+		unsigned long lp_clk_min, unsigned long lp_clk_max,
+		struct dsi_lp_clock_info *lp_cinfo)
 {
-	unsigned long dsi_fclk = cinfo->dsi_pll_hsdiv_dsi_clk;
 	unsigned lp_clk_div;
 	unsigned long lp_clk;
 
@@ -1306,8 +1294,8 @@ static int dsi_lp_clock_calc(struct dsi_clock_info *cinfo,
 	if (lp_clk < lp_clk_min || lp_clk > lp_clk_max)
 		return -EINVAL;
 
-	cinfo->lp_clk_div = lp_clk_div;
-	cinfo->lp_clk = lp_clk;
+	lp_cinfo->lp_clk_div = lp_clk_div;
+	lp_cinfo->lp_clk = lp_clk;
 
 	return 0;
 }
@@ -1318,10 +1306,12 @@ static int dsi_set_lp_clk_divisor(struct platform_device *dsidev)
 	unsigned long dsi_fclk;
 	unsigned lp_clk_div;
 	unsigned long lp_clk;
+	unsigned lpdiv_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_LPDIV);
+
 
-	lp_clk_div = dsi->user_dsi_cinfo.lp_clk_div;
+	lp_clk_div = dsi->user_lp_cinfo.lp_clk_div;
 
-	if (lp_clk_div == 0 || lp_clk_div > dsi->lpdiv_max)
+	if (lp_clk_div == 0 || lp_clk_div > lpdiv_max)
 		return -EINVAL;
 
 	dsi_fclk = dsi_fclk_rate(dsidev);
@@ -1329,8 +1319,8 @@ static int dsi_set_lp_clk_divisor(struct platform_device *dsidev)
 	lp_clk = dsi_fclk / 2 / lp_clk_div;
 
 	DSSDBG("LP_CLK_DIV %u, LP_CLK %lu\n", lp_clk_div, lp_clk);
-	dsi->current_cinfo.lp_clk = lp_clk;
-	dsi->current_cinfo.lp_clk_div = lp_clk_div;
+	dsi->current_lp_cinfo.lp_clk = lp_clk;
+	dsi->current_lp_cinfo.lp_clk_div = lp_clk_div;
 
 	/* LP_CLK_DIVISOR */
 	REG_FLD_MOD(dsidev, DSI_CLK_CTRL, lp_clk_div, 12, 0);
@@ -1391,286 +1381,33 @@ static int dsi_pll_power(struct platform_device *dsidev,
 	return 0;
 }
 
-unsigned long dsi_get_pll_clkin(struct platform_device *dsidev)
-{
-	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
-	return clk_get_rate(dsi->sys_clk);
-}
-
-bool dsi_hsdiv_calc(struct platform_device *dsidev, unsigned long pll,
-		unsigned long out_min, dsi_hsdiv_calc_func func, void *data)
-{
-	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
-	int regm, regm_start, regm_stop;
-	unsigned long out_max;
-	unsigned long out;
-
-	out_min = out_min ? out_min : 1;
-	out_max = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
-
-	regm_start = max(DIV_ROUND_UP(pll, out_max), 1ul);
-	regm_stop = min(pll / out_min, dsi->regm_dispc_max);
-
-	for (regm = regm_start; regm <= regm_stop; ++regm) {
-		out = pll / regm;
-
-		if (func(regm, out, data))
-			return true;
-	}
-
-	return false;
-}
-
-bool dsi_pll_calc(struct platform_device *dsidev, unsigned long clkin,
-		unsigned long pll_min, unsigned long pll_max,
-		dsi_pll_calc_func func, void *data)
-{
-	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
-	int regn, regn_start, regn_stop;
-	int regm, regm_start, regm_stop;
-	unsigned long fint, pll;
-	const unsigned long pll_hw_max = 1800000000;
-	unsigned long fint_hw_min, fint_hw_max;
-
-	fint_hw_min = dsi->fint_min;
-	fint_hw_max = dsi->fint_max;
 
-	regn_start = max(DIV_ROUND_UP(clkin, fint_hw_max), 1ul);
-	regn_stop = min(clkin / fint_hw_min, dsi->regn_max);
-
-	pll_max = pll_max ? pll_max : ULONG_MAX;
-
-	for (regn = regn_start; regn <= regn_stop; ++regn) {
-		fint = clkin / regn;
-
-		regm_start = max(DIV_ROUND_UP(DIV_ROUND_UP(pll_min, fint), 2),
-				1ul);
-		regm_stop = min3(pll_max / fint / 2,
-				pll_hw_max / fint / 2,
-				dsi->regm_max);
-
-		for (regm = regm_start; regm <= regm_stop; ++regm) {
-			pll = 2 * regm * fint;
-
-			if (func(regn, regm, fint, pll, data))
-				return true;
-		}
-	}
-
-	return false;
-}
-
-/* calculate clock rates using dividers in cinfo */
-static int dsi_calc_clock_rates(struct platform_device *dsidev,
-		struct dsi_clock_info *cinfo)
-{
-	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
-
-	if (cinfo->regn == 0 || cinfo->regn > dsi->regn_max)
-		return -EINVAL;
-
-	if (cinfo->regm == 0 || cinfo->regm > dsi->regm_max)
-		return -EINVAL;
-
-	if (cinfo->regm_dispc > dsi->regm_dispc_max)
-		return -EINVAL;
-
-	if (cinfo->regm_dsi > dsi->regm_dsi_max)
-		return -EINVAL;
-
-	cinfo->clkin = clk_get_rate(dsi->sys_clk);
-	cinfo->fint = cinfo->clkin / cinfo->regn;
-
-	if (cinfo->fint > dsi->fint_max || cinfo->fint < dsi->fint_min)
-		return -EINVAL;
-
-	cinfo->clkin4ddr = 2 * cinfo->regm * cinfo->fint;
-
-	if (cinfo->clkin4ddr > 1800 * 1000 * 1000)
-		return -EINVAL;
-
-	if (cinfo->regm_dispc > 0)
-		cinfo->dsi_pll_hsdiv_dispc_clk =
-			cinfo->clkin4ddr / cinfo->regm_dispc;
-	else
-		cinfo->dsi_pll_hsdiv_dispc_clk = 0;
-
-	if (cinfo->regm_dsi > 0)
-		cinfo->dsi_pll_hsdiv_dsi_clk =
-			cinfo->clkin4ddr / cinfo->regm_dsi;
-	else
-		cinfo->dsi_pll_hsdiv_dsi_clk = 0;
-
-	return 0;
-}
-
-static void dsi_pll_calc_dsi_fck(struct dsi_clock_info *cinfo)
+static void dsi_pll_calc_dsi_fck(struct dss_pll_clock_info *cinfo)
 {
 	unsigned long max_dsi_fck;
 
 	max_dsi_fck = dss_feat_get_param_max(FEAT_PARAM_DSI_FCK);
 
-	cinfo->regm_dsi = DIV_ROUND_UP(cinfo->clkin4ddr, max_dsi_fck);
-	cinfo->dsi_pll_hsdiv_dsi_clk = cinfo->clkin4ddr / cinfo->regm_dsi;
+	cinfo->mX[HSDIV_DSI] = DIV_ROUND_UP(cinfo->clkdco, max_dsi_fck);
+	cinfo->clkout[HSDIV_DSI] = cinfo->clkdco / cinfo->mX[HSDIV_DSI];
 }
 
-int dsi_pll_set_clock_div(struct platform_device *dsidev,
-		struct dsi_clock_info *cinfo)
+static int dsi_pll_enable(struct dss_pll *pll)
 {
-	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+	struct dsi_data *dsi = container_of(pll, struct dsi_data, pll);
+	struct platform_device *dsidev = dsi->pdev;
 	int r = 0;
-	u32 l;
-	int f = 0;
-	u8 regn_start, regn_end, regm_start, regm_end;
-	u8 regm_dispc_start, regm_dispc_end, regm_dsi_start, regm_dsi_end;
-
-	DSSDBG("DSI PLL clock config starts");
-
-	dsi->current_cinfo.clkin = cinfo->clkin;
-	dsi->current_cinfo.fint = cinfo->fint;
-	dsi->current_cinfo.clkin4ddr = cinfo->clkin4ddr;
-	dsi->current_cinfo.dsi_pll_hsdiv_dispc_clk =
-			cinfo->dsi_pll_hsdiv_dispc_clk;
-	dsi->current_cinfo.dsi_pll_hsdiv_dsi_clk =
-			cinfo->dsi_pll_hsdiv_dsi_clk;
-
-	dsi->current_cinfo.regn = cinfo->regn;
-	dsi->current_cinfo.regm = cinfo->regm;
-	dsi->current_cinfo.regm_dispc = cinfo->regm_dispc;
-	dsi->current_cinfo.regm_dsi = cinfo->regm_dsi;
-
-	DSSDBG("DSI Fint %ld\n", cinfo->fint);
-
-	DSSDBG("clkin rate %ld\n", cinfo->clkin);
-
-	/* DSIPHY == CLKIN4DDR */
-	DSSDBG("CLKIN4DDR = 2 * %d / %d * %lu = %lu\n",
-			cinfo->regm,
-			cinfo->regn,
-			cinfo->clkin,
-			cinfo->clkin4ddr);
-
-	DSSDBG("Data rate on 1 DSI lane %ld Mbps\n",
-			cinfo->clkin4ddr / 1000 / 1000 / 2);
-
-	DSSDBG("Clock lane freq %ld Hz\n", cinfo->clkin4ddr / 4);
-
-	DSSDBG("regm_dispc = %d, %s (%s) = %lu\n", cinfo->regm_dispc,
-		dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC),
-		dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC),
-		cinfo->dsi_pll_hsdiv_dispc_clk);
-	DSSDBG("regm_dsi = %d, %s (%s) = %lu\n", cinfo->regm_dsi,
-		dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI),
-		dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI),
-		cinfo->dsi_pll_hsdiv_dsi_clk);
-
-	dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGN, &regn_start, &regn_end);
-	dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGM, &regm_start, &regm_end);
-	dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGM_DISPC, &regm_dispc_start,
-			&regm_dispc_end);
-	dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGM_DSI, &regm_dsi_start,
-			&regm_dsi_end);
-
-	/* DSI_PLL_AUTOMODE = manual */
-	REG_FLD_MOD(dsidev, DSI_PLL_CONTROL, 0, 0, 0);
-
-	l = dsi_read_reg(dsidev, DSI_PLL_CONFIGURATION1);
-	l = FLD_MOD(l, 1, 0, 0);		/* DSI_PLL_STOPMODE */
-	/* DSI_PLL_REGN */
-	l = FLD_MOD(l, cinfo->regn - 1, regn_start, regn_end);
-	/* DSI_PLL_REGM */
-	l = FLD_MOD(l, cinfo->regm, regm_start, regm_end);
-	/* DSI_CLOCK_DIV */
-	l = FLD_MOD(l, cinfo->regm_dispc > 0 ? cinfo->regm_dispc - 1 : 0,
-			regm_dispc_start, regm_dispc_end);
-	/* DSIPROTO_CLOCK_DIV */
-	l = FLD_MOD(l, cinfo->regm_dsi > 0 ? cinfo->regm_dsi - 1 : 0,
-			regm_dsi_start, regm_dsi_end);
-	dsi_write_reg(dsidev, DSI_PLL_CONFIGURATION1, l);
-
-	BUG_ON(cinfo->fint < dsi->fint_min || cinfo->fint > dsi->fint_max);
-
-	l = dsi_read_reg(dsidev, DSI_PLL_CONFIGURATION2);
-
-	if (dss_has_feature(FEAT_DSI_PLL_FREQSEL)) {
-		f = cinfo->fint < 1000000 ? 0x3 :
-			cinfo->fint < 1250000 ? 0x4 :
-			cinfo->fint < 1500000 ? 0x5 :
-			cinfo->fint < 1750000 ? 0x6 :
-			0x7;
-
-		l = FLD_MOD(l, f, 4, 1);	/* DSI_PLL_FREQSEL */
-	} else if (dss_has_feature(FEAT_DSI_PLL_SELFREQDCO)) {
-		f = cinfo->clkin4ddr < 1000000000 ? 0x2 : 0x4;
-
-		l = FLD_MOD(l, f, 3, 1);	/* PLL_SELFREQDCO */
-	}
-
-	l = FLD_MOD(l, 1, 13, 13);		/* DSI_PLL_REFEN */
-	l = FLD_MOD(l, 0, 14, 14);		/* DSIPHY_CLKINEN */
-	l = FLD_MOD(l, 1, 20, 20);		/* DSI_HSDIVBYPASS */
-	if (dss_has_feature(FEAT_DSI_PLL_REFSEL))
-		l = FLD_MOD(l, 3, 22, 21);	/* REF_SYSCLK = sysclk */
-	dsi_write_reg(dsidev, DSI_PLL_CONFIGURATION2, l);
-
-	REG_FLD_MOD(dsidev, DSI_PLL_GO, 1, 0, 0);	/* DSI_PLL_GO */
-
-	if (wait_for_bit_change(dsidev, DSI_PLL_GO, 0, 0) != 0) {
-		DSSERR("dsi pll go bit not going down.\n");
-		r = -EIO;
-		goto err;
-	}
-
-	if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 1, 1) != 1) {
-		DSSERR("cannot lock PLL\n");
-		r = -EIO;
-		goto err;
-	}
-
-	dsi->pll_locked = 1;
-
-	l = dsi_read_reg(dsidev, DSI_PLL_CONFIGURATION2);
-	l = FLD_MOD(l, 0, 0, 0);	/* DSI_PLL_IDLE */
-	l = FLD_MOD(l, 0, 5, 5);	/* DSI_PLL_PLLLPMODE */
-	l = FLD_MOD(l, 0, 6, 6);	/* DSI_PLL_LOWCURRSTBY */
-	l = FLD_MOD(l, 0, 7, 7);	/* DSI_PLL_TIGHTPHASELOCK */
-	l = FLD_MOD(l, 0, 8, 8);	/* DSI_PLL_DRIFTGUARDEN */
-	l = FLD_MOD(l, 0, 10, 9);	/* DSI_PLL_LOCKSEL */
-	l = FLD_MOD(l, 1, 13, 13);	/* DSI_PLL_REFEN */
-	l = FLD_MOD(l, 1, 14, 14);	/* DSIPHY_CLKINEN */
-	l = FLD_MOD(l, 0, 15, 15);	/* DSI_BYPASSEN */
-	l = FLD_MOD(l, 1, 16, 16);	/* DSS_CLOCK_EN */
-	l = FLD_MOD(l, 0, 17, 17);	/* DSS_CLOCK_PWDN */
-	l = FLD_MOD(l, 1, 18, 18);	/* DSI_PROTO_CLOCK_EN */
-	l = FLD_MOD(l, 0, 19, 19);	/* DSI_PROTO_CLOCK_PWDN */
-	l = FLD_MOD(l, 0, 20, 20);	/* DSI_HSDIVBYPASS */
-	dsi_write_reg(dsidev, DSI_PLL_CONFIGURATION2, l);
-
-	DSSDBG("PLL config done\n");
-err:
-	return r;
-}
-
-int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk,
-		bool enable_hsdiv)
-{
-	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
-	int r = 0;
-	enum dsi_pll_power_state pwstate;
 
 	DSSDBG("PLL init\n");
 
-	/*
-	 * It seems that on many OMAPs we need to enable both to have a
-	 * functional HSDivider.
-	 */
-	enable_hsclk = enable_hsdiv = true;
-
 	r = dsi_regulator_init(dsidev);
 	if (r)
 		return r;
 
-	dsi_enable_pll_clock(dsidev, 1);
+	r = dsi_runtime_get(dsidev);
+	if (r)
+		return r;
+
 	/*
 	 * Note: SCP CLK is not required on OMAP3, but it is required on OMAP4.
 	 */
@@ -1697,16 +1434,7 @@ int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk,
 	 * fill the whole display. No idea about this */
 	dispc_pck_free_enable(0);
 
-	if (enable_hsclk && enable_hsdiv)
-		pwstate = DSI_PLL_POWER_ON_ALL;
-	else if (enable_hsclk)
-		pwstate = DSI_PLL_POWER_ON_HSCLK;
-	else if (enable_hsdiv)
-		pwstate = DSI_PLL_POWER_ON_DIV;
-	else
-		pwstate = DSI_PLL_POWER_OFF;
-
-	r = dsi_pll_power(dsidev, pwstate);
+	r = dsi_pll_power(dsidev, DSI_PLL_POWER_ON_ALL);
 
 	if (r)
 		goto err1;
@@ -1721,15 +1449,14 @@ err1:
 	}
 err0:
 	dsi_disable_scp_clk(dsidev);
-	dsi_enable_pll_clock(dsidev, 0);
+	dsi_runtime_put(dsidev);
 	return r;
 }
 
-void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes)
+static void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes)
 {
 	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 
-	dsi->pll_locked = 0;
 	dsi_pll_power(dsidev, DSI_PLL_POWER_OFF);
 	if (disconnect_lanes) {
 		WARN_ON(!dsi->vdds_dsi_enabled);
@@ -1738,18 +1465,27 @@ void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes)
 	}
 
 	dsi_disable_scp_clk(dsidev);
-	dsi_enable_pll_clock(dsidev, 0);
+	dsi_runtime_put(dsidev);
 
 	DSSDBG("PLL uninit done\n");
 }
 
+static void dsi_pll_disable(struct dss_pll *pll)
+{
+	struct dsi_data *dsi = container_of(pll, struct dsi_data, pll);
+	struct platform_device *dsidev = dsi->pdev;
+
+	dsi_pll_uninit(dsidev, true);
+}
+
 static void dsi_dump_dsidev_clocks(struct platform_device *dsidev,
 		struct seq_file *s)
 {
 	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
-	struct dsi_clock_info *cinfo = &dsi->current_cinfo;
+	struct dss_pll_clock_info *cinfo = &dsi->pll.cinfo;
 	enum omap_dss_clk_source dispc_clk_src, dsi_clk_src;
 	int dsi_module = dsi->module_id;
+	struct dss_pll *pll = &dsi->pll;
 
 	dispc_clk_src = dss_get_dispc_clk_source();
 	dsi_clk_src = dss_get_dsi_clk_source(dsi_module);
@@ -1759,28 +1495,28 @@ static void dsi_dump_dsidev_clocks(struct platform_device *dsidev,
 
 	seq_printf(s,	"- DSI%d PLL -\n", dsi_module + 1);
 
-	seq_printf(s,	"dsi pll clkin\t%lu\n", cinfo->clkin);
+	seq_printf(s,	"dsi pll clkin\t%lu\n", clk_get_rate(pll->clkin));
 
-	seq_printf(s,	"Fint\t\t%-16luregn %u\n", cinfo->fint, cinfo->regn);
+	seq_printf(s,	"Fint\t\t%-16lun %u\n", cinfo->fint, cinfo->n);
 
-	seq_printf(s,	"CLKIN4DDR\t%-16luregm %u\n",
-			cinfo->clkin4ddr, cinfo->regm);
+	seq_printf(s,	"CLKIN4DDR\t%-16lum %u\n",
+			cinfo->clkdco, cinfo->m);
 
-	seq_printf(s,	"DSI_PLL_HSDIV_DISPC (%s)\t%-16luregm_dispc %u\t(%s)\n",
+	seq_printf(s,	"DSI_PLL_HSDIV_DISPC (%s)\t%-16lum_dispc %u\t(%s)\n",
 			dss_feat_get_clk_source_name(dsi_module == 0 ?
 				OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC :
 				OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC),
-			cinfo->dsi_pll_hsdiv_dispc_clk,
-			cinfo->regm_dispc,
+			cinfo->clkout[HSDIV_DISPC],
+			cinfo->mX[HSDIV_DISPC],
 			dispc_clk_src == OMAP_DSS_CLK_SRC_FCK ?
 			"off" : "on");
 
-	seq_printf(s,	"DSI_PLL_HSDIV_DSI (%s)\t%-16luregm_dsi %u\t(%s)\n",
+	seq_printf(s,	"DSI_PLL_HSDIV_DSI (%s)\t%-16lum_dsi %u\t(%s)\n",
 			dss_feat_get_clk_source_name(dsi_module == 0 ?
 				OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI :
 				OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI),
-			cinfo->dsi_pll_hsdiv_dsi_clk,
-			cinfo->regm_dsi,
+			cinfo->clkout[HSDIV_DSI],
+			cinfo->mX[HSDIV_DSI],
 			dsi_clk_src == OMAP_DSS_CLK_SRC_FCK ?
 			"off" : "on");
 
@@ -1793,11 +1529,11 @@ static void dsi_dump_dsidev_clocks(struct platform_device *dsidev,
 	seq_printf(s,	"DSI_FCLK\t%lu\n", dsi_fclk_rate(dsidev));
 
 	seq_printf(s,	"DDR_CLK\t\t%lu\n",
-			cinfo->clkin4ddr / 4);
+			cinfo->clkdco / 4);
 
 	seq_printf(s,	"TxByteClkHS\t%lu\n", dsi_get_txbyteclkhs(dsidev));
 
-	seq_printf(s,	"LP_CLK\t\t%lu\n", cinfo->lp_clk);
+	seq_printf(s,	"LP_CLK\t\t%lu\n", dsi->current_lp_cinfo.lp_clk);
 
 	dsi_runtime_put(dsidev);
 }
@@ -2132,7 +1868,7 @@ static inline unsigned ns2ddr(struct platform_device *dsidev, unsigned ns)
 	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 
 	/* convert time in ns to ddr ticks, rounding up */
-	unsigned long ddr_clk = dsi->current_cinfo.clkin4ddr / 4;
+	unsigned long ddr_clk = dsi->pll.cinfo.clkdco / 4;
 	return (ns * (ddr_clk / 1000 / 1000) + 999) / 1000;
 }
 
@@ -2140,7 +1876,7 @@ static inline unsigned ddr2ns(struct platform_device *dsidev, unsigned ddr)
 {
 	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 
-	unsigned long ddr_clk = dsi->current_cinfo.clkin4ddr / 4;
+	unsigned long ddr_clk = dsi->pll.cinfo.clkdco / 4;
 	return ddr * 1000 * 1000 / (ddr_clk / 1000);
 }
 
@@ -3730,7 +3466,7 @@ static void dsi_config_cmd_mode_interleaving(struct platform_device *dsidev)
 	struct omap_video_timings *timings = &dsi->timings;
 	int bpp = dsi_get_pixel_size(dsi->pix_fmt);
 	int ndl = dsi->num_lanes_used - 1;
-	int dsi_fclk_hsdiv = dsi->user_dsi_cinfo.regm_dsi + 1;
+	int dsi_fclk_hsdiv = dsi->user_dsi_cinfo.mX[HSDIV_DSI] + 1;
 	int hsa_interleave_hs = 0, hsa_interleave_lp = 0;
 	int hfp_interleave_hs = 0, hfp_interleave_lp = 0;
 	int hbp_interleave_hs = 0, hbp_interleave_lp = 0;
@@ -4441,18 +4177,12 @@ static void dsi_display_uninit_dispc(struct platform_device *dsidev,
 static int dsi_configure_dsi_clocks(struct platform_device *dsidev)
 {
 	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
-	struct dsi_clock_info cinfo;
+	struct dss_pll_clock_info cinfo;
 	int r;
 
 	cinfo = dsi->user_dsi_cinfo;
 
-	r = dsi_calc_clock_rates(dsidev, &cinfo);
-	if (r) {
-		DSSERR("Failed to calc dsi clocks\n");
-		return r;
-	}
-
-	r = dsi_pll_set_clock_div(dsidev, &cinfo);
+	r = dss_pll_set_config(&dsi->pll, &cinfo);
 	if (r) {
 		DSSERR("Failed to set dsi clocks\n");
 		return r;
@@ -4466,7 +4196,7 @@ static int dsi_display_init_dsi(struct platform_device *dsidev)
 	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 	int r;
 
-	r = dsi_pll_init(dsidev, true, true);
+	r = dss_pll_enable(&dsi->pll);
 	if (r)
 		goto err0;
 
@@ -4510,7 +4240,7 @@ err3:
 err2:
 	dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK);
 err1:
-	dsi_pll_uninit(dsidev, true);
+	dss_pll_disable(&dsi->pll);
 err0:
 	return r;
 }
@@ -4551,8 +4281,6 @@ static int dsi_display_enable(struct omap_dss_device *dssdev)
 	if (r)
 		goto err_get_dsi;
 
-	dsi_enable_pll_clock(dsidev, 1);
-
 	_dsi_initialize_irq(dsidev);
 
 	r = dsi_display_init_dsi(dsidev);
@@ -4564,7 +4292,6 @@ static int dsi_display_enable(struct omap_dss_device *dssdev)
 	return 0;
 
 err_init_dsi:
-	dsi_enable_pll_clock(dsidev, 0);
 	dsi_runtime_put(dsidev);
 err_get_dsi:
 	mutex_unlock(&dsi->lock);
@@ -4592,7 +4319,6 @@ static void dsi_display_disable(struct omap_dss_device *dssdev,
 	dsi_display_uninit_dsi(dsidev, disconnect_lanes, enter_ulps);
 
 	dsi_runtime_put(dsidev);
-	dsi_enable_pll_clock(dsidev, 0);
 
 	mutex_unlock(&dsi->lock);
 }
@@ -4713,29 +4439,30 @@ static bool dsi_cm_calc_dispc_cb(int lckd, int pckd, unsigned long lck,
 	return true;
 }
 
-static bool dsi_cm_calc_hsdiv_cb(int regm_dispc, unsigned long dispc,
+static bool dsi_cm_calc_hsdiv_cb(int m_dispc, unsigned long dispc,
 		void *data)
 {
 	struct dsi_clk_calc_ctx *ctx = data;
 
-	ctx->dsi_cinfo.regm_dispc = regm_dispc;
-	ctx->dsi_cinfo.dsi_pll_hsdiv_dispc_clk = dispc;
+	ctx->dsi_cinfo.mX[HSDIV_DISPC] = m_dispc;
+	ctx->dsi_cinfo.clkout[HSDIV_DISPC] = dispc;
 
 	return dispc_div_calc(dispc, ctx->req_pck_min, ctx->req_pck_max,
 			dsi_cm_calc_dispc_cb, ctx);
 }
 
-static bool dsi_cm_calc_pll_cb(int regn, int regm, unsigned long fint,
-		unsigned long pll, void *data)
+static bool dsi_cm_calc_pll_cb(int n, int m, unsigned long fint,
+		unsigned long clkdco, void *data)
 {
 	struct dsi_clk_calc_ctx *ctx = data;
 
-	ctx->dsi_cinfo.regn = regn;
-	ctx->dsi_cinfo.regm = regm;
+	ctx->dsi_cinfo.n = n;
+	ctx->dsi_cinfo.m = m;
 	ctx->dsi_cinfo.fint = fint;
-	ctx->dsi_cinfo.clkin4ddr = pll;
+	ctx->dsi_cinfo.clkdco = clkdco;
 
-	return dsi_hsdiv_calc(ctx->dsidev, pll, ctx->req_pck_min,
+	return dss_pll_hsdiv_calc(ctx->pll, clkdco, ctx->req_pck_min,
+			dss_feat_get_param_max(FEAT_PARAM_DSS_FCK),
 			dsi_cm_calc_hsdiv_cb, ctx);
 }
 
@@ -4748,7 +4475,7 @@ static bool dsi_cm_calc(struct dsi_data *dsi,
 	unsigned long pll_min, pll_max;
 	unsigned long pck, txbyteclk;
 
-	clkin = clk_get_rate(dsi->sys_clk);
+	clkin = clk_get_rate(dsi->pll.clkin);
 	bitspp = dsi_get_pixel_size(cfg->pixel_format);
 	ndl = dsi->num_lanes_used - 1;
 
@@ -4764,16 +4491,16 @@ static bool dsi_cm_calc(struct dsi_data *dsi,
 
 	memset(ctx, 0, sizeof(*ctx));
 	ctx->dsidev = dsi->pdev;
+	ctx->pll = &dsi->pll;
 	ctx->config = cfg;
 	ctx->req_pck_min = pck;
 	ctx->req_pck_nom = pck;
 	ctx->req_pck_max = pck * 3 / 2;
-	ctx->dsi_cinfo.clkin = clkin;
 
 	pll_min = max(cfg->hs_clk_min * 4, txbyteclk * 4 * 4);
 	pll_max = cfg->hs_clk_max * 4;
 
-	return dsi_pll_calc(dsi->pdev, clkin,
+	return dss_pll_calc(ctx->pll, clkin,
 			pll_min, pll_max,
 			dsi_cm_calc_pll_cb, ctx);
 }
@@ -4784,7 +4511,7 @@ static bool dsi_vm_calc_blanking(struct dsi_clk_calc_ctx *ctx)
 	const struct omap_dss_dsi_config *cfg = ctx->config;
 	int bitspp = dsi_get_pixel_size(cfg->pixel_format);
 	int ndl = dsi->num_lanes_used - 1;
-	unsigned long hsclk = ctx->dsi_cinfo.clkin4ddr / 4;
+	unsigned long hsclk = ctx->dsi_cinfo.clkdco / 4;
 	unsigned long byteclk = hsclk / 4;
 
 	unsigned long dispc_pck, req_pck_min, req_pck_nom, req_pck_max;
@@ -4999,14 +4726,14 @@ static bool dsi_vm_calc_dispc_cb(int lckd, int pckd, unsigned long lck,
 	return true;
 }
 
-static bool dsi_vm_calc_hsdiv_cb(int regm_dispc, unsigned long dispc,
+static bool dsi_vm_calc_hsdiv_cb(int m_dispc, unsigned long dispc,
 		void *data)
 {
 	struct dsi_clk_calc_ctx *ctx = data;
 	unsigned long pck_max;
 
-	ctx->dsi_cinfo.regm_dispc = regm_dispc;
-	ctx->dsi_cinfo.dsi_pll_hsdiv_dispc_clk = dispc;
+	ctx->dsi_cinfo.mX[HSDIV_DISPC] = m_dispc;
+	ctx->dsi_cinfo.clkout[HSDIV_DISPC] = dispc;
 
 	/*
 	 * In burst mode we can let the dispc pck be arbitrarily high, but it
@@ -5022,17 +4749,18 @@ static bool dsi_vm_calc_hsdiv_cb(int regm_dispc, unsigned long dispc,
 			dsi_vm_calc_dispc_cb, ctx);
 }
 
-static bool dsi_vm_calc_pll_cb(int regn, int regm, unsigned long fint,
-		unsigned long pll, void *data)
+static bool dsi_vm_calc_pll_cb(int n, int m, unsigned long fint,
+		unsigned long clkdco, void *data)
 {
 	struct dsi_clk_calc_ctx *ctx = data;
 
-	ctx->dsi_cinfo.regn = regn;
-	ctx->dsi_cinfo.regm = regm;
+	ctx->dsi_cinfo.n = n;
+	ctx->dsi_cinfo.m = m;
 	ctx->dsi_cinfo.fint = fint;
-	ctx->dsi_cinfo.clkin4ddr = pll;
+	ctx->dsi_cinfo.clkdco = clkdco;
 
-	return dsi_hsdiv_calc(ctx->dsidev, pll, ctx->req_pck_min,
+	return dss_pll_hsdiv_calc(ctx->pll, clkdco, ctx->req_pck_min,
+			dss_feat_get_param_max(FEAT_PARAM_DSS_FCK),
 			dsi_vm_calc_hsdiv_cb, ctx);
 }
 
@@ -5048,14 +4776,13 @@ static bool dsi_vm_calc(struct dsi_data *dsi,
 	int bitspp = dsi_get_pixel_size(cfg->pixel_format);
 	unsigned long byteclk_min;
 
-	clkin = clk_get_rate(dsi->sys_clk);
+	clkin = clk_get_rate(dsi->pll.clkin);
 
 	memset(ctx, 0, sizeof(*ctx));
 	ctx->dsidev = dsi->pdev;
+	ctx->pll = &dsi->pll;
 	ctx->config = cfg;
 
-	ctx->dsi_cinfo.clkin = clkin;
-
 	/* these limits should come from the panel driver */
 	ctx->req_pck_min = t->pixelclock - 1000;
 	ctx->req_pck_nom = t->pixelclock;
@@ -5074,7 +4801,7 @@ static bool dsi_vm_calc(struct dsi_data *dsi,
 		pll_max = byteclk_max * 4 * 4;
 	}
 
-	return dsi_pll_calc(dsi->pdev, clkin,
+	return dss_pll_calc(ctx->pll, clkin,
 			pll_min, pll_max,
 			dsi_vm_calc_pll_cb, ctx);
 }
@@ -5106,8 +4833,8 @@ static int dsi_set_config(struct omap_dss_device *dssdev,
 
 	dsi_pll_calc_dsi_fck(&ctx.dsi_cinfo);
 
-	r = dsi_lp_clock_calc(&ctx.dsi_cinfo, config->lp_clk_min,
-			config->lp_clk_max);
+	r = dsi_lp_clock_calc(ctx.dsi_cinfo.clkout[HSDIV_DSI],
+		config->lp_clk_min, config->lp_clk_max, &dsi->user_lp_cinfo);
 	if (r) {
 		DSSERR("failed to find suitable DSI LP clock settings\n");
 		goto err;
@@ -5234,35 +4961,6 @@ static void dsi_release_vc(struct omap_dss_device *dssdev, int channel)
 	}
 }
 
-void dsi_wait_pll_hsdiv_dispc_active(struct platform_device *dsidev)
-{
-	if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 7, 1) != 1)
-		DSSERR("%s (%s) not active\n",
-			dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC),
-			dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC));
-}
-
-void dsi_wait_pll_hsdiv_dsi_active(struct platform_device *dsidev)
-{
-	if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 8, 1) != 1)
-		DSSERR("%s (%s) not active\n",
-			dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI),
-			dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI));
-}
-
-static void dsi_calc_clock_param_ranges(struct platform_device *dsidev)
-{
-	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
-
-	dsi->regn_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGN);
-	dsi->regm_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGM);
-	dsi->regm_dispc_max =
-		dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGM_DISPC);
-	dsi->regm_dsi_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGM_DSI);
-	dsi->fint_min = dss_feat_get_param_min(FEAT_PARAM_DSIPLL_FINT);
-	dsi->fint_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_FINT);
-	dsi->lpdiv_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_LPDIV);
-}
 
 static int dsi_get_clocks(struct platform_device *dsidev)
 {
@@ -5277,14 +4975,6 @@ static int dsi_get_clocks(struct platform_device *dsidev)
 
 	dsi->dss_clk = clk;
 
-	clk = devm_clk_get(&dsidev->dev, "sys_clk");
-	if (IS_ERR(clk)) {
-		DSSERR("can't get sys_clk\n");
-		return PTR_ERR(clk);
-	}
-
-	dsi->sys_clk = clk;
-
 	return 0;
 }
 
@@ -5453,6 +5143,135 @@ err:
 	return r;
 }
 
+static const struct dss_pll_ops dsi_pll_ops = {
+	.enable = dsi_pll_enable,
+	.disable = dsi_pll_disable,
+	.set_config = dss_pll_write_config_type_a,
+};
+
+static const struct dss_pll_hw dss_omap3_dsi_pll_hw = {
+	.n_max = (1 << 7) - 1,
+	.m_max = (1 << 11) - 1,
+	.mX_max = (1 << 4) - 1,
+	.fint_min = 750000,
+	.fint_max = 2100000,
+	.clkdco_low = 1000000000,
+	.clkdco_max = 1800000000,
+
+	.n_msb = 7,
+	.n_lsb = 1,
+	.m_msb = 18,
+	.m_lsb = 8,
+
+	.mX_msb[0] = 22,
+	.mX_lsb[0] = 19,
+	.mX_msb[1] = 26,
+	.mX_lsb[1] = 23,
+
+	.has_stopmode = true,
+	.has_freqsel = true,
+	.has_selfreqdco = false,
+	.has_refsel = false,
+};
+
+static const struct dss_pll_hw dss_omap4_dsi_pll_hw = {
+	.n_max = (1 << 8) - 1,
+	.m_max = (1 << 12) - 1,
+	.mX_max = (1 << 5) - 1,
+	.fint_min = 500000,
+	.fint_max = 2500000,
+	.clkdco_low = 1000000000,
+	.clkdco_max = 1800000000,
+
+	.n_msb = 8,
+	.n_lsb = 1,
+	.m_msb = 20,
+	.m_lsb = 9,
+
+	.mX_msb[0] = 25,
+	.mX_lsb[0] = 21,
+	.mX_msb[1] = 30,
+	.mX_lsb[1] = 26,
+
+	.has_stopmode = true,
+	.has_freqsel = false,
+	.has_selfreqdco = false,
+	.has_refsel = false,
+};
+
+static const struct dss_pll_hw dss_omap5_dsi_pll_hw = {
+	.n_max = (1 << 8) - 1,
+	.m_max = (1 << 12) - 1,
+	.mX_max = (1 << 5) - 1,
+	.fint_min = 150000,
+	.fint_max = 52000000,
+	.clkdco_low = 1000000000,
+	.clkdco_max = 1800000000,
+
+	.n_msb = 8,
+	.n_lsb = 1,
+	.m_msb = 20,
+	.m_lsb = 9,
+
+	.mX_msb[0] = 25,
+	.mX_lsb[0] = 21,
+	.mX_msb[1] = 30,
+	.mX_lsb[1] = 26,
+
+	.has_stopmode = true,
+	.has_freqsel = false,
+	.has_selfreqdco = true,
+	.has_refsel = true,
+};
+
+static int dsi_init_pll_data(struct platform_device *dsidev)
+{
+	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+	struct dss_pll *pll = &dsi->pll;
+	struct clk *clk;
+	int r;
+
+	clk = devm_clk_get(&dsidev->dev, "sys_clk");
+	if (IS_ERR(clk)) {
+		DSSERR("can't get sys_clk\n");
+		return PTR_ERR(clk);
+	}
+
+	pll->name = dsi->module_id == 0 ? "dsi0" : "dsi1";
+	pll->clkin = clk;
+	pll->base = dsi->pll_base;
+
+	switch (omapdss_get_version()) {
+	case OMAPDSS_VER_OMAP34xx_ES1:
+	case OMAPDSS_VER_OMAP34xx_ES3:
+	case OMAPDSS_VER_OMAP3630:
+	case OMAPDSS_VER_AM35xx:
+		pll->hw = &dss_omap3_dsi_pll_hw;
+		break;
+
+	case OMAPDSS_VER_OMAP4430_ES1:
+	case OMAPDSS_VER_OMAP4430_ES2:
+	case OMAPDSS_VER_OMAP4:
+		pll->hw = &dss_omap4_dsi_pll_hw;
+		break;
+
+	case OMAPDSS_VER_OMAP5:
+		pll->hw = &dss_omap5_dsi_pll_hw;
+		break;
+
+	default:
+		return -ENODEV;
+	}
+
+	pll->ops = &dsi_pll_ops;
+
+	r = dss_pll_register(pll);
+	if (r)
+		return r;
+
+	return 0;
+}
+
 /* DSI1 HW IP initialisation */
 static int omap_dsihw_probe(struct platform_device *dsidev)
 {
@@ -5598,12 +5417,12 @@ static int omap_dsihw_probe(struct platform_device *dsidev)
 		dsi->vc[i].vc_id = 0;
 	}
 
-	dsi_calc_clock_param_ranges(dsidev);
-
 	r = dsi_get_clocks(dsidev);
 	if (r)
 		return r;
 
+	dsi_init_pll_data(dsidev);
+
 	pm_runtime_enable(&dsidev->dev);
 
 	r = dsi_runtime_get(dsidev);
@@ -5672,6 +5491,8 @@ static int __exit omap_dsihw_remove(struct platform_device *dsidev)
 
 	WARN_ON(dsi->scp_clk_refcount > 0);
 
+	dss_pll_unregister(&dsi->pll);
+
 	dsi_uninit_output(dsidev);
 
 	pm_runtime_disable(&dsidev->dev);
diff --git a/drivers/video/fbdev/omap2/dss/dss-of.c b/drivers/video/fbdev/omap2/dss/dss-of.c
index a4b20aaf6142..928ee639c0c1 100644
--- a/drivers/video/fbdev/omap2/dss/dss-of.c
+++ b/drivers/video/fbdev/omap2/dss/dss-of.c
@@ -20,6 +20,8 @@
 
 #include <video/omapdss.h>
 
+#include "dss.h"
+
 struct device_node *
 omapdss_of_get_next_port(const struct device_node *parent,
 			 struct device_node *prev)
@@ -84,20 +86,17 @@ omapdss_of_get_next_endpoint(const struct device_node *parent,
 }
 EXPORT_SYMBOL_GPL(omapdss_of_get_next_endpoint);
 
-static struct device_node *
-omapdss_of_get_remote_device_node(const struct device_node *node)
+struct device_node *dss_of_port_get_parent_device(struct device_node *port)
 {
 	struct device_node *np;
 	int i;
 
-	np = of_parse_phandle(node, "remote-endpoint", 0);
-
-	if (!np)
+	if (!port)
 		return NULL;
 
-	np = of_get_next_parent(np);
+	np = of_get_next_parent(port);
 
-	for (i = 0; i < 3 && np; ++i) {
+	for (i = 0; i < 2 && np; ++i) {
 		struct property *prop;
 
 		prop = of_find_property(np, "compatible", NULL);
@@ -111,6 +110,31 @@ omapdss_of_get_remote_device_node(const struct device_node *node)
 	return NULL;
 }
 
+u32 dss_of_port_get_port_number(struct device_node *port)
+{
+	int r;
+	u32 reg;
+
+	r = of_property_read_u32(port, "reg", &reg);
+	if (r)
+		reg = 0;
+
+	return reg;
+}
+
+static struct device_node *omapdss_of_get_remote_port(const struct device_node *node)
+{
+	struct device_node *np;
+
+	np = of_parse_phandle(node, "remote-endpoint", 0);
+	if (!np)
+		return NULL;
+
+	np = of_get_next_parent(np);
+
+	return np;
+}
+
 struct device_node *
 omapdss_of_get_first_endpoint(const struct device_node *parent)
 {
@@ -133,27 +157,25 @@ struct omap_dss_device *
 omapdss_of_find_source_for_first_ep(struct device_node *node)
 {
 	struct device_node *ep;
-	struct device_node *src_node;
+	struct device_node *src_port;
 	struct omap_dss_device *src;
 
 	ep = omapdss_of_get_first_endpoint(node);
 	if (!ep)
 		return ERR_PTR(-EINVAL);
 
-	src_node = omapdss_of_get_remote_device_node(ep);
-
-	of_node_put(ep);
-
-	if (!src_node)
+	src_port = omapdss_of_get_remote_port(ep);
+	if (!src_port) {
+		of_node_put(ep);
 		return ERR_PTR(-EINVAL);
+	}
 
-	src = omap_dss_find_output_by_node(src_node);
+	of_node_put(ep);
 
-	of_node_put(src_node);
+	src = omap_dss_find_output_by_port_node(src_port);
 
-	if (!src)
-		return ERR_PTR(-EPROBE_DEFER);
+	of_node_put(src_port);
 
-	return src;
+	return src ? src : ERR_PTR(-EPROBE_DEFER);
 }
 EXPORT_SYMBOL_GPL(omapdss_of_find_source_for_first_ep);
diff --git a/drivers/video/fbdev/omap2/dss/dss.c b/drivers/video/fbdev/omap2/dss/dss.c
index 14bcd6c43f72..702c495083ed 100644
--- a/drivers/video/fbdev/omap2/dss/dss.c
+++ b/drivers/video/fbdev/omap2/dss/dss.c
@@ -70,7 +70,9 @@ struct dss_features {
 	u8 fck_div_max;
 	u8 dss_fck_multiplier;
 	const char *parent_clk_name;
-	int (*dpi_select_source)(enum omap_channel channel);
+	enum omap_display_type *ports;
+	int num_ports;
+	int (*dpi_select_source)(int port, enum omap_channel channel);
 };
 
 static struct {
@@ -294,7 +296,6 @@ static void dss_dump_regs(struct seq_file *s)
 
 static void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src)
 {
-	struct platform_device *dsidev;
 	int b;
 	u8 start, end;
 
@@ -304,13 +305,9 @@ static void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src)
 		break;
 	case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
 		b = 1;
-		dsidev = dsi_get_dsidev_from_id(0);
-		dsi_wait_pll_hsdiv_dispc_active(dsidev);
 		break;
 	case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
 		b = 2;
-		dsidev = dsi_get_dsidev_from_id(1);
-		dsi_wait_pll_hsdiv_dispc_active(dsidev);
 		break;
 	default:
 		BUG();
@@ -327,7 +324,6 @@ static void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src)
 void dss_select_dsi_clk_source(int dsi_module,
 		enum omap_dss_clk_source clk_src)
 {
-	struct platform_device *dsidev;
 	int b, pos;
 
 	switch (clk_src) {
@@ -337,14 +333,10 @@ void dss_select_dsi_clk_source(int dsi_module,
 	case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI:
 		BUG_ON(dsi_module != 0);
 		b = 1;
-		dsidev = dsi_get_dsidev_from_id(0);
-		dsi_wait_pll_hsdiv_dsi_active(dsidev);
 		break;
 	case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI:
 		BUG_ON(dsi_module != 1);
 		b = 1;
-		dsidev = dsi_get_dsidev_from_id(1);
-		dsi_wait_pll_hsdiv_dsi_active(dsidev);
 		break;
 	default:
 		BUG();
@@ -360,7 +352,6 @@ void dss_select_dsi_clk_source(int dsi_module,
 void dss_select_lcd_clk_source(enum omap_channel channel,
 		enum omap_dss_clk_source clk_src)
 {
-	struct platform_device *dsidev;
 	int b, ix, pos;
 
 	if (!dss_has_feature(FEAT_LCD_CLK_SRC)) {
@@ -375,15 +366,11 @@ void dss_select_lcd_clk_source(enum omap_channel channel,
 	case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
 		BUG_ON(channel != OMAP_DSS_CHANNEL_LCD);
 		b = 1;
-		dsidev = dsi_get_dsidev_from_id(0);
-		dsi_wait_pll_hsdiv_dispc_active(dsidev);
 		break;
 	case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
 		BUG_ON(channel != OMAP_DSS_CHANNEL_LCD2 &&
 		       channel != OMAP_DSS_CHANNEL_LCD3);
 		b = 1;
-		dsidev = dsi_get_dsidev_from_id(1);
-		dsi_wait_pll_hsdiv_dispc_active(dsidev);
 		break;
 	default:
 		BUG();
@@ -564,7 +551,7 @@ enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void)
 	return REG_GET(DSS_CONTROL, 15, 15);
 }
 
-static int dss_dpi_select_source_omap2_omap3(enum omap_channel channel)
+static int dss_dpi_select_source_omap2_omap3(int port, enum omap_channel channel)
 {
 	if (channel != OMAP_DSS_CHANNEL_LCD)
 		return -EINVAL;
@@ -572,7 +559,7 @@ static int dss_dpi_select_source_omap2_omap3(enum omap_channel channel)
 	return 0;
 }
 
-static int dss_dpi_select_source_omap4(enum omap_channel channel)
+static int dss_dpi_select_source_omap4(int port, enum omap_channel channel)
 {
 	int val;
 
@@ -592,7 +579,7 @@ static int dss_dpi_select_source_omap4(enum omap_channel channel)
 	return 0;
 }
 
-static int dss_dpi_select_source_omap5(enum omap_channel channel)
+static int dss_dpi_select_source_omap5(int port, enum omap_channel channel)
 {
 	int val;
 
@@ -618,9 +605,9 @@ static int dss_dpi_select_source_omap5(enum omap_channel channel)
 	return 0;
 }
 
-int dss_dpi_select_source(enum omap_channel channel)
+int dss_dpi_select_source(int port, enum omap_channel channel)
 {
-	return dss.feat->dpi_select_source(channel);
+	return dss.feat->dpi_select_source(port, channel);
 }
 
 static int dss_get_clocks(void)
@@ -689,6 +676,16 @@ void dss_debug_dump_clocks(struct seq_file *s)
 }
 #endif
 
+
+static enum omap_display_type omap2plus_ports[] = {
+	OMAP_DISPLAY_TYPE_DPI,
+};
+
+static enum omap_display_type omap34xx_ports[] = {
+	OMAP_DISPLAY_TYPE_DPI,
+	OMAP_DISPLAY_TYPE_SDI,
+};
+
 static const struct dss_features omap24xx_dss_feats __initconst = {
 	/*
 	 * fck div max is really 16, but the divider range has gaps. The range
@@ -698,6 +695,8 @@ static const struct dss_features omap24xx_dss_feats __initconst = {
 	.dss_fck_multiplier	=	2,
 	.parent_clk_name	=	"core_ck",
 	.dpi_select_source	=	&dss_dpi_select_source_omap2_omap3,
+	.ports			=	omap2plus_ports,
+	.num_ports		=	ARRAY_SIZE(omap2plus_ports),
 };
 
 static const struct dss_features omap34xx_dss_feats __initconst = {
@@ -705,6 +704,8 @@ static const struct dss_features omap34xx_dss_feats __initconst = {
 	.dss_fck_multiplier	=	2,
 	.parent_clk_name	=	"dpll4_ck",
 	.dpi_select_source	=	&dss_dpi_select_source_omap2_omap3,
+	.ports			=	omap34xx_ports,
+	.num_ports		=	ARRAY_SIZE(omap34xx_ports),
 };
 
 static const struct dss_features omap3630_dss_feats __initconst = {
@@ -712,6 +713,8 @@ static const struct dss_features omap3630_dss_feats __initconst = {
 	.dss_fck_multiplier	=	1,
 	.parent_clk_name	=	"dpll4_ck",
 	.dpi_select_source	=	&dss_dpi_select_source_omap2_omap3,
+	.ports			=	omap2plus_ports,
+	.num_ports		=	ARRAY_SIZE(omap2plus_ports),
 };
 
 static const struct dss_features omap44xx_dss_feats __initconst = {
@@ -719,6 +722,8 @@ static const struct dss_features omap44xx_dss_feats __initconst = {
 	.dss_fck_multiplier	=	1,
 	.parent_clk_name	=	"dpll_per_x2_ck",
 	.dpi_select_source	=	&dss_dpi_select_source_omap4,
+	.ports			=	omap2plus_ports,
+	.num_ports		=	ARRAY_SIZE(omap2plus_ports),
 };
 
 static const struct dss_features omap54xx_dss_feats __initconst = {
@@ -726,6 +731,8 @@ static const struct dss_features omap54xx_dss_feats __initconst = {
 	.dss_fck_multiplier	=	1,
 	.parent_clk_name	=	"dpll_per_x2_ck",
 	.dpi_select_source	=	&dss_dpi_select_source_omap5,
+	.ports			=	omap2plus_ports,
+	.num_ports		=	ARRAY_SIZE(omap2plus_ports),
 };
 
 static const struct dss_features am43xx_dss_feats __initconst = {
@@ -733,6 +740,8 @@ static const struct dss_features am43xx_dss_feats __initconst = {
 	.dss_fck_multiplier	=	0,
 	.parent_clk_name	=	NULL,
 	.dpi_select_source	=	&dss_dpi_select_source_omap2_omap3,
+	.ports			=	omap2plus_ports,
+	.num_ports		=	ARRAY_SIZE(omap2plus_ports),
 };
 
 static int __init dss_init_features(struct platform_device *pdev)
@@ -798,37 +807,77 @@ static int __init dss_init_ports(struct platform_device *pdev)
 	if (!port)
 		return 0;
 
+	if (dss.feat->num_ports == 0)
+		return 0;
+
 	do {
+		enum omap_display_type port_type;
 		u32 reg;
 
 		r = of_property_read_u32(port, "reg", &reg);
 		if (r)
 			reg = 0;
 
-#ifdef CONFIG_OMAP2_DSS_DPI
-		if (reg == 0)
-			dpi_init_port(pdev, port);
-#endif
+		if (reg >= dss.feat->num_ports)
+			continue;
 
-#ifdef CONFIG_OMAP2_DSS_SDI
-		if (reg == 1)
-			sdi_init_port(pdev, port);
-#endif
+		port_type = dss.feat->ports[reg];
 
+		switch (port_type) {
+		case OMAP_DISPLAY_TYPE_DPI:
+			dpi_init_port(pdev, port);
+			break;
+		case OMAP_DISPLAY_TYPE_SDI:
+			sdi_init_port(pdev, port);
+			break;
+		default:
+			break;
+		}
 	} while ((port = omapdss_of_get_next_port(parent, port)) != NULL);
 
 	return 0;
 }
 
-static void __exit dss_uninit_ports(void)
+static void __exit dss_uninit_ports(struct platform_device *pdev)
 {
-#ifdef CONFIG_OMAP2_DSS_DPI
-	dpi_uninit_port();
-#endif
+	struct device_node *parent = pdev->dev.of_node;
+	struct device_node *port;
 
-#ifdef CONFIG_OMAP2_DSS_SDI
-	sdi_uninit_port();
-#endif
+	if (parent == NULL)
+		return;
+
+	port = omapdss_of_get_next_port(parent, NULL);
+	if (!port)
+		return;
+
+	if (dss.feat->num_ports == 0)
+		return;
+
+	do {
+		enum omap_display_type port_type;
+		u32 reg;
+		int r;
+
+		r = of_property_read_u32(port, "reg", &reg);
+		if (r)
+			reg = 0;
+
+		if (reg >= dss.feat->num_ports)
+			continue;
+
+		port_type = dss.feat->ports[reg];
+
+		switch (port_type) {
+		case OMAP_DISPLAY_TYPE_DPI:
+			dpi_uninit_port(port);
+			break;
+		case OMAP_DISPLAY_TYPE_SDI:
+			sdi_uninit_port(port);
+			break;
+		default:
+			break;
+		}
+	} while ((port = omapdss_of_get_next_port(parent, port)) != NULL);
 }
 
 /* DSS HW IP initialisation */
@@ -910,7 +959,7 @@ err_setup_clocks:
 
 static int __exit omap_dsshw_remove(struct platform_device *pdev)
 {
-	dss_uninit_ports();
+	dss_uninit_ports(pdev);
 
 	pm_runtime_disable(&pdev->dev);
 
diff --git a/drivers/video/fbdev/omap2/dss/dss.h b/drivers/video/fbdev/omap2/dss/dss.h
index 8ff22c134c62..14fb0c23f4a2 100644
--- a/drivers/video/fbdev/omap2/dss/dss.h
+++ b/drivers/video/fbdev/omap2/dss/dss.h
@@ -100,35 +100,77 @@ enum dss_writeback_channel {
 	DSS_WB_LCD3_MGR =	7,
 };
 
-struct dispc_clock_info {
+struct dss_pll;
+
+#define DSS_PLL_MAX_HSDIVS 4
+
+/*
+ * Type-A PLLs: clkout[]/mX[] refer to hsdiv outputs m4, m5, m6, m7.
+ * Type-B PLLs: clkout[0] refers to m2.
+ */
+struct dss_pll_clock_info {
 	/* rates that we get with dividers below */
-	unsigned long lck;
-	unsigned long pck;
+	unsigned long fint;
+	unsigned long clkdco;
+	unsigned long clkout[DSS_PLL_MAX_HSDIVS];
 
 	/* dividers */
-	u16 lck_div;
-	u16 pck_div;
+	u16 n;
+	u16 m;
+	u32 mf;
+	u16 mX[DSS_PLL_MAX_HSDIVS];
+	u16 sd;
+};
+
+struct dss_pll_ops {
+	int (*enable)(struct dss_pll *pll);
+	void (*disable)(struct dss_pll *pll);
+	int (*set_config)(struct dss_pll *pll,
+		const struct dss_pll_clock_info *cinfo);
+};
+
+struct dss_pll_hw {
+	unsigned n_max;
+	unsigned m_min;
+	unsigned m_max;
+	unsigned mX_max;
+
+	unsigned long fint_min, fint_max;
+	unsigned long clkdco_min, clkdco_low, clkdco_max;
+
+	u8 n_msb, n_lsb;
+	u8 m_msb, m_lsb;
+	u8 mX_msb[DSS_PLL_MAX_HSDIVS], mX_lsb[DSS_PLL_MAX_HSDIVS];
+
+	bool has_stopmode;
+	bool has_freqsel;
+	bool has_selfreqdco;
+	bool has_refsel;
 };
 
-struct dsi_clock_info {
+struct dss_pll {
+	const char *name;
+
+	struct clk *clkin;
+	struct regulator *regulator;
+
+	void __iomem *base;
+
+	const struct dss_pll_hw *hw;
+
+	const struct dss_pll_ops *ops;
+
+	struct dss_pll_clock_info cinfo;
+};
+
+struct dispc_clock_info {
 	/* rates that we get with dividers below */
-	unsigned long fint;
-	unsigned long clkin4ddr;
-	unsigned long clkin;
-	unsigned long dsi_pll_hsdiv_dispc_clk;	/* OMAP3: DSI1_PLL_CLK
-						 * OMAP4: PLLx_CLK1 */
-	unsigned long dsi_pll_hsdiv_dsi_clk;	/* OMAP3: DSI2_PLL_CLK
-						 * OMAP4: PLLx_CLK2 */
-	unsigned long lp_clk;
+	unsigned long lck;
+	unsigned long pck;
 
 	/* dividers */
-	u16 regn;
-	u16 regm;
-	u16 regm_dispc;	/* OMAP3: REGM3
-			 * OMAP4: REGM4 */
-	u16 regm_dsi;	/* OMAP3: REGM4
-			 * OMAP4: REGM5 */
-	u16 lp_clk_div;
+	u16 lck_div;
+	u16 pck_div;
 };
 
 struct dss_lcd_mgr_config {
@@ -209,12 +251,16 @@ int dss_init_platform_driver(void) __init;
 void dss_uninit_platform_driver(void);
 
 unsigned long dss_get_dispc_clk_rate(void);
-int dss_dpi_select_source(enum omap_channel channel);
+int dss_dpi_select_source(int port, enum omap_channel channel);
 void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select);
 enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void);
 const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src);
 void dss_dump_clocks(struct seq_file *s);
 
+/* dss-of */
+struct device_node *dss_of_port_get_parent_device(struct device_node *port);
+u32 dss_of_port_get_port_number(struct device_node *port);
+
 #if defined(CONFIG_OMAP2_DSS_DEBUGFS)
 void dss_debug_dump_clocks(struct seq_file *s);
 #endif
@@ -244,16 +290,22 @@ bool dss_div_calc(unsigned long pck, unsigned long fck_min,
 int sdi_init_platform_driver(void) __init;
 void sdi_uninit_platform_driver(void) __exit;
 
+#ifdef CONFIG_OMAP2_DSS_SDI
 int sdi_init_port(struct platform_device *pdev, struct device_node *port) __init;
-void sdi_uninit_port(void) __exit;
+void sdi_uninit_port(struct device_node *port) __exit;
+#else
+static inline int __init sdi_init_port(struct platform_device *pdev,
+		struct device_node *port)
+{
+	return 0;
+}
+static inline void __exit sdi_uninit_port(struct device_node *port)
+{
+}
+#endif
 
 /* DSI */
 
-typedef bool (*dsi_pll_calc_func)(int regn, int regm, unsigned long fint,
-		unsigned long pll, void *data);
-typedef bool (*dsi_hsdiv_calc_func)(int regm_dispc, unsigned long dispc,
-		void *data);
-
 #ifdef CONFIG_OMAP2_DSS_DSI
 
 struct dentry;
@@ -262,104 +314,36 @@ struct file_operations;
 int dsi_init_platform_driver(void) __init;
 void dsi_uninit_platform_driver(void) __exit;
 
-int dsi_runtime_get(struct platform_device *dsidev);
-void dsi_runtime_put(struct platform_device *dsidev);
-
 void dsi_dump_clocks(struct seq_file *s);
 
 void dsi_irq_handler(void);
 u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt);
 
-unsigned long dsi_get_pll_clkin(struct platform_device *dsidev);
-
-bool dsi_hsdiv_calc(struct platform_device *dsidev, unsigned long pll,
-		unsigned long out_min, dsi_hsdiv_calc_func func, void *data);
-bool dsi_pll_calc(struct platform_device *dsidev, unsigned long clkin,
-		unsigned long pll_min, unsigned long pll_max,
-		dsi_pll_calc_func func, void *data);
-
-unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev);
-int dsi_pll_set_clock_div(struct platform_device *dsidev,
-		struct dsi_clock_info *cinfo);
-int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk,
-		bool enable_hsdiv);
-void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes);
-void dsi_wait_pll_hsdiv_dispc_active(struct platform_device *dsidev);
-void dsi_wait_pll_hsdiv_dsi_active(struct platform_device *dsidev);
-struct platform_device *dsi_get_dsidev_from_id(int module);
 #else
-static inline int dsi_runtime_get(struct platform_device *dsidev)
-{
-	return 0;
-}
-static inline void dsi_runtime_put(struct platform_device *dsidev)
-{
-}
 static inline u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt)
 {
 	WARN("%s: DSI not compiled in, returning pixel_size as 0\n", __func__);
 	return 0;
 }
-static inline unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev)
-{
-	WARN("%s: DSI not compiled in, returning rate as 0\n", __func__);
-	return 0;
-}
-static inline int dsi_pll_set_clock_div(struct platform_device *dsidev,
-		struct dsi_clock_info *cinfo)
-{
-	WARN("%s: DSI not compiled in\n", __func__);
-	return -ENODEV;
-}
-static inline int dsi_pll_init(struct platform_device *dsidev,
-		bool enable_hsclk, bool enable_hsdiv)
-{
-	WARN("%s: DSI not compiled in\n", __func__);
-	return -ENODEV;
-}
-static inline void dsi_pll_uninit(struct platform_device *dsidev,
-		bool disconnect_lanes)
-{
-}
-static inline void dsi_wait_pll_hsdiv_dispc_active(struct platform_device *dsidev)
-{
-}
-static inline void dsi_wait_pll_hsdiv_dsi_active(struct platform_device *dsidev)
-{
-}
-static inline struct platform_device *dsi_get_dsidev_from_id(int module)
-{
-	return NULL;
-}
-
-static inline unsigned long dsi_get_pll_clkin(struct platform_device *dsidev)
-{
-	return 0;
-}
-
-static inline bool dsi_hsdiv_calc(struct platform_device *dsidev,
-		unsigned long pll, unsigned long out_min,
-		dsi_hsdiv_calc_func func, void *data)
-{
-	return false;
-}
-
-static inline bool dsi_pll_calc(struct platform_device *dsidev,
-		unsigned long clkin,
-		unsigned long pll_min, unsigned long pll_max,
-		dsi_pll_calc_func func, void *data)
-{
-	return false;
-}
-
 #endif
 
 /* DPI */
 int dpi_init_platform_driver(void) __init;
 void dpi_uninit_platform_driver(void) __exit;
 
+#ifdef CONFIG_OMAP2_DSS_DPI
 int dpi_init_port(struct platform_device *pdev, struct device_node *port) __init;
-void dpi_uninit_port(void) __exit;
+void dpi_uninit_port(struct device_node *port) __exit;
+#else
+static inline int __init dpi_init_port(struct platform_device *pdev,
+		struct device_node *port)
+{
+	return 0;
+}
+static inline void __exit dpi_uninit_port(struct device_node *port)
+{
+}
+#endif
 
 /* DISPC */
 int dispc_init_platform_driver(void) __init;
@@ -438,4 +422,29 @@ static inline void dss_collect_irq_stats(u32 irqstatus, unsigned *irq_arr)
 }
 #endif
 
+/* PLL */
+typedef bool (*dss_pll_calc_func)(int n, int m, unsigned long fint,
+		unsigned long clkdco, void *data);
+typedef bool (*dss_hsdiv_calc_func)(int m_dispc, unsigned long dispc,
+		void *data);
+
+int dss_pll_register(struct dss_pll *pll);
+void dss_pll_unregister(struct dss_pll *pll);
+struct dss_pll *dss_pll_find(const char *name);
+int dss_pll_enable(struct dss_pll *pll);
+void dss_pll_disable(struct dss_pll *pll);
+int dss_pll_set_config(struct dss_pll *pll,
+		const struct dss_pll_clock_info *cinfo);
+
+bool dss_pll_hsdiv_calc(const struct dss_pll *pll, unsigned long clkdco,
+		unsigned long out_min, unsigned long out_max,
+		dss_hsdiv_calc_func func, void *data);
+bool dss_pll_calc(const struct dss_pll *pll, unsigned long clkin,
+		unsigned long pll_min, unsigned long pll_max,
+		dss_pll_calc_func func, void *data);
+int dss_pll_write_config_type_a(struct dss_pll *pll,
+		const struct dss_pll_clock_info *cinfo);
+int dss_pll_write_config_type_b(struct dss_pll *pll,
+		const struct dss_pll_clock_info *cinfo);
+
 #endif
diff --git a/drivers/video/fbdev/omap2/dss/dss_features.c b/drivers/video/fbdev/omap2/dss/dss_features.c
index 15088df7bd16..0e3da809473c 100644
--- a/drivers/video/fbdev/omap2/dss/dss_features.c
+++ b/drivers/video/fbdev/omap2/dss/dss_features.c
@@ -72,10 +72,6 @@ static const struct dss_reg_field omap2_dss_reg_fields[] = {
 	[FEAT_REG_HORIZONTALACCU]		= { 9, 0 },
 	[FEAT_REG_VERTICALACCU]			= { 25, 16 },
 	[FEAT_REG_DISPC_CLK_SWITCH]		= { 0, 0 },
-	[FEAT_REG_DSIPLL_REGN]			= { 0, 0 },
-	[FEAT_REG_DSIPLL_REGM]			= { 0, 0 },
-	[FEAT_REG_DSIPLL_REGM_DISPC]		= { 0, 0 },
-	[FEAT_REG_DSIPLL_REGM_DSI]		= { 0, 0 },
 };
 
 static const struct dss_reg_field omap3_dss_reg_fields[] = {
@@ -87,10 +83,6 @@ static const struct dss_reg_field omap3_dss_reg_fields[] = {
 	[FEAT_REG_HORIZONTALACCU]		= { 9, 0 },
 	[FEAT_REG_VERTICALACCU]			= { 25, 16 },
 	[FEAT_REG_DISPC_CLK_SWITCH]		= { 0, 0 },
-	[FEAT_REG_DSIPLL_REGN]			= { 7, 1 },
-	[FEAT_REG_DSIPLL_REGM]			= { 18, 8 },
-	[FEAT_REG_DSIPLL_REGM_DISPC]		= { 22, 19 },
-	[FEAT_REG_DSIPLL_REGM_DSI]		= { 26, 23 },
 };
 
 static const struct dss_reg_field am43xx_dss_reg_fields[] = {
@@ -113,10 +105,6 @@ static const struct dss_reg_field omap4_dss_reg_fields[] = {
 	[FEAT_REG_HORIZONTALACCU]		= { 10, 0 },
 	[FEAT_REG_VERTICALACCU]			= { 26, 16 },
 	[FEAT_REG_DISPC_CLK_SWITCH]		= { 9, 8 },
-	[FEAT_REG_DSIPLL_REGN]			= { 8, 1 },
-	[FEAT_REG_DSIPLL_REGM]			= { 20, 9 },
-	[FEAT_REG_DSIPLL_REGM_DISPC]		= { 25, 21 },
-	[FEAT_REG_DSIPLL_REGM_DSI]		= { 30, 26 },
 };
 
 static const struct dss_reg_field omap5_dss_reg_fields[] = {
@@ -128,10 +116,6 @@ static const struct dss_reg_field omap5_dss_reg_fields[] = {
 	[FEAT_REG_HORIZONTALACCU]		= { 10, 0 },
 	[FEAT_REG_VERTICALACCU]			= { 26, 16 },
 	[FEAT_REG_DISPC_CLK_SWITCH]		= { 9, 7 },
-	[FEAT_REG_DSIPLL_REGN]			= { 8, 1 },
-	[FEAT_REG_DSIPLL_REGM]			= { 20, 9 },
-	[FEAT_REG_DSIPLL_REGM_DISPC]		= { 25, 21 },
-	[FEAT_REG_DSIPLL_REGM_DSI]		= { 30, 26 },
 };
 
 static const enum omap_display_type omap2_dss_supported_displays[] = {
@@ -437,12 +421,6 @@ static const char * const omap5_dss_clk_source_names[] = {
 static const struct dss_param_range omap2_dss_param_range[] = {
 	[FEAT_PARAM_DSS_FCK]			= { 0, 133000000 },
 	[FEAT_PARAM_DSS_PCD]			= { 2, 255 },
-	[FEAT_PARAM_DSIPLL_REGN]		= { 0, 0 },
-	[FEAT_PARAM_DSIPLL_REGM]		= { 0, 0 },
-	[FEAT_PARAM_DSIPLL_REGM_DISPC]		= { 0, 0 },
-	[FEAT_PARAM_DSIPLL_REGM_DSI]		= { 0, 0 },
-	[FEAT_PARAM_DSIPLL_FINT]		= { 0, 0 },
-	[FEAT_PARAM_DSIPLL_LPDIV]		= { 0, 0 },
 	[FEAT_PARAM_DOWNSCALE]			= { 1, 2 },
 	/*
 	 * Assuming the line width buffer to be 768 pixels as OMAP2 DISPC
@@ -454,11 +432,6 @@ static const struct dss_param_range omap2_dss_param_range[] = {
 static const struct dss_param_range omap3_dss_param_range[] = {
 	[FEAT_PARAM_DSS_FCK]			= { 0, 173000000 },
 	[FEAT_PARAM_DSS_PCD]			= { 1, 255 },
-	[FEAT_PARAM_DSIPLL_REGN]		= { 0, (1 << 7) - 1 },
-	[FEAT_PARAM_DSIPLL_REGM]		= { 0, (1 << 11) - 1 },
-	[FEAT_PARAM_DSIPLL_REGM_DISPC]		= { 0, (1 << 4) - 1 },
-	[FEAT_PARAM_DSIPLL_REGM_DSI]		= { 0, (1 << 4) - 1 },
-	[FEAT_PARAM_DSIPLL_FINT]		= { 750000, 2100000 },
 	[FEAT_PARAM_DSIPLL_LPDIV]		= { 1, (1 << 13) - 1},
 	[FEAT_PARAM_DSI_FCK]			= { 0, 173000000 },
 	[FEAT_PARAM_DOWNSCALE]			= { 1, 4 },
@@ -475,11 +448,6 @@ static const struct dss_param_range am43xx_dss_param_range[] = {
 static const struct dss_param_range omap4_dss_param_range[] = {
 	[FEAT_PARAM_DSS_FCK]			= { 0, 186000000 },
 	[FEAT_PARAM_DSS_PCD]			= { 1, 255 },
-	[FEAT_PARAM_DSIPLL_REGN]		= { 0, (1 << 8) - 1 },
-	[FEAT_PARAM_DSIPLL_REGM]		= { 0, (1 << 12) - 1 },
-	[FEAT_PARAM_DSIPLL_REGM_DISPC]		= { 0, (1 << 5) - 1 },
-	[FEAT_PARAM_DSIPLL_REGM_DSI]		= { 0, (1 << 5) - 1 },
-	[FEAT_PARAM_DSIPLL_FINT]		= { 500000, 2500000 },
 	[FEAT_PARAM_DSIPLL_LPDIV]		= { 0, (1 << 13) - 1 },
 	[FEAT_PARAM_DSI_FCK]			= { 0, 170000000 },
 	[FEAT_PARAM_DOWNSCALE]			= { 1, 4 },
@@ -489,11 +457,6 @@ static const struct dss_param_range omap4_dss_param_range[] = {
 static const struct dss_param_range omap5_dss_param_range[] = {
 	[FEAT_PARAM_DSS_FCK]			= { 0, 209250000 },
 	[FEAT_PARAM_DSS_PCD]			= { 1, 255 },
-	[FEAT_PARAM_DSIPLL_REGN]		= { 0, (1 << 8) - 1 },
-	[FEAT_PARAM_DSIPLL_REGM]		= { 0, (1 << 12) - 1 },
-	[FEAT_PARAM_DSIPLL_REGM_DISPC]		= { 0, (1 << 5) - 1 },
-	[FEAT_PARAM_DSIPLL_REGM_DSI]		= { 0, (1 << 5) - 1 },
-	[FEAT_PARAM_DSIPLL_FINT]		= { 150000, 52000000 },
 	[FEAT_PARAM_DSIPLL_LPDIV]		= { 0, (1 << 13) - 1 },
 	[FEAT_PARAM_DSI_FCK]			= { 0, 209250000 },
 	[FEAT_PARAM_DOWNSCALE]			= { 1, 4 },
@@ -517,7 +480,6 @@ static const enum dss_feat_id omap3430_dss_feat_list[] = {
 	FEAT_LINEBUFFERSPLIT,
 	FEAT_ROWREPEATENABLE,
 	FEAT_RESIZECONF,
-	FEAT_DSI_PLL_FREQSEL,
 	FEAT_DSI_REVERSE_TXCLKESC,
 	FEAT_VENC_REQUIRES_TV_DAC_CLK,
 	FEAT_CPR,
@@ -537,7 +499,6 @@ static const enum dss_feat_id am35xx_dss_feat_list[] = {
 	FEAT_LINEBUFFERSPLIT,
 	FEAT_ROWREPEATENABLE,
 	FEAT_RESIZECONF,
-	FEAT_DSI_PLL_FREQSEL,
 	FEAT_DSI_REVERSE_TXCLKESC,
 	FEAT_VENC_REQUIRES_TV_DAC_CLK,
 	FEAT_CPR,
@@ -572,7 +533,6 @@ static const enum dss_feat_id omap3630_dss_feat_list[] = {
 	FEAT_ROWREPEATENABLE,
 	FEAT_RESIZECONF,
 	FEAT_DSI_PLL_PWR_BUG,
-	FEAT_DSI_PLL_FREQSEL,
 	FEAT_CPR,
 	FEAT_PRELOAD,
 	FEAT_FIR_COEF_V,
@@ -654,8 +614,6 @@ static const enum dss_feat_id omap5_dss_feat_list[] = {
 	FEAT_ALPHA_FREE_ZORDER,
 	FEAT_FIFO_MERGE,
 	FEAT_BURST_2D,
-	FEAT_DSI_PLL_SELFREQDCO,
-	FEAT_DSI_PLL_REFSEL,
 	FEAT_DSI_PHY_DCC,
 	FEAT_MFLAG,
 };
diff --git a/drivers/video/fbdev/omap2/dss/dss_features.h b/drivers/video/fbdev/omap2/dss/dss_features.h
index e3ef3b714896..100f7a2d0638 100644
--- a/drivers/video/fbdev/omap2/dss/dss_features.h
+++ b/drivers/video/fbdev/omap2/dss/dss_features.h
@@ -41,7 +41,6 @@ enum dss_feat_id {
 	FEAT_LCD_CLK_SRC,
 	/* DSI-PLL power command 0x3 is not working */
 	FEAT_DSI_PLL_PWR_BUG,
-	FEAT_DSI_PLL_FREQSEL,
 	FEAT_DSI_DCS_CMD_CONFIG_VC,
 	FEAT_DSI_VC_OCP_WIDTH,
 	FEAT_DSI_REVERSE_TXCLKESC,
@@ -61,8 +60,6 @@ enum dss_feat_id {
 	/* An unknown HW bug causing the normal FIFO thresholds not to work */
 	FEAT_OMAP3_DSI_FIFO_BUG,
 	FEAT_BURST_2D,
-	FEAT_DSI_PLL_SELFREQDCO,
-	FEAT_DSI_PLL_REFSEL,
 	FEAT_DSI_PHY_DCC,
 	FEAT_MFLAG,
 };
@@ -77,20 +74,11 @@ enum dss_feat_reg_field {
 	FEAT_REG_HORIZONTALACCU,
 	FEAT_REG_VERTICALACCU,
 	FEAT_REG_DISPC_CLK_SWITCH,
-	FEAT_REG_DSIPLL_REGN,
-	FEAT_REG_DSIPLL_REGM,
-	FEAT_REG_DSIPLL_REGM_DISPC,
-	FEAT_REG_DSIPLL_REGM_DSI,
 };
 
 enum dss_range_param {
 	FEAT_PARAM_DSS_FCK,
 	FEAT_PARAM_DSS_PCD,
-	FEAT_PARAM_DSIPLL_REGN,
-	FEAT_PARAM_DSIPLL_REGM,
-	FEAT_PARAM_DSIPLL_REGM_DISPC,
-	FEAT_PARAM_DSIPLL_REGM_DSI,
-	FEAT_PARAM_DSIPLL_FINT,
 	FEAT_PARAM_DSIPLL_LPDIV,
 	FEAT_PARAM_DSI_FCK,
 	FEAT_PARAM_DOWNSCALE,
diff --git a/drivers/video/fbdev/omap2/dss/hdmi.h b/drivers/video/fbdev/omap2/dss/hdmi.h
index 262771b9b76b..e4a32fe77b02 100644
--- a/drivers/video/fbdev/omap2/dss/hdmi.h
+++ b/drivers/video/fbdev/omap2/dss/hdmi.h
@@ -101,13 +101,6 @@ enum hdmi_core_hdmi_dvi {
 	HDMI_HDMI = 1
 };
 
-enum hdmi_clk_refsel {
-	HDMI_REFSEL_PCLK = 0,
-	HDMI_REFSEL_REF1 = 1,
-	HDMI_REFSEL_REF2 = 2,
-	HDMI_REFSEL_SYSCLK = 3
-};
-
 enum hdmi_packing_mode {
 	HDMI_PACK_10b_RGB_YUV444 = 0,
 	HDMI_PACK_24b_RGB_YUV444_YUV422 = 1,
@@ -160,7 +153,8 @@ enum hdmi_audio_blk_strt_end_sig {
 
 enum hdmi_core_audio_layout {
 	HDMI_AUDIO_LAYOUT_2CH = 0,
-	HDMI_AUDIO_LAYOUT_8CH = 1
+	HDMI_AUDIO_LAYOUT_8CH = 1,
+	HDMI_AUDIO_LAYOUT_6CH = 2
 };
 
 enum hdmi_core_cts_mode {
@@ -191,17 +185,6 @@ struct hdmi_config {
 	enum hdmi_core_hdmi_dvi hdmi_dvi_mode;
 };
 
-/* HDMI PLL structure */
-struct hdmi_pll_info {
-	u16 regn;
-	u16 regm;
-	u32 regmf;
-	u16 regm2;
-	u16 regsd;
-	u16 dcofreq;
-	enum hdmi_clk_refsel refsel;
-};
-
 struct hdmi_audio_format {
 	enum hdmi_stereo_channels		stereo_channels;
 	u8					active_chnnls_msk;
@@ -249,12 +232,15 @@ struct hdmi_core_audio_config {
 
 struct hdmi_wp_data {
 	void __iomem *base;
+	phys_addr_t phys_base;
 };
 
 struct hdmi_pll_data {
+	struct dss_pll pll;
+
 	void __iomem *base;
 
-	struct hdmi_pll_info info;
+	struct hdmi_wp_data *wp;
 };
 
 struct hdmi_phy_data {
@@ -316,16 +302,19 @@ void hdmi_wp_video_config_timing(struct hdmi_wp_data *wp,
 void hdmi_wp_init_vid_fmt_timings(struct hdmi_video_format *video_fmt,
 		struct omap_video_timings *timings, struct hdmi_config *param);
 int hdmi_wp_init(struct platform_device *pdev, struct hdmi_wp_data *wp);
+phys_addr_t hdmi_wp_get_audio_dma_addr(struct hdmi_wp_data *wp);
 
 /* HDMI PLL funcs */
-int hdmi_pll_enable(struct hdmi_pll_data *pll, struct hdmi_wp_data *wp);
-void hdmi_pll_disable(struct hdmi_pll_data *pll, struct hdmi_wp_data *wp);
 void hdmi_pll_dump(struct hdmi_pll_data *pll, struct seq_file *s);
-void hdmi_pll_compute(struct hdmi_pll_data *pll, unsigned long clkin, int phy);
-int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll);
+void hdmi_pll_compute(struct hdmi_pll_data *pll,
+	unsigned long target_tmds, struct dss_pll_clock_info *pi);
+int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll,
+	struct hdmi_wp_data *wp);
+void hdmi_pll_uninit(struct hdmi_pll_data *hpll);
 
 /* HDMI PHY funcs */
-int hdmi_phy_configure(struct hdmi_phy_data *phy, struct hdmi_config *cfg);
+int hdmi_phy_configure(struct hdmi_phy_data *phy, unsigned long hfbitclk,
+	unsigned long lfbitclk);
 void hdmi_phy_dump(struct hdmi_phy_data *phy, struct seq_file *s);
 int hdmi_phy_init(struct platform_device *pdev, struct hdmi_phy_data *phy);
 int hdmi_phy_parse_lanes(struct hdmi_phy_data *phy, const u32 *lanes);
@@ -334,7 +323,7 @@ int hdmi_phy_parse_lanes(struct hdmi_phy_data *phy, const u32 *lanes);
 int hdmi_parse_lanes_of(struct platform_device *pdev, struct device_node *ep,
 	struct hdmi_phy_data *phy);
 
-#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) || defined(CONFIG_OMAP5_DSS_HDMI_AUDIO)
+/* Audio funcs */
 int hdmi_compute_acr(u32 pclk, u32 sample_freq, u32 *n, u32 *cts);
 int hdmi_wp_audio_enable(struct hdmi_wp_data *wp, bool enable);
 int hdmi_wp_audio_core_req_enable(struct hdmi_wp_data *wp, bool enable);
@@ -342,9 +331,33 @@ void hdmi_wp_audio_config_format(struct hdmi_wp_data *wp,
 		struct hdmi_audio_format *aud_fmt);
 void hdmi_wp_audio_config_dma(struct hdmi_wp_data *wp,
 		struct hdmi_audio_dma *aud_dma);
-static inline bool hdmi_mode_has_audio(int mode)
+static inline bool hdmi_mode_has_audio(struct hdmi_config *cfg)
 {
-	return mode == HDMI_HDMI ? true : false;
+	return cfg->hdmi_dvi_mode == HDMI_HDMI ? true : false;
 }
-#endif
+
+/* HDMI DRV data */
+struct omap_hdmi {
+	struct mutex lock;
+	struct platform_device *pdev;
+
+	struct hdmi_wp_data	wp;
+	struct hdmi_pll_data	pll;
+	struct hdmi_phy_data	phy;
+	struct hdmi_core_data	core;
+
+	struct hdmi_config cfg;
+
+	struct regulator *vdda_reg;
+
+	bool core_enabled;
+	bool display_enabled;
+
+	struct omap_dss_device output;
+
+	struct platform_device *audio_pdev;
+	void (*audio_abort_cb)(struct device *dev);
+	int wp_idlemode;
+};
+
 #endif
diff --git a/drivers/video/fbdev/omap2/dss/hdmi4.c b/drivers/video/fbdev/omap2/dss/hdmi4.c
index 9a8713ca090c..f1a02bf938ee 100644
--- a/drivers/video/fbdev/omap2/dss/hdmi4.c
+++ b/drivers/video/fbdev/omap2/dss/hdmi4.c
@@ -33,29 +33,14 @@
 #include <linux/gpio.h>
 #include <linux/regulator/consumer.h>
 #include <video/omapdss.h>
+#include <sound/omap-hdmi-audio.h>
 
 #include "hdmi4_core.h"
 #include "dss.h"
 #include "dss_features.h"
+#include "hdmi.h"
 
-static struct {
-	struct mutex lock;
-	struct platform_device *pdev;
-
-	struct hdmi_wp_data	wp;
-	struct hdmi_pll_data	pll;
-	struct hdmi_phy_data	phy;
-	struct hdmi_core_data	core;
-
-	struct hdmi_config cfg;
-
-	struct clk *sys_clk;
-	struct regulator *vdda_hdmi_dac_reg;
-
-	bool core_enabled;
-
-	struct omap_dss_device output;
-} hdmi;
+static struct omap_hdmi hdmi;
 
 static int hdmi_runtime_get(void)
 {
@@ -117,7 +102,7 @@ static int hdmi_init_regulator(void)
 	int r;
 	struct regulator *reg;
 
-	if (hdmi.vdda_hdmi_dac_reg != NULL)
+	if (hdmi.vdda_reg != NULL)
 		return 0;
 
 	reg = devm_regulator_get(&hdmi.pdev->dev, "vdda");
@@ -137,7 +122,7 @@ static int hdmi_init_regulator(void)
 		}
 	}
 
-	hdmi.vdda_hdmi_dac_reg = reg;
+	hdmi.vdda_reg = reg;
 
 	return 0;
 }
@@ -146,7 +131,7 @@ static int hdmi_power_on_core(struct omap_dss_device *dssdev)
 {
 	int r;
 
-	r = regulator_enable(hdmi.vdda_hdmi_dac_reg);
+	r = regulator_enable(hdmi.vdda_reg);
 	if (r)
 		return r;
 
@@ -162,7 +147,7 @@ static int hdmi_power_on_core(struct omap_dss_device *dssdev)
 	return 0;
 
 err_runtime_get:
-	regulator_disable(hdmi.vdda_hdmi_dac_reg);
+	regulator_disable(hdmi.vdda_reg);
 
 	return r;
 }
@@ -172,7 +157,7 @@ static void hdmi_power_off_core(struct omap_dss_device *dssdev)
 	hdmi.core_enabled = false;
 
 	hdmi_runtime_put();
-	regulator_disable(hdmi.vdda_hdmi_dac_reg);
+	regulator_disable(hdmi.vdda_reg);
 }
 
 static int hdmi_power_on_full(struct omap_dss_device *dssdev)
@@ -180,8 +165,8 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev)
 	int r;
 	struct omap_video_timings *p;
 	struct omap_overlay_manager *mgr = hdmi.output.manager;
-	unsigned long phy;
 	struct hdmi_wp_data *wp = &hdmi.wp;
+	struct dss_pll_clock_info hdmi_cinfo = { 0 };
 
 	r = hdmi_power_on_core(dssdev);
 	if (r)
@@ -195,19 +180,22 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev)
 
 	DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", p->x_res, p->y_res);
 
-	/* the functions below use kHz pixel clock. TODO: change to Hz */
-	phy = p->pixelclock / 1000;
-
-	hdmi_pll_compute(&hdmi.pll, clk_get_rate(hdmi.sys_clk), phy);
+	hdmi_pll_compute(&hdmi.pll, p->pixelclock, &hdmi_cinfo);
 
-	/* config the PLL and PHY hdmi_set_pll_pwrfirst */
-	r = hdmi_pll_enable(&hdmi.pll, &hdmi.wp);
+	r = dss_pll_enable(&hdmi.pll.pll);
 	if (r) {
-		DSSDBG("Failed to lock PLL\n");
+		DSSERR("Failed to enable PLL\n");
 		goto err_pll_enable;
 	}
 
-	r = hdmi_phy_configure(&hdmi.phy, &hdmi.cfg);
+	r = dss_pll_set_config(&hdmi.pll.pll, &hdmi_cinfo);
+	if (r) {
+		DSSERR("Failed to configure PLL\n");
+		goto err_pll_cfg;
+	}
+
+	r = hdmi_phy_configure(&hdmi.phy, hdmi_cinfo.clkdco,
+		hdmi_cinfo.clkout[0]);
 	if (r) {
 		DSSDBG("Failed to configure PHY\n");
 		goto err_phy_cfg;
@@ -244,7 +232,8 @@ err_vid_enable:
 err_phy_cfg:
 	hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF);
 err_phy_pwr:
-	hdmi_pll_disable(&hdmi.pll, &hdmi.wp);
+err_pll_cfg:
+	dss_pll_disable(&hdmi.pll.pll);
 err_pll_enable:
 	hdmi_power_off_core(dssdev);
 	return -EIO;
@@ -262,7 +251,7 @@ static void hdmi_power_off_full(struct omap_dss_device *dssdev)
 
 	hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF);
 
-	hdmi_pll_disable(&hdmi.pll, &hdmi.wp);
+	dss_pll_disable(&hdmi.pll.pll);
 
 	hdmi_power_off_core(dssdev);
 }
@@ -352,6 +341,8 @@ static int hdmi_display_enable(struct omap_dss_device *dssdev)
 		goto err0;
 	}
 
+	hdmi.display_enabled = true;
+
 	mutex_unlock(&hdmi.lock);
 	return 0;
 
@@ -366,8 +357,13 @@ static void hdmi_display_disable(struct omap_dss_device *dssdev)
 
 	mutex_lock(&hdmi.lock);
 
+	if (hdmi.audio_pdev && hdmi.audio_abort_cb)
+		hdmi.audio_abort_cb(&hdmi.audio_pdev->dev);
+
 	hdmi_power_off_full(dssdev);
 
+	hdmi.display_enabled = false;
+
 	mutex_unlock(&hdmi.lock);
 }
 
@@ -404,21 +400,6 @@ static void hdmi_core_disable(struct omap_dss_device *dssdev)
 	mutex_unlock(&hdmi.lock);
 }
 
-static int hdmi_get_clocks(struct platform_device *pdev)
-{
-	struct clk *clk;
-
-	clk = devm_clk_get(&pdev->dev, "sys_clk");
-	if (IS_ERR(clk)) {
-		DSSERR("can't get sys_clk\n");
-		return PTR_ERR(clk);
-	}
-
-	hdmi.sys_clk = clk;
-
-	return 0;
-}
-
 static int hdmi_connect(struct omap_dss_device *dssdev,
 		struct omap_dss_device *dst)
 {
@@ -484,112 +465,6 @@ static int hdmi_read_edid(struct omap_dss_device *dssdev,
 	return r;
 }
 
-#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
-static int hdmi_audio_enable(struct omap_dss_device *dssdev)
-{
-	int r;
-
-	mutex_lock(&hdmi.lock);
-
-	if (!hdmi_mode_has_audio(hdmi.cfg.hdmi_dvi_mode)) {
-		r = -EPERM;
-		goto err;
-	}
-
-	r = hdmi_wp_audio_enable(&hdmi.wp, true);
-	if (r)
-		goto err;
-
-	mutex_unlock(&hdmi.lock);
-	return 0;
-
-err:
-	mutex_unlock(&hdmi.lock);
-	return r;
-}
-
-static void hdmi_audio_disable(struct omap_dss_device *dssdev)
-{
-	hdmi_wp_audio_enable(&hdmi.wp, false);
-}
-
-static int hdmi_audio_start(struct omap_dss_device *dssdev)
-{
-	return hdmi4_audio_start(&hdmi.core, &hdmi.wp);
-}
-
-static void hdmi_audio_stop(struct omap_dss_device *dssdev)
-{
-	hdmi4_audio_stop(&hdmi.core, &hdmi.wp);
-}
-
-static bool hdmi_audio_supported(struct omap_dss_device *dssdev)
-{
-	bool r;
-
-	mutex_lock(&hdmi.lock);
-
-	r = hdmi_mode_has_audio(hdmi.cfg.hdmi_dvi_mode);
-
-	mutex_unlock(&hdmi.lock);
-	return r;
-}
-
-static int hdmi_audio_config(struct omap_dss_device *dssdev,
-		struct omap_dss_audio *audio)
-{
-	int r;
-	u32 pclk = hdmi.cfg.timings.pixelclock;
-
-	mutex_lock(&hdmi.lock);
-
-	if (!hdmi_mode_has_audio(hdmi.cfg.hdmi_dvi_mode)) {
-		r = -EPERM;
-		goto err;
-	}
-
-	r = hdmi4_audio_config(&hdmi.core, &hdmi.wp, audio, pclk);
-	if (r)
-		goto err;
-
-	mutex_unlock(&hdmi.lock);
-	return 0;
-
-err:
-	mutex_unlock(&hdmi.lock);
-	return r;
-}
-#else
-static int hdmi_audio_enable(struct omap_dss_device *dssdev)
-{
-	return -EPERM;
-}
-
-static void hdmi_audio_disable(struct omap_dss_device *dssdev)
-{
-}
-
-static int hdmi_audio_start(struct omap_dss_device *dssdev)
-{
-	return -EPERM;
-}
-
-static void hdmi_audio_stop(struct omap_dss_device *dssdev)
-{
-}
-
-static bool hdmi_audio_supported(struct omap_dss_device *dssdev)
-{
-	return false;
-}
-
-static int hdmi_audio_config(struct omap_dss_device *dssdev,
-		struct omap_dss_audio *audio)
-{
-	return -EPERM;
-}
-#endif
-
 static int hdmi_set_infoframe(struct omap_dss_device *dssdev,
 		const struct hdmi_avi_infoframe *avi)
 {
@@ -618,13 +493,6 @@ static const struct omapdss_hdmi_ops hdmi_ops = {
 	.read_edid		= hdmi_read_edid,
 	.set_infoframe		= hdmi_set_infoframe,
 	.set_hdmi_mode		= hdmi_set_hdmi_mode,
-
-	.audio_enable		= hdmi_audio_enable,
-	.audio_disable		= hdmi_audio_disable,
-	.audio_start		= hdmi_audio_start,
-	.audio_stop		= hdmi_audio_stop,
-	.audio_supported	= hdmi_audio_supported,
-	.audio_config		= hdmi_audio_config,
 };
 
 static void hdmi_init_output(struct platform_device *pdev)
@@ -642,7 +510,7 @@ static void hdmi_init_output(struct platform_device *pdev)
 	omapdss_register_output(out);
 }
 
-static void __exit hdmi_uninit_output(struct platform_device *pdev)
+static void hdmi_uninit_output(struct platform_device *pdev)
 {
 	struct omap_dss_device *out = &hdmi.output;
 
@@ -671,6 +539,112 @@ err:
 	return r;
 }
 
+/* Audio callbacks */
+static int hdmi_audio_startup(struct device *dev,
+			      void (*abort_cb)(struct device *dev))
+{
+	struct omap_hdmi *hd = dev_get_drvdata(dev);
+	int ret = 0;
+
+	mutex_lock(&hd->lock);
+
+	if (!hdmi_mode_has_audio(&hd->cfg) || !hd->display_enabled) {
+		ret = -EPERM;
+		goto out;
+	}
+
+	hd->audio_abort_cb = abort_cb;
+
+out:
+	mutex_unlock(&hd->lock);
+
+	return ret;
+}
+
+static int hdmi_audio_shutdown(struct device *dev)
+{
+	struct omap_hdmi *hd = dev_get_drvdata(dev);
+
+	mutex_lock(&hd->lock);
+	hd->audio_abort_cb = NULL;
+	mutex_unlock(&hd->lock);
+
+	return 0;
+}
+
+static int hdmi_audio_start(struct device *dev)
+{
+	struct omap_hdmi *hd = dev_get_drvdata(dev);
+
+	WARN_ON(!hdmi_mode_has_audio(&hd->cfg));
+	WARN_ON(!hd->display_enabled);
+
+	hdmi_wp_audio_enable(&hd->wp, true);
+	hdmi4_audio_start(&hd->core, &hd->wp);
+
+	return 0;
+}
+
+static void hdmi_audio_stop(struct device *dev)
+{
+	struct omap_hdmi *hd = dev_get_drvdata(dev);
+
+	WARN_ON(!hdmi_mode_has_audio(&hd->cfg));
+	WARN_ON(!hd->display_enabled);
+
+	hdmi4_audio_stop(&hd->core, &hd->wp);
+	hdmi_wp_audio_enable(&hd->wp, false);
+}
+
+static int hdmi_audio_config(struct device *dev,
+			     struct omap_dss_audio *dss_audio)
+{
+	struct omap_hdmi *hd = dev_get_drvdata(dev);
+	int ret;
+
+	mutex_lock(&hd->lock);
+
+	if (!hdmi_mode_has_audio(&hd->cfg) || !hd->display_enabled) {
+		ret = -EPERM;
+		goto out;
+	}
+
+	ret = hdmi4_audio_config(&hd->core, &hd->wp, dss_audio,
+				 hd->cfg.timings.pixelclock);
+
+out:
+	mutex_unlock(&hd->lock);
+
+	return ret;
+}
+
+static const struct omap_hdmi_audio_ops hdmi_audio_ops = {
+	.audio_startup = hdmi_audio_startup,
+	.audio_shutdown = hdmi_audio_shutdown,
+	.audio_start = hdmi_audio_start,
+	.audio_stop = hdmi_audio_stop,
+	.audio_config = hdmi_audio_config,
+};
+
+static int hdmi_audio_register(struct device *dev)
+{
+	struct omap_hdmi_audio_pdata pdata = {
+		.dev = dev,
+		.dss_version = omapdss_get_version(),
+		.audio_dma_addr = hdmi_wp_get_audio_dma_addr(&hdmi.wp),
+		.ops = &hdmi_audio_ops,
+	};
+
+	hdmi.audio_pdev = platform_device_register_data(
+		dev, "omap-hdmi-audio", PLATFORM_DEVID_AUTO,
+		&pdata, sizeof(pdata));
+
+	if (IS_ERR(hdmi.audio_pdev))
+		return PTR_ERR(hdmi.audio_pdev);
+
+	return 0;
+}
+
 /* HDMI HW IP initialisation */
 static int omapdss_hdmihw_probe(struct platform_device *pdev)
 {
@@ -678,6 +652,7 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev)
 	int irq;
 
 	hdmi.pdev = pdev;
+	dev_set_drvdata(&pdev->dev, &hdmi);
 
 	mutex_init(&hdmi.lock);
 
@@ -691,28 +666,23 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev)
 	if (r)
 		return r;
 
-	r = hdmi_pll_init(pdev, &hdmi.pll);
+	r = hdmi_pll_init(pdev, &hdmi.pll, &hdmi.wp);
 	if (r)
 		return r;
 
 	r = hdmi_phy_init(pdev, &hdmi.phy);
 	if (r)
-		return r;
+		goto err;
 
 	r = hdmi4_core_init(pdev, &hdmi.core);
 	if (r)
-		return r;
-
-	r = hdmi_get_clocks(pdev);
-	if (r) {
-		DSSERR("can't get clocks\n");
-		return r;
-	}
+		goto err;
 
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0) {
 		DSSERR("platform_get_irq failed\n");
-		return -ENODEV;
+		r = -ENODEV;
+		goto err;
 	}
 
 	r = devm_request_threaded_irq(&pdev->dev, irq,
@@ -720,22 +690,38 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev)
 			IRQF_ONESHOT, "OMAP HDMI", &hdmi.wp);
 	if (r) {
 		DSSERR("HDMI IRQ request failed\n");
-		return r;
+		goto err;
 	}
 
 	pm_runtime_enable(&pdev->dev);
 
 	hdmi_init_output(pdev);
 
+	r = hdmi_audio_register(&pdev->dev);
+	if (r) {
+		DSSERR("Registering HDMI audio failed\n");
+		hdmi_uninit_output(pdev);
+		pm_runtime_disable(&pdev->dev);
+		return r;
+	}
+
 	dss_debugfs_create_file("hdmi", hdmi_dump_regs);
 
 	return 0;
+err:
+	hdmi_pll_uninit(&hdmi.pll);
+	return r;
 }
 
 static int __exit omapdss_hdmihw_remove(struct platform_device *pdev)
 {
+	if (hdmi.audio_pdev)
+		platform_device_unregister(hdmi.audio_pdev);
+
 	hdmi_uninit_output(pdev);
 
+	hdmi_pll_uninit(&hdmi.pll);
+
 	pm_runtime_disable(&pdev->dev);
 
 	return 0;
@@ -743,8 +729,6 @@ static int __exit omapdss_hdmihw_remove(struct platform_device *pdev)
 
 static int hdmi_runtime_suspend(struct device *dev)
 {
-	clk_disable_unprepare(hdmi.sys_clk);
-
 	dispc_runtime_put();
 
 	return 0;
@@ -758,8 +742,6 @@ static int hdmi_runtime_resume(struct device *dev)
 	if (r < 0)
 		return r;
 
-	clk_prepare_enable(hdmi.sys_clk);
-
 	return 0;
 }
 
diff --git a/drivers/video/fbdev/omap2/dss/hdmi4_core.c b/drivers/video/fbdev/omap2/dss/hdmi4_core.c
index 4ad39cfce254..7eafea5b8e19 100644
--- a/drivers/video/fbdev/omap2/dss/hdmi4_core.c
+++ b/drivers/video/fbdev/omap2/dss/hdmi4_core.c
@@ -31,10 +31,8 @@
 #include <linux/platform_device.h>
 #include <linux/string.h>
 #include <linux/seq_file.h>
-#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
 #include <sound/asound.h>
 #include <sound/asoundef.h>
-#endif
 
 #include "hdmi4_core.h"
 #include "dss_features.h"
@@ -530,7 +528,6 @@ void hdmi4_core_dump(struct hdmi_core_data *core, struct seq_file *s)
 	DUMPCOREAV(HDMI_CORE_AV_CEC_ADDR_ID);
 }
 
-#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
 static void hdmi_core_audio_config(struct hdmi_core_data *core,
 					struct hdmi_core_audio_config *cfg)
 {
@@ -877,17 +874,6 @@ void hdmi4_audio_stop(struct hdmi_core_data *core, struct hdmi_wp_data *wp)
 	hdmi_wp_audio_core_req_enable(wp, false);
 }
 
-int hdmi4_audio_get_dma_port(u32 *offset, u32 *size)
-{
-	if (!offset || !size)
-		return -EINVAL;
-	*offset = HDMI_WP_AUDIO_DATA;
-	*size = 4;
-	return 0;
-}
-
-#endif
-
 int hdmi4_core_init(struct platform_device *pdev, struct hdmi_core_data *core)
 {
 	struct resource *res;
diff --git a/drivers/video/fbdev/omap2/dss/hdmi4_core.h b/drivers/video/fbdev/omap2/dss/hdmi4_core.h
index 827909eb6c50..a069f96ec6f6 100644
--- a/drivers/video/fbdev/omap2/dss/hdmi4_core.h
+++ b/drivers/video/fbdev/omap2/dss/hdmi4_core.h
@@ -266,12 +266,8 @@ void hdmi4_configure(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
 void hdmi4_core_dump(struct hdmi_core_data *core, struct seq_file *s);
 int hdmi4_core_init(struct platform_device *pdev, struct hdmi_core_data *core);
 
-#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
 int hdmi4_audio_start(struct hdmi_core_data *core, struct hdmi_wp_data *wp);
 void hdmi4_audio_stop(struct hdmi_core_data *core, struct hdmi_wp_data *wp);
 int hdmi4_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
 		struct omap_dss_audio *audio, u32 pclk);
-int hdmi4_audio_get_dma_port(u32 *offset, u32 *size);
-#endif
-
 #endif
diff --git a/drivers/video/fbdev/omap2/dss/hdmi5.c b/drivers/video/fbdev/omap2/dss/hdmi5.c
index 169b764bb9d4..d9d0d781625a 100644
--- a/drivers/video/fbdev/omap2/dss/hdmi5.c
+++ b/drivers/video/fbdev/omap2/dss/hdmi5.c
@@ -38,29 +38,13 @@
 #include <linux/gpio.h>
 #include <linux/regulator/consumer.h>
 #include <video/omapdss.h>
+#include <sound/omap-hdmi-audio.h>
 
 #include "hdmi5_core.h"
 #include "dss.h"
 #include "dss_features.h"
 
-static struct {
-	struct mutex lock;
-	struct platform_device *pdev;
-
-	struct hdmi_wp_data	wp;
-	struct hdmi_pll_data	pll;
-	struct hdmi_phy_data	phy;
-	struct hdmi_core_data	core;
-
-	struct hdmi_config cfg;
-
-	struct clk *sys_clk;
-	struct regulator *vdda_reg;
-
-	bool core_enabled;
-
-	struct omap_dss_device output;
-} hdmi;
+static struct omap_hdmi hdmi;
 
 static int hdmi_runtime_get(void)
 {
@@ -198,7 +182,7 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev)
 	int r;
 	struct omap_video_timings *p;
 	struct omap_overlay_manager *mgr = hdmi.output.manager;
-	unsigned long phy;
+	struct dss_pll_clock_info hdmi_cinfo = { 0 };
 
 	r = hdmi_power_on_core(dssdev);
 	if (r)
@@ -208,24 +192,27 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev)
 
 	DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", p->x_res, p->y_res);
 
-	/* the functions below use kHz pixel clock. TODO: change to Hz */
-	phy = p->pixelclock / 1000;
-
-	hdmi_pll_compute(&hdmi.pll, clk_get_rate(hdmi.sys_clk), phy);
+	hdmi_pll_compute(&hdmi.pll, p->pixelclock, &hdmi_cinfo);
 
 	/* disable and clear irqs */
 	hdmi_wp_clear_irqenable(&hdmi.wp, 0xffffffff);
 	hdmi_wp_set_irqstatus(&hdmi.wp,
 			hdmi_wp_get_irqstatus(&hdmi.wp));
 
-	/* config the PLL and PHY hdmi_set_pll_pwrfirst */
-	r = hdmi_pll_enable(&hdmi.pll, &hdmi.wp);
+	r = dss_pll_enable(&hdmi.pll.pll);
 	if (r) {
-		DSSDBG("Failed to lock PLL\n");
+		DSSERR("Failed to enable PLL\n");
 		goto err_pll_enable;
 	}
 
-	r = hdmi_phy_configure(&hdmi.phy, &hdmi.cfg);
+	r = dss_pll_set_config(&hdmi.pll.pll, &hdmi_cinfo);
+	if (r) {
+		DSSERR("Failed to configure PLL\n");
+		goto err_pll_cfg;
+	}
+
+	r = hdmi_phy_configure(&hdmi.phy, hdmi_cinfo.clkdco,
+		hdmi_cinfo.clkout[0]);
 	if (r) {
 		DSSDBG("Failed to start PHY\n");
 		goto err_phy_cfg;
@@ -262,7 +249,8 @@ err_vid_enable:
 	hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF);
 err_phy_pwr:
 err_phy_cfg:
-	hdmi_pll_disable(&hdmi.pll, &hdmi.wp);
+err_pll_cfg:
+	dss_pll_disable(&hdmi.pll.pll);
 err_pll_enable:
 	hdmi_power_off_core(dssdev);
 	return -EIO;
@@ -280,7 +268,7 @@ static void hdmi_power_off_full(struct omap_dss_device *dssdev)
 
 	hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF);
 
-	hdmi_pll_disable(&hdmi.pll, &hdmi.wp);
+	dss_pll_disable(&hdmi.pll.pll);
 
 	hdmi_power_off_core(dssdev);
 }
@@ -290,6 +278,10 @@ static int hdmi_display_check_timing(struct omap_dss_device *dssdev,
 {
 	struct omap_dss_device *out = &hdmi.output;
 
+	/* TODO: proper interlace support */
+	if (timings->interlace)
+		return -EINVAL;
+
 	if (!dispc_mgr_timings_ok(out->dispc_channel, timings))
 		return -EINVAL;
 
@@ -377,6 +369,8 @@ static int hdmi_display_enable(struct omap_dss_device *dssdev)
 		goto err0;
 	}
 
+	hdmi.display_enabled = true;
+
 	mutex_unlock(&hdmi.lock);
 	return 0;
 
@@ -391,8 +385,13 @@ static void hdmi_display_disable(struct omap_dss_device *dssdev)
 
 	mutex_lock(&hdmi.lock);
 
+	if (hdmi.audio_pdev && hdmi.audio_abort_cb)
+		hdmi.audio_abort_cb(&hdmi.audio_pdev->dev);
+
 	hdmi_power_off_full(dssdev);
 
+	hdmi.display_enabled = false;
+
 	mutex_unlock(&hdmi.lock);
 }
 
@@ -429,21 +428,6 @@ static void hdmi_core_disable(struct omap_dss_device *dssdev)
 	mutex_unlock(&hdmi.lock);
 }
 
-static int hdmi_get_clocks(struct platform_device *pdev)
-{
-	struct clk *clk;
-
-	clk = devm_clk_get(&pdev->dev, "sys_clk");
-	if (IS_ERR(clk)) {
-		DSSERR("can't get sys_clk\n");
-		return PTR_ERR(clk);
-	}
-
-	hdmi.sys_clk = clk;
-
-	return 0;
-}
-
 static int hdmi_connect(struct omap_dss_device *dssdev,
 		struct omap_dss_device *dst)
 {
@@ -509,112 +493,6 @@ static int hdmi_read_edid(struct omap_dss_device *dssdev,
 	return r;
 }
 
-#if defined(CONFIG_OMAP5_DSS_HDMI_AUDIO)
-static int hdmi_audio_enable(struct omap_dss_device *dssdev)
-{
-	int r;
-
-	mutex_lock(&hdmi.lock);
-
-	if (!hdmi_mode_has_audio(hdmi.cfg.hdmi_dvi_mode)) {
-		r = -EPERM;
-		goto err;
-	}
-
-	r = hdmi_wp_audio_enable(&hdmi.wp, true);
-	if (r)
-		goto err;
-
-	mutex_unlock(&hdmi.lock);
-	return 0;
-
-err:
-	mutex_unlock(&hdmi.lock);
-	return r;
-}
-
-static void hdmi_audio_disable(struct omap_dss_device *dssdev)
-{
-	hdmi_wp_audio_enable(&hdmi.wp, false);
-}
-
-static int hdmi_audio_start(struct omap_dss_device *dssdev)
-{
-	return hdmi_wp_audio_core_req_enable(&hdmi.wp, true);
-}
-
-static void hdmi_audio_stop(struct omap_dss_device *dssdev)
-{
-	hdmi_wp_audio_core_req_enable(&hdmi.wp, false);
-}
-
-static bool hdmi_audio_supported(struct omap_dss_device *dssdev)
-{
-	bool r;
-
-	mutex_lock(&hdmi.lock);
-
-	r = hdmi_mode_has_audio(hdmi.cfg.hdmi_dvi_mode);
-
-	mutex_unlock(&hdmi.lock);
-	return r;
-}
-
-static int hdmi_audio_config(struct omap_dss_device *dssdev,
-		struct omap_dss_audio *audio)
-{
-	int r;
-	u32 pclk = hdmi.cfg.timings.pixelclock;
-
-	mutex_lock(&hdmi.lock);
-
-	if (!hdmi_mode_has_audio(hdmi.cfg.hdmi_dvi_mode)) {
-		r = -EPERM;
-		goto err;
-	}
-
-	r = hdmi5_audio_config(&hdmi.core, &hdmi.wp, audio, pclk);
-	if (r)
-		goto err;
-
-	mutex_unlock(&hdmi.lock);
-	return 0;
-
-err:
-	mutex_unlock(&hdmi.lock);
-	return r;
-}
-#else
-static int hdmi_audio_enable(struct omap_dss_device *dssdev)
-{
-	return -EPERM;
-}
-
-static void hdmi_audio_disable(struct omap_dss_device *dssdev)
-{
-}
-
-static int hdmi_audio_start(struct omap_dss_device *dssdev)
-{
-	return -EPERM;
-}
-
-static void hdmi_audio_stop(struct omap_dss_device *dssdev)
-{
-}
-
-static bool hdmi_audio_supported(struct omap_dss_device *dssdev)
-{
-	return false;
-}
-
-static int hdmi_audio_config(struct omap_dss_device *dssdev,
-		struct omap_dss_audio *audio)
-{
-	return -EPERM;
-}
-#endif
-
 static int hdmi_set_infoframe(struct omap_dss_device *dssdev,
 		const struct hdmi_avi_infoframe *avi)
 {
@@ -643,13 +521,6 @@ static const struct omapdss_hdmi_ops hdmi_ops = {
 	.read_edid		= hdmi_read_edid,
 	.set_infoframe		= hdmi_set_infoframe,
 	.set_hdmi_mode		= hdmi_set_hdmi_mode,
-
-	.audio_enable		= hdmi_audio_enable,
-	.audio_disable		= hdmi_audio_disable,
-	.audio_start		= hdmi_audio_start,
-	.audio_stop		= hdmi_audio_stop,
-	.audio_supported	= hdmi_audio_supported,
-	.audio_config		= hdmi_audio_config,
 };
 
 static void hdmi_init_output(struct platform_device *pdev)
@@ -667,7 +538,7 @@ static void hdmi_init_output(struct platform_device *pdev)
 	omapdss_register_output(out);
 }
 
-static void __exit hdmi_uninit_output(struct platform_device *pdev)
+static void hdmi_uninit_output(struct platform_device *pdev)
 {
 	struct omap_dss_device *out = &hdmi.output;
 
@@ -696,6 +567,119 @@ err:
 	return r;
 }
 
+/* Audio callbacks */
+static int hdmi_audio_startup(struct device *dev,
+			      void (*abort_cb)(struct device *dev))
+{
+	struct omap_hdmi *hd = dev_get_drvdata(dev);
+	int ret = 0;
+
+	mutex_lock(&hd->lock);
+
+	if (!hdmi_mode_has_audio(&hd->cfg) || !hd->display_enabled) {
+		ret = -EPERM;
+		goto out;
+	}
+
+	hd->audio_abort_cb = abort_cb;
+
+out:
+	mutex_unlock(&hd->lock);
+
+	return ret;
+}
+
+static int hdmi_audio_shutdown(struct device *dev)
+{
+	struct omap_hdmi *hd = dev_get_drvdata(dev);
+
+	mutex_lock(&hd->lock);
+	hd->audio_abort_cb = NULL;
+	mutex_unlock(&hd->lock);
+
+	return 0;
+}
+
+static int hdmi_audio_start(struct device *dev)
+{
+	struct omap_hdmi *hd = dev_get_drvdata(dev);
+
+	WARN_ON(!hdmi_mode_has_audio(&hd->cfg));
+	WARN_ON(!hd->display_enabled);
+
+	/* No-idle while playing audio, store the old value */
+	hd->wp_idlemode = REG_GET(hdmi.wp.base, HDMI_WP_SYSCONFIG, 3, 2);
+	REG_FLD_MOD(hdmi.wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2);
+
+	hdmi_wp_audio_enable(&hd->wp, true);
+	hdmi_wp_audio_core_req_enable(&hd->wp, true);
+
+	return 0;
+}
+
+static void hdmi_audio_stop(struct device *dev)
+{
+	struct omap_hdmi *hd = dev_get_drvdata(dev);
+
+	WARN_ON(!hdmi_mode_has_audio(&hd->cfg));
+	WARN_ON(!hd->display_enabled);
+
+	hdmi_wp_audio_core_req_enable(&hd->wp, false);
+	hdmi_wp_audio_enable(&hd->wp, false);
+
+	/* Playback stopped, restore original idlemode */
+	REG_FLD_MOD(hdmi.wp.base, HDMI_WP_SYSCONFIG, hd->wp_idlemode, 3, 2);
+}
+
+static int hdmi_audio_config(struct device *dev,
+			     struct omap_dss_audio *dss_audio)
+{
+	struct omap_hdmi *hd = dev_get_drvdata(dev);
+	int ret;
+
+	mutex_lock(&hd->lock);
+
+	if (!hdmi_mode_has_audio(&hd->cfg) || !hd->display_enabled) {
+		ret = -EPERM;
+		goto out;
+	}
+
+	ret = hdmi5_audio_config(&hd->core, &hd->wp, dss_audio,
+				 hd->cfg.timings.pixelclock);
+
+out:
+	mutex_unlock(&hd->lock);
+
+	return ret;
+}
+
+static const struct omap_hdmi_audio_ops hdmi_audio_ops = {
+	.audio_startup = hdmi_audio_startup,
+	.audio_shutdown = hdmi_audio_shutdown,
+	.audio_start = hdmi_audio_start,
+	.audio_stop = hdmi_audio_stop,
+	.audio_config = hdmi_audio_config,
+};
+
+static int hdmi_audio_register(struct device *dev)
+{
+	struct omap_hdmi_audio_pdata pdata = {
+		.dev = dev,
+		.dss_version = omapdss_get_version(),
+		.audio_dma_addr = hdmi_wp_get_audio_dma_addr(&hdmi.wp),
+		.ops = &hdmi_audio_ops,
+	};
+
+	hdmi.audio_pdev = platform_device_register_data(
+		dev, "omap-hdmi-audio", PLATFORM_DEVID_AUTO,
+		&pdata, sizeof(pdata));
+
+	if (IS_ERR(hdmi.audio_pdev))
+		return PTR_ERR(hdmi.audio_pdev);
+
+	return 0;
+}
+
 /* HDMI HW IP initialisation */
 static int omapdss_hdmihw_probe(struct platform_device *pdev)
 {
@@ -703,6 +687,7 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev)
 	int irq;
 
 	hdmi.pdev = pdev;
+	dev_set_drvdata(&pdev->dev, &hdmi);
 
 	mutex_init(&hdmi.lock);
 
@@ -716,28 +701,23 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev)
 	if (r)
 		return r;
 
-	r = hdmi_pll_init(pdev, &hdmi.pll);
+	r = hdmi_pll_init(pdev, &hdmi.pll, &hdmi.wp);
 	if (r)
 		return r;
 
 	r = hdmi_phy_init(pdev, &hdmi.phy);
 	if (r)
-		return r;
+		goto err;
 
 	r = hdmi5_core_init(pdev, &hdmi.core);
 	if (r)
-		return r;
-
-	r = hdmi_get_clocks(pdev);
-	if (r) {
-		DSSERR("can't get clocks\n");
-		return r;
-	}
+		goto err;
 
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0) {
 		DSSERR("platform_get_irq failed\n");
-		return -ENODEV;
+		r = -ENODEV;
+		goto err;
 	}
 
 	r = devm_request_threaded_irq(&pdev->dev, irq,
@@ -745,22 +725,38 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev)
 			IRQF_ONESHOT, "OMAP HDMI", &hdmi.wp);
 	if (r) {
 		DSSERR("HDMI IRQ request failed\n");
-		return r;
+		goto err;
 	}
 
 	pm_runtime_enable(&pdev->dev);
 
 	hdmi_init_output(pdev);
 
+	r = hdmi_audio_register(&pdev->dev);
+	if (r) {
+		DSSERR("Registering HDMI audio failed %d\n", r);
+		hdmi_uninit_output(pdev);
+		pm_runtime_disable(&pdev->dev);
+		return r;
+	}
+
 	dss_debugfs_create_file("hdmi", hdmi_dump_regs);
 
 	return 0;
+err:
+	hdmi_pll_uninit(&hdmi.pll);
+	return r;
 }
 
 static int __exit omapdss_hdmihw_remove(struct platform_device *pdev)
 {
+	if (hdmi.audio_pdev)
+		platform_device_unregister(hdmi.audio_pdev);
+
 	hdmi_uninit_output(pdev);
 
+	hdmi_pll_uninit(&hdmi.pll);
+
 	pm_runtime_disable(&pdev->dev);
 
 	return 0;
@@ -768,8 +764,6 @@ static int __exit omapdss_hdmihw_remove(struct platform_device *pdev)
 
 static int hdmi_runtime_suspend(struct device *dev)
 {
-	clk_disable_unprepare(hdmi.sys_clk);
-
 	dispc_runtime_put();
 
 	return 0;
@@ -783,8 +777,6 @@ static int hdmi_runtime_resume(struct device *dev)
 	if (r < 0)
 		return r;
 
-	clk_prepare_enable(hdmi.sys_clk);
-
 	return 0;
 }
 
diff --git a/drivers/video/fbdev/omap2/dss/hdmi5_core.c b/drivers/video/fbdev/omap2/dss/hdmi5_core.c
index 83acbf7a8c89..a3cfe3d708f7 100644
--- a/drivers/video/fbdev/omap2/dss/hdmi5_core.c
+++ b/drivers/video/fbdev/omap2/dss/hdmi5_core.c
@@ -30,10 +30,8 @@
 #include <linux/string.h>
 #include <linux/seq_file.h>
 #include <drm/drm_edid.h>
-#if defined(CONFIG_OMAP5_DSS_HDMI_AUDIO)
 #include <sound/asound.h>
 #include <sound/asoundef.h>
-#endif
 
 #include "hdmi5_core.h"
 
@@ -644,9 +642,6 @@ void hdmi5_configure(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
 	hdmi_core_enable_interrupts(core);
 }
 
-
-#if defined(CONFIG_OMAP5_DSS_HDMI_AUDIO)
-
 static void hdmi5_core_audio_config(struct hdmi_core_data *core,
 			struct hdmi_core_audio_config *cfg)
 {
@@ -721,7 +716,7 @@ static void hdmi5_core_audio_config(struct hdmi_core_data *core,
 
 	/* Source number */
 	val = cfg->iec60958_cfg->status[2] & IEC958_AES2_CON_SOURCE;
-	REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(2), val, 3, 4);
+	REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(2), val, 3, 0);
 
 	/* Channel number right 0  */
 	REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(3), 2, 3, 0);
@@ -879,6 +874,9 @@ int hdmi5_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
 	/* only LPCM atm */
 	audio_format.type = HDMI_AUDIO_TYPE_LPCM;
 
+	/* only allowed option */
+	audio_format.sample_order = HDMI_AUDIO_SAMPLE_LEFT_FIRST;
+
 	/* disable start/stop signals of IEC 60958 blocks */
 	audio_format.en_sig_blk_strt_end = HDMI_AUDIO_BLOCK_SIG_STARTEND_ON;
 
@@ -894,7 +892,6 @@ int hdmi5_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
 
 	return 0;
 }
-#endif
 
 int hdmi5_core_init(struct platform_device *pdev, struct hdmi_core_data *core)
 {
diff --git a/drivers/video/fbdev/omap2/dss/hdmi5_core.h b/drivers/video/fbdev/omap2/dss/hdmi5_core.h
index ce7e9f376f04..f2f1022c5516 100644
--- a/drivers/video/fbdev/omap2/dss/hdmi5_core.h
+++ b/drivers/video/fbdev/omap2/dss/hdmi5_core.h
@@ -299,8 +299,6 @@ void hdmi5_configure(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
 			struct hdmi_config *cfg);
 int hdmi5_core_init(struct platform_device *pdev, struct hdmi_core_data *core);
 
-#if defined(CONFIG_OMAP5_DSS_HDMI_AUDIO)
 int hdmi5_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
 			struct omap_dss_audio *audio, u32 pclk);
 #endif
-#endif
diff --git a/drivers/video/fbdev/omap2/dss/hdmi_common.c b/drivers/video/fbdev/omap2/dss/hdmi_common.c
index 7d5f1039de9f..1b8fcc6c4ba1 100644
--- a/drivers/video/fbdev/omap2/dss/hdmi_common.c
+++ b/drivers/video/fbdev/omap2/dss/hdmi_common.c
@@ -48,7 +48,6 @@ int hdmi_parse_lanes_of(struct platform_device *pdev, struct device_node *ep,
 	return 0;
 }
 
-#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
 int hdmi_compute_acr(u32 pclk, u32 sample_freq, u32 *n, u32 *cts)
 {
 	u32 deep_color;
@@ -147,4 +146,3 @@ int hdmi_compute_acr(u32 pclk, u32 sample_freq, u32 *n, u32 *cts)
 
 	return 0;
 }
-#endif
diff --git a/drivers/video/fbdev/omap2/dss/hdmi_phy.c b/drivers/video/fbdev/omap2/dss/hdmi_phy.c
index e007ac892d79..bc9e07d2afbe 100644
--- a/drivers/video/fbdev/omap2/dss/hdmi_phy.c
+++ b/drivers/video/fbdev/omap2/dss/hdmi_phy.c
@@ -20,9 +20,7 @@
 
 struct hdmi_phy_features {
 	bool bist_ctrl;
-	bool calc_freqout;
 	bool ldo_voltage;
-	unsigned long dcofreq_min;
 	unsigned long max_phy;
 };
 
@@ -132,7 +130,8 @@ static void hdmi_phy_configure_lanes(struct hdmi_phy_data *phy)
 	REG_FLD_MOD(phy->base, HDMI_TXPHY_PAD_CFG_CTRL, pol_val, 30, 27);
 }
 
-int hdmi_phy_configure(struct hdmi_phy_data *phy, struct hdmi_config *cfg)
+int hdmi_phy_configure(struct hdmi_phy_data *phy, unsigned long hfbitclk,
+	unsigned long lfbitclk)
 {
 	u8 freqout;
 
@@ -149,20 +148,16 @@ int hdmi_phy_configure(struct hdmi_phy_data *phy, struct hdmi_config *cfg)
 	if (phy_feat->bist_ctrl)
 		REG_FLD_MOD(phy->base, HDMI_TXPHY_BIST_CONTROL, 1, 11, 11);
 
-	if (phy_feat->calc_freqout) {
-		/* DCOCLK/10 is pixel clock, compare pclk with DCOCLK_MIN/10 */
-		u32 dco_min = phy_feat->dcofreq_min / 10;
-		u32 pclk = cfg->timings.pixelclock;
-
-		if (pclk < dco_min)
-			freqout = 0;
-		else if ((pclk >= dco_min) && (pclk < phy_feat->max_phy))
-			freqout = 1;
-		else
-			freqout = 2;
-	} else {
+	/*
+	 * If the hfbitclk != lfbitclk, it means the lfbitclk was configured
+	 * to be used for TMDS.
+	 */
+	if (hfbitclk != lfbitclk)
+		freqout = 0;
+	else if (hfbitclk / 10 < phy_feat->max_phy)
 		freqout = 1;
-	}
+	else
+		freqout = 2;
 
 	/*
 	 * Write to phy address 0 to configure the clock
@@ -184,17 +179,13 @@ int hdmi_phy_configure(struct hdmi_phy_data *phy, struct hdmi_config *cfg)
 
 static const struct hdmi_phy_features omap44xx_phy_feats = {
 	.bist_ctrl	=	false,
-	.calc_freqout	=	false,
 	.ldo_voltage	=	true,
-	.dcofreq_min	=	500000000,
 	.max_phy	=	185675000,
 };
 
 static const struct hdmi_phy_features omap54xx_phy_feats = {
 	.bist_ctrl	=	true,
-	.calc_freqout	=	true,
 	.ldo_voltage	=	false,
-	.dcofreq_min	=	750000000,
 	.max_phy	=	186000000,
 };
 
diff --git a/drivers/video/fbdev/omap2/dss/hdmi_pll.c b/drivers/video/fbdev/omap2/dss/hdmi_pll.c
index 6d92bb32fe51..87accdb59c81 100644
--- a/drivers/video/fbdev/omap2/dss/hdmi_pll.c
+++ b/drivers/video/fbdev/omap2/dss/hdmi_pll.c
@@ -15,26 +15,13 @@
 #include <linux/err.h>
 #include <linux/io.h>
 #include <linux/platform_device.h>
+#include <linux/clk.h>
+
 #include <video/omapdss.h>
 
 #include "dss.h"
 #include "hdmi.h"
 
-#define HDMI_DEFAULT_REGN 16
-#define HDMI_DEFAULT_REGM2 1
-
-struct hdmi_pll_features {
-	bool sys_reset;
-	/* this is a hack, need to replace it with a better computation of M2 */
-	bool bound_dcofreq;
-	unsigned long fint_min, fint_max;
-	u16 regm_max;
-	unsigned long dcofreq_low_min, dcofreq_low_max;
-	unsigned long dcofreq_high_min, dcofreq_high_max;
-};
-
-static const struct hdmi_pll_features *pll_feat;
-
 void hdmi_pll_dump(struct hdmi_pll_data *pll, struct seq_file *s)
 {
 #define DUMPPLL(r) seq_printf(s, "%-35s %08x\n", #r,\
@@ -51,228 +38,189 @@ void hdmi_pll_dump(struct hdmi_pll_data *pll, struct seq_file *s)
 	DUMPPLL(PLLCTRL_CFG4);
 }
 
-void hdmi_pll_compute(struct hdmi_pll_data *pll, unsigned long clkin, int phy)
+void hdmi_pll_compute(struct hdmi_pll_data *pll,
+	unsigned long target_tmds, struct dss_pll_clock_info *pi)
 {
-	struct hdmi_pll_info *pi = &pll->info;
-	unsigned long refclk;
-	u32 mf;
+	unsigned long fint, clkdco, clkout;
+	unsigned long target_bitclk, target_clkdco;
+	unsigned long min_dco;
+	unsigned n, m, mf, m2, sd;
+	unsigned long clkin;
+	const struct dss_pll_hw *hw = pll->pll.hw;
 
-	/* use our funky units */
-	clkin /= 10000;
+	clkin = clk_get_rate(pll->pll.clkin);
 
-	/*
-	 * Input clock is predivided by N + 1
-	 * out put of which is reference clk
-	 */
+	DSSDBG("clkin %lu, target tmds %lu\n", clkin, target_tmds);
 
-	pi->regn = HDMI_DEFAULT_REGN;
+	target_bitclk = target_tmds * 10;
 
-	refclk = clkin / pi->regn;
+	/* Fint */
+	n = DIV_ROUND_UP(clkin, hw->fint_max);
+	fint = clkin / n;
 
-	/* temorary hack to make sure DCO freq isn't calculated too low */
-	if (pll_feat->bound_dcofreq && phy <= 65000)
-		pi->regm2 = 3;
-	else
-		pi->regm2 = HDMI_DEFAULT_REGM2;
-
-	/*
-	 * multiplier is pixel_clk/ref_clk
-	 * Multiplying by 100 to avoid fractional part removal
-	 */
-	pi->regm = phy * pi->regm2 / refclk;
-
-	/*
-	 * fractional multiplier is remainder of the difference between
-	 * multiplier and actual phy(required pixel clock thus should be
-	 * multiplied by 2^18(262144) divided by the reference clock
-	 */
-	mf = (phy - pi->regm / pi->regm2 * refclk) * 262144;
-	pi->regmf = pi->regm2 * mf / refclk;
-
-	/*
-	 * Dcofreq should be set to 1 if required pixel clock
-	 * is greater than 1000MHz
-	 */
-	pi->dcofreq = phy > 1000 * 100;
-	pi->regsd = ((pi->regm * clkin / 10) / (pi->regn * 250) + 5) / 10;
-
-	/* Set the reference clock to sysclk reference */
-	pi->refsel = HDMI_REFSEL_SYSCLK;
-
-	DSSDBG("M = %d Mf = %d\n", pi->regm, pi->regmf);
-	DSSDBG("range = %d sd = %d\n", pi->dcofreq, pi->regsd);
-}
+	/* adjust m2 so that the clkdco will be high enough */
+	min_dco = roundup(hw->clkdco_min, fint);
+	m2 = DIV_ROUND_UP(min_dco, target_bitclk);
+	if (m2 == 0)
+		m2 = 1;
 
+	target_clkdco = target_bitclk * m2;
+	m = target_clkdco / fint;
 
-static int hdmi_pll_config(struct hdmi_pll_data *pll)
-{
-	u32 r;
-	struct hdmi_pll_info *fmt = &pll->info;
+	clkdco = fint * m;
 
-	/* PLL start always use manual mode */
-	REG_FLD_MOD(pll->base, PLLCTRL_PLL_CONTROL, 0x0, 0, 0);
-
-	r = hdmi_read_reg(pll->base, PLLCTRL_CFG1);
-	r = FLD_MOD(r, fmt->regm, 20, 9);	/* CFG1_PLL_REGM */
-	r = FLD_MOD(r, fmt->regn - 1, 8, 1);	/* CFG1_PLL_REGN */
-	hdmi_write_reg(pll->base, PLLCTRL_CFG1, r);
-
-	r = hdmi_read_reg(pll->base, PLLCTRL_CFG2);
-
-	r = FLD_MOD(r, 0x0, 12, 12);	/* PLL_HIGHFREQ divide by 2 */
-	r = FLD_MOD(r, 0x1, 13, 13);	/* PLL_REFEN */
-	r = FLD_MOD(r, 0x0, 14, 14);	/* PHY_CLKINEN de-assert during locking */
-	r = FLD_MOD(r, fmt->refsel, 22, 21);	/* REFSEL */
-
-	if (fmt->dcofreq)
-		r = FLD_MOD(r, 0x4, 3, 1);	/* 1000MHz and 2000MHz */
+	/* adjust clkdco with fractional mf */
+	if (WARN_ON(target_clkdco - clkdco > fint))
+		mf = 0;
 	else
-		r = FLD_MOD(r, 0x2, 3, 1);	/* 500MHz and 1000MHz */
-
-	hdmi_write_reg(pll->base, PLLCTRL_CFG2, r);
-
-	REG_FLD_MOD(pll->base, PLLCTRL_CFG3, fmt->regsd, 17, 10);
+		mf = (u32)div_u64(262144ull * (target_clkdco - clkdco), fint);
 
-	r = hdmi_read_reg(pll->base, PLLCTRL_CFG4);
-	r = FLD_MOD(r, fmt->regm2, 24, 18);
-	r = FLD_MOD(r, fmt->regmf, 17, 0);
-	hdmi_write_reg(pll->base, PLLCTRL_CFG4, r);
+	if (mf > 0)
+		clkdco += (u32)div_u64((u64)mf * fint, 262144);
 
-	/* go now */
-	REG_FLD_MOD(pll->base, PLLCTRL_PLL_GO, 0x1, 0, 0);
+	clkout = clkdco / m2;
 
-	/* wait for bit change */
-	if (hdmi_wait_for_bit_change(pll->base, PLLCTRL_PLL_GO,
-			0, 0, 0) != 0) {
-		DSSERR("PLL GO bit not clearing\n");
-		return -ETIMEDOUT;
-	}
+	/* sigma-delta */
+	sd = DIV_ROUND_UP(fint * m, 250000000);
 
-	/* Wait till the lock bit is set in PLL status */
-	if (hdmi_wait_for_bit_change(pll->base,
-			PLLCTRL_PLL_STATUS, 1, 1, 1) != 1) {
-		DSSERR("cannot lock PLL\n");
-		DSSERR("CFG1 0x%x\n",
-			hdmi_read_reg(pll->base, PLLCTRL_CFG1));
-		DSSERR("CFG2 0x%x\n",
-			hdmi_read_reg(pll->base, PLLCTRL_CFG2));
-		DSSERR("CFG4 0x%x\n",
-			hdmi_read_reg(pll->base, PLLCTRL_CFG4));
-		return -ETIMEDOUT;
-	}
+	DSSDBG("N = %u, M = %u, M.f = %u, M2 = %u, SD = %u\n",
+		n, m, mf, m2, sd);
+	DSSDBG("Fint %lu, clkdco %lu, clkout %lu\n", fint, clkdco, clkout);
 
-	DSSDBG("PLL locked!\n");
+	pi->n = n;
+	pi->m = m;
+	pi->mf = mf;
+	pi->mX[0] = m2;
+	pi->sd = sd;
 
-	return 0;
+	pi->fint = fint;
+	pi->clkdco = clkdco;
+	pi->clkout[0] = clkout;
 }
 
-static int hdmi_pll_reset(struct hdmi_pll_data *pll)
-{
-	/* SYSRESET  controlled by power FSM */
-	REG_FLD_MOD(pll->base, PLLCTRL_PLL_CONTROL, pll_feat->sys_reset, 3, 3);
-
-	/* READ 0x0 reset is in progress */
-	if (hdmi_wait_for_bit_change(pll->base, PLLCTRL_PLL_STATUS, 0, 0, 1)
-			!= 1) {
-		DSSERR("Failed to sysreset PLL\n");
-		return -ETIMEDOUT;
-	}
-
-	return 0;
-}
-
-int hdmi_pll_enable(struct hdmi_pll_data *pll, struct hdmi_wp_data *wp)
+static int hdmi_pll_enable(struct dss_pll *dsspll)
 {
+	struct hdmi_pll_data *pll = container_of(dsspll, struct hdmi_pll_data, pll);
+	struct hdmi_wp_data *wp = pll->wp;
 	u16 r = 0;
 
-	r = hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_ALLOFF);
-	if (r)
-		return r;
-
 	r = hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_BOTHON_ALLCLKS);
 	if (r)
 		return r;
 
-	r = hdmi_pll_reset(pll);
-	if (r)
-		return r;
-
-	r = hdmi_pll_config(pll);
-	if (r)
-		return r;
-
 	return 0;
 }
 
-void hdmi_pll_disable(struct hdmi_pll_data *pll, struct hdmi_wp_data *wp)
+static void hdmi_pll_disable(struct dss_pll *dsspll)
 {
+	struct hdmi_pll_data *pll = container_of(dsspll, struct hdmi_pll_data, pll);
+	struct hdmi_wp_data *wp = pll->wp;
+
 	hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_ALLOFF);
 }
 
-static const struct hdmi_pll_features omap44xx_pll_feats = {
-	.sys_reset		=	false,
-	.bound_dcofreq		=	false,
-	.fint_min		=	500000,
-	.fint_max		=	2500000,
-	.regm_max		=	4095,
-	.dcofreq_low_min	=	500000000,
-	.dcofreq_low_max	=	1000000000,
-	.dcofreq_high_min	=	1000000000,
-	.dcofreq_high_max	=	2000000000,
+static const struct dss_pll_ops dsi_pll_ops = {
+	.enable = hdmi_pll_enable,
+	.disable = hdmi_pll_disable,
+	.set_config = dss_pll_write_config_type_b,
 };
 
-static const struct hdmi_pll_features omap54xx_pll_feats = {
-	.sys_reset		=	true,
-	.bound_dcofreq		=	true,
-	.fint_min		=	620000,
-	.fint_max		=	2500000,
-	.regm_max		=	2046,
-	.dcofreq_low_min	=	750000000,
-	.dcofreq_low_max	=	1500000000,
-	.dcofreq_high_min	=	1250000000,
-	.dcofreq_high_max	=	2500000000UL,
+static const struct dss_pll_hw dss_omap4_hdmi_pll_hw = {
+	.n_max = 255,
+	.m_min = 20,
+	.m_max = 4095,
+	.mX_max = 127,
+	.fint_min = 500000,
+	.fint_max = 2500000,
+	.clkdco_max = 1800000000,
+
+	.clkdco_min = 500000000,
+	.clkdco_low = 1000000000,
+	.clkdco_max = 2000000000,
+
+	.n_msb = 8,
+	.n_lsb = 1,
+	.m_msb = 20,
+	.m_lsb = 9,
+
+	.mX_msb[0] = 24,
+	.mX_lsb[0] = 18,
+
+	.has_selfreqdco = true,
 };
 
-static int hdmi_pll_init_features(struct platform_device *pdev)
+static const struct dss_pll_hw dss_omap5_hdmi_pll_hw = {
+	.n_max = 255,
+	.m_min = 20,
+	.m_max = 2045,
+	.mX_max = 127,
+	.fint_min = 620000,
+	.fint_max = 2500000,
+	.clkdco_max = 1800000000,
+
+	.clkdco_min = 750000000,
+	.clkdco_low = 1500000000,
+	.clkdco_max = 2500000000UL,
+
+	.n_msb = 8,
+	.n_lsb = 1,
+	.m_msb = 20,
+	.m_lsb = 9,
+
+	.mX_msb[0] = 24,
+	.mX_lsb[0] = 18,
+
+	.has_selfreqdco = true,
+	.has_refsel = true,
+};
+
+static int dsi_init_pll_data(struct platform_device *pdev, struct hdmi_pll_data *hpll)
 {
-	struct hdmi_pll_features *dst;
-	const struct hdmi_pll_features *src;
+	struct dss_pll *pll = &hpll->pll;
+	struct clk *clk;
+	int r;
 
-	dst = devm_kzalloc(&pdev->dev, sizeof(*dst), GFP_KERNEL);
-	if (!dst) {
-		dev_err(&pdev->dev, "Failed to allocate HDMI PHY Features\n");
-		return -ENOMEM;
+	clk = devm_clk_get(&pdev->dev, "sys_clk");
+	if (IS_ERR(clk)) {
+		DSSERR("can't get sys_clk\n");
+		return PTR_ERR(clk);
 	}
 
+	pll->name = "hdmi";
+	pll->base = hpll->base;
+	pll->clkin = clk;
+
 	switch (omapdss_get_version()) {
 	case OMAPDSS_VER_OMAP4430_ES1:
 	case OMAPDSS_VER_OMAP4430_ES2:
 	case OMAPDSS_VER_OMAP4:
-		src = &omap44xx_pll_feats;
+		pll->hw = &dss_omap4_hdmi_pll_hw;
 		break;
 
 	case OMAPDSS_VER_OMAP5:
-		src = &omap54xx_pll_feats;
+		pll->hw = &dss_omap5_hdmi_pll_hw;
 		break;
 
 	default:
 		return -ENODEV;
 	}
 
-	memcpy(dst, src, sizeof(*dst));
-	pll_feat = dst;
+	pll->ops = &dsi_pll_ops;
+
+	r = dss_pll_register(pll);
+	if (r)
+		return r;
 
 	return 0;
 }
 
-int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll)
+int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll,
+	struct hdmi_wp_data *wp)
 {
 	int r;
 	struct resource *res;
 
-	r = hdmi_pll_init_features(pdev);
-	if (r)
-		return r;
+	pll->wp = wp;
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pll");
 	if (!res) {
@@ -286,5 +234,18 @@ int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll)
 		return PTR_ERR(pll->base);
 	}
 
+	r = dsi_init_pll_data(pdev, pll);
+	if (r) {
+		DSSERR("failed to init HDMI PLL\n");
+		return r;
+	}
+
 	return 0;
 }
+
+void hdmi_pll_uninit(struct hdmi_pll_data *hpll)
+{
+	struct dss_pll *pll = &hpll->pll;
+
+	dss_pll_unregister(pll);
+}
diff --git a/drivers/video/fbdev/omap2/dss/hdmi_wp.c b/drivers/video/fbdev/omap2/dss/hdmi_wp.c
index 496327e2b21b..c15377e242cc 100644
--- a/drivers/video/fbdev/omap2/dss/hdmi_wp.c
+++ b/drivers/video/fbdev/omap2/dss/hdmi_wp.c
@@ -185,7 +185,6 @@ void hdmi_wp_init_vid_fmt_timings(struct hdmi_video_format *video_fmt,
 	timings->interlace = param->timings.interlace;
 }
 
-#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) || defined(CONFIG_OMAP5_DSS_HDMI_AUDIO)
 void hdmi_wp_audio_config_format(struct hdmi_wp_data *wp,
 		struct hdmi_audio_format *aud_fmt)
 {
@@ -194,8 +193,12 @@ void hdmi_wp_audio_config_format(struct hdmi_wp_data *wp,
 	DSSDBG("Enter hdmi_wp_audio_config_format\n");
 
 	r = hdmi_read_reg(wp->base, HDMI_WP_AUDIO_CFG);
-	r = FLD_MOD(r, aud_fmt->stereo_channels, 26, 24);
-	r = FLD_MOD(r, aud_fmt->active_chnnls_msk, 23, 16);
+	if (omapdss_get_version() == OMAPDSS_VER_OMAP4430_ES1 ||
+	    omapdss_get_version() == OMAPDSS_VER_OMAP4430_ES2 ||
+	    omapdss_get_version() == OMAPDSS_VER_OMAP4) {
+		r = FLD_MOD(r, aud_fmt->stereo_channels, 26, 24);
+		r = FLD_MOD(r, aud_fmt->active_chnnls_msk, 23, 16);
+	}
 	r = FLD_MOD(r, aud_fmt->en_sig_blk_strt_end, 5, 5);
 	r = FLD_MOD(r, aud_fmt->type, 4, 4);
 	r = FLD_MOD(r, aud_fmt->justification, 3, 3);
@@ -236,7 +239,6 @@ int hdmi_wp_audio_core_req_enable(struct hdmi_wp_data *wp, bool enable)
 
 	return 0;
 }
-#endif
 
 int hdmi_wp_init(struct platform_device *pdev, struct hdmi_wp_data *wp)
 {
@@ -247,6 +249,7 @@ int hdmi_wp_init(struct platform_device *pdev, struct hdmi_wp_data *wp)
 		DSSERR("can't get WP mem resource\n");
 		return -EINVAL;
 	}
+	wp->phys_base = res->start;
 
 	wp->base = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(wp->base)) {
@@ -256,3 +259,8 @@ int hdmi_wp_init(struct platform_device *pdev, struct hdmi_wp_data *wp)
 
 	return 0;
 }
+
+phys_addr_t hdmi_wp_get_audio_dma_addr(struct hdmi_wp_data *wp)
+{
+	return wp->phys_base + HDMI_WP_AUDIO_DATA;
+}
diff --git a/drivers/video/fbdev/omap2/dss/output.c b/drivers/video/fbdev/omap2/dss/output.c
index 2ab3afa615e8..16072159bd24 100644
--- a/drivers/video/fbdev/omap2/dss/output.c
+++ b/drivers/video/fbdev/omap2/dss/output.c
@@ -19,6 +19,7 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
+#include <linux/of.h>
 
 #include <video/omapdss.h>
 
@@ -131,18 +132,30 @@ struct omap_dss_device *omap_dss_find_output(const char *name)
 }
 EXPORT_SYMBOL(omap_dss_find_output);
 
-struct omap_dss_device *omap_dss_find_output_by_node(struct device_node *node)
+struct omap_dss_device *omap_dss_find_output_by_port_node(struct device_node *port)
 {
+	struct device_node *src_node;
 	struct omap_dss_device *out;
+	u32 reg;
+
+	src_node = dss_of_port_get_parent_device(port);
+	if (!src_node)
+		return NULL;
+
+	reg = dss_of_port_get_port_number(port);
 
 	list_for_each_entry(out, &output_list, list) {
-		if (out->dev->of_node == node)
+		if (out->dev->of_node == src_node && out->port_num == reg) {
+			of_node_put(src_node);
 			return omap_dss_get_device(out);
+		}
 	}
 
+	of_node_put(src_node);
+
 	return NULL;
 }
-EXPORT_SYMBOL(omap_dss_find_output_by_node);
+EXPORT_SYMBOL(omap_dss_find_output_by_port_node);
 
 struct omap_dss_device *omapdss_find_output_from_display(struct omap_dss_device *dssdev)
 {
diff --git a/drivers/video/fbdev/omap2/dss/pll.c b/drivers/video/fbdev/omap2/dss/pll.c
new file mode 100644
index 000000000000..50bc62c5d367
--- /dev/null
+++ b/drivers/video/fbdev/omap2/dss/pll.c
@@ -0,0 +1,378 @@
+/*
+ * Copyright (C) 2014 Texas Instruments Incorporated
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define DSS_SUBSYS_NAME "PLL"
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/regulator/consumer.h>
+#include <linux/sched.h>
+
+#include <video/omapdss.h>
+
+#include "dss.h"
+
+#define PLL_CONTROL			0x0000
+#define PLL_STATUS			0x0004
+#define PLL_GO				0x0008
+#define PLL_CONFIGURATION1		0x000C
+#define PLL_CONFIGURATION2		0x0010
+#define PLL_CONFIGURATION3		0x0014
+#define PLL_SSC_CONFIGURATION1		0x0018
+#define PLL_SSC_CONFIGURATION2		0x001C
+#define PLL_CONFIGURATION4		0x0020
+
+static struct dss_pll *dss_plls[4];
+
+int dss_pll_register(struct dss_pll *pll)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(dss_plls); ++i) {
+		if (!dss_plls[i]) {
+			dss_plls[i] = pll;
+			return 0;
+		}
+	}
+
+	return -EBUSY;
+}
+
+void dss_pll_unregister(struct dss_pll *pll)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(dss_plls); ++i) {
+		if (dss_plls[i] == pll) {
+			dss_plls[i] = NULL;
+			return;
+		}
+	}
+}
+
+struct dss_pll *dss_pll_find(const char *name)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(dss_plls); ++i) {
+		if (dss_plls[i] && strcmp(dss_plls[i]->name, name) == 0)
+			return dss_plls[i];
+	}
+
+	return NULL;
+}
+
+int dss_pll_enable(struct dss_pll *pll)
+{
+	int r;
+
+	r = clk_prepare_enable(pll->clkin);
+	if (r)
+		return r;
+
+	if (pll->regulator) {
+		r = regulator_enable(pll->regulator);
+		if (r)
+			goto err_reg;
+	}
+
+	r = pll->ops->enable(pll);
+	if (r)
+		goto err_enable;
+
+	return 0;
+
+err_enable:
+	regulator_disable(pll->regulator);
+err_reg:
+	clk_disable_unprepare(pll->clkin);
+	return r;
+}
+
+void dss_pll_disable(struct dss_pll *pll)
+{
+	pll->ops->disable(pll);
+
+	if (pll->regulator)
+		regulator_disable(pll->regulator);
+
+	clk_disable_unprepare(pll->clkin);
+
+	memset(&pll->cinfo, 0, sizeof(pll->cinfo));
+}
+
+int dss_pll_set_config(struct dss_pll *pll, const struct dss_pll_clock_info *cinfo)
+{
+	int r;
+
+	r = pll->ops->set_config(pll, cinfo);
+	if (r)
+		return r;
+
+	pll->cinfo = *cinfo;
+
+	return 0;
+}
+
+bool dss_pll_hsdiv_calc(const struct dss_pll *pll, unsigned long clkdco,
+		unsigned long out_min, unsigned long out_max,
+		dss_hsdiv_calc_func func, void *data)
+{
+	const struct dss_pll_hw *hw = pll->hw;
+	int m, m_start, m_stop;
+	unsigned long out;
+
+	out_min = out_min ? out_min : 1;
+	out_max = out_max ? out_max : ULONG_MAX;
+
+	m_start = max(DIV_ROUND_UP(clkdco, out_max), 1ul);
+
+	m_stop = min((unsigned)(clkdco / out_min), hw->mX_max);
+
+	for (m = m_start; m <= m_stop; ++m) {
+		out = clkdco / m;
+
+		if (func(m, out, data))
+			return true;
+	}
+
+	return false;
+}
+
+bool dss_pll_calc(const struct dss_pll *pll, unsigned long clkin,
+		unsigned long pll_min, unsigned long pll_max,
+		dss_pll_calc_func func, void *data)
+{
+	const struct dss_pll_hw *hw = pll->hw;
+	int n, n_start, n_stop;
+	int m, m_start, m_stop;
+	unsigned long fint, clkdco;
+	unsigned long pll_hw_max;
+	unsigned long fint_hw_min, fint_hw_max;
+
+	pll_hw_max = hw->clkdco_max;
+
+	fint_hw_min = hw->fint_min;
+	fint_hw_max = hw->fint_max;
+
+	n_start = max(DIV_ROUND_UP(clkin, fint_hw_max), 1ul);
+	n_stop = min((unsigned)(clkin / fint_hw_min), hw->n_max);
+
+	pll_max = pll_max ? pll_max : ULONG_MAX;
+
+	for (n = n_start; n <= n_stop; ++n) {
+		fint = clkin / n;
+
+		m_start = max(DIV_ROUND_UP(DIV_ROUND_UP(pll_min, fint), 2),
+				1ul);
+		m_stop = min3((unsigned)(pll_max / fint / 2),
+				(unsigned)(pll_hw_max / fint / 2),
+				hw->m_max);
+
+		for (m = m_start; m <= m_stop; ++m) {
+			clkdco = 2 * m * fint;
+
+			if (func(n, m, fint, clkdco, data))
+				return true;
+		}
+	}
+
+	return false;
+}
+
+static int wait_for_bit_change(void __iomem *reg, int bitnum, int value)
+{
+	unsigned long timeout;
+	ktime_t wait;
+	int t;
+
+	/* first busyloop to see if the bit changes right away */
+	t = 100;
+	while (t-- > 0) {
+		if (FLD_GET(readl_relaxed(reg), bitnum, bitnum) == value)
+			return value;
+	}
+
+	/* then loop for 500ms, sleeping for 1ms in between */
+	timeout = jiffies + msecs_to_jiffies(500);
+	while (time_before(jiffies, timeout)) {
+		if (FLD_GET(readl_relaxed(reg), bitnum, bitnum) == value)
+			return value;
+
+		wait = ns_to_ktime(1000 * 1000);
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_hrtimeout(&wait, HRTIMER_MODE_REL);
+	}
+
+	return !value;
+}
+
+static int dss_wait_hsdiv_ack(struct dss_pll *pll, u32 hsdiv_ack_mask)
+{
+	int t = 100;
+
+	while (t-- > 0) {
+		u32 v = readl_relaxed(pll->base + PLL_STATUS);
+		v &= hsdiv_ack_mask;
+		if (v == hsdiv_ack_mask)
+			return 0;
+	}
+
+	return -ETIMEDOUT;
+}
+
+int dss_pll_write_config_type_a(struct dss_pll *pll,
+		const struct dss_pll_clock_info *cinfo)
+{
+	const struct dss_pll_hw *hw = pll->hw;
+	void __iomem *base = pll->base;
+	int r = 0;
+	u32 l;
+
+	l = 0;
+	if (hw->has_stopmode)
+		l = FLD_MOD(l, 1, 0, 0);		/* PLL_STOPMODE */
+	l = FLD_MOD(l, cinfo->n - 1, hw->n_msb, hw->n_lsb);	/* PLL_REGN */
+	l = FLD_MOD(l, cinfo->m, hw->m_msb, hw->m_lsb);		/* PLL_REGM */
+	/* M4 */
+	l = FLD_MOD(l, cinfo->mX[0] ? cinfo->mX[0] - 1 : 0,
+			hw->mX_msb[0], hw->mX_lsb[0]);
+	/* M5 */
+	l = FLD_MOD(l, cinfo->mX[1] ? cinfo->mX[1] - 1 : 0,
+			hw->mX_msb[1], hw->mX_lsb[1]);
+	writel_relaxed(l, base + PLL_CONFIGURATION1);
+
+	l = 0;
+	/* M6 */
+	l = FLD_MOD(l, cinfo->mX[2] ? cinfo->mX[2] - 1 : 0,
+			hw->mX_msb[2], hw->mX_lsb[2]);
+	/* M7 */
+	l = FLD_MOD(l, cinfo->mX[3] ? cinfo->mX[3] - 1 : 0,
+			hw->mX_msb[3], hw->mX_lsb[3]);
+	writel_relaxed(l, base + PLL_CONFIGURATION3);
+
+	l = readl_relaxed(base + PLL_CONFIGURATION2);
+	if (hw->has_freqsel) {
+		u32 f = cinfo->fint < 1000000 ? 0x3 :
+			cinfo->fint < 1250000 ? 0x4 :
+			cinfo->fint < 1500000 ? 0x5 :
+			cinfo->fint < 1750000 ? 0x6 :
+			0x7;
+
+		l = FLD_MOD(l, f, 4, 1);	/* PLL_FREQSEL */
+	} else if (hw->has_selfreqdco) {
+		u32 f = cinfo->clkdco < hw->clkdco_low ? 0x2 : 0x4;
+
+		l = FLD_MOD(l, f, 3, 1);	/* PLL_SELFREQDCO */
+	}
+	l = FLD_MOD(l, 1, 13, 13);		/* PLL_REFEN */
+	l = FLD_MOD(l, 0, 14, 14);		/* PHY_CLKINEN */
+	l = FLD_MOD(l, 0, 16, 16);		/* M4_CLOCK_EN */
+	l = FLD_MOD(l, 0, 18, 18);		/* M5_CLOCK_EN */
+	l = FLD_MOD(l, 1, 20, 20);		/* HSDIVBYPASS */
+	if (hw->has_refsel)
+		l = FLD_MOD(l, 3, 22, 21);	/* REFSEL = sysclk */
+	l = FLD_MOD(l, 0, 23, 23);		/* M6_CLOCK_EN */
+	l = FLD_MOD(l, 0, 25, 25);		/* M7_CLOCK_EN */
+	writel_relaxed(l, base + PLL_CONFIGURATION2);
+
+	writel_relaxed(1, base + PLL_GO);	/* PLL_GO */
+
+	if (wait_for_bit_change(base + PLL_GO, 0, 0) != 0) {
+		DSSERR("DSS DPLL GO bit not going down.\n");
+		r = -EIO;
+		goto err;
+	}
+
+	if (wait_for_bit_change(base + PLL_STATUS, 1, 1) != 1) {
+		DSSERR("cannot lock DSS DPLL\n");
+		r = -EIO;
+		goto err;
+	}
+
+	l = readl_relaxed(base + PLL_CONFIGURATION2);
+	l = FLD_MOD(l, 1, 14, 14);			/* PHY_CLKINEN */
+	l = FLD_MOD(l, cinfo->mX[0] ? 1 : 0, 16, 16);	/* M4_CLOCK_EN */
+	l = FLD_MOD(l, cinfo->mX[1] ? 1 : 0, 18, 18);	/* M5_CLOCK_EN */
+	l = FLD_MOD(l, 0, 20, 20);			/* HSDIVBYPASS */
+	l = FLD_MOD(l, cinfo->mX[2] ? 1 : 0, 23, 23);	/* M6_CLOCK_EN */
+	l = FLD_MOD(l, cinfo->mX[3] ? 1 : 0, 25, 25);	/* M7_CLOCK_EN */
+	writel_relaxed(l, base + PLL_CONFIGURATION2);
+
+	r = dss_wait_hsdiv_ack(pll,
+		(cinfo->mX[0] ? BIT(7) : 0) |
+		(cinfo->mX[1] ? BIT(8) : 0) |
+		(cinfo->mX[2] ? BIT(10) : 0) |
+		(cinfo->mX[3] ? BIT(11) : 0));
+	if (r) {
+		DSSERR("failed to enable HSDIV clocks\n");
+		goto err;
+	}
+
+err:
+	return r;
+}
+
+int dss_pll_write_config_type_b(struct dss_pll *pll,
+		const struct dss_pll_clock_info *cinfo)
+{
+	const struct dss_pll_hw *hw = pll->hw;
+	void __iomem *base = pll->base;
+	u32 l;
+
+	l = 0;
+	l = FLD_MOD(l, cinfo->m, 20, 9);	/* PLL_REGM */
+	l = FLD_MOD(l, cinfo->n - 1, 8, 1);	/* PLL_REGN */
+	writel_relaxed(l, base + PLL_CONFIGURATION1);
+
+	l = readl_relaxed(base + PLL_CONFIGURATION2);
+	l = FLD_MOD(l, 0x0, 12, 12);	/* PLL_HIGHFREQ divide by 2 */
+	l = FLD_MOD(l, 0x1, 13, 13);	/* PLL_REFEN */
+	l = FLD_MOD(l, 0x0, 14, 14);	/* PHY_CLKINEN */
+	if (hw->has_refsel)
+		l = FLD_MOD(l, 0x3, 22, 21);	/* REFSEL = SYSCLK */
+
+	/* PLL_SELFREQDCO */
+	if (cinfo->clkdco > hw->clkdco_low)
+		l = FLD_MOD(l, 0x4, 3, 1);
+	else
+		l = FLD_MOD(l, 0x2, 3, 1);
+	writel_relaxed(l, base + PLL_CONFIGURATION2);
+
+	l = readl_relaxed(base + PLL_CONFIGURATION3);
+	l = FLD_MOD(l, cinfo->sd, 17, 10);	/* PLL_REGSD */
+	writel_relaxed(l, base + PLL_CONFIGURATION3);
+
+	l = readl_relaxed(base + PLL_CONFIGURATION4);
+	l = FLD_MOD(l, cinfo->mX[0], 24, 18);	/* PLL_REGM2 */
+	l = FLD_MOD(l, cinfo->mf, 17, 0);	/* PLL_REGM_F */
+	writel_relaxed(l, base + PLL_CONFIGURATION4);
+
+	writel_relaxed(1, base + PLL_GO);	/* PLL_GO */
+
+	if (wait_for_bit_change(base + PLL_GO, 0, 0) != 0) {
+		DSSERR("DSS DPLL GO bit not going down.\n");
+		return -EIO;
+	}
+
+	if (wait_for_bit_change(base + PLL_STATUS, 1, 1) != 1) {
+		DSSERR("cannot lock DSS DPLL\n");
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
diff --git a/drivers/video/fbdev/omap2/dss/sdi.c b/drivers/video/fbdev/omap2/dss/sdi.c
index 4c9c46d4ea60..d9b10f27be20 100644
--- a/drivers/video/fbdev/omap2/dss/sdi.c
+++ b/drivers/video/fbdev/omap2/dss/sdi.c
@@ -425,7 +425,7 @@ err_datapairs:
 	return r;
 }
 
-void __exit sdi_uninit_port(void)
+void __exit sdi_uninit_port(struct device_node *port)
 {
 	if (!sdi.port_initialized)
 		return;
diff --git a/drivers/video/fbdev/s3fb.c b/drivers/video/fbdev/s3fb.c
index c43b969e1e23..f0ae61a37f04 100644
--- a/drivers/video/fbdev/s3fb.c
+++ b/drivers/video/fbdev/s3fb.c
@@ -1182,7 +1182,7 @@ static int s3_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
 
 	pcibios_bus_to_resource(dev->bus, &vga_res, &bus_reg);
 
-	par->state.vgabase = (void __iomem *) vga_res.start;
+	par->state.vgabase = (void __iomem *) (unsigned long) vga_res.start;
 
 	/* Unlock regs */
 	cr38 = vga_rcrt(par->state.vgabase, 0x38);
diff --git a/drivers/video/fbdev/sh_mobile_lcdcfb.c b/drivers/video/fbdev/sh_mobile_lcdcfb.c
index 2bcc84ac18c7..cfde21d81c15 100644
--- a/drivers/video/fbdev/sh_mobile_lcdcfb.c
+++ b/drivers/video/fbdev/sh_mobile_lcdcfb.c
@@ -2181,8 +2181,7 @@ sh_mobile_lcdc_channel_fb_cleanup(struct sh_mobile_lcdc_chan *ch)
 	if (!info || !info->device)
 		return;
 
-	if (ch->sglist)
-		vfree(ch->sglist);
+	vfree(ch->sglist);
 
 	fb_dealloc_cmap(&info->cmap);
 	framebuffer_release(info);
diff --git a/drivers/video/fbdev/simplefb.c b/drivers/video/fbdev/simplefb.c
index 210f3a02121a..b2ae9254fd75 100644
--- a/drivers/video/fbdev/simplefb.c
+++ b/drivers/video/fbdev/simplefb.c
@@ -26,6 +26,8 @@
 #include <linux/module.h>
 #include <linux/platform_data/simplefb.h>
 #include <linux/platform_device.h>
+#include <linux/clk-provider.h>
+#include <linux/of_platform.h>
 
 static struct fb_fix_screeninfo simplefb_fix = {
 	.id		= "simple",
@@ -41,6 +43,8 @@ static struct fb_var_screeninfo simplefb_var = {
 	.vmode		= FB_VMODE_NONINTERLACED,
 };
 
+#define PSEUDO_PALETTE_SIZE 16
+
 static int simplefb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
 			      u_int transp, struct fb_info *info)
 {
@@ -50,7 +54,7 @@ static int simplefb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
 	u32 cb = blue >> (16 - info->var.blue.length);
 	u32 value;
 
-	if (regno >= 16)
+	if (regno >= PSEUDO_PALETTE_SIZE)
 		return -EINVAL;
 
 	value = (cr << info->var.red.offset) |
@@ -163,11 +167,113 @@ static int simplefb_parse_pd(struct platform_device *pdev,
 	return 0;
 }
 
+struct simplefb_par {
+	u32 palette[PSEUDO_PALETTE_SIZE];
+#if defined CONFIG_OF && defined CONFIG_COMMON_CLK
+	int clk_count;
+	struct clk **clks;
+#endif
+};
+
+#if defined CONFIG_OF && defined CONFIG_COMMON_CLK
+/*
+ * Clock handling code.
+ *
+ * Here we handle the clocks property of our "simple-framebuffer" dt node.
+ * This is necessary so that we can make sure that any clocks needed by
+ * the display engine that the bootloader set up for us (and for which it
+ * provided a simplefb dt node), stay up, for the life of the simplefb
+ * driver.
+ *
+ * When the driver unloads, we cleanly disable, and then release the clocks.
+ *
+ * We only complain about errors here, no action is taken as the most likely
+ * error can only happen due to a mismatch between the bootloader which set
+ * up simplefb, and the clock definitions in the device tree. Chances are
+ * that there are no adverse effects, and if there are, a clean teardown of
+ * the fb probe will not help us much either. So just complain and carry on,
+ * and hope that the user actually gets a working fb at the end of things.
+ */
+static int simplefb_clocks_init(struct simplefb_par *par,
+				struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct clk *clock;
+	int i, ret;
+
+	if (dev_get_platdata(&pdev->dev) || !np)
+		return 0;
+
+	par->clk_count = of_clk_get_parent_count(np);
+	if (par->clk_count <= 0)
+		return 0;
+
+	par->clks = kcalloc(par->clk_count, sizeof(struct clk *), GFP_KERNEL);
+	if (!par->clks)
+		return -ENOMEM;
+
+	for (i = 0; i < par->clk_count; i++) {
+		clock = of_clk_get(np, i);
+		if (IS_ERR(clock)) {
+			if (PTR_ERR(clock) == -EPROBE_DEFER) {
+				while (--i >= 0) {
+					if (par->clks[i])
+						clk_put(par->clks[i]);
+				}
+				kfree(par->clks);
+				return -EPROBE_DEFER;
+			}
+			dev_err(&pdev->dev, "%s: clock %d not found: %ld\n",
+				__func__, i, PTR_ERR(clock));
+			continue;
+		}
+		par->clks[i] = clock;
+	}
+
+	for (i = 0; i < par->clk_count; i++) {
+		if (par->clks[i]) {
+			ret = clk_prepare_enable(par->clks[i]);
+			if (ret) {
+				dev_err(&pdev->dev,
+					"%s: failed to enable clock %d: %d\n",
+					__func__, i, ret);
+				clk_put(par->clks[i]);
+				par->clks[i] = NULL;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static void simplefb_clocks_destroy(struct simplefb_par *par)
+{
+	int i;
+
+	if (!par->clks)
+		return;
+
+	for (i = 0; i < par->clk_count; i++) {
+		if (par->clks[i]) {
+			clk_disable_unprepare(par->clks[i]);
+			clk_put(par->clks[i]);
+		}
+	}
+
+	kfree(par->clks);
+}
+#else
+static int simplefb_clocks_init(struct simplefb_par *par,
+	struct platform_device *pdev) { return 0; }
+static void simplefb_clocks_destroy(struct simplefb_par *par) { }
+#endif
+
 static int simplefb_probe(struct platform_device *pdev)
 {
 	int ret;
 	struct simplefb_params params;
 	struct fb_info *info;
+	struct simplefb_par *par;
 	struct resource *mem;
 
 	if (fb_get_options("simplefb", NULL))
@@ -188,11 +294,13 @@ static int simplefb_probe(struct platform_device *pdev)
 		return -EINVAL;
 	}
 
-	info = framebuffer_alloc(sizeof(u32) * 16, &pdev->dev);
+	info = framebuffer_alloc(sizeof(struct simplefb_par), &pdev->dev);
 	if (!info)
 		return -ENOMEM;
 	platform_set_drvdata(pdev, info);
 
+	par = info->par;
+
 	info->fix = simplefb_fix;
 	info->fix.smem_start = mem->start;
 	info->fix.smem_len = resource_size(mem);
@@ -211,8 +319,8 @@ static int simplefb_probe(struct platform_device *pdev)
 
 	info->apertures = alloc_apertures(1);
 	if (!info->apertures) {
-		framebuffer_release(info);
-		return -ENOMEM;
+		ret = -ENOMEM;
+		goto error_fb_release;
 	}
 	info->apertures->ranges[0].base = info->fix.smem_start;
 	info->apertures->ranges[0].size = info->fix.smem_len;
@@ -222,10 +330,14 @@ static int simplefb_probe(struct platform_device *pdev)
 	info->screen_base = ioremap_wc(info->fix.smem_start,
 				       info->fix.smem_len);
 	if (!info->screen_base) {
-		framebuffer_release(info);
-		return -ENODEV;
+		ret = -ENOMEM;
+		goto error_fb_release;
 	}
-	info->pseudo_palette = (void *)(info + 1);
+	info->pseudo_palette = par->palette;
+
+	ret = simplefb_clocks_init(par, pdev);
+	if (ret < 0)
+		goto error_unmap;
 
 	dev_info(&pdev->dev, "framebuffer at 0x%lx, 0x%x bytes, mapped to 0x%p\n",
 			     info->fix.smem_start, info->fix.smem_len,
@@ -238,21 +350,29 @@ static int simplefb_probe(struct platform_device *pdev)
 	ret = register_framebuffer(info);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "Unable to register simplefb: %d\n", ret);
-		iounmap(info->screen_base);
-		framebuffer_release(info);
-		return ret;
+		goto error_clocks;
 	}
 
 	dev_info(&pdev->dev, "fb%d: simplefb registered!\n", info->node);
 
 	return 0;
+
+error_clocks:
+	simplefb_clocks_destroy(par);
+error_unmap:
+	iounmap(info->screen_base);
+error_fb_release:
+	framebuffer_release(info);
+	return ret;
 }
 
 static int simplefb_remove(struct platform_device *pdev)
 {
 	struct fb_info *info = platform_get_drvdata(pdev);
+	struct simplefb_par *par = info->par;
 
 	unregister_framebuffer(info);
+	simplefb_clocks_destroy(par);
 	framebuffer_release(info);
 
 	return 0;
@@ -273,7 +393,27 @@ static struct platform_driver simplefb_driver = {
 	.probe = simplefb_probe,
 	.remove = simplefb_remove,
 };
-module_platform_driver(simplefb_driver);
+
+static int __init simplefb_init(void)
+{
+	int ret;
+	struct device_node *np;
+
+	ret = platform_driver_register(&simplefb_driver);
+	if (ret)
+		return ret;
+
+	if (IS_ENABLED(CONFIG_OF) && of_chosen) {
+		for_each_child_of_node(of_chosen, np) {
+			if (of_device_is_compatible(np, "simple-framebuffer"))
+				of_platform_device_create(np, NULL, NULL);
+		}
+	}
+
+	return 0;
+}
+
+fs_initcall(simplefb_init);
 
 MODULE_AUTHOR("Stephen Warren <swarren@wwwdotorg.org>");
 MODULE_DESCRIPTION("Simple framebuffer driver");
diff --git a/drivers/video/fbdev/sis/sis_main.c b/drivers/video/fbdev/sis/sis_main.c
index e5d11b1892e8..fcf610edf217 100644
--- a/drivers/video/fbdev/sis/sis_main.c
+++ b/drivers/video/fbdev/sis/sis_main.c
@@ -5989,7 +5989,7 @@ static int sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
 	if(!ivideo->sisvga_enabled) {
 		if(pci_enable_device(pdev)) {
-			if(ivideo->nbridge) pci_dev_put(ivideo->nbridge);
+			pci_dev_put(ivideo->nbridge);
 			framebuffer_release(sis_fb_info);
 			return -EIO;
 		}
@@ -6202,10 +6202,8 @@ error_0:	iounmap(ivideo->video_vbase);
 error_1:	release_mem_region(ivideo->video_base, ivideo->video_size);
 error_2:	release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
 error_3:	vfree(ivideo->bios_abase);
-		if(ivideo->lpcdev)
-			pci_dev_put(ivideo->lpcdev);
-		if(ivideo->nbridge)
-			pci_dev_put(ivideo->nbridge);
+		pci_dev_put(ivideo->lpcdev);
+		pci_dev_put(ivideo->nbridge);
 		if(!ivideo->sisvga_enabled)
 			pci_disable_device(pdev);
 		framebuffer_release(sis_fb_info);
@@ -6505,11 +6503,9 @@ static void sisfb_remove(struct pci_dev *pdev)
 
 	vfree(ivideo->bios_abase);
 
-	if(ivideo->lpcdev)
-		pci_dev_put(ivideo->lpcdev);
+	pci_dev_put(ivideo->lpcdev);
 
-	if(ivideo->nbridge)
-		pci_dev_put(ivideo->nbridge);
+	pci_dev_put(ivideo->nbridge);
 
 #ifdef CONFIG_MTRR
 	/* Release MTRR region */
diff --git a/drivers/video/fbdev/sm501fb.c b/drivers/video/fbdev/sm501fb.c
index 9e74e8fbe074..8b98b011fc04 100644
--- a/drivers/video/fbdev/sm501fb.c
+++ b/drivers/video/fbdev/sm501fb.c
@@ -1988,6 +1988,7 @@ static int sm501fb_probe(struct platform_device *pdev)
 	if (info->fb[HEAD_PANEL] == NULL &&
 	    info->fb[HEAD_CRT] == NULL) {
 		dev_err(dev, "no framebuffers found\n");
+		ret = -ENODEV;
 		goto err_alloc;
 	}
 
diff --git a/drivers/video/fbdev/smscufx.c b/drivers/video/fbdev/smscufx.c
index d513ed6a49f2..9279e5f6696e 100644
--- a/drivers/video/fbdev/smscufx.c
+++ b/drivers/video/fbdev/smscufx.c
@@ -1142,8 +1142,7 @@ static void ufx_free_framebuffer_work(struct work_struct *work)
 		fb_dealloc_cmap(&info->cmap);
 	if (info->monspecs.modedb)
 		fb_destroy_modedb(info->monspecs.modedb);
-	if (info->screen_base)
-		vfree(info->screen_base);
+	vfree(info->screen_base);
 
 	fb_destroy_modelist(&info->modelist);
 
@@ -1743,8 +1742,7 @@ error:
 				fb_dealloc_cmap(&info->cmap);
 			if (info->monspecs.modedb)
 				fb_destroy_modedb(info->monspecs.modedb);
-			if (info->screen_base)
-				vfree(info->screen_base);
+			vfree(info->screen_base);
 
 			fb_destroy_modelist(&info->modelist);
 
diff --git a/drivers/video/fbdev/udlfb.c b/drivers/video/fbdev/udlfb.c
index 046d51d83d74..ff2b8731a2dc 100644
--- a/drivers/video/fbdev/udlfb.c
+++ b/drivers/video/fbdev/udlfb.c
@@ -922,8 +922,7 @@ static void dlfb_free(struct kref *kref)
 {
 	struct dlfb_data *dev = container_of(kref, struct dlfb_data, kref);
 
-	if (dev->backing_buffer)
-		vfree(dev->backing_buffer);
+	vfree(dev->backing_buffer);
 
 	kfree(dev->edid);
 
@@ -953,8 +952,7 @@ static void dlfb_free_framebuffer(struct dlfb_data *dev)
 			fb_dealloc_cmap(&info->cmap);
 		if (info->monspecs.modedb)
 			fb_destroy_modedb(info->monspecs.modedb);
-		if (info->screen_base)
-			vfree(info->screen_base);
+		vfree(info->screen_base);
 
 		fb_destroy_modelist(&info->modelist);
 
@@ -1203,8 +1201,7 @@ static int dlfb_realloc_framebuffer(struct dlfb_data *dev, struct fb_info *info)
 		if (!new_back)
 			pr_info("No shadow/backing buffer allocated\n");
 		else {
-			if (dev->backing_buffer)
-				vfree(dev->backing_buffer);
+			vfree(dev->backing_buffer);
 			dev->backing_buffer = new_back;
 		}
 	}
diff --git a/drivers/video/fbdev/uvesafb.c b/drivers/video/fbdev/uvesafb.c
index 509d452e8f91..d32d1c4d1b99 100644
--- a/drivers/video/fbdev/uvesafb.c
+++ b/drivers/video/fbdev/uvesafb.c
@@ -1219,8 +1219,7 @@ static int uvesafb_release(struct fb_info *info, int user)
 	uvesafb_vbe_state_restore(par, par->vbe_state_orig);
 out:
 	atomic_dec(&par->ref_count);
-	if (task)
-		uvesafb_free(task);
+	uvesafb_free(task);
 	return 0;
 }
 
@@ -1923,8 +1922,7 @@ static int uvesafb_init(void)
 			err = -ENOMEM;
 
 		if (err) {
-			if (uvesafb_device)
-				platform_device_put(uvesafb_device);
+			platform_device_put(uvesafb_device);
 			platform_driver_unregister(&uvesafb_driver);
 			cn_del_callback(&uvesafb_cn_id);
 			return err;
diff --git a/drivers/video/fbdev/via/viafbdev.c b/drivers/video/fbdev/via/viafbdev.c
index 325c43c6ff97..f9718f012aae 100644
--- a/drivers/video/fbdev/via/viafbdev.c
+++ b/drivers/video/fbdev/via/viafbdev.c
@@ -1937,8 +1937,7 @@ out_fb1_unreg_lcd_cle266:
 out_dealloc_cmap:
 	fb_dealloc_cmap(&viafbinfo->cmap);
 out_fb1_release:
-	if (viafbinfo1)
-		framebuffer_release(viafbinfo1);
+	framebuffer_release(viafbinfo1);
 out_fb_release:
 	i2c_bus_free(viaparinfo->shared);
 	framebuffer_release(viafbinfo);
diff --git a/drivers/video/fbdev/vt8623fb.c b/drivers/video/fbdev/vt8623fb.c
index 5c7cbc6c6236..ea7f056ed5fe 100644
--- a/drivers/video/fbdev/vt8623fb.c
+++ b/drivers/video/fbdev/vt8623fb.c
@@ -731,7 +731,7 @@ static int vt8623_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
 
 	pcibios_bus_to_resource(dev->bus, &vga_res, &bus_reg);
 
-	par->state.vgabase = (void __iomem *) vga_res.start;
+	par->state.vgabase = (void __iomem *) (unsigned long) vga_res.start;
 
 	/* Find how many physical memory there is on card */
 	memsize1 = (vga_rseq(par->state.vgabase, 0x34) + 1) >> 1;
diff --git a/include/linux/of.h b/include/linux/of.h
index 1a66b8881c01..b47096730dc5 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -108,8 +108,6 @@ static inline struct device_node *of_node_get(struct device_node *node)
 static inline void of_node_put(struct device_node *node) { }
 #endif /* !CONFIG_OF_DYNAMIC */
 
-#ifdef CONFIG_OF
-
 /* Pointer for first entry in chain of all nodes. */
 extern struct device_node *of_allnodes;
 extern struct device_node *of_chosen;
@@ -117,6 +115,7 @@ extern struct device_node *of_aliases;
 extern struct device_node *of_stdout;
 extern raw_spinlock_t devtree_lock;
 
+#ifdef CONFIG_OF
 static inline bool is_of_node(struct fwnode_handle *fwnode)
 {
 	return fwnode && fwnode->type == FWNODE_OF;
diff --git a/include/sound/omap-hdmi-audio.h b/include/sound/omap-hdmi-audio.h
new file mode 100644
index 000000000000..afdb416898e0
--- /dev/null
+++ b/include/sound/omap-hdmi-audio.h
@@ -0,0 +1,43 @@
+/*
+ * hdmi-audio.c -- OMAP4+ DSS HDMI audio support library
+ *
+ * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Author: Jyri Sarha <jsarha@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ */
+
+#include <video/omapdss.h>
+
+#ifndef __OMAP_HDMI_AUDIO_H__
+#define __OMAP_HDMI_AUDIO_H__
+
+struct omap_hdmi_audio_ops {
+	int (*audio_startup)(struct device *dev,
+			     void (*abort_cb)(struct device *dev));
+	int (*audio_shutdown)(struct device *dev);
+	int (*audio_start)(struct device *dev);
+	void (*audio_stop)(struct device *dev);
+	int (*audio_config)(struct device *dev,
+			    struct omap_dss_audio *dss_audio);
+};
+
+/* HDMI audio initalization data */
+struct omap_hdmi_audio_pdata {
+	struct device *dev;
+	enum omapdss_version dss_version;
+	phys_addr_t audio_dma_addr;
+
+	const struct omap_hdmi_audio_ops *ops;
+};
+
+#endif /* __OMAP_HDMI_AUDIO_H__ */
diff --git a/include/video/omapdss.h b/include/video/omapdss.h
index 069dfca9549a..6a84498ea513 100644
--- a/include/video/omapdss.h
+++ b/include/video/omapdss.h
@@ -166,13 +166,6 @@ enum omap_dss_display_state {
 	OMAP_DSS_DISPLAY_ACTIVE,
 };
 
-enum omap_dss_audio_state {
-	OMAP_DSS_AUDIO_DISABLED = 0,
-	OMAP_DSS_AUDIO_ENABLED,
-	OMAP_DSS_AUDIO_CONFIGURED,
-	OMAP_DSS_AUDIO_PLAYING,
-};
-
 struct omap_dss_audio {
 	struct snd_aes_iec958 *iec;
 	struct snd_cea_861_aud_if *cea;
@@ -635,19 +628,6 @@ struct omapdss_hdmi_ops {
 	int (*set_hdmi_mode)(struct omap_dss_device *dssdev, bool hdmi_mode);
 	int (*set_infoframe)(struct omap_dss_device *dssdev,
 		const struct hdmi_avi_infoframe *avi);
-
-	/*
-	 * Note: These functions might sleep. Do not call while
-	 * holding a spinlock/readlock.
-	 */
-	int (*audio_enable)(struct omap_dss_device *dssdev);
-	void (*audio_disable)(struct omap_dss_device *dssdev);
-	bool (*audio_supported)(struct omap_dss_device *dssdev);
-	int (*audio_config)(struct omap_dss_device *dssdev,
-		struct omap_dss_audio *audio);
-	/* Note: These functions may not sleep */
-	int (*audio_start)(struct omap_dss_device *dssdev);
-	void (*audio_stop)(struct omap_dss_device *dssdev);
 };
 
 struct omapdss_dsi_ops {
@@ -783,8 +763,6 @@ struct omap_dss_device {
 
 	enum omap_dss_display_state state;
 
-	enum omap_dss_audio_state audio_state;
-
 	/* OMAP DSS output specific fields */
 
 	struct list_head list;
@@ -795,6 +773,9 @@ struct omap_dss_device {
 	/* output instance */
 	enum omap_dss_output_id id;
 
+	/* the port number in the DT node */
+	int port_num;
+
 	/* dynamic fields */
 	struct omap_overlay_manager *manager;
 
@@ -858,24 +839,6 @@ struct omap_dss_driver {
 	int (*set_hdmi_mode)(struct omap_dss_device *dssdev, bool hdmi_mode);
 	int (*set_hdmi_infoframe)(struct omap_dss_device *dssdev,
 		const struct hdmi_avi_infoframe *avi);
-
-	/*
-	 * For display drivers that support audio. This encompasses
-	 * HDMI and DisplayPort at the moment.
-	 */
-	/*
-	 * Note: These functions might sleep. Do not call while
-	 * holding a spinlock/readlock.
-	 */
-	int (*audio_enable)(struct omap_dss_device *dssdev);
-	void (*audio_disable)(struct omap_dss_device *dssdev);
-	bool (*audio_supported)(struct omap_dss_device *dssdev);
-	int (*audio_config)(struct omap_dss_device *dssdev,
-		struct omap_dss_audio *audio);
-	/* Note: These functions may not sleep */
-	int (*audio_start)(struct omap_dss_device *dssdev);
-	void (*audio_stop)(struct omap_dss_device *dssdev);
-
 };
 
 enum omapdss_version omapdss_get_version(void);
@@ -918,7 +881,7 @@ int omapdss_register_output(struct omap_dss_device *output);
 void omapdss_unregister_output(struct omap_dss_device *output);
 struct omap_dss_device *omap_dss_get_output(enum omap_dss_output_id id);
 struct omap_dss_device *omap_dss_find_output(const char *name);
-struct omap_dss_device *omap_dss_find_output_by_node(struct device_node *node);
+struct omap_dss_device *omap_dss_find_output_by_port_node(struct device_node *port);
 int omapdss_output_set_device(struct omap_dss_device *out,
 		struct omap_dss_device *dssdev);
 int omapdss_output_unset_device(struct omap_dss_device *out);
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig
index d44463a7b0fa..3dfcadf00e55 100644
--- a/sound/soc/omap/Kconfig
+++ b/sound/soc/omap/Kconfig
@@ -12,8 +12,20 @@ config SND_OMAP_SOC_MCBSP
 config SND_OMAP_SOC_MCPDM
 	tristate
 
-config SND_OMAP_SOC_HDMI
-	tristate
+config SND_OMAP_SOC_HDMI_AUDIO
+	tristate "HDMI audio support for OMAP4+ based SoCs"
+	depends on SND_OMAP_SOC
+	help
+	  For HDMI audio to work OMAPDSS HDMI support should be
+	  enabled.
+	  The hdmi audio driver implements cpu-dai component using the
+	  callbacks provided by OMAPDSS and registers the component
+	  under DSS HDMI device. Omap-pcm is registered for platform
+	  component also under DSS HDMI device. Dummy codec is used as
+	  as codec component. The hdmi audio driver implements also
+	  the card and registers it under its own platform device.
+	  The device for the dirver is registered by OMAPDSS hdmi
+	  driver.
 
 config SND_OMAP_SOC_N810
 	tristate "SoC Audio support for Nokia N810"
@@ -100,16 +112,6 @@ config SND_OMAP_SOC_OMAP_ABE_TWL6040
 	  - PandaBoard (4430)
 	  - PandaBoardES (4460)
 
-config SND_OMAP_SOC_OMAP_HDMI
-	tristate "SoC Audio support for Texas Instruments OMAP HDMI"
-	depends on SND_OMAP_SOC && OMAP4_DSS_HDMI && OMAP2_DSS
-	select SND_OMAP_SOC_HDMI
-	select SND_SOC_HDMI_CODEC
-	select OMAP4_DSS_HDMI_AUDIO
-	help
-	  Say Y if you want to add support for SoC HDMI audio on Texas Instruments
-	  OMAP4 chips
-
 config SND_OMAP_SOC_OMAP3_PANDORA
 	tristate "SoC Audio support for OMAP3 Pandora"
 	depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP3_PANDORA
diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile
index a725905b2c68..db36fbd5d1a0 100644
--- a/sound/soc/omap/Makefile
+++ b/sound/soc/omap/Makefile
@@ -3,13 +3,13 @@ snd-soc-omap-objs := omap-pcm.o
 snd-soc-omap-dmic-objs := omap-dmic.o
 snd-soc-omap-mcbsp-objs := omap-mcbsp.o mcbsp.o
 snd-soc-omap-mcpdm-objs := omap-mcpdm.o
-snd-soc-omap-hdmi-objs := omap-hdmi.o
+snd-soc-omap-hdmi-audio-objs := omap-hdmi-audio.o
 
 obj-$(CONFIG_SND_OMAP_SOC) += snd-soc-omap.o
 obj-$(CONFIG_SND_OMAP_SOC_DMIC) += snd-soc-omap-dmic.o
 obj-$(CONFIG_SND_OMAP_SOC_MCBSP) += snd-soc-omap-mcbsp.o
 obj-$(CONFIG_SND_OMAP_SOC_MCPDM) += snd-soc-omap-mcpdm.o
-obj-$(CONFIG_SND_OMAP_SOC_HDMI) += snd-soc-omap-hdmi.o
+obj-$(CONFIG_SND_OMAP_SOC_HDMI_AUDIO) += snd-soc-omap-hdmi-audio.o
 
 # OMAP Machine Support
 snd-soc-n810-objs := n810.o
@@ -20,7 +20,6 @@ snd-soc-am3517evm-objs := am3517evm.o
 snd-soc-omap-abe-twl6040-objs := omap-abe-twl6040.o
 snd-soc-omap-twl4030-objs := omap-twl4030.o
 snd-soc-omap3pandora-objs := omap3pandora.o
-snd-soc-omap-hdmi-card-objs := omap-hdmi-card.o
 
 obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o
 obj-$(CONFIG_SND_OMAP_SOC_RX51) += snd-soc-rx51.o
@@ -30,4 +29,3 @@ obj-$(CONFIG_SND_OMAP_SOC_AM3517EVM) += snd-soc-am3517evm.o
 obj-$(CONFIG_SND_OMAP_SOC_OMAP_ABE_TWL6040) += snd-soc-omap-abe-twl6040.o
 obj-$(CONFIG_SND_OMAP_SOC_OMAP_TWL4030) += snd-soc-omap-twl4030.o
 obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o
-obj-$(CONFIG_SND_OMAP_SOC_OMAP_HDMI) += snd-soc-omap-hdmi-card.o
diff --git a/sound/soc/omap/omap-hdmi-audio.c b/sound/soc/omap/omap-hdmi-audio.c
new file mode 100644
index 000000000000..3f9ac7dbdc80
--- /dev/null
+++ b/sound/soc/omap/omap-hdmi-audio.c
@@ -0,0 +1,407 @@
+/*
+ * omap-hdmi-audio.c -- OMAP4+ DSS HDMI audio support library
+ *
+ * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Author: Jyri Sarha <jsarha@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#include <linux/platform_device.h>
+#include <sound/soc.h>
+#include <sound/pcm_params.h>
+#include <sound/dmaengine_pcm.h>
+#include <uapi/sound/asound.h>
+#include <sound/asoundef.h>
+#include <sound/omap-pcm.h>
+#include <sound/omap-hdmi-audio.h>
+#include <video/omapdss.h>
+
+#define DRV_NAME "omap-hdmi-audio"
+
+struct hdmi_audio_data {
+	struct snd_soc_card *card;
+
+	const struct omap_hdmi_audio_ops *ops;
+	struct device *dssdev;
+	struct snd_dmaengine_dai_dma_data dma_data;
+	struct omap_dss_audio dss_audio;
+	struct snd_aes_iec958 iec;
+	struct snd_cea_861_aud_if cea;
+
+	struct mutex current_stream_lock;
+	struct snd_pcm_substream *current_stream;
+};
+
+static
+struct hdmi_audio_data *card_drvdata_substream(struct snd_pcm_substream *ss)
+{
+	struct snd_soc_pcm_runtime *rtd = ss->private_data;
+
+	return snd_soc_card_get_drvdata(rtd->card);
+}
+
+static void hdmi_dai_abort(struct device *dev)
+{
+	struct hdmi_audio_data *ad = dev_get_drvdata(dev);
+
+	mutex_lock(&ad->current_stream_lock);
+	if (ad->current_stream && ad->current_stream->runtime &&
+	    snd_pcm_running(ad->current_stream)) {
+		dev_err(dev, "HDMI display disabled, aborting playback\n");
+		snd_pcm_stream_lock_irq(ad->current_stream);
+		snd_pcm_stop(ad->current_stream, SNDRV_PCM_STATE_DISCONNECTED);
+		snd_pcm_stream_unlock_irq(ad->current_stream);
+	}
+	mutex_unlock(&ad->current_stream_lock);
+}
+
+static int hdmi_dai_startup(struct snd_pcm_substream *substream,
+			    struct snd_soc_dai *dai)
+{
+	struct hdmi_audio_data *ad = card_drvdata_substream(substream);
+	int ret;
+	/*
+	 * Make sure that the period bytes are multiple of the DMA packet size.
+	 * Largest packet size we use is 32 32-bit words = 128 bytes
+	 */
+	ret = snd_pcm_hw_constraint_step(substream->runtime, 0,
+					 SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 128);
+	if (ret < 0) {
+		dev_err(dai->dev, "could not apply constraint\n");
+		return ret;
+	}
+
+	snd_soc_dai_set_dma_data(dai, substream, &ad->dma_data);
+
+	mutex_lock(&ad->current_stream_lock);
+	ad->current_stream = substream;
+	mutex_unlock(&ad->current_stream_lock);
+
+	ret = ad->ops->audio_startup(ad->dssdev, hdmi_dai_abort);
+
+	if (ret) {
+		mutex_lock(&ad->current_stream_lock);
+		ad->current_stream = NULL;
+		mutex_unlock(&ad->current_stream_lock);
+	}
+
+	return ret;
+}
+
+static int hdmi_dai_hw_params(struct snd_pcm_substream *substream,
+			      struct snd_pcm_hw_params *params,
+			      struct snd_soc_dai *dai)
+{
+	struct hdmi_audio_data *ad = card_drvdata_substream(substream);
+	struct snd_aes_iec958 *iec = &ad->iec;
+	struct snd_cea_861_aud_if *cea = &ad->cea;
+
+	WARN_ON(ad->current_stream != substream);
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		ad->dma_data.maxburst = 16;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		ad->dma_data.maxburst = 32;
+		break;
+	default:
+		dev_err(dai->dev, "format not supported!\n");
+		return -EINVAL;
+	}
+
+	ad->dss_audio.iec = iec;
+	ad->dss_audio.cea = cea;
+	/*
+	 * fill the IEC-60958 channel status word
+	 */
+	/* initialize the word bytes */
+	memset(iec->status, 0, sizeof(iec->status));
+
+	/* specify IEC-60958-3 (commercial use) */
+	iec->status[0] &= ~IEC958_AES0_PROFESSIONAL;
+
+	/* specify that the audio is LPCM*/
+	iec->status[0] &= ~IEC958_AES0_NONAUDIO;
+
+	iec->status[0] |= IEC958_AES0_CON_NOT_COPYRIGHT;
+
+	iec->status[0] |= IEC958_AES0_CON_EMPHASIS_NONE;
+
+	iec->status[0] |= IEC958_AES1_PRO_MODE_NOTID;
+
+	iec->status[1] = IEC958_AES1_CON_GENERAL;
+
+	iec->status[2] |= IEC958_AES2_CON_SOURCE_UNSPEC;
+
+	iec->status[2] |= IEC958_AES2_CON_CHANNEL_UNSPEC;
+
+	switch (params_rate(params)) {
+	case 32000:
+		iec->status[3] |= IEC958_AES3_CON_FS_32000;
+		break;
+	case 44100:
+		iec->status[3] |= IEC958_AES3_CON_FS_44100;
+		break;
+	case 48000:
+		iec->status[3] |= IEC958_AES3_CON_FS_48000;
+		break;
+	case 88200:
+		iec->status[3] |= IEC958_AES3_CON_FS_88200;
+		break;
+	case 96000:
+		iec->status[3] |= IEC958_AES3_CON_FS_96000;
+		break;
+	case 176400:
+		iec->status[3] |= IEC958_AES3_CON_FS_176400;
+		break;
+	case 192000:
+		iec->status[3] |= IEC958_AES3_CON_FS_192000;
+		break;
+	default:
+		dev_err(dai->dev, "rate not supported!\n");
+		return -EINVAL;
+	}
+
+	/* specify the clock accuracy */
+	iec->status[3] |= IEC958_AES3_CON_CLOCK_1000PPM;
+
+	/*
+	 * specify the word length. The same word length value can mean
+	 * two different lengths. Hence, we need to specify the maximum
+	 * word length as well.
+	 */
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		iec->status[4] |= IEC958_AES4_CON_WORDLEN_20_16;
+		iec->status[4] &= ~IEC958_AES4_CON_MAX_WORDLEN_24;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		iec->status[4] |= IEC958_AES4_CON_WORDLEN_24_20;
+		iec->status[4] |= IEC958_AES4_CON_MAX_WORDLEN_24;
+		break;
+	default:
+		dev_err(dai->dev, "format not supported!\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * Fill the CEA-861 audio infoframe (see spec for details)
+	 */
+
+	cea->db1_ct_cc = (params_channels(params) - 1)
+		& CEA861_AUDIO_INFOFRAME_DB1CC;
+	cea->db1_ct_cc |= CEA861_AUDIO_INFOFRAME_DB1CT_FROM_STREAM;
+
+	cea->db2_sf_ss = CEA861_AUDIO_INFOFRAME_DB2SF_FROM_STREAM;
+	cea->db2_sf_ss |= CEA861_AUDIO_INFOFRAME_DB2SS_FROM_STREAM;
+
+	cea->db3 = 0; /* not used, all zeros */
+
+	/*
+	 * The OMAP HDMI IP requires to use the 8-channel channel code when
+	 * transmitting more than two channels.
+	 */
+	if (params_channels(params) == 2)
+		cea->db4_ca = 0x0;
+	else
+		cea->db4_ca = 0x13;
+
+	cea->db5_dminh_lsv = CEA861_AUDIO_INFOFRAME_DB5_DM_INH_PROHIBITED;
+	/* the expression is trivial but makes clear what we are doing */
+	cea->db5_dminh_lsv |= (0 & CEA861_AUDIO_INFOFRAME_DB5_LSV);
+
+	return ad->ops->audio_config(ad->dssdev, &ad->dss_audio);
+}
+
+static int hdmi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
+			    struct snd_soc_dai *dai)
+{
+	struct hdmi_audio_data *ad = card_drvdata_substream(substream);
+	int err = 0;
+
+	WARN_ON(ad->current_stream != substream);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		err = ad->ops->audio_start(ad->dssdev);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		ad->ops->audio_stop(ad->dssdev);
+		break;
+	default:
+		err = -EINVAL;
+	}
+	return err;
+}
+
+static void hdmi_dai_shutdown(struct snd_pcm_substream *substream,
+			      struct snd_soc_dai *dai)
+{
+	struct hdmi_audio_data *ad = card_drvdata_substream(substream);
+
+	WARN_ON(ad->current_stream != substream);
+
+	ad->ops->audio_shutdown(ad->dssdev);
+
+	mutex_lock(&ad->current_stream_lock);
+	ad->current_stream = NULL;
+	mutex_unlock(&ad->current_stream_lock);
+}
+
+static const struct snd_soc_dai_ops hdmi_dai_ops = {
+	.startup	= hdmi_dai_startup,
+	.hw_params	= hdmi_dai_hw_params,
+	.trigger	= hdmi_dai_trigger,
+	.shutdown	= hdmi_dai_shutdown,
+};
+
+static const struct snd_soc_component_driver omap_hdmi_component = {
+	.name = "omapdss_hdmi",
+};
+
+static struct snd_soc_dai_driver omap5_hdmi_dai = {
+	.name = "omap5-hdmi-dai",
+	.playback = {
+		.channels_min = 2,
+		.channels_max = 8,
+		.rates = (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+			  SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
+			  SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
+			  SNDRV_PCM_RATE_192000),
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+	.ops = &hdmi_dai_ops,
+};
+
+static struct snd_soc_dai_driver omap4_hdmi_dai = {
+	.name = "omap4-hdmi-dai",
+	.playback = {
+		.channels_min = 2,
+		.channels_max = 8,
+		.rates = (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+			  SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
+			  SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
+			  SNDRV_PCM_RATE_192000),
+		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
+	},
+	.ops = &hdmi_dai_ops,
+};
+
+static int omap_hdmi_audio_probe(struct platform_device *pdev)
+{
+	struct omap_hdmi_audio_pdata *ha = pdev->dev.platform_data;
+	struct device *dev = &pdev->dev;
+	struct hdmi_audio_data *ad;
+	struct snd_soc_dai_driver *dai_drv;
+	struct snd_soc_card *card;
+	int ret;
+
+	if (!ha) {
+		dev_err(dev, "No platform data\n");
+		return -EINVAL;
+	}
+
+	ad = devm_kzalloc(dev, sizeof(*ad), GFP_KERNEL);
+	if (!ad)
+		return -ENOMEM;
+	ad->dssdev = ha->dev;
+	ad->ops = ha->ops;
+	ad->dma_data.addr = ha->audio_dma_addr;
+	ad->dma_data.filter_data = "audio_tx";
+	ad->dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+	mutex_init(&ad->current_stream_lock);
+
+	switch (ha->dss_version) {
+	case OMAPDSS_VER_OMAP4430_ES1:
+	case OMAPDSS_VER_OMAP4430_ES2:
+	case OMAPDSS_VER_OMAP4:
+		dai_drv = &omap4_hdmi_dai;
+		break;
+	case OMAPDSS_VER_OMAP5:
+		dai_drv = &omap5_hdmi_dai;
+		break;
+	default:
+		return -EINVAL;
+	}
+	ret = snd_soc_register_component(ad->dssdev, &omap_hdmi_component,
+					 dai_drv, 1);
+	if (ret)
+		return ret;
+
+	ret = omap_pcm_platform_register(ad->dssdev);
+	if (ret)
+		return ret;
+
+	card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+	card->name = devm_kasprintf(dev, GFP_KERNEL,
+				    "HDMI %s", dev_name(ad->dssdev));
+	card->owner = THIS_MODULE;
+	card->dai_link =
+		devm_kzalloc(dev, sizeof(*(card->dai_link)), GFP_KERNEL);
+	card->dai_link->name = card->name;
+	card->dai_link->stream_name = card->name;
+	card->dai_link->cpu_dai_name = dev_name(ad->dssdev);
+	card->dai_link->platform_name = dev_name(ad->dssdev);
+	card->dai_link->codec_name = "snd-soc-dummy";
+	card->dai_link->codec_dai_name = "snd-soc-dummy-dai";
+	card->num_links = 1;
+	card->dev = dev;
+
+	ret = snd_soc_register_card(card);
+	if (ret) {
+		dev_err(dev, "snd_soc_register_card failed (%d)\n", ret);
+		snd_soc_unregister_component(ad->dssdev);
+		return ret;
+	}
+
+	ad->card = card;
+	snd_soc_card_set_drvdata(card, ad);
+
+	dev_set_drvdata(dev, ad);
+
+	return 0;
+}
+
+static int omap_hdmi_audio_remove(struct platform_device *pdev)
+{
+	struct hdmi_audio_data *ad = platform_get_drvdata(pdev);
+
+	snd_soc_unregister_card(ad->card);
+	snd_soc_unregister_component(ad->dssdev);
+	return 0;
+}
+
+static struct platform_driver hdmi_audio_driver = {
+	.driver = {
+		.name = DRV_NAME,
+		.owner = THIS_MODULE,
+	},
+	.probe = omap_hdmi_audio_probe,
+	.remove = omap_hdmi_audio_remove,
+};
+
+module_platform_driver(hdmi_audio_driver);
+
+MODULE_AUTHOR("Jyri Sarha <jsarha@ti.com>");
+MODULE_DESCRIPTION("OMAP HDMI Audio Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/omap/omap-hdmi-card.c b/sound/soc/omap/omap-hdmi-card.c
deleted file mode 100644
index f649fe84b629..000000000000
--- a/sound/soc/omap/omap-hdmi-card.c
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * omap-hdmi-card.c
- *
- * OMAP ALSA SoC machine driver for TI OMAP HDMI
- * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
- * Author: Ricardo Neri <ricardo.neri@ti.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include <linux/module.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <asm/mach-types.h>
-#include <video/omapdss.h>
-
-#define DRV_NAME "omap-hdmi-audio"
-
-static struct snd_soc_dai_link omap_hdmi_dai = {
-	.name = "HDMI",
-	.stream_name = "HDMI",
-	.cpu_dai_name = "omap-hdmi-audio-dai",
-	.platform_name = "omap-hdmi-audio-dai",
-	.codec_name = "hdmi-audio-codec",
-	.codec_dai_name = "hdmi-hifi",
-};
-
-static struct snd_soc_card snd_soc_omap_hdmi = {
-	.name = "OMAPHDMI",
-	.owner = THIS_MODULE,
-	.dai_link = &omap_hdmi_dai,
-	.num_links = 1,
-};
-
-static int omap_hdmi_probe(struct platform_device *pdev)
-{
-	struct snd_soc_card *card = &snd_soc_omap_hdmi;
-	int ret;
-
-	card->dev = &pdev->dev;
-
-	ret = snd_soc_register_card(card);
-	if (ret) {
-		dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
-		card->dev = NULL;
-		return ret;
-	}
-	return 0;
-}
-
-static int omap_hdmi_remove(struct platform_device *pdev)
-{
-	struct snd_soc_card *card = platform_get_drvdata(pdev);
-
-	snd_soc_unregister_card(card);
-	card->dev = NULL;
-	return 0;
-}
-
-static struct platform_driver omap_hdmi_driver = {
-	.driver = {
-		.name = DRV_NAME,
-		.owner = THIS_MODULE,
-	},
-	.probe = omap_hdmi_probe,
-	.remove = omap_hdmi_remove,
-};
-
-module_platform_driver(omap_hdmi_driver);
-
-MODULE_AUTHOR("Ricardo Neri <ricardo.neri@ti.com>");
-MODULE_DESCRIPTION("OMAP HDMI machine ASoC driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/omap/omap-hdmi.c b/sound/soc/omap/omap-hdmi.c
deleted file mode 100644
index eb9c39299f81..000000000000
--- a/sound/soc/omap/omap-hdmi.c
+++ /dev/null
@@ -1,364 +0,0 @@
-/*
- * omap-hdmi.c
- *
- * OMAP ALSA SoC DAI driver for HDMI audio on OMAP4 processors.
- * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/
- * Authors: Jorge Candelaria <jorge.candelaria@ti.com>
- *          Ricardo Neri <ricardo.neri@ti.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/initval.h>
-#include <sound/soc.h>
-#include <sound/asound.h>
-#include <sound/asoundef.h>
-#include <sound/dmaengine_pcm.h>
-#include <video/omapdss.h>
-#include <sound/omap-pcm.h>
-
-#include "omap-hdmi.h"
-
-#define DRV_NAME "omap-hdmi-audio-dai"
-
-struct hdmi_priv {
-	struct snd_dmaengine_dai_dma_data dma_data;
-	unsigned int dma_req;
-	struct omap_dss_audio dss_audio;
-	struct snd_aes_iec958 iec;
-	struct snd_cea_861_aud_if cea;
-	struct omap_dss_device *dssdev;
-};
-
-static int omap_hdmi_dai_startup(struct snd_pcm_substream *substream,
-				  struct snd_soc_dai *dai)
-{
-	struct hdmi_priv *priv = snd_soc_dai_get_drvdata(dai);
-	int err;
-	/*
-	 * Make sure that the period bytes are multiple of the DMA packet size.
-	 * Largest packet size we use is 32 32-bit words = 128 bytes
-	 */
-	err = snd_pcm_hw_constraint_step(substream->runtime, 0,
-				 SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 128);
-	if (err < 0) {
-		dev_err(dai->dev, "could not apply constraint\n");
-		return err;
-	}
-
-	if (!priv->dssdev->driver->audio_supported(priv->dssdev)) {
-		dev_err(dai->dev, "audio not supported\n");
-		return -ENODEV;
-	}
-
-	snd_soc_dai_set_dma_data(dai, substream, &priv->dma_data);
-
-	return 0;
-}
-
-static int omap_hdmi_dai_prepare(struct snd_pcm_substream *substream,
-				struct snd_soc_dai *dai)
-{
-	struct hdmi_priv *priv = snd_soc_dai_get_drvdata(dai);
-
-	return priv->dssdev->driver->audio_enable(priv->dssdev);
-}
-
-static int omap_hdmi_dai_hw_params(struct snd_pcm_substream *substream,
-				    struct snd_pcm_hw_params *params,
-				    struct snd_soc_dai *dai)
-{
-	struct hdmi_priv *priv = snd_soc_dai_get_drvdata(dai);
-	struct snd_aes_iec958 *iec = &priv->iec;
-	struct snd_cea_861_aud_if *cea = &priv->cea;
-	int err = 0;
-
-	switch (params_format(params)) {
-	case SNDRV_PCM_FORMAT_S16_LE:
-		priv->dma_data.maxburst = 16;
-		break;
-	case SNDRV_PCM_FORMAT_S24_LE:
-		priv->dma_data.maxburst = 32;
-		break;
-	default:
-		dev_err(dai->dev, "format not supported!\n");
-		return -EINVAL;
-	}
-
-	/*
-	 * fill the IEC-60958 channel status word
-	 */
-	/* initialize the word bytes */
-	memset(iec->status, 0, sizeof(iec->status));
-
-	/* specify IEC-60958-3 (commercial use) */
-	iec->status[0] &= ~IEC958_AES0_PROFESSIONAL;
-
-	/* specify that the audio is LPCM*/
-	iec->status[0] &= ~IEC958_AES0_NONAUDIO;
-
-	iec->status[0] |= IEC958_AES0_CON_NOT_COPYRIGHT;
-
-	iec->status[0] |= IEC958_AES0_CON_EMPHASIS_NONE;
-
-	iec->status[0] |= IEC958_AES1_PRO_MODE_NOTID;
-
-	iec->status[1] = IEC958_AES1_CON_GENERAL;
-
-	iec->status[2] |= IEC958_AES2_CON_SOURCE_UNSPEC;
-
-	iec->status[2] |= IEC958_AES2_CON_CHANNEL_UNSPEC;
-
-	switch (params_rate(params)) {
-	case 32000:
-		iec->status[3] |= IEC958_AES3_CON_FS_32000;
-		break;
-	case 44100:
-		iec->status[3] |= IEC958_AES3_CON_FS_44100;
-		break;
-	case 48000:
-		iec->status[3] |= IEC958_AES3_CON_FS_48000;
-		break;
-	case 88200:
-		iec->status[3] |= IEC958_AES3_CON_FS_88200;
-		break;
-	case 96000:
-		iec->status[3] |= IEC958_AES3_CON_FS_96000;
-		break;
-	case 176400:
-		iec->status[3] |= IEC958_AES3_CON_FS_176400;
-		break;
-	case 192000:
-		iec->status[3] |= IEC958_AES3_CON_FS_192000;
-		break;
-	default:
-		dev_err(dai->dev, "rate not supported!\n");
-		return -EINVAL;
-	}
-
-	/* specify the clock accuracy */
-	iec->status[3] |= IEC958_AES3_CON_CLOCK_1000PPM;
-
-	/*
-	 * specify the word length. The same word length value can mean
-	 * two different lengths. Hence, we need to specify the maximum
-	 * word length as well.
-	 */
-	switch (params_format(params)) {
-	case SNDRV_PCM_FORMAT_S16_LE:
-		iec->status[4] |= IEC958_AES4_CON_WORDLEN_20_16;
-		iec->status[4] &= ~IEC958_AES4_CON_MAX_WORDLEN_24;
-		break;
-	case SNDRV_PCM_FORMAT_S24_LE:
-		iec->status[4] |= IEC958_AES4_CON_WORDLEN_24_20;
-		iec->status[4] |= IEC958_AES4_CON_MAX_WORDLEN_24;
-		break;
-	default:
-		dev_err(dai->dev, "format not supported!\n");
-		return -EINVAL;
-	}
-
-	/*
-	 * Fill the CEA-861 audio infoframe (see spec for details)
-	 */
-
-	cea->db1_ct_cc = (params_channels(params) - 1)
-		& CEA861_AUDIO_INFOFRAME_DB1CC;
-	cea->db1_ct_cc |= CEA861_AUDIO_INFOFRAME_DB1CT_FROM_STREAM;
-
-	cea->db2_sf_ss = CEA861_AUDIO_INFOFRAME_DB2SF_FROM_STREAM;
-	cea->db2_sf_ss |= CEA861_AUDIO_INFOFRAME_DB2SS_FROM_STREAM;
-
-	cea->db3 = 0; /* not used, all zeros */
-
-	/*
-	 * The OMAP HDMI IP requires to use the 8-channel channel code when
-	 * transmitting more than two channels.
-	 */
-	if (params_channels(params) == 2)
-		cea->db4_ca = 0x0;
-	else
-		cea->db4_ca = 0x13;
-
-	cea->db5_dminh_lsv = CEA861_AUDIO_INFOFRAME_DB5_DM_INH_PROHIBITED;
-	/* the expression is trivial but makes clear what we are doing */
-	cea->db5_dminh_lsv |= (0 & CEA861_AUDIO_INFOFRAME_DB5_LSV);
-
-	priv->dss_audio.iec = iec;
-	priv->dss_audio.cea = cea;
-
-	err = priv->dssdev->driver->audio_config(priv->dssdev,
-						 &priv->dss_audio);
-
-	return err;
-}
-
-static int omap_hdmi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
-				struct snd_soc_dai *dai)
-{
-	struct hdmi_priv *priv = snd_soc_dai_get_drvdata(dai);
-	int err = 0;
-
-	switch (cmd) {
-	case SNDRV_PCM_TRIGGER_START:
-	case SNDRV_PCM_TRIGGER_RESUME:
-	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		err = priv->dssdev->driver->audio_start(priv->dssdev);
-		break;
-	case SNDRV_PCM_TRIGGER_STOP:
-	case SNDRV_PCM_TRIGGER_SUSPEND:
-	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-		priv->dssdev->driver->audio_stop(priv->dssdev);
-		break;
-	default:
-		err = -EINVAL;
-	}
-	return err;
-}
-
-static void omap_hdmi_dai_shutdown(struct snd_pcm_substream *substream,
-				struct snd_soc_dai *dai)
-{
-	struct hdmi_priv *priv = snd_soc_dai_get_drvdata(dai);
-
-	priv->dssdev->driver->audio_disable(priv->dssdev);
-}
-
-static const struct snd_soc_dai_ops omap_hdmi_dai_ops = {
-	.startup	= omap_hdmi_dai_startup,
-	.hw_params	= omap_hdmi_dai_hw_params,
-	.prepare	= omap_hdmi_dai_prepare,
-	.trigger	= omap_hdmi_dai_trigger,
-	.shutdown	= omap_hdmi_dai_shutdown,
-};
-
-static struct snd_soc_dai_driver omap_hdmi_dai = {
-	.playback = {
-		.channels_min = 2,
-		.channels_max = 8,
-		.rates = OMAP_HDMI_RATES,
-		.formats = OMAP_HDMI_FORMATS,
-	},
-	.ops = &omap_hdmi_dai_ops,
-};
-
-static const struct snd_soc_component_driver omap_hdmi_component = {
-	.name		= DRV_NAME,
-};
-
-static int omap_hdmi_probe(struct platform_device *pdev)
-{
-	int ret;
-	struct resource *hdmi_rsrc;
-	struct hdmi_priv *hdmi_data;
-	bool hdmi_dev_found = false;
-
-	hdmi_data = devm_kzalloc(&pdev->dev, sizeof(*hdmi_data), GFP_KERNEL);
-	if (hdmi_data == NULL) {
-		dev_err(&pdev->dev, "Cannot allocate memory for HDMI data\n");
-		return -ENOMEM;
-	}
-
-	hdmi_rsrc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!hdmi_rsrc) {
-		dev_err(&pdev->dev, "Cannot obtain IORESOURCE_MEM HDMI\n");
-		return -ENODEV;
-	}
-
-	hdmi_data->dma_data.addr = hdmi_rsrc->start + OMAP_HDMI_AUDIO_DMA_PORT;
-
-	hdmi_rsrc = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-	if (!hdmi_rsrc) {
-		dev_err(&pdev->dev, "Cannot obtain IORESOURCE_DMA HDMI\n");
-		return -ENODEV;
-	}
-
-	hdmi_data->dma_req = hdmi_rsrc->start;
-	hdmi_data->dma_data.filter_data = &hdmi_data->dma_req;
-	hdmi_data->dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-
-	/*
-	 * TODO: We assume that there is only one DSS HDMI device. Future
-	 * OMAP implementations may support more than one HDMI devices and
-	 * we should provided separate audio support for all of them.
-	 */
-	/* Find an HDMI device. */
-	for_each_dss_dev(hdmi_data->dssdev) {
-		omap_dss_get_device(hdmi_data->dssdev);
-
-		if (!hdmi_data->dssdev->driver) {
-			omap_dss_put_device(hdmi_data->dssdev);
-			continue;
-		}
-
-		if (hdmi_data->dssdev->type == OMAP_DISPLAY_TYPE_HDMI) {
-			hdmi_dev_found = true;
-			break;
-		}
-	}
-
-	if (!hdmi_dev_found) {
-		dev_err(&pdev->dev, "no driver for HDMI display found\n");
-		return -ENODEV;
-	}
-
-	dev_set_drvdata(&pdev->dev, hdmi_data);
-	ret = snd_soc_register_component(&pdev->dev, &omap_hdmi_component,
-					 &omap_hdmi_dai, 1);
-
-	if (ret)
-		return ret;
-
-	return omap_pcm_platform_register(&pdev->dev);
-}
-
-static int omap_hdmi_remove(struct platform_device *pdev)
-{
-	struct hdmi_priv *hdmi_data = dev_get_drvdata(&pdev->dev);
-
-	snd_soc_unregister_component(&pdev->dev);
-
-	if (hdmi_data == NULL) {
-		dev_err(&pdev->dev, "cannot obtain HDMi data\n");
-		return -ENODEV;
-	}
-
-	omap_dss_put_device(hdmi_data->dssdev);
-	return 0;
-}
-
-static struct platform_driver hdmi_dai_driver = {
-	.driver = {
-		.name = DRV_NAME,
-		.owner = THIS_MODULE,
-	},
-	.probe = omap_hdmi_probe,
-	.remove = omap_hdmi_remove,
-};
-
-module_platform_driver(hdmi_dai_driver);
-
-MODULE_AUTHOR("Jorge Candelaria <jorge.candelaria@ti.com>");
-MODULE_AUTHOR("Ricardo Neri <ricardo.neri@ti.com>");
-MODULE_DESCRIPTION("OMAP HDMI SoC Interface");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/omap/omap-hdmi.h b/sound/soc/omap/omap-hdmi.h
deleted file mode 100644
index 6ad2bf4f2697..000000000000
--- a/sound/soc/omap/omap-hdmi.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * omap-hdmi.h
- *
- * Definitions for OMAP ALSA SoC DAI driver for HDMI audio on OMAP4 processors.
- * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/
- * Authors: Jorge Candelaria <jorge.candelaria@ti.com>
- *          Ricardo Neri <ricardo.neri@ti.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#ifndef __OMAP_HDMI_H__
-#define __OMAP_HDMI_H__
-
-#define OMAP_HDMI_AUDIO_DMA_PORT 0x8c
-
-#define OMAP_HDMI_RATES	(SNDRV_PCM_RATE_32000 | \
-				SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \
-				SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | \
-				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000)
-
-#define OMAP_HDMI_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
-				SNDRV_PCM_FMTBIT_S24_LE)
-
-#endif