video: tegra: delay HDMI hotplug detection until after resume
authorErik Gilling <konkers@android.com>
Wed, 10 Nov 2010 23:32:58 +0000 (15:32 -0800)
committerErik Gilling <konkers@android.com>
Thu, 11 Nov 2010 00:50:48 +0000 (16:50 -0800)
Change-Id: I87c35dc3e1287fc1d936e554013deb2f92cbd6f4
Signed-off-by: Erik Gilling <konkers@android.com>
drivers/video/tegra/dc/dc.c
drivers/video/tegra/dc/dc_priv.h
drivers/video/tegra/dc/hdmi.c

index d802535b913bb1f8a90f5eae08cee1779d9c09ef..f10f3c441e01bc08b6307dcf529447f55b53065e 100644 (file)
@@ -1102,6 +1102,10 @@ static int tegra_dc_suspend(struct nvhost_device *ndev, pm_message_t state)
        dev_info(&ndev->dev, "suspend\n");
 
        mutex_lock(&dc->lock);
+
+       if (dc->out_ops && dc->out_ops->suspend)
+               dc->out_ops->suspend(dc);
+
        if (dc->enabled) {
                tegra_fb_suspend(dc->fb);
                _tegra_dc_disable(dc);
@@ -1120,6 +1124,9 @@ static int tegra_dc_resume(struct nvhost_device *ndev)
        mutex_lock(&dc->lock);
        if (dc->enabled)
                _tegra_dc_enable(dc);
+
+       if (dc->out_ops && dc->out_ops->resume)
+               dc->out_ops->resume(dc);
        mutex_unlock(&dc->lock);
 
        return 0;
index 39a03e8fb9c0644603e28d7f4acd4eeefada786f..7d0e340a6ee219e4faa9edd2c97c7b67baa066ba 100644 (file)
@@ -42,6 +42,11 @@ struct tegra_dc_out_ops {
        void (*enable)(struct tegra_dc *dc);
        /* disable output.  dc clocks are on at this point */
        void (*disable)(struct tegra_dc *dc);
+
+       /* suspend output.  dc clocks are on at this point */
+       void (*suspend)(struct tegra_dc *dc);
+       /* resume output.  dc clocks are on at this point */
+       void (*resume)(struct tegra_dc *dc);
 };
 
 struct tegra_dc {
index f2179c3a785718d3c48230ed6ad4e5a0d7aa008c..6ad63ba791a4c7f4b996789b5157346b86d83e34 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
+#include <linux/spinlock.h>
 #include <linux/workqueue.h>
 
 #include <mach/clk.h>
@@ -52,6 +53,10 @@ struct tegra_dc_hdmi_data {
 
        struct clk                      *disp1_clk;
        struct clk                      *disp2_clk;
+
+       spinlock_t                      suspend_lock;
+       bool                            suspended;
+       bool                            hpd_pending;
 };
 
 const struct fb_videomode tegra_dc_hdmi_supported_modes[] = {
@@ -470,15 +475,49 @@ static irqreturn_t tegra_dc_hdmi_irq(int irq, void *ptr)
 {
        struct tegra_dc *dc = ptr;
        struct tegra_dc_hdmi_data *hdmi = tegra_dc_get_outdata(dc);
+       unsigned long flags;
 
-       if (tegra_dc_hdmi_hpd(dc))
-               schedule_delayed_work(&hdmi->work, msecs_to_jiffies(100));
-       else
-               schedule_delayed_work(&hdmi->work, msecs_to_jiffies(0));
+       spin_lock_irqsave(&hdmi->suspend_lock, flags);
+       if (hdmi->suspended) {
+               hdmi->hpd_pending = true;
+       } else {
+               if (tegra_dc_hdmi_hpd(dc))
+                       schedule_delayed_work(&hdmi->work, msecs_to_jiffies(100));
+               else
+                       schedule_delayed_work(&hdmi->work, msecs_to_jiffies(0));
+       }
+       spin_unlock_irqrestore(&hdmi->suspend_lock, flags);
 
        return IRQ_HANDLED;
 }
 
+static void tegra_dc_hdmi_suspend(struct tegra_dc *dc)
+{
+       struct tegra_dc_hdmi_data *hdmi = tegra_dc_get_outdata(dc);
+       unsigned long flags;
+
+       spin_lock_irqsave(&hdmi->suspend_lock, flags);
+       hdmi->suspended = true;
+       spin_unlock_irqrestore(&hdmi->suspend_lock, flags);
+}
+
+static void tegra_dc_hdmi_resume(struct tegra_dc *dc)
+{
+       struct tegra_dc_hdmi_data *hdmi = tegra_dc_get_outdata(dc);
+       unsigned long flags;
+
+       spin_lock_irqsave(&hdmi->suspend_lock, flags);
+       hdmi->suspended = false;
+       if (hdmi->hpd_pending) {
+               if (tegra_dc_hdmi_hpd(dc))
+                       schedule_delayed_work(&hdmi->work, msecs_to_jiffies(100));
+               else
+                       schedule_delayed_work(&hdmi->work, msecs_to_jiffies(0));
+               hdmi->hpd_pending = false;
+       }
+       spin_unlock_irqrestore(&hdmi->suspend_lock, flags);
+}
+
 static int tegra_dc_hdmi_init(struct tegra_dc *dc)
 {
        struct tegra_dc_hdmi_data *hdmi;
@@ -561,6 +600,9 @@ static int tegra_dc_hdmi_init(struct tegra_dc *dc)
        hdmi->clk = clk;
        hdmi->disp1_clk = disp1_clk;
        hdmi->disp2_clk = disp2_clk;
+       hdmi->suspended = false;
+       hdmi->hpd_pending = false;
+       spin_lock_init(&hdmi->suspend_lock);
 
        dc->out->depth = 24;
 
@@ -1054,5 +1096,7 @@ struct tegra_dc_out_ops tegra_dc_hdmi_ops = {
        .enable = tegra_dc_hdmi_enable,
        .disable = tegra_dc_hdmi_disable,
        .detect = tegra_dc_hdmi_detect,
+       .suspend = tegra_dc_hdmi_suspend,
+       .resume = tegra_dc_hdmi_resume,
 };