Skip to content

Commit

Permalink
video: exynos_dp: Add device tree support to DP driver
Browse files Browse the repository at this point in the history
This patch enables device tree based discovery support for DP driver.
The driver is modified to handle platform data in both the cases:
with DT and non-DT.

Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
Signed-off-by: Jingoo Han <jg1.han@samsung.com>
  • Loading branch information
Ajay Kumar authored and Jingoo Han committed Nov 29, 2012
1 parent f4a75d2 commit c4e235c
Show file tree
Hide file tree
Showing 2 changed files with 198 additions and 20 deletions.
216 changes: 196 additions & 20 deletions drivers/video/exynos/exynos_dp_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/of.h>

#include <video/exynos_dp.h>

Expand Down Expand Up @@ -856,6 +857,145 @@ static irqreturn_t exynos_dp_irq_handler(int irq, void *arg)
return IRQ_HANDLED;
}

#ifdef CONFIG_OF
static struct exynos_dp_platdata *exynos_dp_dt_parse_pdata(struct device *dev)
{
struct device_node *dp_node = dev->of_node;
struct exynos_dp_platdata *pd;
struct video_info *dp_video_config;

pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
if (!pd) {
dev_err(dev, "memory allocation for pdata failed\n");
return ERR_PTR(-ENOMEM);
}
dp_video_config = devm_kzalloc(dev,
sizeof(*dp_video_config), GFP_KERNEL);

if (!dp_video_config) {
dev_err(dev, "memory allocation for video config failed\n");
return ERR_PTR(-ENOMEM);
}
pd->video_info = dp_video_config;

dp_video_config->h_sync_polarity =
of_property_read_bool(dp_node, "hsync-active-high");

dp_video_config->v_sync_polarity =
of_property_read_bool(dp_node, "vsync-active-high");

dp_video_config->interlaced =
of_property_read_bool(dp_node, "interlaced");

if (of_property_read_u32(dp_node, "samsung,color-space",
&dp_video_config->color_space)) {
dev_err(dev, "failed to get color-space\n");
return ERR_PTR(-EINVAL);
}

if (of_property_read_u32(dp_node, "samsung,dynamic-range",
&dp_video_config->dynamic_range)) {
dev_err(dev, "failed to get dynamic-range\n");
return ERR_PTR(-EINVAL);
}

if (of_property_read_u32(dp_node, "samsung,ycbcr-coeff",
&dp_video_config->ycbcr_coeff)) {
dev_err(dev, "failed to get ycbcr-coeff\n");
return ERR_PTR(-EINVAL);
}

if (of_property_read_u32(dp_node, "samsung,color-depth",
&dp_video_config->color_depth)) {
dev_err(dev, "failed to get color-depth\n");
return ERR_PTR(-EINVAL);
}

if (of_property_read_u32(dp_node, "samsung,link-rate",
&dp_video_config->link_rate)) {
dev_err(dev, "failed to get link-rate\n");
return ERR_PTR(-EINVAL);
}

if (of_property_read_u32(dp_node, "samsung,lane-count",
&dp_video_config->lane_count)) {
dev_err(dev, "failed to get lane-count\n");
return ERR_PTR(-EINVAL);
}

return pd;
}

static int exynos_dp_dt_parse_phydata(struct exynos_dp_device *dp)
{
struct device_node *dp_phy_node;
u32 phy_base;

dp_phy_node = of_find_node_by_name(dp->dev->of_node, "dptx-phy");
if (!dp_phy_node) {
dev_err(dp->dev, "could not find dptx-phy node\n");
return -ENODEV;
}

if (of_property_read_u32(dp_phy_node, "reg", &phy_base)) {
dev_err(dp->dev, "faild to get reg for dptx-phy\n");
return -EINVAL;
}

if (of_property_read_u32(dp_phy_node, "samsung,enable-mask",
&dp->enable_mask)) {
dev_err(dp->dev, "faild to get enable-mask for dptx-phy\n");
return -EINVAL;
}

dp->phy_addr = ioremap(phy_base, SZ_4);
if (!dp->phy_addr) {
dev_err(dp->dev, "failed to ioremap dp-phy\n");
return -ENOMEM;
}

return 0;
}

static void exynos_dp_phy_init(struct exynos_dp_device *dp)
{
u32 reg;

reg = __raw_readl(dp->phy_addr);
reg |= dp->enable_mask;
__raw_writel(reg, dp->phy_addr);
}

static void exynos_dp_phy_exit(struct exynos_dp_device *dp)
{
u32 reg;

reg = __raw_readl(dp->phy_addr);
reg &= ~(dp->enable_mask);
__raw_writel(reg, dp->phy_addr);
}
#else
static struct exynos_dp_platdata *exynos_dp_dt_parse_pdata(struct device *dev)
{
return NULL;
}

static int exynos_dp_dt_parse_phydata(struct exynos_dp_device *dp)
{
return -EINVAL;
}

