diff options
Diffstat (limited to 'kernel/drivers/video/fbdev/omap2/dss/hdmi4.c')
-rw-r--r-- | kernel/drivers/video/fbdev/omap2/dss/hdmi4.c | 96 |
1 files changed, 79 insertions, 17 deletions
diff --git a/kernel/drivers/video/fbdev/omap2/dss/hdmi4.c b/kernel/drivers/video/fbdev/omap2/dss/hdmi4.c index 916d47978..94c8d5549 100644 --- a/kernel/drivers/video/fbdev/omap2/dss/hdmi4.c +++ b/kernel/drivers/video/fbdev/omap2/dss/hdmi4.c @@ -32,6 +32,7 @@ #include <linux/clk.h> #include <linux/gpio.h> #include <linux/regulator/consumer.h> +#include <linux/component.h> #include <video/omapdss.h> #include <sound/omap-hdmi-audio.h> @@ -229,9 +230,9 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev) err_mgr_enable: hdmi_wp_video_stop(&hdmi.wp); err_vid_enable: -err_phy_cfg: hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF); err_phy_pwr: +err_phy_cfg: err_pll_cfg: dss_pll_disable(&hdmi.pll.pll); err_pll_enable: @@ -320,9 +321,22 @@ static int read_edid(u8 *buf, int len) return r; } +static void hdmi_start_audio_stream(struct omap_hdmi *hd) +{ + hdmi_wp_audio_enable(&hd->wp, true); + hdmi4_audio_start(&hd->core, &hd->wp); +} + +static void hdmi_stop_audio_stream(struct omap_hdmi *hd) +{ + hdmi4_audio_stop(&hd->core, &hd->wp); + hdmi_wp_audio_enable(&hd->wp, false); +} + static int hdmi_display_enable(struct omap_dss_device *dssdev) { struct omap_dss_device *out = &hdmi.output; + unsigned long flags; int r = 0; DSSDBG("ENTER hdmi_display_enable\n"); @@ -341,7 +355,21 @@ static int hdmi_display_enable(struct omap_dss_device *dssdev) goto err0; } + if (hdmi.audio_configured) { + r = hdmi4_audio_config(&hdmi.core, &hdmi.wp, &hdmi.audio_config, + hdmi.cfg.timings.pixelclock); + if (r) { + DSSERR("Error restoring audio configuration: %d", r); + hdmi.audio_abort_cb(&hdmi.pdev->dev); + hdmi.audio_configured = false; + } + } + + spin_lock_irqsave(&hdmi.audio_playing_lock, flags); + if (hdmi.audio_configured && hdmi.audio_playing) + hdmi_start_audio_stream(&hdmi); hdmi.display_enabled = true; + spin_unlock_irqrestore(&hdmi.audio_playing_lock, flags); mutex_unlock(&hdmi.lock); return 0; @@ -353,17 +381,19 @@ err0: static void hdmi_display_disable(struct omap_dss_device *dssdev) { + unsigned long flags; + DSSDBG("Enter hdmi_display_disable\n"); mutex_lock(&hdmi.lock); - if (hdmi.audio_pdev && hdmi.audio_abort_cb) - hdmi.audio_abort_cb(&hdmi.audio_pdev->dev); + spin_lock_irqsave(&hdmi.audio_playing_lock, flags); + hdmi_stop_audio_stream(&hdmi); + hdmi.display_enabled = false; + spin_unlock_irqrestore(&hdmi.audio_playing_lock, flags); hdmi_power_off_full(dssdev); - hdmi.display_enabled = false; - mutex_unlock(&hdmi.lock); } @@ -567,6 +597,8 @@ static int hdmi_audio_shutdown(struct device *dev) mutex_lock(&hd->lock); hd->audio_abort_cb = NULL; + hd->audio_configured = false; + hd->audio_playing = false; mutex_unlock(&hd->lock); return 0; @@ -575,25 +607,34 @@ static int hdmi_audio_shutdown(struct device *dev) static int hdmi_audio_start(struct device *dev) { struct omap_hdmi *hd = dev_get_drvdata(dev); + unsigned long flags; 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); + spin_lock_irqsave(&hd->audio_playing_lock, flags); + if (hd->display_enabled) + hdmi_start_audio_stream(hd); + hd->audio_playing = true; + + spin_unlock_irqrestore(&hd->audio_playing_lock, flags); return 0; } static void hdmi_audio_stop(struct device *dev) { struct omap_hdmi *hd = dev_get_drvdata(dev); + unsigned long flags; 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); + spin_lock_irqsave(&hd->audio_playing_lock, flags); + + if (hd->display_enabled) + hdmi_stop_audio_stream(hd); + hd->audio_playing = false; + + spin_unlock_irqrestore(&hd->audio_playing_lock, flags); } static int hdmi_audio_config(struct device *dev, @@ -611,7 +652,10 @@ static int hdmi_audio_config(struct device *dev, ret = hdmi4_audio_config(&hd->core, &hd->wp, dss_audio, hd->cfg.timings.pixelclock); - + if (!ret) { + hd->audio_configured = true; + hd->audio_config = *dss_audio; + } out: mutex_unlock(&hd->lock); @@ -646,8 +690,9 @@ static int hdmi_audio_register(struct device *dev) } /* HDMI HW IP initialisation */ -static int omapdss_hdmihw_probe(struct platform_device *pdev) +static int hdmi4_bind(struct device *dev, struct device *master, void *data) { + struct platform_device *pdev = to_platform_device(dev); int r; int irq; @@ -655,6 +700,7 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, &hdmi); mutex_init(&hdmi.lock); + spin_lock_init(&hdmi.audio_playing_lock); if (pdev->dev.of_node) { r = hdmi_probe_of(pdev); @@ -713,8 +759,10 @@ err: return r; } -static int __exit omapdss_hdmihw_remove(struct platform_device *pdev) +static void hdmi4_unbind(struct device *dev, struct device *master, void *data) { + struct platform_device *pdev = to_platform_device(dev); + if (hdmi.audio_pdev) platform_device_unregister(hdmi.audio_pdev); @@ -723,7 +771,21 @@ static int __exit omapdss_hdmihw_remove(struct platform_device *pdev) hdmi_pll_uninit(&hdmi.pll); pm_runtime_disable(&pdev->dev); +} + +static const struct component_ops hdmi4_component_ops = { + .bind = hdmi4_bind, + .unbind = hdmi4_unbind, +}; +static int hdmi4_probe(struct platform_device *pdev) +{ + return component_add(&pdev->dev, &hdmi4_component_ops); +} + +static int hdmi4_remove(struct platform_device *pdev) +{ + component_del(&pdev->dev, &hdmi4_component_ops); return 0; } @@ -756,8 +818,8 @@ static const struct of_device_id hdmi_of_match[] = { }; static struct platform_driver omapdss_hdmihw_driver = { - .probe = omapdss_hdmihw_probe, - .remove = __exit_p(omapdss_hdmihw_remove), + .probe = hdmi4_probe, + .remove = hdmi4_remove, .driver = { .name = "omapdss_hdmi", .pm = &hdmi_pm_ops, @@ -771,7 +833,7 @@ int __init hdmi4_init_platform_driver(void) return platform_driver_register(&omapdss_hdmihw_driver); } -void __exit hdmi4_uninit_platform_driver(void) +void hdmi4_uninit_platform_driver(void) { platform_driver_unregister(&omapdss_hdmihw_driver); } |