diff options
author | Sebastien Jan <s-jan@ti.com> | 2011-04-07 08:38:42 +0100 |
---|---|---|
committer | Andy Green <andy.green@linaro.org> | 2011-04-07 08:38:42 +0100 |
commit | ecfaee825b9df66c99c65c678eff3e399a82848e (patch) | |
tree | 32c439c649b82a718907e5ac8bf2ab88df2e0155 /drivers/video | |
parent | 49da1a9af916aea045cd523822904406856dc387 (diff) |
OMAP4: DSS: add generic notifier mechanism
A callback can be registered by the dssdev client in order to be
notified of resolution changes, for example an external monitor
that is hot-plugged.
Multiple clients can now register for notification from one
dssdev, and the notification mechanism can be extended in the
future to add other events.
This is a port of Rob Clark's <rob@ti.com> original patch.
Signed-off-by: Sebastien Jan <s-jan@ti.com>
Diffstat (limited to 'drivers/video')
-rw-r--r-- | drivers/video/omap2/dss/core.c | 3 | ||||
-rw-r--r-- | drivers/video/omap2/dss/display.c | 49 | ||||
-rw-r--r-- | drivers/video/omap2/dss/hdmi.c | 9 |
3 files changed, 60 insertions, 1 deletions
diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c index 1aa2ed1e786..19075085f96 100644 --- a/drivers/video/omap2/dss/core.c +++ b/drivers/video/omap2/dss/core.c @@ -491,6 +491,9 @@ int omap_dss_register_device(struct omap_dss_device *dssdev) dssdev->dev.parent = &dss_bus; dssdev->dev.release = omap_dss_dev_release; dev_set_name(&dssdev->dev, "display%d", dev_num++); + + BLOCKING_INIT_NOTIFIER_HEAD(&dssdev->notifier); + return device_register(&dssdev->dev); } diff --git a/drivers/video/omap2/dss/display.c b/drivers/video/omap2/dss/display.c index a85a6f38b40..fa9df604387 100644 --- a/drivers/video/omap2/dss/display.c +++ b/drivers/video/omap2/dss/display.c @@ -26,6 +26,7 @@ #include <linux/module.h> #include <linux/jiffies.h> #include <linux/platform_device.h> +#include <linux/slab.h> #include <plat/display.h> #include "dss.h" @@ -614,3 +615,51 @@ void omap_dss_stop_device(struct omap_dss_device *dssdev) } EXPORT_SYMBOL(omap_dss_stop_device); +/* since omap_dss_update_size can be called in irq context, schedule work from + * work-queue to deliver notification to client.. + */ +struct notify_work { + struct work_struct work; + struct omap_dss_device *dssdev; + enum omap_dss_event evt; +}; + +static void notify_worker(struct work_struct *work) +{ + struct notify_work *nw = + container_of(work, struct notify_work, work); + struct omap_dss_device *dssdev = nw->dssdev; + blocking_notifier_call_chain(&dssdev->notifier, nw->evt, dssdev); + kfree(work); +} + +/** + * Called by lower level driver to notify about a change in resolution, etc. + */ +void omap_dss_notify(struct omap_dss_device *dssdev, enum omap_dss_event evt) +{ + struct notify_work *nw = + kmalloc(sizeof(struct notify_work), GFP_KERNEL); + if (nw) { + INIT_WORK(&nw->work, notify_worker); + nw->dssdev = dssdev; + nw->evt = evt; + schedule_work(&nw->work); + } +} +EXPORT_SYMBOL(omap_dss_notify); + +void omap_dss_add_notify(struct omap_dss_device *dssdev, + struct notifier_block *nb) +{ + blocking_notifier_chain_register(&dssdev->notifier, nb); +} +EXPORT_SYMBOL(omap_dss_add_notify); + +void omap_dss_remove_notify(struct omap_dss_device *dssdev, + struct notifier_block *nb) +{ + blocking_notifier_chain_unregister(&dssdev->notifier, nb); +} +EXPORT_SYMBOL(omap_dss_remove_notify); + diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c index 0d44f070ef3..71900d44a4f 100644 --- a/drivers/video/omap2/dss/hdmi.c +++ b/drivers/video/omap2/dss/hdmi.c @@ -1104,6 +1104,7 @@ static void hdmi_enable_clocks(int enable) static int hdmi_power_on(struct omap_dss_device *dssdev) { int r, code = 0; + int dirty = true; struct hdmi_pll_info pll_data; struct omap_video_timings *p; int clkin, n, phy; @@ -1119,8 +1120,10 @@ static int hdmi_power_on(struct omap_dss_device *dssdev) dssdev->panel.timings.y_res); if (!hdmi.custom_set) { + code = get_timings_index(); DSSDBG("Read EDID as no EDID is not set on poweron\n"); hdmi_read_edid(p); + dirty = get_timings_index() != code; } code = get_timings_index(); dssdev->panel.timings = cea_vesa_timings[code].timings; @@ -1134,7 +1137,11 @@ static int hdmi_power_on(struct omap_dss_device *dssdev) hdmi_wp_video_start(0); - /* config the PLL and PHY first */ + if (dirty) { + omap_dss_notify(dssdev, OMAP_DSS_SIZE_CHANGE); + } + + /* config the PLL and PHY first */ r = hdmi_pll_program(&pll_data); if (r) { DSSDBG("Failed to lock PLL\n"); |