static void exynos_dp_phy_init(struct exynos_dp_device *dp)
{
return;
}

static void exynos_dp_phy_exit(struct exynos_dp_device *dp)
{
return;
}
#endif /* CONFIG_OF */

static int __devinit exynos_dp_probe(struct platform_device *pdev)
{
struct resource *res;
Expand All @@ -864,12 +1004,6 @@ static int __devinit exynos_dp_probe(struct platform_device *pdev)

int ret = 0;

pdata = pdev->dev.platform_data;
if (!pdata) {
dev_err(&pdev->dev, "no platform data\n");
return -EINVAL;
}

dp = devm_kzalloc(&pdev->dev, sizeof(struct exynos_dp_device),
GFP_KERNEL);
if (!dp) {
Expand All @@ -879,6 +1013,22 @@ static int __devinit exynos_dp_probe(struct platform_device *pdev)

dp->dev = &pdev->dev;

if (pdev->dev.of_node) {
pdata = exynos_dp_dt_parse_pdata(&pdev->dev);
if (IS_ERR(pdata))
return PTR_ERR(pdata);

ret = exynos_dp_dt_parse_phydata(dp);
if (ret)
return ret;
} else {
pdata = pdev->dev.platform_data;
if (!pdata) {
dev_err(&pdev->dev, "no platform data\n");
return -EINVAL;
}
}

dp->clock = devm_clk_get(&pdev->dev, "dp");
if (IS_ERR(dp->clock)) {
dev_err(&pdev->dev, "failed to get clock\n");
Expand Down Expand Up @@ -909,8 +1059,14 @@ static int __devinit exynos_dp_probe(struct platform_device *pdev)
}

dp->video_info = pdata->video_info;
if (pdata->phy_init)
pdata->phy_init();

if (pdev->dev.of_node) {
if (dp->phy_addr)
exynos_dp_phy_init(dp);
} else {
if (pdata->phy_init)
pdata->phy_init();
}

exynos_dp_init_dp(dp);

Expand Down Expand Up @@ -953,8 +1109,13 @@ 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 (pdata && pdata->phy_exit)
pdata->phy_exit();
if (pdev->dev.of_node) {
if (dp->phy_addr)
exynos_dp_phy_exit(dp);
} else {
if (pdata->phy_exit)
pdata->phy_exit();
}

clk_disable_unprepare(dp->clock);

Expand All @@ -964,12 +1125,16 @@ static int __devexit exynos_dp_remove(struct platform_device *pdev)
#ifdef CONFIG_PM_SLEEP
static int exynos_dp_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct exynos_dp_platdata *pdata = pdev->dev.platform_data;
struct exynos_dp_device *dp = platform_get_drvdata(pdev);
struct exynos_dp_platdata *pdata = dev->platform_data;
struct exynos_dp_device *dp = dev_get_drvdata(dev);

if (pdata && pdata->phy_exit)
pdata->phy_exit();
if (dev->of_node) {
if (dp->phy_addr)
exynos_dp_phy_exit(dp);
} else {
if (pdata->phy_exit)
pdata->phy_exit();
}

clk_disable_unprepare(dp->clock);

Expand All @@ -978,12 +1143,16 @@ static int exynos_dp_suspend(struct device *dev)

static int exynos_dp_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct exynos_dp_platdata *pdata = pdev->dev.platform_data;
struct exynos_dp_device *dp = platform_get_drvdata(pdev);
struct exynos_dp_platdata *pdata = dev->platform_data;
struct exynos_dp_device *dp = dev_get_drvdata(dev);

if (pdata && pdata->phy_init)
pdata->phy_init();
if (dev->of_node) {
if (dp->phy_addr)
exynos_dp_phy_init(dp);
} else {
if (pdata->phy_init)
pdata->phy_init();
}

clk_prepare_enable(dp->clock);

Expand Down Expand Up @@ -1013,13 +1182,20 @@ static const struct dev_pm_ops exynos_dp_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(exynos_dp_suspend, exynos_dp_resume)
};

static const struct of_device_id exynos_dp_match[] = {
{ .compatible = "samsung,exynos5-dp" },
{},
};
MODULE_DEVICE_TABLE(of, exynos_dp_match);

static struct platform_driver exynos_dp_driver = {
.probe = exynos_dp_probe,
.remove = __devexit_p(exynos_dp_remove),
.driver = {
.name = "exynos-dp",
.owner = THIS_MODULE,
.pm = &exynos_dp_pm_ops,
.of_match_table = of_match_ptr(exynos_dp_match),
},
};

Expand Down
2 changes: 2 additions & 0 deletions drivers/video/exynos/exynos_dp_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ struct exynos_dp_device {
struct clk *clock;
unsigned int irq;
void __iomem *reg_base;
void __iomem *phy_addr;
unsigned int enable_mask;

struct video_info *video_info;
struct link_train link_train;
Expand Down

0 comments on commit c4e235c

Please sign in to comment.