diff options
author | Tomi Valkeinen <tomi.valkeinen@ti.com> | 2011-05-27 10:52:19 +0300 |
---|---|---|
committer | Tomi Valkeinen <tomi.valkeinen@ti.com> | 2011-07-25 10:22:04 +0300 |
commit | 4fbafaf371be780ed2cd73a520dfeafa1ea73e24 (patch) | |
tree | 50be77c643fe710ce07bfea5e21587f9f5c38ac5 /drivers/video/omap2/dss/hdmi.c | |
parent | de3050a74e2d2830189ceaa5f5fc05b776518d68 (diff) |
OMAP: DSS2: Use PM runtime & HWMOD support
Use PM runtime and HWMOD support to handle enabling and disabling of DSS
modules.
Each DSS module will have get and put functions which can be used to
enable and disable that module. The functions use pm_runtime and hwmod
opt-clocks to enable the hardware.
Acked-by: Kevin Hilman <khilman@ti.com>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
Diffstat (limited to 'drivers/video/omap2/dss/hdmi.c')
-rw-r--r-- | drivers/video/omap2/dss/hdmi.c | 161 |
1 files changed, 121 insertions, 40 deletions
diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c index b630c988fd51..635cc002a438 100644 --- a/drivers/video/omap2/dss/hdmi.c +++ b/drivers/video/omap2/dss/hdmi.c @@ -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, }, }; |