video/exynos: dp: Move hotplug into a workqueue
authorSean Paul <seanpaul@chromium.org>
Fri, 3 Aug 2012 05:47:53 +0000 (22:47 -0700)
committerGerrit <chrome-bot@google.com>
Tue, 7 Aug 2012 16:08:39 +0000 (09:08 -0700)
Move the hotplug related code from probe and resume into a workqueue.
This allows us to initialize the DP driver (and resume it) when there
is no monitor connected.

BUG=chrome-os-partner:10829
BUG=chrome-os-partner:11158
BUG=chrome-os-partner:12046
TEST=Tested on snow, screen came up on power-on and resume

Change-Id: I1cd21d8430541396a376dc31c0be51a29f0560fc
Signed-off-by: Sean Paul <seanpaul@chromium.org>
Reviewed-on: https://gerrit.chromium.org/gerrit/29143
Reviewed-by: Olof Johansson <olofj@chromium.org>
drivers/video/exynos/exynos_dp_core.c
drivers/video/exynos/exynos_dp_core.h

index b98daa7..ac67b83 100644 (file)
@@ -728,7 +728,7 @@ static int exynos_dp_set_hw_link_train(struct exynos_dp_device *dp,
 
        if (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
                dev_err(dp->dev, "PLL is not locked yet.\n");
-               return -EINVAL;
+               return -EAGAIN;
        }
 
        exynos_dp_reset_macro(dp);
@@ -812,22 +812,19 @@ static int exynos_dp_set_link_train(struct exynos_dp_device *dp,
        return retval;
 }
 
-static void exynos_dp_config_video(struct work_struct *work)
+static int exynos_dp_config_video(struct exynos_dp_device *dp)
 {
-       struct exynos_dp_device *dp;
        int retval = 0;
        int timeout_loop = 0;
        int done_count = 0;
 
-       dp = container_of(work, struct exynos_dp_device, config_work);
-
        exynos_dp_config_video_slave_mode(dp);
 
        exynos_dp_set_video_color_format(dp);
 
        if (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
                dev_err(dp->dev, "PLL is not locked yet.\n");
-               return;
+               return -EINVAL;
        }
 
        for (;;) {
@@ -836,7 +833,7 @@ static void exynos_dp_config_video(struct work_struct *work)
                        break;
                if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
                        dev_err(dp->dev, "Timeout of video streamclk ok\n");
-                       return;
+                       return -ETIMEDOUT;
                }
 
                mdelay(100);
@@ -870,7 +867,7 @@ static void exynos_dp_config_video(struct work_struct *work)
                }
                if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
                        dev_err(dp->dev, "Timeout of video streamclk ok\n");
-                       return;
+                       return -ETIMEDOUT;
                }
 
                mdelay(100);
@@ -878,6 +875,8 @@ static void exynos_dp_config_video(struct work_struct *work)
 
        if (retval != 0)
                dev_err(dp->dev, "Video stream is not detected!\n");
+
+       return retval;
 }
 
 static void exynos_dp_enable_scramble(struct exynos_dp_device *dp, bool enable)
@@ -913,6 +912,47 @@ static irqreturn_t exynos_dp_irq_handler(int irq, void *arg)
        return IRQ_HANDLED;
 }
 
+static void exynos_dp_hotplug(struct work_struct *work)
+{
+       struct exynos_dp_device *dp;
+       int ret;
+
+       dp = container_of(work, struct exynos_dp_device, hotplug_work);
+
+       ret = exynos_dp_detect_hpd(dp);
+       if (ret) {
+               dev_err(dp->dev, "unable to detect hpd\n");
+               return;
+       }
+
+       ret = exynos_dp_handle_edid(dp);
+       if (ret) {
+               dev_err(dp->dev, "unable to handle edid\n");
+               return;
+       }
+
+       if (dp->training_type == SW_LINK_TRAINING)
+               ret = exynos_dp_set_link_train(dp, dp->video_info->lane_count,
+                                               dp->video_info->link_rate);
+       else
+               ret = exynos_dp_set_hw_link_train(dp,
+                       dp->video_info->lane_count, dp->video_info->link_rate);
+       if (ret) {
+               dev_err(dp->dev, "unable to do link train\n");
+               return;
+       }
+
+       exynos_dp_enable_scramble(dp, 1);
+       exynos_dp_enable_rx_to_enhanced_mode(dp, 1);
+       exynos_dp_enable_enhanced_mode(dp, 1);
+
+       exynos_dp_set_lane_count(dp, dp->video_info->lane_count);
+       exynos_dp_set_link_bandwidth(dp, dp->video_info->link_rate);
+
+       exynos_dp_init_video(dp);
+       exynos_dp_config_video(dp);
+}
+
 static int __devinit exynos_dp_probe(struct platform_device *pdev)
 {
        struct resource *res;
@@ -975,6 +1015,7 @@ static int __devinit exynos_dp_probe(struct platform_device *pdev)
                goto err_ioremap;
        }
 
