From: Sean Paul Date: Fri, 3 Aug 2012 05:47:53 +0000 (-0700) Subject: video/exynos: dp: Move hotplug into a workqueue X-Git-Url: http://git.cascardo.eti.br/?a=commitdiff_plain;h=1430d140de72e9c2632a12d937d976b3bc48ed64;p=cascardo%2Flinux.git video/exynos: dp: Move hotplug into a workqueue 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 Reviewed-on: https://gerrit.chromium.org/gerrit/29143 Reviewed-by: Olof Johansson --- diff --git a/drivers/video/exynos/exynos_dp_core.c b/drivers/video/exynos/exynos_dp_core.c index b98daa7dc269..ac67b83a3842 100644 --- a/drivers/video/exynos/exynos_dp_core.c +++ b/drivers/video/exynos/exynos_dp_core.c @@ -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; } diff --git a/drivers/video/exynos/exynos_dp_core.h b/drivers/video/exynos/exynos_dp_core.h index 1a35c9a23286..a4c02789d5a4 100644 --- a/drivers/video/exynos/exynos_dp_core.h +++ b/drivers/video/exynos/exynos_dp_core.h @@ -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 */