diff options
-rw-r--r-- | drivers/gpu/drm/bridge/Kconfig | 12 | ||||
-rw-r--r-- | drivers/gpu/drm/bridge/ptn3460.c | 124 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_dp_core.c | 22 |
3 files changed, 91 insertions, 67 deletions
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index b70f3c8d4e8a..ffa3e061a618 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig | |||
@@ -1,10 +1,12 @@ | |||
1 | config DRM_PTN3460 | 1 | config DRM_DW_HDMI |
2 | tristate "PTN3460 DP/LVDS bridge" | 2 | tristate |
3 | depends on DRM | 3 | depends on DRM |
4 | select DRM_KMS_HELPER | 4 | select DRM_KMS_HELPER |
5 | ---help--- | ||
6 | 5 | ||
7 | config DRM_DW_HDMI | 6 | config DRM_PTN3460 |
8 | tristate | 7 | tristate "PTN3460 DP/LVDS bridge" |
9 | depends on DRM | 8 | depends on DRM |
9 | depends on OF | ||
10 | select DRM_KMS_HELPER | 10 | select DRM_KMS_HELPER |
11 | ---help--- | ||
12 | ptn3460 eDP-LVDS bridge chip driver. | ||
diff --git a/drivers/gpu/drm/bridge/ptn3460.c b/drivers/gpu/drm/bridge/ptn3460.c index 4a818c1b62e0..7adeb607f6fb 100644 --- a/drivers/gpu/drm/bridge/ptn3460.c +++ b/drivers/gpu/drm/bridge/ptn3460.c | |||
@@ -36,7 +36,6 @@ | |||
36 | struct ptn3460_bridge { | 36 | struct ptn3460_bridge { |
37 | struct drm_connector connector; | 37 | struct drm_connector connector; |
38 | struct i2c_client *client; | 38 | struct i2c_client *client; |
39 | struct drm_encoder *encoder; | ||
40 | struct drm_bridge bridge; | 39 | struct drm_bridge bridge; |
41 | struct edid *edid; | 40 | struct edid *edid; |
42 | int gpio_pd_n; | 41 | int gpio_pd_n; |
@@ -176,13 +175,6 @@ static void ptn3460_post_disable(struct drm_bridge *bridge) | |||
176 | { | 175 | { |
177 | } | 176 | } |
178 | 177 | ||
179 | static struct drm_bridge_funcs ptn3460_bridge_funcs = { | ||
180 | .pre_enable = ptn3460_pre_enable, | ||
181 | .enable = ptn3460_enable, | ||
182 | .disable = ptn3460_disable, | ||
183 | .post_disable = ptn3460_post_disable, | ||
184 | }; | ||
185 | |||
186 | static int ptn3460_get_modes(struct drm_connector *connector) | 178 | static int ptn3460_get_modes(struct drm_connector *connector) |
187 | { | 179 | { |
188 | struct ptn3460_bridge *ptn_bridge; | 180 | struct ptn3460_bridge *ptn_bridge; |
@@ -227,7 +219,7 @@ static struct drm_encoder *ptn3460_best_encoder(struct drm_connector *connector) | |||
227 | { | 219 | { |
228 | struct ptn3460_bridge *ptn_bridge = connector_to_ptn3460(connector); | 220 | struct ptn3460_bridge *ptn_bridge = connector_to_ptn3460(connector); |
229 | 221 | ||
230 | return ptn_bridge->encoder; | 222 | return ptn_bridge->bridge.encoder; |
231 | } | 223 | } |
232 | 224 | ||
233 | static struct drm_connector_helper_funcs ptn3460_connector_helper_funcs = { | 225 | static struct drm_connector_helper_funcs ptn3460_connector_helper_funcs = { |
@@ -253,31 +245,66 @@ static struct drm_connector_funcs ptn3460_connector_funcs = { | |||
253 | .destroy = ptn3460_connector_destroy, | 245 | .destroy = ptn3460_connector_destroy, |
254 | }; | 246 | }; |
255 | 247 | ||
256 | int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder, | 248 | int ptn3460_bridge_attach(struct drm_bridge *bridge) |
257 | struct i2c_client *client, struct device_node *node) | ||
258 | { | 249 | { |
250 | struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge); | ||
259 | int ret; | 251 | int ret; |
252 | |||
253 | if (!bridge->encoder) { | ||
254 | DRM_ERROR("Parent encoder object not found"); | ||
255 | return -ENODEV; | ||
256 | } | ||
257 | |||
258 | ret = drm_connector_init(bridge->dev, &ptn_bridge->connector, | ||
259 | &ptn3460_connector_funcs, DRM_MODE_CONNECTOR_LVDS); | ||
260 | if (ret) { | ||
261 | DRM_ERROR("Failed to initialize connector with drm\n"); | ||
262 | return ret; | ||
263 | } | ||
264 | drm_connector_helper_add(&ptn_bridge->connector, | ||
265 | &ptn3460_connector_helper_funcs); | ||
266 | drm_connector_register(&ptn_bridge->connector); | ||
267 | drm_mode_connector_attach_encoder(&ptn_bridge->connector, | ||
268 | bridge->encoder); | ||
269 | |||
270 | return ret; | ||
271 | } | ||
272 | |||
273 | static struct drm_bridge_funcs ptn3460_bridge_funcs = { | ||
274 | .pre_enable = ptn3460_pre_enable, | ||
275 | .enable = ptn3460_enable, | ||
276 | .disable = ptn3460_disable, | ||
277 | .post_disable = ptn3460_post_disable, | ||
278 | .attach = ptn3460_bridge_attach, | ||
279 | }; | ||
280 | |||
281 | static int ptn3460_probe(struct i2c_client *client, | ||
282 | const struct i2c_device_id *id) | ||
283 | { | ||
284 | struct device *dev = &client->dev; | ||
260 | struct ptn3460_bridge *ptn_bridge; | 285 | struct ptn3460_bridge *ptn_bridge; |
286 | int ret; | ||
261 | 287 | ||
262 | ptn_bridge = devm_kzalloc(dev->dev, sizeof(*ptn_bridge), GFP_KERNEL); | 288 | ptn_bridge = devm_kzalloc(dev, sizeof(*ptn_bridge), GFP_KERNEL); |
263 | if (!ptn_bridge) { | 289 | if (!ptn_bridge) { |
264 | return -ENOMEM; | 290 | return -ENOMEM; |
265 | } | 291 | } |
266 | 292 | ||
267 | ptn_bridge->client = client; | 293 | ptn_bridge->client = client; |
268 | ptn_bridge->encoder = encoder; | 294 | ptn_bridge->gpio_pd_n = of_get_named_gpio(dev->of_node, |
269 | ptn_bridge->gpio_pd_n = of_get_named_gpio(node, "powerdown-gpio", 0); | 295 | "powerdown-gpio", 0); |
270 | if (gpio_is_valid(ptn_bridge->gpio_pd_n)) { | 296 | if (gpio_is_valid(ptn_bridge->gpio_pd_n)) { |
271 | ret = gpio_request_one(ptn_bridge->gpio_pd_n, | 297 | ret = gpio_request_one(ptn_bridge->gpio_pd_n, |
272 | GPIOF_OUT_INIT_HIGH, "PTN3460_PD_N"); | 298 | GPIOF_OUT_INIT_HIGH, "PTN3460_PD_N"); |
273 | if (ret) { | 299 | if (ret) { |
274 | dev_err(&client->dev, | 300 | dev_err(dev, "Request powerdown-gpio failed (%d)\n", |
275 | "Request powerdown-gpio failed (%d)\n", ret); | 301 | ret); |
276 | return ret; | 302 | return ret; |
277 | } | 303 | } |
278 | } | 304 | } |
279 | 305 | ||
280 | ptn_bridge->gpio_rst_n = of_get_named_gpio(node, "reset-gpio", 0); | 306 | ptn_bridge->gpio_rst_n = of_get_named_gpio(dev->of_node, |
307 | "reset-gpio", 0); | ||
281 | if (gpio_is_valid(ptn_bridge->gpio_rst_n)) { | 308 | if (gpio_is_valid(ptn_bridge->gpio_rst_n)) { |
282 | /* | 309 | /* |
283 | * Request the reset pin low to avoid the bridge being | 310 | * Request the reset pin low to avoid the bridge being |
@@ -286,39 +313,27 @@ int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder, | |||
286 | ret = gpio_request_one(ptn_bridge->gpio_rst_n, | 313 | ret = gpio_request_one(ptn_bridge->gpio_rst_n, |
287 | GPIOF_OUT_INIT_LOW, "PTN3460_RST_N"); | 314 | GPIOF_OUT_INIT_LOW, "PTN3460_RST_N"); |
288 | if (ret) { | 315 | if (ret) { |
289 | dev_err(&client->dev, | 316 | dev_err(dev, "Request reset-gpio failed (%d)\n", ret); |
290 | "Request reset-gpio failed (%d)\n", ret); | ||
291 | gpio_free(ptn_bridge->gpio_pd_n); | 317 | gpio_free(ptn_bridge->gpio_pd_n); |
292 | return ret; | 318 | return ret; |
293 | } | 319 | } |
294 | } | 320 | } |
295 | 321 | ||
296 | ret = of_property_read_u32(node, "edid-emulation", | 322 | ret = of_property_read_u32(dev->of_node, "edid-emulation", |
297 | &ptn_bridge->edid_emulation); | 323 | &ptn_bridge->edid_emulation); |
298 | if (ret) { | 324 | if (ret) { |
299 | dev_err(&client->dev, "Can't read EDID emulation value\n"); | 325 | dev_err(dev, "Can't read EDID emulation value\n"); |
300 | goto err; | 326 | goto err; |
301 | } | 327 | } |
302 | 328 | ||
303 | ptn_bridge->bridge.funcs = &ptn3460_bridge_funcs; | 329 | ptn_bridge->bridge.funcs = &ptn3460_bridge_funcs; |
304 | ret = drm_bridge_attach(dev, &ptn_bridge->bridge); | 330 | ret = drm_bridge_add(&ptn_bridge->bridge); |
305 | if (ret) { | 331 | if (ret) { |
306 | DRM_ERROR("Failed to initialize bridge with drm\n"); | 332 | DRM_ERROR("Failed to add bridge\n"); |
307 | goto err; | 333 | goto err; |
308 | } | 334 | } |
309 | 335 | ||
310 | encoder->bridge = &ptn_bridge->bridge; | 336 | i2c_set_clientdata(client, ptn_bridge); |
311 | |||
312 | ret = drm_connector_init(dev, &ptn_bridge->connector, | ||
313 | &ptn3460_connector_funcs, DRM_MODE_CONNECTOR_LVDS); | ||
314 | if (ret) { | ||
315 | DRM_ERROR("Failed to initialize connector with drm\n"); | ||
316 | goto err; | ||
317 | } | ||
318 | drm_connector_helper_add(&ptn_bridge->connector, | ||
319 | &ptn3460_connector_helper_funcs); | ||
320 | drm_connector_register(&ptn_bridge->connector); | ||
321 | drm_mode_connector_attach_encoder(&ptn_bridge->connector, encoder); | ||
322 | 337 | ||
323 | return 0; | 338 | return 0; |
324 | 339 | ||
@@ -329,16 +344,45 @@ err: | |||
329 | gpio_free(ptn_bridge->gpio_rst_n); | 344 | gpio_free(ptn_bridge->gpio_rst_n); |
330 | return ret; | 345 | return ret; |
331 | } | 346 | } |
332 | EXPORT_SYMBOL(ptn3460_init); | ||
333 | 347 | ||
334 | void ptn3460_destroy(struct drm_bridge *bridge) | 348 | static int ptn3460_remove(struct i2c_client *client) |
335 | { | 349 | { |
336 | struct ptn3460_bridge *ptn_bridge = bridge->driver_private; | 350 | struct ptn3460_bridge *ptn_bridge = i2c_get_clientdata(client); |
351 | |||
352 | drm_bridge_remove(&ptn_bridge->bridge); | ||
337 | 353 | ||
338 | if (gpio_is_valid(ptn_bridge->gpio_pd_n)) | 354 | if (gpio_is_valid(ptn_bridge->gpio_pd_n)) |
339 | gpio_free(ptn_bridge->gpio_pd_n); | 355 | gpio_free(ptn_bridge->gpio_pd_n); |
340 | if (gpio_is_valid(ptn_bridge->gpio_rst_n)) | 356 | if (gpio_is_valid(ptn_bridge->gpio_rst_n)) |
341 | gpio_free(ptn_bridge->gpio_rst_n); | 357 | gpio_free(ptn_bridge->gpio_rst_n); |
342 | /* Nothing else to free, we've got devm allocated memory */ | 358 | |
359 | return 0; | ||
343 | } | 360 | } |
344 | EXPORT_SYMBOL(ptn3460_destroy); | 361 | |
362 | static const struct i2c_device_id ptn3460_i2c_table[] = { | ||
363 | {"nxp,ptn3460", 0}, | ||
364 | {}, | ||
365 | }; | ||
366 | MODULE_DEVICE_TABLE(i2c, ptn3460_i2c_table); | ||
367 | |||
368 | static const struct of_device_id ptn3460_match[] = { | ||
369 | { .compatible = "nxp,ptn3460" }, | ||
370 | {}, | ||
371 | }; | ||
372 | MODULE_DEVICE_TABLE(of, ptn3460_match); | ||
373 | |||
374 | static struct i2c_driver ptn3460_driver = { | ||
375 | .id_table = ptn3460_i2c_table, | ||
376 | .probe = ptn3460_probe, | ||
377 | .remove = ptn3460_remove, | ||
378 | .driver = { | ||
379 | .name = "nxp,ptn3460", | ||
380 | .owner = THIS_MODULE, | ||
381 | .of_match_table = ptn3460_match, | ||
382 | }, | ||
383 | }; | ||
384 | module_i2c_driver(ptn3460_driver); | ||
385 | |||
386 | MODULE_AUTHOR("Sean Paul <seanpaul@chromium.org>"); | ||
387 | MODULE_DESCRIPTION("NXP ptn3460 eDP-LVDS converter driver"); | ||
388 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c index 34d46aa75416..27e3d272ca2d 100644 --- a/drivers/gpu/drm/exynos/exynos_dp_core.c +++ b/drivers/gpu/drm/exynos/exynos_dp_core.c | |||
@@ -993,32 +993,10 @@ static struct drm_connector_helper_funcs exynos_dp_connector_helper_funcs = { | |||
993 | .best_encoder = exynos_dp_best_encoder, | 993 | .best_encoder = exynos_dp_best_encoder, |
994 | }; | 994 | }; |
995 | 995 | ||
996 | static bool find_bridge(const char *compat, struct bridge_init *bridge) | ||
997 | { | ||
998 | bridge->client = NULL; | ||
999 | bridge->node = of_find_compatible_node(NULL, NULL, compat); | ||
1000 | if (!bridge->node) | ||
1001 | return false; | ||
1002 | |||
1003 | bridge->client = of_find_i2c_device_by_node(bridge->node); | ||
1004 | if (!bridge->client) | ||
1005 | return false; | ||
1006 | |||
1007 | return true; | ||
1008 | } | ||
1009 | |||
1010 | /* returns the number of bridges attached */ | 996 | /* returns the number of bridges attached */ |
1011 | static int exynos_drm_attach_lcd_bridge(struct drm_device *dev, | 997 | static int exynos_drm_attach_lcd_bridge(struct drm_device *dev, |
1012 | struct drm_encoder *encoder) | 998 | struct drm_encoder *encoder) |
1013 | { | 999 | { |
1014 | struct bridge_init bridge; | ||
1015 | int ret; | ||
1016 | |||
1017 | if (find_bridge("nxp,ptn3460", &bridge)) { | ||
1018 | ret = ptn3460_init(dev, encoder, bridge.client, bridge.node); | ||
1019 | if (!ret) | ||
1020 | return 1; | ||
1021 | } | ||
1022 | return 0; | 1000 | return 0; |
1023 | } | 1001 | } |
1024 | 1002 | ||