+       dp->training_type = pdata->training_type;
        dp->video_info = pdata->video_info;
        if (pdata->phy_init)
                pdata->phy_init();
@@ -988,43 +1029,13 @@ static int __devinit exynos_dp_probe(struct platform_device *pdev)
                goto err_ioremap;
        }
 
-       ret = exynos_dp_detect_hpd(dp);
-       if (ret) {
-               dev_err(&pdev->dev, "unable to detect hpd\n");
-               goto err_irq;
-       }
-
-       exynos_dp_handle_edid(dp);
-
-       if (pdata->training_type == SW_LINK_TRAINING)
-               ret = exynos_dp_set_link_train(dp, dp->video_info->lane_count,
-                                               dp->video_info->link_rate);
-       else
-               ret = exynos_dp_set_hw_link_train(dp,
-                       dp->video_info->lane_count, dp->video_info->link_rate);
-       if (ret) {
-               dev_err(&pdev->dev, "unable to do link train\n");
-               goto err_irq;
-       }
-
-       exynos_dp_enable_scramble(dp, 1);
-       exynos_dp_enable_rx_to_enhanced_mode(dp, 1);
-       exynos_dp_enable_enhanced_mode(dp, 1);
-
-       exynos_dp_set_lane_count(dp, dp->video_info->lane_count);
-       exynos_dp_set_link_bandwidth(dp, dp->video_info->link_rate);
-
-       exynos_dp_init_video(dp);
-
-       INIT_WORK(&dp->config_work, exynos_dp_config_video);
-       schedule_work(&dp->config_work);
+       INIT_WORK(&dp->hotplug_work, exynos_dp_hotplug);
 
        platform_set_drvdata(pdev, dp);
+       schedule_work(&dp->hotplug_work);
 
        return 0;
 
-err_irq:
-       free_irq(dp->irq, dp);
 err_ioremap:
        iounmap(dp->reg_base);
 err_req_region:
@@ -1042,8 +1053,8 @@ static int __devexit exynos_dp_remove(struct platform_device *pdev)
        struct exynos_dp_platdata *pdata = pdev->dev.platform_data;
        struct exynos_dp_device *dp = platform_get_drvdata(pdev);
 
-       if (work_pending(&dp->config_work))
-               flush_work_sync(&dp->config_work);
+       if (work_pending(&dp->hotplug_work))
+               flush_work_sync(&dp->hotplug_work);
 
        if (pdata && pdata->phy_exit)
                pdata->phy_exit();
@@ -1068,8 +1079,8 @@ static int exynos_dp_suspend(struct device *dev)
        struct exynos_dp_platdata *pdata = pdev->dev.platform_data;
        struct exynos_dp_device *dp = platform_get_drvdata(pdev);
 
-       if (work_pending(&dp->config_work))
-               flush_work_sync(&dp->config_work);
+       if (work_pending(&dp->hotplug_work))
+               flush_work_sync(&dp->hotplug_work);
 
        if (pdata && pdata->phy_exit)
                pdata->phy_exit();
@@ -1091,26 +1102,7 @@ static int exynos_dp_resume(struct device *dev)
        clk_enable(dp->clock);
 
        exynos_dp_init_dp(dp);
-
-       exynos_dp_detect_hpd(dp);
-       exynos_dp_handle_edid(dp);
-
-       if (pdata->training_type == SW_LINK_TRAINING)
-               exynos_dp_set_link_train(dp, dp->video_info->lane_count,
-                                               dp->video_info->link_rate);
-       else
-               exynos_dp_set_hw_link_train(dp,
-                       dp->video_info->lane_count, dp->video_info->link_rate);
-
-       exynos_dp_enable_scramble(dp, 1);
-       exynos_dp_enable_rx_to_enhanced_mode(dp, 1);
-       exynos_dp_enable_enhanced_mode(dp, 1);
-
-       exynos_dp_set_lane_count(dp, dp->video_info->lane_count);
-       exynos_dp_set_link_bandwidth(dp, dp->video_info->link_rate);
-
-       exynos_dp_init_video(dp);
-       schedule_work(&dp->config_work);
+       schedule_work(&dp->hotplug_work);
 
        return 0;
 }
index 1a35c9a..a4c0278 100644 (file)
@@ -32,8 +32,9 @@ struct exynos_dp_device {
        void __iomem            *reg_base;
 
        struct video_info       *video_info;
+       enum link_training_type training_type;
        struct link_train       link_train;
-       struct work_struct      config_work;
+       struct work_struct      hotplug_work;
 };
 
 /* exynos_dp_reg.c */