diff mbox

[2/3] drm: exynos: hdmi: add exynos5 support to hdmi driver

Message ID 1347451727-13386-3-git-send-email-rahul.sharma@samsung.com (mailing list archive)
State New, archived
Headers show

Commit Message

Rahul Sharma Sept. 12, 2012, 12:08 p.m. UTC
Added support for exynos5 to hdmi driver. Resource init
is splitted for exynos5 and exynos4. Exynos5 hdmi driver
is dt based while exynos4 hdmi driver is not.

Signed-off-by: Rahul Sharma <rahul.sharma@samsung.com>
Signed-off-by: Shirish S <s.shirish@samsung.com>
Signed-off-by: Fahad Kunnathadi <fahad.k@samsung.com>
---
 drivers/gpu/drm/exynos/exynos_hdmi.c |  300 ++++++++++++++++++++++++++++++----
 1 files changed, 269 insertions(+), 31 deletions(-)

Comments

Joonyoung Shim Sept. 13, 2012, 1:23 a.m. UTC | #1
Hi, Rahul.

Overall, i think this patch causes messy codes.

On 09/12/2012 09:08 PM, Rahul Sharma wrote:
> Added support for exynos5 to hdmi driver. Resource init
> is splitted for exynos5 and exynos4. Exynos5 hdmi driver
> is dt based while exynos4 hdmi driver is not.
>
> Signed-off-by: Rahul Sharma <rahul.sharma@samsung.com>
> Signed-off-by: Shirish S <s.shirish@samsung.com>
> Signed-off-by: Fahad Kunnathadi <fahad.k@samsung.com>
> ---
>   drivers/gpu/drm/exynos/exynos_hdmi.c |  300 ++++++++++++++++++++++++++++++----
>   1 files changed, 269 insertions(+), 31 deletions(-)
>
> diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
> index a6aea6f..5236256 100644
> --- a/drivers/gpu/drm/exynos/exynos_hdmi.c
> +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
> @@ -32,6 +32,9 @@
>   #include <linux/pm_runtime.h>
>   #include <linux/clk.h>
>   #include <linux/regulator/consumer.h>
> +#include <linux/io.h>
> +#include <linux/of_gpio.h>
> +#include <plat/gpio-cfg.h>
>   
>   #include <drm/exynos_drm.h>
>   
> @@ -61,11 +64,13 @@ struct hdmi_context {
>   	bool				powered;
>   	bool				is_v13;
>   	bool				dvi_mode;
> +	bool				is_soc_exynos5;
>   	struct mutex			hdmi_mutex;
>   
>   	void __iomem			*regs;
> -	unsigned int			external_irq;
> -	unsigned int			internal_irq;
> +	int						external_irq;
> +	int						internal_irq;
> +	int						hpd_gpio;
>   
>   	struct i2c_client		*ddc_port;
>   	struct i2c_client		*hdmiphy_port;
> @@ -953,6 +958,23 @@ static inline void hdmi_reg_writemask(struct hdmi_context *hdata,
>   	writel(value, hdata->regs + reg_id);
>   }
>   
> +static void hdmi_cfg_hpd(struct hdmi_context *hdata, bool internal)
> +{
> +	if (!internal) {
> +		s3c_gpio_cfgpin(hdata->hpd_gpio, S3C_GPIO_SFN(0xf));
> +		s3c_gpio_setpull(hdata->hpd_gpio, S3C_GPIO_PULL_DOWN);
> +	} else {
> +		s3c_gpio_cfgpin(hdata->hpd_gpio, S3C_GPIO_SFN(3));
> +		s3c_gpio_setpull(hdata->hpd_gpio, S3C_GPIO_PULL_NONE);
> +	}
> +}
> +

Don't use SoC specific functions in the driver.

> +static int hdmi_get_hpd(struct hdmi_context *hdata)
> +{
> +	int gpio_stat = gpio_get_value(hdata->hpd_gpio);
> +	return gpio_stat;
> +}
> +

Actually, above two functions should come from platform data, but these
will remove soon.

>   static void hdmi_v13_regs_dump(struct hdmi_context *hdata, char *prefix)
>   {
>   #define DUMPREG(reg_id) \
> @@ -2026,6 +2048,9 @@ static void hdmi_poweron(struct hdmi_context *hdata)
>   
>   	if (hdata->cfg_hpd)
>   		hdata->cfg_hpd(true);
> +	else
> +		hdmi_cfg_hpd(hdata, true);
> +
>   	mutex_unlock(&hdata->hdmi_mutex);
>   
>   	pm_runtime_get_sync(hdata->dev);
> @@ -2063,6 +2088,8 @@ static void hdmi_poweroff(struct hdmi_context *hdata)
>   	mutex_lock(&hdata->hdmi_mutex);
>   	if (hdata->cfg_hpd)
>   		hdata->cfg_hpd(false);
> +	else
> +		hdmi_cfg_hpd(hdata, false);
>   
>   	hdata->powered = false;
>   
> @@ -2110,17 +2137,16 @@ static irqreturn_t hdmi_external_irq_thread(int irq, void *arg)
>   	struct exynos_drm_hdmi_context *ctx = arg;
>   	struct hdmi_context *hdata = ctx->ctx;
>   
> -	if (!hdata->get_hpd)
> -		goto out;
> -
>   	mutex_lock(&hdata->hdmi_mutex);
> -	hdata->hpd = hdata->get_hpd();
> +	if (hdata->get_hpd)
> +		hdata->hpd = hdata->get_hpd();
> +	else
> +		hdata->hpd = hdmi_get_hpd(hdata);
>   	mutex_unlock(&hdata->hdmi_mutex);
>   
>   	if (ctx->drm_dev)
>   		drm_helper_hpd_irq_event(ctx->drm_dev);
>   
> -out:
>   	return IRQ_HANDLED;
>   }
>   
> @@ -2203,23 +2229,25 @@ static int __devinit hdmi_resources_init(struct hdmi_context *hdata)
>   
>   	clk_set_parent(res->sclk_hdmi, res->sclk_pixel);
>   
> -	res->regul_bulk = kzalloc(ARRAY_SIZE(supply) *
> -		sizeof(res->regul_bulk[0]), GFP_KERNEL);
> -	if (!res->regul_bulk) {
> -		DRM_ERROR("failed to get memory for regulators\n");
> -		goto fail;
> -	}
> -	for (i = 0; i < ARRAY_SIZE(supply); ++i) {
> -		res->regul_bulk[i].supply = supply[i];
> -		res->regul_bulk[i].consumer = NULL;
> -	}
> -	ret = regulator_bulk_get(dev, ARRAY_SIZE(supply), res->regul_bulk);
> -	if (ret) {
> -		DRM_ERROR("failed to get regulators\n");
> -		goto fail;
> +	if (!hdata->is_soc_exynos5) {
> +		res->regul_bulk = kzalloc(ARRAY_SIZE(supply) *
> +			sizeof(res->regul_bulk[0]), GFP_KERNEL);
> +		if (!res->regul_bulk) {
> +			DRM_ERROR("failed to get memory for regulators\n");
> +			goto fail;
> +		}
> +		for (i = 0; i < ARRAY_SIZE(supply); ++i) {
> +			res->regul_bulk[i].supply = supply[i];
> +			res->regul_bulk[i].consumer = NULL;
> +		}
> +		ret = regulator_bulk_get(dev, ARRAY_SIZE(supply),
> +			res->regul_bulk);
> +		if (ret) {
> +			DRM_ERROR("failed to get regulators\n");
> +			goto fail;
> +		}
> +		res->regul_count = ARRAY_SIZE(supply);
>   	}
> -	res->regul_count = ARRAY_SIZE(supply);
> -
>   	return 0;
>   fail:
>   	DRM_ERROR("HDMI resource init - failed\n");
> @@ -2262,7 +2290,8 @@ void hdmi_attach_hdmiphy_client(struct i2c_client *hdmiphy)
>   		hdmi_hdmiphy = hdmiphy;
>   }
>   
> -static int __devinit hdmi_probe(struct platform_device *pdev)
> +static int __devinit hdmi_resources_init_exynos4(
> +	struct platform_device *pdev)
>   {
>   	struct device *dev = &pdev->dev;
>   	struct exynos_drm_hdmi_context *drm_hdmi_ctx;
> @@ -2271,7 +2300,7 @@ static int __devinit hdmi_probe(struct platform_device *pdev)
>   	struct resource *res;
>   	int ret;
>   
> -	DRM_DEBUG_KMS("[%d]\n", __LINE__);
> +	DRM_DEBUG_KMS("[%d][%s]\n", __LINE__, __func__);
>   
>   	pdata = pdev->dev.platform_data;
>   	if (!pdata) {
> @@ -2304,14 +2333,21 @@ static int __devinit hdmi_probe(struct platform_device *pdev)
>   	hdata->cfg_hpd = pdata->cfg_hpd;
>   	hdata->get_hpd = pdata->get_hpd;
>   	hdata->dev = dev;
> +	hdata->is_soc_exynos5 = false;
>   
>   	ret = hdmi_resources_init(hdata);
>   	if (ret) {
>   		ret = -EINVAL;
> +		DRM_ERROR("hdmi_resources_init failed\n");
>   		goto err_data;
>   	}
>   
>   	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!res) {
> +		DRM_ERROR("failed to find registers\n");
> +		ret = -ENOENT;
> +		goto err_resource;
> +	}
>   
>   	hdata->regs = devm_request_and_ioremap(&pdev->dev, res);
>   	if (!hdata->regs) {
> @@ -2340,7 +2376,7 @@ static int __devinit hdmi_probe(struct platform_device *pdev)
>   
>   	hdata->external_irq = platform_get_irq_byname(pdev, "external_irq");
>   	if (hdata->external_irq < 0) {
> -		DRM_ERROR("failed to get platform irq\n");
> +		DRM_ERROR("failed to get platform external irq\n");
>   		ret = hdata->external_irq;
>   		goto err_hdmiphy;
>   	}
> @@ -2357,7 +2393,7 @@ static int __devinit hdmi_probe(struct platform_device *pdev)
>   			IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
>   			"hdmi_external", drm_hdmi_ctx);
>   	if (ret) {
> -		DRM_ERROR("failed to register hdmi internal interrupt\n");
> +		DRM_ERROR("failed to register hdmi external interrupt\n");
>   		goto err_hdmiphy;
>   	}
>   
> @@ -2372,10 +2408,157 @@ static int __devinit hdmi_probe(struct platform_device *pdev)
>   		goto err_free_irq;
>   	}
>   
> -	/* register specific callbacks to common hdmi. */
> -	exynos_hdmi_ops_register(&hdmi_ops);
> +	return 0;
>   
> -	pm_runtime_enable(dev);
> +err_free_irq:
> +	free_irq(hdata->external_irq, drm_hdmi_ctx);
> +err_hdmiphy:
> +	i2c_del_driver(&hdmiphy_driver);
> +err_ddc:
> +	i2c_del_driver(&ddc_driver);
> +err_resource:
> +	hdmi_resources_cleanup(hdata);
> +err_data:
> +	return ret;
> +}
> +
> +static int __devinit hdmi_resources_init_exynos5(
> +			struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct exynos_drm_hdmi_context *drm_hdmi_ctx;
> +	struct hdmi_context *hdata;
> +	struct resource *res;
> +	unsigned int value;
> +	int ret;
> +	enum of_gpio_flags flags;
> +
> +	DRM_DEBUG_KMS("[%d][%s]\n", __LINE__, __func__);
> +
> +	drm_hdmi_ctx = devm_kzalloc(&pdev->dev, sizeof(*drm_hdmi_ctx),
> +								GFP_KERNEL);
> +	if (!drm_hdmi_ctx) {
> +		DRM_ERROR("failed to allocate common hdmi context.\n");
> +		return -ENOMEM;
> +	}
> +
> +	hdata = devm_kzalloc(&pdev->dev, sizeof(struct hdmi_context),
> +								GFP_KERNEL);
> +	if (!hdata) {
> +		DRM_ERROR("out of memory\n");
> +		return -ENOMEM;
> +	}
> +
> +	mutex_init(&hdata->hdmi_mutex);
> +
> +	drm_hdmi_ctx->ctx = (void *)hdata;
> +	hdata->parent_ctx = (void *)drm_hdmi_ctx;
> +
> +	platform_set_drvdata(pdev, drm_hdmi_ctx);
> +
> +	if (!of_property_read_u32(pdev->dev.of_node,
> +				"v13_support", &value)) {
> +		hdata->is_v13 = (value == 0) ? false : true;
> +	} else {
> +		DRM_ERROR("no hdmi version property found\n");
> +		ret = -EINVAL;
> +		goto err_data;
> +	}
> +
> +	if (!of_find_property(pdev->dev.of_node,
> +				"hpd-gpio", &value)){
> +		DRM_ERROR("no hpd gpio property found\n");
> +		ret = -EINVAL;
> +		goto err_data;
> +	}
> +
> +	hdata->hpd_gpio = of_get_named_gpio_flags(pdev->dev.of_node,
> +				"hpd-gpio", 0, &flags);
> +
> +	if (!gpio_is_valid(hdata->hpd_gpio)) {
> +		DRM_ERROR("failed to get hpd gpio.");
> +		ret = -EINVAL;
> +		goto err_data;
> +	}
> +
> +	hdata->cfg_hpd = NULL;
> +	hdata->get_hpd = NULL;
> +	hdata->dev = dev;
> +	hdata->is_soc_exynos5 = true;
> +
> +	ret = hdmi_resources_init(hdata);
> +	if (ret) {
> +		ret = -EINVAL;
> +		DRM_ERROR("failed hdmi_resources_init.");
> +		goto err_data;
> +	}
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!res) {
> +		DRM_ERROR("failed to find registers\n");
> +		ret = -ENOENT;
> +		goto err_resource;
> +	}
> +
> +	hdata->regs = devm_request_and_ioremap(&pdev->dev, res);
> +	if (!hdata->regs) {
> +		DRM_ERROR("failed to map registers\n");
> +		ret = -ENXIO;
> +		goto err_resource;
> +	}
> +
> +	/* DDC i2c driver */
> +	if (i2c_add_driver(&ddc_driver)) {
> +		DRM_ERROR("failed to register ddc i2c driver\n");
> +		ret = -ENOENT;
> +		goto err_resource;
> +	}
> +
> +	hdata->ddc_port = hdmi_ddc;
> +
> +	/* hdmiphy i2c driver */
> +	if (i2c_add_driver(&hdmiphy_driver)) {
> +		DRM_ERROR("failed to register hdmiphy i2c driver\n");
> +		ret = -ENOENT;
> +		goto err_ddc;
> +	}
> +
> +	hdata->hdmiphy_port = hdmi_hdmiphy;
> +
> +	hdata->external_irq = gpio_to_irq(hdata->hpd_gpio);
> +
> +	if (hdata->external_irq < 0) {
> +		DRM_ERROR("failed to get platform external irq\n");
> +		ret = hdata->external_irq;
> +		goto err_hdmiphy;
> +	}
> +
> +	hdata->internal_irq = platform_get_irq(pdev, 0);
> +
> +	if (hdata->internal_irq < 0) {
> +		DRM_ERROR("failed to get platform internal irq\n");
> +		ret = hdata->internal_irq;
> +		goto err_hdmiphy;
> +	}
> +
> +	ret = request_threaded_irq(hdata->external_irq, NULL,
> +			hdmi_external_irq_thread, IRQF_TRIGGER_RISING |
> +			IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
> +			"hdmi_external", drm_hdmi_ctx);
> +	if (ret) {
> +		DRM_ERROR("failed to register hdmi external interrupt\n");
> +		goto err_hdmiphy;
> +	}
> +
> +	hdmi_cfg_hpd(hdata, false);
> +
> +	ret = request_threaded_irq(hdata->internal_irq, NULL,
> +			hdmi_internal_irq_thread, IRQF_ONESHOT,
> +			"hdmi_internal", drm_hdmi_ctx);
> +	if (ret) {
> +		DRM_ERROR("failed to register hdmi internal interrupt\n");
> +		goto err_free_irq;
> +	}
>   
>   	return 0;
>   
> @@ -2391,6 +2574,41 @@ err_data:
>   	return ret;
>   }
>   
> +static int __devinit hdmi_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct exynos_drm_hdmi_context *drm_hdmi_ctx;
> +	bool is_soc_exynos5 = false;
> +	int ret;
> +
> +	DRM_DEBUG_KMS("[%d][%s]\n", __LINE__, __func__);
> +
> +	if (pdev->dev.of_node &&
> +			of_device_is_compatible(pdev->dev.of_node,
> +			"samsung,exynos5-hdmi")) {
> +			is_soc_exynos5 = true;
> +	}
> +
> +	/* acquire resources: regs, irqs, clocks */
> +	if (is_soc_exynos5)
> +		ret = hdmi_resources_init_exynos5(pdev);
> +	else
> +		ret = hdmi_resources_init_exynos4(pdev);

