-
Notifications
You must be signed in to change notification settings - Fork 159
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix for drm initialization before i2c probe
Patch for 3.8
- Loading branch information
Cody Lacey
committed
Aug 13, 2013
1 parent
2b8f0cd
commit 9f2dada
Showing
1 changed file
with
191 additions
and
0 deletions.
There are no files selected for viewing
191 changes: 191 additions & 0 deletions
191
patches/hdmi/0022-drm-tilcdc-fixing-i2c-slave-initialization-race.patch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,191 @@ | ||
From e0ccb9374fdd0613a3b181f5e0f662afd3da8bff Mon Sep 17 00:00:00 2001 | ||
From: Cody Lacey <clacey@ti.com> | ||
Date: Fri, 9 Aug 2013 12:19:20 -0500 | ||
Subject: [PATCH 22/27] drm/tilcdc fixing i2c/slave initialization race | ||
|
||
In certain senarios drm will initialize before i2c this means that i2c | ||
slave devices like the nxp tda998x will fail to be probed. This patch | ||
detects this condition then defers the probe of the slave device and | ||
the tilcdc main driver. | ||
|
||
Created by: Darren Etheridge <detheridge@ti.com> | ||
This change was modified by Cody Lacey to work with the 3.8 kernel. | ||
--- | ||
drivers/gpu/drm/tilcdc/tilcdc_drv.c | 10 ++++++ | ||
drivers/gpu/drm/tilcdc/tilcdc_drv.h | 1 + | ||
drivers/gpu/drm/tilcdc/tilcdc_slave.c | 62 ++++++++++++++++++--------------- | ||
3 files changed, 44 insertions(+), 29 deletions(-) | ||
|
||
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c | ||
index 31e039e..09ae498 100644 | ||
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c | ||
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c | ||
@@ -28,6 +28,7 @@ | ||
#include <linux/of_gpio.h> | ||
|
||
static LIST_HEAD(module_list); | ||
+static bool slave_probing; | ||
|
||
void tilcdc_module_init(struct tilcdc_module *mod, const char *name, | ||
const struct tilcdc_module_ops *funcs) | ||
@@ -43,6 +44,11 @@ void tilcdc_module_cleanup(struct tilcdc_module *mod) | ||
list_del(&mod->list); | ||
} | ||
|
||
+void tilcdc_slave_probedefer(bool defered) | ||
+{ | ||
+ slave_probing = defered; | ||
+} | ||
+ | ||
static struct of_device_id tilcdc_of_match[]; | ||
|
||
static struct drm_framebuffer *tilcdc_fb_create(struct drm_device *dev, | ||
@@ -608,6 +614,10 @@ static int tilcdc_pdev_probe(struct platform_device *pdev) | ||
return -ENXIO; | ||
} | ||
|
||
+ /* defer probing if slave is in deferred probing */ | ||
+ if (slave_probing == true) | ||
+ return -EPROBE_DEFER; | ||
+ | ||
return drm_platform_init(&tilcdc_driver, pdev); | ||
} | ||
|
||
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.h b/drivers/gpu/drm/tilcdc/tilcdc_drv.h | ||
index 40ff5d4..254bba60 100644 | ||
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.h | ||
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.h | ||
@@ -116,6 +116,7 @@ void tilcdc_module_init(struct tilcdc_module *mod, const char *name, | ||
const struct tilcdc_module_ops *funcs); | ||
void tilcdc_module_cleanup(struct tilcdc_module *mod); | ||
|
||
+void tilcdc_slave_probedefer(bool defered); | ||
|
||
/* Panel config that needs to be set in the crtc, but is not coming from | ||
* the mode timings. The display module is expected to call | ||
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_slave.c b/drivers/gpu/drm/tilcdc/tilcdc_slave.c | ||
index 440de4e..667540c 100644 | ||
--- a/drivers/gpu/drm/tilcdc/tilcdc_slave.c | ||
+++ b/drivers/gpu/drm/tilcdc/tilcdc_slave.c | ||
@@ -363,6 +363,7 @@ static int slave_probe(struct platform_device *pdev) | ||
struct slave_module *slave_mod; | ||
struct tilcdc_module *mod; | ||
struct pinctrl_state *state; | ||
+ struct i2c_adapter *slavei2c; | ||
uint32_t i2c_phandle; | ||
char *state_name; | ||
int ret = -EINVAL; | ||
@@ -373,14 +374,38 @@ static int slave_probe(struct platform_device *pdev) | ||
return -ENXIO; | ||
} | ||
|
||
+ /* Bail out early if i2c not specified */ | ||
+ if (of_property_read_u32(node, "i2c", &i2c_phandle)) { | ||
+ dev_err(&pdev->dev, "could not get i2c bus phandle\n"); | ||
+ return ret; | ||
+ } | ||
+ | ||
+ i2c_node = of_find_node_by_phandle(i2c_phandle); | ||
+ if (!i2c_node) { | ||
+ dev_err(&pdev->dev, "could not get i2c bus node\n"); | ||
+ return ret; | ||
+ } | ||
+ | ||
+ /* but defer the probe if it can't be initialized it might come later */ | ||
+ slavei2c = of_find_i2c_adapter_by_node(i2c_node); | ||
+ of_node_put(i2c_node); | ||
+ if (!slavei2c) { | ||
+ ret = -EPROBE_DEFER; | ||
+ tilcdc_slave_probedefer(true); | ||
+ dev_err(&pdev->dev, "could not get i2c\n"); | ||
+ return ret; | ||
+ } | ||
+ | ||
slave_mod = kzalloc(sizeof(*slave_mod), GFP_KERNEL); | ||
if (!slave_mod) | ||
return -ENOMEM; | ||
|
||
- platform_set_drvdata(pdev, slave_mod); | ||
- | ||
mod = &slave_mod->base; | ||
|
||
+ slave_mod->i2c = slavei2c; | ||
+ | ||
+ platform_set_drvdata(pdev, slave_mod); | ||
+ | ||
tilcdc_module_init(mod, "slave", &slave_module_ops); | ||
|
||
state_name = kmalloc(strlen(PINCTRL_STATE_DEFAULT) + 1, | ||
@@ -388,7 +413,7 @@ static int slave_probe(struct platform_device *pdev) | ||
if (state_name == NULL) { | ||
dev_err(dev, "Failed to allocate state name\n"); | ||
ret = -ENOMEM; | ||
- goto fail; | ||
+ return ret; | ||
} | ||
slave_mod->selected_state_name = state_name; | ||
strcpy(slave_mod->selected_state_name, PINCTRL_STATE_DEFAULT); | ||
@@ -397,7 +422,7 @@ static int slave_probe(struct platform_device *pdev) | ||
if (IS_ERR(slave_mod->pinctrl)) { | ||
dev_err(dev, "Failed to get pinctrl\n"); | ||
ret = PTR_RET(slave_mod->pinctrl); | ||
- goto fail; | ||
+ return ret; | ||
} | ||
|
||
/* try to select default state at first (if it exists) */ | ||
@@ -407,7 +432,7 @@ static int slave_probe(struct platform_device *pdev) | ||
ret = pinctrl_select_state(slave_mod->pinctrl, state); | ||
if (ret != 0) { | ||
dev_err(dev, "Failed to select default state\n"); | ||
- goto fail; | ||
+ return ret; | ||
} | ||
} else { | ||
slave_mod->selected_state_name = '\0'; | ||
@@ -417,39 +442,18 @@ static int slave_probe(struct platform_device *pdev) | ||
ret = sysfs_create_group(&dev->kobj, &pinmux_attr_group); | ||
if (ret) { | ||
dev_err(dev, "Failed to create sysfs group\n"); | ||
- goto fail; | ||
- } | ||
- | ||
- if (of_property_read_u32(node, "i2c", &i2c_phandle)) { | ||
- dev_err(&pdev->dev, "could not get i2c bus phandle\n"); | ||
- goto fail; | ||
- } | ||
- | ||
- i2c_node = of_find_node_by_phandle(i2c_phandle); | ||
- if (!i2c_node) { | ||
- dev_err(&pdev->dev, "could not get i2c bus node\n"); | ||
- goto fail; | ||
- } | ||
- | ||
- slave_mod->i2c = of_find_i2c_adapter_by_node(i2c_node); | ||
- if (!slave_mod->i2c) { | ||
- dev_err(&pdev->dev, "could not get i2c\n"); | ||
- goto fail; | ||
+ return ret; | ||
} | ||
|
||
slave_mod->info = tilcdc_of_get_panel_info(node); | ||
if (!slave_mod->info) { | ||
dev_err(&pdev->dev, "could not get panel info\n"); | ||
- goto fail; | ||
+ return ret; | ||
} | ||
|
||
- of_node_put(i2c_node); | ||
+ tilcdc_slave_probedefer(false); | ||
|
||
return 0; | ||
- | ||
-fail: | ||
- slave_destroy(mod); | ||
- return ret; | ||
} | ||
|
||
static int slave_remove(struct platform_device *pdev) | ||
-- | ||
1.7.9.5 | ||
|