OMAP: DSS2: Use PM runtime & HWMOD support
[deliverable/linux.git] / drivers / video / omap2 / dss / hdmi.c
index b630c988fd5125f9990d57a16db969ab0c4cf684..635cc002a4382983bc189fb16ad49987eb8275a6 100644 (file)
@@ -30,6 +30,8 @@
 #include <linux/delay.h>
 #include <linux/string.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/clk.h>
 #include <video/omapdss.h>
 #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
        defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
@@ -52,6 +54,9 @@ static struct {
        u8 edid_set;
        bool custom_set;
        struct hdmi_config cfg;
+
+       struct clk *sys_clk;
+       struct clk *hdmi_clk;
 } hdmi;
 
 /*
@@ -163,6 +168,27 @@ static inline int hdmi_wait_for_bit_change(const struct hdmi_reg idx,
        return val;
 }
 
+static int hdmi_runtime_get(void)
+{
+       int r;
+
+       DSSDBG("hdmi_runtime_get\n");
+
+       r = pm_runtime_get_sync(&hdmi.pdev->dev);
+       WARN_ON(r < 0);
+       return r < 0 ? r : 0;
+}
+
+static void hdmi_runtime_put(void)
+{
+       int r;
+
+       DSSDBG("hdmi_runtime_put\n");
+
+       r = pm_runtime_put(&hdmi.pdev->dev);
+       WARN_ON(r < 0);
+}
+
 int hdmi_init_display(struct omap_dss_device *dssdev)
 {
        DSSDBG("init_display\n");
@@ -312,30 +338,11 @@ static int hdmi_phy_init(void)
        return 0;
 }
 
-static int hdmi_wait_softreset(void)
-{
-       /* reset W1 */
-       REG_FLD_MOD(HDMI_WP_SYSCONFIG, 0x1, 0, 0);
-
-       /* wait till SOFTRESET == 0 */
-       if (hdmi_wait_for_bit_change(HDMI_WP_SYSCONFIG, 0, 0, 0) != 0) {
-               DSSERR("sysconfig reset failed\n");
-               return -ETIMEDOUT;
-       }
-
-       return 0;
-}
-
 static int hdmi_pll_program(struct hdmi_pll_info *fmt)
 {
        u16 r = 0;
        enum hdmi_clk_refsel refsel;
 
-       /* wait for wrapper reset */
-       r = hdmi_wait_softreset();
-       if (r)
-               return r;
-
        r = hdmi_set_pll_pwr(HDMI_PLLPWRCMD_ALLOFF);
        if (r)
                return r;
@@ -1065,7 +1072,7 @@ static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy,
        unsigned long clkin, refclk;
        u32 mf;
 
-       clkin = dss_clk_get_rate(DSS_CLK_SYSCK) / 10000;
+       clkin = clk_get_rate(hdmi.sys_clk) / 10000;
        /*
         * Input clock is predivided by N + 1
         * out put of which is reference clk
@@ -1099,16 +1106,6 @@ static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy,
        DSSDBG("range = %d sd = %d\n", pi->dcofreq, pi->regsd);
 }
 
-static void hdmi_enable_clocks(int enable)
-{
-       if (enable)
-               dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK |
-                               DSS_CLK_SYSCK | DSS_CLK_VIDFCK);
-       else
-               dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK |
-                               DSS_CLK_SYSCK | DSS_CLK_VIDFCK);
-}
-
 static int hdmi_power_on(struct omap_dss_device *dssdev)
 {
        int r, code = 0;
@@ -1116,7 +1113,9 @@ static int hdmi_power_on(struct omap_dss_device *dssdev)
        struct omap_video_timings *p;
        unsigned long phy;
 
-       hdmi_enable_clocks(1);
+       r = hdmi_runtime_get();
+       if (r)
+               return r;
 
        dispc_enable_channel(OMAP_DSS_CHANNEL_DIGIT, 0);
 
@@ -1181,7 +1180,7 @@ static int hdmi_power_on(struct omap_dss_device *dssdev)
 
        return 0;
 err:
-       hdmi_enable_clocks(0);
+       hdmi_runtime_put();
        return -EIO;
 }
 
@@ -1192,7 +1191,7 @@ static void hdmi_power_off(struct omap_dss_device *dssdev)
        hdmi_wp_video_start(0);
        hdmi_phy_off();
        hdmi_set_pll_pwr(HDMI_PLLPWRCMD_ALLOFF);
-       hdmi_enable_clocks(0);
+       hdmi_runtime_put();
 
        hdmi.edid_set = 0;
 }
@@ -1687,14 +1686,43 @@ static struct snd_soc_dai_driver hdmi_codec_dai_drv = {
 };
 #endif
 
+static int hdmi_get_clocks(struct platform_device *pdev)
+{
+       struct clk *clk;
+
+       clk = 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;
+
+       clk = clk_get(&pdev->dev, "fck");
+       if (IS_ERR(clk)) {
+               DSSERR("can't get fck\n");
+               clk_put(hdmi.sys_clk);
+               return PTR_ERR(clk);
+       }
+
+       hdmi.hdmi_clk = clk;
+
+       return 0;
+}
+
+static void hdmi_put_clocks(void)
+{
+       if (hdmi.sys_clk)
+               clk_put(hdmi.sys_clk);
+       if (hdmi.hdmi_clk)
+               clk_put(hdmi.hdmi_clk);
+}
+
 /* HDMI HW IP initialisation */
 static int omapdss_hdmihw_probe(struct platform_device *pdev)
 {
        struct resource *hdmi_mem;
-#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
-       defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
-       int ret;
-#endif
+       int r;
 
        hdmi.pdata = pdev->dev.platform_data;
        hdmi.pdev = pdev;
@@ -1714,17 +1742,25 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
 
+       r = hdmi_get_clocks(pdev);
+       if (r) {
+               iounmap(hdmi.base_wp);
+               return r;
+       }
+
+       pm_runtime_enable(&pdev->dev);
+
        hdmi_panel_init();
 
 #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
        defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
 
        /* Register ASoC codec DAI */
-       ret = snd_soc_register_codec(&pdev->dev, &hdmi_audio_codec_drv,
+       r = snd_soc_register_codec(&pdev->dev, &hdmi_audio_codec_drv,
                                        &hdmi_codec_dai_drv, 1);
-       if (ret) {
+       if (r) {
                DSSERR("can't register ASoC HDMI audio codec\n");
-               return ret;
+               return r;
        }
 #endif
        return 0;
@@ -1739,17 +1775,62 @@ static int omapdss_hdmihw_remove(struct platform_device *pdev)
        snd_soc_unregister_codec(&pdev->dev);
 #endif
 
+       pm_runtime_disable(&pdev->dev);
+
+       hdmi_put_clocks();
+
        iounmap(hdmi.base_wp);
 
        return 0;
 }
 
+static int hdmi_runtime_suspend(struct device *dev)
+{
+       clk_disable(hdmi.hdmi_clk);
+       clk_disable(hdmi.sys_clk);
+
+       dispc_runtime_put();
+       dss_runtime_put();
+
+       return 0;
+}
+
+static int hdmi_runtime_resume(struct device *dev)
+{
+       int r;
+
+       r = dss_runtime_get();
+       if (r < 0)
+               goto err_get_dss;
+
+       r = dispc_runtime_get();
+       if (r < 0)
+               goto err_get_dispc;
+
+
+       clk_enable(hdmi.sys_clk);
+       clk_enable(hdmi.hdmi_clk);
+
+       return 0;
+
+err_get_dispc:
+       dss_runtime_put();
+err_get_dss:
+       return r;
+}
+
+static const struct dev_pm_ops hdmi_pm_ops = {
+       .runtime_suspend = hdmi_runtime_suspend,
+       .runtime_resume = hdmi_runtime_resume,
+};
+
 static struct platform_driver omapdss_hdmihw_driver = {
        .probe          = omapdss_hdmihw_probe,
        .remove         = omapdss_hdmihw_remove,
        .driver         = {
                .name   = "omapdss_hdmi",
                .owner  = THIS_MODULE,
+               .pm     = &hdmi_pm_ops,
        },
 };
 
This page took 0.02892 seconds and 5 git commands to generate.