I think it isn't good to split using is_soc_exynos5 because the exynos5
hdmi is almost same that of exynos4x12.

> +	if (ret)
> +		goto err_data;
> +
> +	drm_hdmi_ctx = platform_get_drvdata(pdev);
> +
> +	/* register specific callbacks to common hdmi. */
> +	exynos_hdmi_ops_register(&hdmi_ops);
> +
> +	pm_runtime_enable(dev);
> +
> +	return 0;
> +
> +err_data:	return ret;
> +}
> +
>   static int __devexit hdmi_remove(struct platform_device *pdev)
>   {
>   	struct device *dev = &pdev->dev;
> @@ -2444,12 +2662,32 @@ static int hdmi_resume(struct device *dev)
>   
>   static SIMPLE_DEV_PM_OPS(hdmi_pm_ops, hdmi_suspend, hdmi_resume);
>   
> +static struct platform_device_id hdmi_driver_types[] = {
> +	{
> +		.name		= "exynos5-hdmi",
> +	}, {
> +		.name		= "exynos4-hdmi",
> +	}, {
> +		/* end node */
> +	}
> +};
> +
> +static struct of_device_id hdmi_match_types[] = {
> +	{
> +		.compatible = "samsung,exynos5-hdmi",
> +	}, {
> +		/* end node */
> +	}
> +};
> +
>   struct platform_driver hdmi_driver = {
>   	.probe		= hdmi_probe,
>   	.remove		= __devexit_p(hdmi_remove),
> +	.id_table	= hdmi_driver_types,
>   	.driver		= {
> -		.name	= "exynos4-hdmi",
> +		.name	= "exynos-hdmi",
>   		.owner	= THIS_MODULE,
>   		.pm	= &hdmi_pm_ops,
> +		.of_match_table = hdmi_match_types,
>   	},
>   };

Thanks.
diff mbox

Patch

diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
index a6aea6f..5236256 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -32,6 +32,9 @@ 
 #include <linux/pm_runtime.h>
 #include <linux/clk.h>
 #include <linux/regulator/consumer.h>
+#include <linux/io.h>
+#include <linux/of_gpio.h>
+#include <plat/gpio-cfg.h>
 
 #include <drm/exynos_drm.h>
 
@@ -61,11 +64,13 @@  struct hdmi_context {
 	bool				powered;
 	bool				is_v13;
 	bool				dvi_mode;
+	bool				is_soc_exynos5;
 	struct mutex			hdmi_mutex;
 
 	void __iomem			*regs;
-	unsigned int			external_irq;
-	unsigned int			internal_irq;
+	int						external_irq;
+	int						internal_irq;
+	int						hpd_gpio;
 
 	struct i2c_client		*ddc_port;
 	struct i2c_client		*hdmiphy_port;
@@ -953,6 +958,23 @@  static inline void hdmi_reg_writemask(struct hdmi_context *hdata,
 	writel(value, hdata->regs + reg_id);
 }
 
+static void hdmi_cfg_hpd(struct hdmi_context *hdata, bool internal)
+{
+	if (!internal) {
+		s3c_gpio_cfgpin(hdata->hpd_gpio, S3C_GPIO_SFN(0xf));
+		s3c_gpio_setpull(hdata->hpd_gpio, S3C_GPIO_PULL_DOWN);
+	} else {
+		s3c_gpio_cfgpin(hdata->hpd_gpio, S3C_GPIO_SFN(3));
+		s3c_gpio_setpull(hdata->hpd_gpio, S3C_GPIO_PULL_NONE);
+	}
+}
+
+static int hdmi_get_hpd(struct hdmi_context *hdata)
+{
+	int gpio_stat = gpio_get_value(hdata->hpd_gpio);
+	return gpio_stat;
+}
+
 static void hdmi_v13_regs_dump(struct hdmi_context *hdata, char *prefix)
 {
 #define DUMPREG(reg_id) \
@@ -2026,6 +2048,9 @@  static void hdmi_poweron(struct hdmi_context *hdata)
 
 	if (hdata->cfg_hpd)
 		hdata->cfg_hpd(true);
+	else
+		hdmi_cfg_hpd(hdata, true);
+
 	mutex_unlock(&hdata->hdmi_mutex);
 
 	pm_runtime_get_sync(hdata->dev);
@@ -2063,6 +2088,8 @@  static void hdmi_poweroff(struct hdmi_context *hdata)
 	mutex_lock(&hdata->hdmi_mutex);
 	if (hdata->cfg_hpd)
 		hdata->cfg_hpd(false);
+	else
+		hdmi_cfg_hpd(hdata, false);
 
 	hdata->powered = false;
 
@@ -2110,17 +2137,16 @@  static irqreturn_t hdmi_external_irq_thread(int irq, void *arg)
 	struct exynos_drm_hdmi_context *ctx = arg;
 	struct hdmi_context *hdata = ctx->ctx;
 
-	if (!hdata->get_hpd)
-		goto out;
-
 	mutex_lock(&hdata->hdmi_mutex);
-	hdata->hpd = hdata->get_hpd();
+	if (hdata->get_hpd)
+		hdata->hpd = hdata->get_hpd();
+	else
+		hdata->hpd = hdmi_get_hpd(hdata);
 	mutex_unlock(&hdata->hdmi_mutex);
 
 	if (ctx->drm_dev)
 		drm_helper_hpd_irq_event(ctx->drm_dev);
 
-out:
 	return IRQ_HANDLED;
 }
 
@@ -2203,23 +2229,25 @@  static int __devinit hdmi_resources_init(struct hdmi_context *hdata)
 
 	clk_set_parent(res->sclk_hdmi, res->sclk_pixel);
 
-	res->regul_bulk = kzalloc(ARRAY_SIZE(supply) *
-		sizeof(res->regul_bulk[0]), GFP_KERNEL);
-	if (!res->regul_bulk) {
-		DRM_ERROR("failed to get memory for regulators\n");
-		goto fail;
-	}
-	for (i = 0; i < ARRAY_SIZE(supply); ++i) {
-		res->regul_bulk[i].supply = supply[i];
-		res->regul_bulk[i].consumer = NULL;
-	}
-	ret = regulator_bulk_get(dev, ARRAY_SIZE(supply), res->regul_bulk);
-	if (ret) {
-		DRM_ERROR("failed to get regulators\n");
-		goto fail;
+	if (!hdata->is_soc_exynos5) {
+		res->regul_bulk = kzalloc(ARRAY_SIZE(supply) *
+			sizeof(res->regul_bulk[0]), GFP_KERNEL);
+		if (!res->regul_bulk) {
+			DRM_ERROR("failed to get memory for regulators\n");
+			goto fail;
+		}
+		for (i = 0; i < ARRAY_SIZE(supply); ++i) {
+			res->regul_bulk[i].supply = supply[i];
+			res->regul_bulk[i].consumer = NULL;
+		}
+		ret = regulator_bulk_get(dev, ARRAY_SIZE(supply),
+			res->regul_bulk);
+		if (ret) {
+			DRM_ERROR("failed to get regulators\n");
+			goto fail;
+		}
+		res->regul_count = ARRAY_SIZE(supply);
 	}
-	res->regul_count = ARRAY_SIZE(supply);
-
 	return 0;
 fail:
 	DRM_ERROR("HDMI resource init - failed\n");
@@ -2262,7 +2290,8 @@  void hdmi_attach_hdmiphy_client(struct i2c_client *hdmiphy)
 		hdmi_hdmiphy = hdmiphy;
 }
 
-static int __devinit hdmi_probe(struct platform_device *pdev)
+static int __devinit hdmi_resources_init_exynos4(
+	struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
 	struct exynos_drm_hdmi_context *drm_hdmi_ctx;
@@ -2271,7 +2300,7 @@  static int __devinit hdmi_probe(struct platform_device *pdev)
 	struct resource *res;
 	int ret;
 
-	DRM_DEBUG_KMS("[%d]\n", __LINE__);
+	DRM_DEBUG_KMS("[%d][%s]\n", __LINE__, __func__);
 
 	pdata = pdev->dev.platform_data;
 	if (!pdata) {
@@ -2304,14 +2333,21 @@  static int __devinit hdmi_probe(struct platform_device *pdev)
 	hdata->cfg_hpd = pdata->cfg_hpd;
 	hdata->get_hpd = pdata->get_hpd;
 	hdata->dev = dev;
+	hdata->is_soc_exynos5 = false;
 
 	ret = hdmi_resources_init(hdata);
 	if (ret) {
 		ret = -EINVAL;
+		DRM_ERROR("hdmi_resources_init failed\n");
 		goto err_data;
 	}
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		DRM_ERROR("failed to find registers\n");
+		ret = -ENOENT;
+		goto err_resource;
+	}
 
 	hdata->regs = devm_request_and_ioremap(&pdev->dev, res);
 	if (!hdata->regs) {
@@ -2340,7 +2376,7 @@  static int __devinit hdmi_probe(struct platform_device *pdev)
 
 	hdata->external_irq = platform_get_irq_byname(pdev, "external_irq");
 	if (hdata->external_irq < 0) {
-		DRM_ERROR("failed to get platform irq\n");
+		DRM_ERROR("failed to get platform external irq\n");
 		ret = hdata->external_irq;
 		goto err_hdmiphy;
 	}
@@ -2357,7 +2393,7 @@  static int __devinit hdmi_probe(struct platform_device *pdev)
 			IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
 			"hdmi_external", drm_hdmi_ctx);
 	if (ret) {
-		DRM_ERROR("failed to register hdmi internal interrupt\n");
+		DRM_ERROR("failed to register hdmi external interrupt\n");
 		goto err_hdmiphy;
 	}
 
@@ -2372,10 +2408,157 @@  static int __devinit hdmi_probe(struct platform_device *pdev)
 		goto err_free_irq;
 	}
 
-	/* register specific callbacks to common hdmi. */
-	exynos_hdmi_ops_register(&hdmi_ops);
+	return 0;
 
-	pm_runtime_enable(dev);
+err_free_irq:
+	free_irq(hdata->external_irq, drm_hdmi_ctx);
+err_hdmiphy:
+	i2c_del_driver(&hdmiphy_driver);
+err_ddc:
+	i2c_del_driver(&ddc_driver);
+err_resource:
+	hdmi_resources_cleanup(hdata);
+err_data:
+	return ret;
+}
+
+static int __devinit hdmi_resources_init_exynos5(
+			struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct exynos_drm_hdmi_context *drm_hdmi_ctx;
+	struct hdmi_context *hdata;
+	struct resource *res;
+	unsigned int value;
+	int ret;
+	enum of_gpio_flags flags;
+
+	DRM_DEBUG_KMS("[%d][%s]\n", __LINE__, __func__);
+
+	drm_hdmi_ctx = devm_kzalloc(&pdev->dev, sizeof(*drm_hdmi_ctx),
+								GFP_KERNEL);
+	if (!drm_hdmi_ctx) {
+		DRM_ERROR("failed to allocate common hdmi context.\n");
+		return -ENOMEM;
+	}
+
+	hdata = devm_kzalloc(&pdev->dev, sizeof(struct hdmi_context),
+								GFP_KERNEL);
+	if (!hdata) {
+		DRM_ERROR("out of memory\n");
+		return -ENOMEM;
+	}
+
+	mutex_init(&hdata->hdmi_mutex);
+
+	drm_hdmi_ctx->ctx = (void *)hdata;
+	hdata->parent_ctx = (void *)drm_hdmi_ctx;
+
+	platform_set_drvdata(pdev, drm_hdmi_ctx);
+
+	if (!of_property_read_u32(pdev->dev.of_node,
+				"v13_support", &value)) {
+		hdata->is_v13 = (value == 0) ? false : true;
+	} else {
+		DRM_ERROR("no hdmi version property found\n");
+		ret = -EINVAL;
+		goto err_data;
+	}
+
+	if (!of_find_property(pdev->dev.of_node,
+				"hpd-gpio", &value)){
+		DRM_ERROR("no hpd gpio property found\n");
+		ret = -EINVAL;
+		goto err_data;
+	}
+
+	hdata->hpd_gpio = of_get_named_gpio_flags(pdev->dev.of_node,
+				"hpd-gpio", 0, &flags);
+
+	if (!gpio_is_valid(hdata->hpd_gpio)) {
+		DRM_ERROR("failed to get hpd gpio.");
+		ret = -EINVAL;
+		goto err_data;
+	}
+
+	hdata->cfg_hpd = NULL;
+	hdata->get_hpd = NULL;
+	hdata->dev = dev;
+	hdata->is_soc_exynos5 = true;
+
+	ret = hdmi_resources_init(hdata);
+	if (ret) {
+		ret = -EINVAL;
+		DRM_ERROR("failed hdmi_resources_init.");
+		goto err_data;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		DRM_ERROR("failed to find registers\n");
+		ret = -ENOENT;
+		goto err_resource;
+	}
+
+	hdata->regs = devm_request_and_ioremap(&pdev->dev, res);
+	if (!hdata->regs) {
+		DRM_ERROR("failed to map registers\n");
+		ret = -ENXIO;
+		goto err_resource;
+	}
+
+	/* DDC i2c driver */
+	if (i2c_add_driver(&ddc_driver)) {
+		DRM_ERROR("failed to register ddc i2c driver\n");
+		ret = -ENOENT;
+		goto err_resource;
+	}
+
+	hdata->ddc_port = hdmi_ddc;
+
+	/* hdmiphy i2c driver */
+	if (i2c_add_driver(&hdmiphy_driver)) {
+		DRM_ERROR("failed to register hdmiphy i2c driver\n");
+		ret = -ENOENT;
+		goto err_ddc;
+	}
+
+	hdata->hdmiphy_port = hdmi_hdmiphy;
+
+	hdata->external_irq = gpio_to_irq(hdata->hpd_gpio);
+
+	if (hdata->external_irq < 0) {
+		DRM_ERROR("failed to get platform external irq\n");
+		ret = hdata->external_irq;
+		goto err_hdmiphy;
+	}
+
+	hdata->internal_irq = platform_get_irq(pdev, 0);
+
+	if (hdata->internal_irq < 0) {
+		DRM_ERROR("failed to get platform internal irq\n");
+		ret = hdata->internal_irq;
+		goto err_hdmiphy;
+	}
+
+	ret = request_threaded_irq(hdata->external_irq, NULL,
+			hdmi_external_irq_thread, IRQF_TRIGGER_RISING |
+			IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+			"hdmi_external", drm_hdmi_ctx);
+	if (ret) {
+		DRM_ERROR("failed to register hdmi external interrupt\n");
+		goto err_hdmiphy;
+	}
+
+	hdmi_cfg_hpd(hdata, false);
+
+	ret = request_threaded_irq(hdata->internal_irq, NULL,
+			hdmi_internal_irq_thread, IRQF_ONESHOT,
+			"hdmi_internal", drm_hdmi_ctx);
+	if (ret) {
+		DRM_ERROR("failed to register hdmi internal interrupt\n");
+		goto err_free_irq;
+	}
 
 	return 0;
 
@@ -2391,6 +2574,41 @@  err_data:
 	return ret;
 }
 
+static int __devinit hdmi_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct exynos_drm_hdmi_context *drm_hdmi_ctx;
+	bool is_soc_exynos5 = false;
+	int ret;
+
+	DRM_DEBUG_KMS("[%d][%s]\n", __LINE__, __func__);
+
+	if (pdev->dev.of_node &&
+			of_device_is_compatible(pdev->dev.of_node,
+			"samsung,exynos5-hdmi")) {
+			is_soc_exynos5 = true;
+	}
+
+	/* acquire resources: regs, irqs, clocks */
+	if (is_soc_exynos5)
+		ret = hdmi_resources_init_exynos5(pdev);
+	else
+		ret = hdmi_resources_init_exynos4(pdev);
+	if (ret)
+		goto err_data;
+
+	drm_hdmi_ctx = platform_get_drvdata(pdev);
+
+	/* register specific callbacks to common hdmi. */
+	exynos_hdmi_ops_register(&hdmi_ops);
+
+	pm_runtime_enable(dev);
+
+	return 0;
+
+err_data:	return ret;
+}
+
 static int __devexit hdmi_remove(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -2444,12 +2662,32 @@  static int hdmi_resume(struct device *dev)
 
 static SIMPLE_DEV_PM_OPS(hdmi_pm_ops, hdmi_suspend, hdmi_resume);
 
+static struct platform_device_id hdmi_driver_types[] = {
+	{
+		.name		= "exynos5-hdmi",
+	}, {
+		.name		= "exynos4-hdmi",
+	}, {
+		/* end node */
+	}
+};
+
+static struct of_device_id hdmi_match_types[] = {
+	{
+		.compatible = "samsung,exynos5-hdmi",
+	}, {
+		/* end node */
+	}
+};
+
 struct platform_driver hdmi_driver = {
 	.probe		= hdmi_probe,
 	.remove		= __devexit_p(hdmi_remove),
+	.id_table	= hdmi_driver_types,
 	.driver		= {
-		.name	= "exynos4-hdmi",
+		.name	= "exynos-hdmi",
 		.owner	= THIS_MODULE,
 		.pm	= &hdmi_pm_ops,
+		.of_match_table = hdmi_match_types,
 	},
 };