.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Parade PS8622 eDP/LVDS bridge driver |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (C) 2014 Google, Inc. |
---|
5 | | - * |
---|
6 | | - * This software is licensed under the terms of the GNU General Public |
---|
7 | | - * License version 2, as published by the Free Software Foundation, and |
---|
8 | | - * may be copied, distributed, and modified under those terms. |
---|
9 | | - * |
---|
10 | | - * This program is distributed in the hope that it will be useful, |
---|
11 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
12 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
13 | | - * GNU General Public License for more details. |
---|
14 | 6 | */ |
---|
15 | 7 | |
---|
16 | 8 | #include <linux/backlight.h> |
---|
17 | 9 | #include <linux/delay.h> |
---|
18 | 10 | #include <linux/err.h> |
---|
19 | | -#include <linux/gpio.h> |
---|
20 | 11 | #include <linux/gpio/consumer.h> |
---|
21 | 12 | #include <linux/i2c.h> |
---|
22 | 13 | #include <linux/module.h> |
---|
.. | .. |
---|
24 | 15 | #include <linux/of_device.h> |
---|
25 | 16 | #include <linux/pm.h> |
---|
26 | 17 | #include <linux/regulator/consumer.h> |
---|
| 18 | + |
---|
27 | 19 | #include <drm/drm_atomic_helper.h> |
---|
| 20 | +#include <drm/drm_bridge.h> |
---|
28 | 21 | #include <drm/drm_crtc.h> |
---|
29 | | -#include <drm/drm_crtc_helper.h> |
---|
30 | 22 | #include <drm/drm_of.h> |
---|
31 | 23 | #include <drm/drm_panel.h> |
---|
32 | | -#include <drm/drmP.h> |
---|
| 24 | +#include <drm/drm_print.h> |
---|
| 25 | +#include <drm/drm_probe_helper.h> |
---|
33 | 26 | |
---|
34 | 27 | /* Brightness scale on the Parade chip */ |
---|
35 | 28 | #define PS8622_MAX_BRIGHTNESS 0xff |
---|
.. | .. |
---|
49 | 42 | #endif |
---|
50 | 43 | |
---|
51 | 44 | struct ps8622_bridge { |
---|
52 | | - struct drm_connector connector; |
---|
53 | 45 | struct i2c_client *client; |
---|
54 | 46 | struct drm_bridge bridge; |
---|
55 | | - struct drm_panel *panel; |
---|
| 47 | + struct drm_bridge *panel_bridge; |
---|
56 | 48 | struct regulator *v12; |
---|
57 | 49 | struct backlight_device *bl; |
---|
58 | 50 | |
---|
.. | .. |
---|
69 | 61 | bridge_to_ps8622(struct drm_bridge *bridge) |
---|
70 | 62 | { |
---|
71 | 63 | return container_of(bridge, struct ps8622_bridge, bridge); |
---|
72 | | -} |
---|
73 | | - |
---|
74 | | -static inline struct ps8622_bridge * |
---|
75 | | - connector_to_ps8622(struct drm_connector *connector) |
---|
76 | | -{ |
---|
77 | | - return container_of(connector, struct ps8622_bridge, connector); |
---|
78 | 64 | } |
---|
79 | 65 | |
---|
80 | 66 | static int ps8622_set(struct i2c_client *client, u8 page, u8 reg, u8 val) |
---|
.. | .. |
---|
372 | 358 | DRM_ERROR("fails to enable ps8622->v12"); |
---|
373 | 359 | } |
---|
374 | 360 | |
---|
375 | | - if (drm_panel_prepare(ps8622->panel)) { |
---|
376 | | - DRM_ERROR("failed to prepare panel\n"); |
---|
377 | | - return; |
---|
378 | | - } |
---|
379 | | - |
---|
380 | 361 | gpiod_set_value(ps8622->gpio_slp, 1); |
---|
381 | 362 | |
---|
382 | 363 | /* |
---|
.. | .. |
---|
406 | 387 | ps8622->enabled = true; |
---|
407 | 388 | } |
---|
408 | 389 | |
---|
409 | | -static void ps8622_enable(struct drm_bridge *bridge) |
---|
410 | | -{ |
---|
411 | | - struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge); |
---|
412 | | - |
---|
413 | | - if (drm_panel_enable(ps8622->panel)) { |
---|
414 | | - DRM_ERROR("failed to enable panel\n"); |
---|
415 | | - return; |
---|
416 | | - } |
---|
417 | | -} |
---|
418 | | - |
---|
419 | 390 | static void ps8622_disable(struct drm_bridge *bridge) |
---|
420 | 391 | { |
---|
421 | | - struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge); |
---|
422 | | - |
---|
423 | | - if (drm_panel_disable(ps8622->panel)) { |
---|
424 | | - DRM_ERROR("failed to disable panel\n"); |
---|
425 | | - return; |
---|
426 | | - } |
---|
| 392 | + /* Delay after panel is disabled */ |
---|
427 | 393 | msleep(PS8622_PWMO_END_T12_MS); |
---|
428 | 394 | } |
---|
429 | 395 | |
---|
.. | .. |
---|
443 | 409 | */ |
---|
444 | 410 | gpiod_set_value(ps8622->gpio_slp, 0); |
---|
445 | 411 | |
---|
446 | | - if (drm_panel_unprepare(ps8622->panel)) { |
---|
447 | | - DRM_ERROR("failed to unprepare panel\n"); |
---|
448 | | - return; |
---|
449 | | - } |
---|
450 | | - |
---|
451 | 412 | if (ps8622->v12) |
---|
452 | 413 | regulator_disable(ps8622->v12); |
---|
453 | 414 | |
---|
.. | .. |
---|
462 | 423 | msleep(PS8622_POWER_OFF_T17_MS); |
---|
463 | 424 | } |
---|
464 | 425 | |
---|
465 | | -static int ps8622_get_modes(struct drm_connector *connector) |
---|
466 | | -{ |
---|
467 | | - struct ps8622_bridge *ps8622; |
---|
468 | | - |
---|
469 | | - ps8622 = connector_to_ps8622(connector); |
---|
470 | | - |
---|
471 | | - return drm_panel_get_modes(ps8622->panel); |
---|
472 | | -} |
---|
473 | | - |
---|
474 | | -static const struct drm_connector_helper_funcs ps8622_connector_helper_funcs = { |
---|
475 | | - .get_modes = ps8622_get_modes, |
---|
476 | | -}; |
---|
477 | | - |
---|
478 | | -static const struct drm_connector_funcs ps8622_connector_funcs = { |
---|
479 | | - .fill_modes = drm_helper_probe_single_connector_modes, |
---|
480 | | - .destroy = drm_connector_cleanup, |
---|
481 | | - .reset = drm_atomic_helper_connector_reset, |
---|
482 | | - .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, |
---|
483 | | - .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, |
---|
484 | | -}; |
---|
485 | | - |
---|
486 | | -static int ps8622_attach(struct drm_bridge *bridge) |
---|
| 426 | +static int ps8622_attach(struct drm_bridge *bridge, |
---|
| 427 | + enum drm_bridge_attach_flags flags) |
---|
487 | 428 | { |
---|
488 | 429 | struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge); |
---|
489 | | - int ret; |
---|
490 | 430 | |
---|
491 | | - if (!bridge->encoder) { |
---|
492 | | - DRM_ERROR("Parent encoder object not found"); |
---|
493 | | - return -ENODEV; |
---|
494 | | - } |
---|
495 | | - |
---|
496 | | - ps8622->connector.polled = DRM_CONNECTOR_POLL_HPD; |
---|
497 | | - ret = drm_connector_init(bridge->dev, &ps8622->connector, |
---|
498 | | - &ps8622_connector_funcs, DRM_MODE_CONNECTOR_LVDS); |
---|
499 | | - if (ret) { |
---|
500 | | - DRM_ERROR("Failed to initialize connector with drm\n"); |
---|
501 | | - return ret; |
---|
502 | | - } |
---|
503 | | - drm_connector_helper_add(&ps8622->connector, |
---|
504 | | - &ps8622_connector_helper_funcs); |
---|
505 | | - drm_connector_register(&ps8622->connector); |
---|
506 | | - drm_connector_attach_encoder(&ps8622->connector, |
---|
507 | | - bridge->encoder); |
---|
508 | | - |
---|
509 | | - if (ps8622->panel) |
---|
510 | | - drm_panel_attach(ps8622->panel, &ps8622->connector); |
---|
511 | | - |
---|
512 | | - drm_helper_hpd_irq_event(ps8622->connector.dev); |
---|
513 | | - |
---|
514 | | - return ret; |
---|
| 431 | + return drm_bridge_attach(ps8622->bridge.encoder, ps8622->panel_bridge, |
---|
| 432 | + &ps8622->bridge, flags); |
---|
515 | 433 | } |
---|
516 | 434 | |
---|
517 | 435 | static const struct drm_bridge_funcs ps8622_bridge_funcs = { |
---|
518 | 436 | .pre_enable = ps8622_pre_enable, |
---|
519 | | - .enable = ps8622_enable, |
---|
520 | 437 | .disable = ps8622_disable, |
---|
521 | 438 | .post_disable = ps8622_post_disable, |
---|
522 | 439 | .attach = ps8622_attach, |
---|
.. | .. |
---|
534 | 451 | { |
---|
535 | 452 | struct device *dev = &client->dev; |
---|
536 | 453 | struct ps8622_bridge *ps8622; |
---|
| 454 | + struct drm_bridge *panel_bridge; |
---|
| 455 | + struct drm_panel *panel; |
---|
537 | 456 | int ret; |
---|
538 | 457 | |
---|
539 | 458 | ps8622 = devm_kzalloc(dev, sizeof(*ps8622), GFP_KERNEL); |
---|
540 | 459 | if (!ps8622) |
---|
541 | 460 | return -ENOMEM; |
---|
542 | 461 | |
---|
543 | | - ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0, &ps8622->panel, NULL); |
---|
| 462 | + ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0, &panel, NULL); |
---|
544 | 463 | if (ret) |
---|
545 | 464 | return ret; |
---|
546 | 465 | |
---|
| 466 | + panel_bridge = devm_drm_panel_bridge_add(dev, panel); |
---|
| 467 | + if (IS_ERR(panel_bridge)) |
---|
| 468 | + return PTR_ERR(panel_bridge); |
---|
| 469 | + |
---|
| 470 | + ps8622->panel_bridge = panel_bridge; |
---|
547 | 471 | ps8622->client = client; |
---|
548 | 472 | |
---|
549 | 473 | ps8622->v12 = devm_regulator_get(dev, "vdd12"); |
---|
.. | .. |
---|
596 | 520 | } |
---|
597 | 521 | |
---|
598 | 522 | ps8622->bridge.funcs = &ps8622_bridge_funcs; |
---|
| 523 | + ps8622->bridge.type = DRM_MODE_CONNECTOR_LVDS; |
---|
599 | 524 | ps8622->bridge.of_node = dev->of_node; |
---|
600 | 525 | drm_bridge_add(&ps8622->bridge); |
---|
601 | 526 | |
---|