1 // SPDX-License-Identifier: GPL-2.0+ 2 3 /* 4 * Copyright 2020 NXP 5 */ 6 7 #include <linux/clk.h> 8 #include <linux/media-bus-format.h> 9 #include <linux/mfd/syscon.h> 10 #include <linux/module.h> 11 #include <linux/of.h> 12 #include <linux/of_graph.h> 13 #include <linux/phy/phy.h> 14 #include <linux/platform_device.h> 15 #include <linux/pm_runtime.h> 16 #include <linux/regmap.h> 17 18 #include <drm/drm_atomic_state_helper.h> 19 #include <drm/drm_bridge.h> 20 #include <drm/drm_connector.h> 21 #include <drm/drm_fourcc.h> 22 #include <drm/drm_of.h> 23 #include <drm/drm_print.h> 24 25 #include "imx-ldb-helper.h" 26 27 #define LDB_CH0_10BIT_EN BIT(22) 28 #define LDB_CH1_10BIT_EN BIT(23) 29 #define LDB_CH0_DATA_WIDTH_24BIT BIT(24) 30 #define LDB_CH1_DATA_WIDTH_24BIT BIT(26) 31 #define LDB_CH0_DATA_WIDTH_30BIT (2 << 24) 32 #define LDB_CH1_DATA_WIDTH_30BIT (2 << 26) 33 34 #define SS_CTRL 0x20 35 #define CH_HSYNC_M(id) BIT(0 + ((id) * 2)) 36 #define CH_VSYNC_M(id) BIT(1 + ((id) * 2)) 37 #define CH_PHSYNC(id) BIT(0 + ((id) * 2)) 38 #define CH_PVSYNC(id) BIT(1 + ((id) * 2)) 39 40 #define DRIVER_NAME "imx8qm-ldb" 41 42 struct imx8qm_ldb_channel { 43 struct ldb_channel base; 44 struct phy *phy; 45 }; 46 47 struct imx8qm_ldb { 48 struct ldb base; 49 struct device *dev; 50 struct imx8qm_ldb_channel channel[MAX_LDB_CHAN_NUM]; 51 struct clk *clk_pixel; 52 struct clk *clk_bypass; 53 int active_chno; 54 }; 55 56 static inline struct imx8qm_ldb_channel * 57 base_to_imx8qm_ldb_channel(struct ldb_channel *base) 58 { 59 return container_of(base, struct imx8qm_ldb_channel, base); 60 } 61 62 static inline struct imx8qm_ldb *base_to_imx8qm_ldb(struct ldb *base) 63 { 64 return container_of(base, struct imx8qm_ldb, base); 65 } 66 67 static void imx8qm_ldb_set_phy_cfg(struct imx8qm_ldb *imx8qm_ldb, 68 unsigned long di_clk, 69 bool is_split, bool is_slave, 70 struct phy_configure_opts_lvds *phy_cfg) 71 { 72 phy_cfg->bits_per_lane_and_dclk_cycle = 7; 73 phy_cfg->lanes = 4; 74 phy_cfg->differential_clk_rate = is_split ? di_clk / 2 : di_clk; 75 phy_cfg->is_slave = is_slave; 76 } 77 78 static int imx8qm_ldb_bridge_atomic_check(struct drm_bridge *bridge, 79 struct drm_bridge_state *bridge_state, 80 struct drm_crtc_state *crtc_state, 81 struct drm_connector_state *conn_state) 82 { 83 struct ldb_channel *ldb_ch = bridge->driver_private; 84 struct ldb *ldb = ldb_ch->ldb; 85 struct imx8qm_ldb_channel *imx8qm_ldb_ch = 86 base_to_imx8qm_ldb_channel(ldb_ch); 87 struct imx8qm_ldb *imx8qm_ldb = base_to_imx8qm_ldb(ldb); 88 struct drm_display_mode *adj = &crtc_state->adjusted_mode; 89 unsigned long di_clk = adj->clock * 1000; 90 bool is_split = ldb_channel_is_split_link(ldb_ch); 91 union phy_configure_opts opts = { }; 92 struct phy_configure_opts_lvds *phy_cfg = &opts.lvds; 93 int ret; 94 95 ret = ldb_bridge_atomic_check_helper(bridge, bridge_state, 96 crtc_state, conn_state); 97 if (ret) 98 return ret; 99 100 imx8qm_ldb_set_phy_cfg(imx8qm_ldb, di_clk, is_split, false, phy_cfg); 101 ret = phy_validate(imx8qm_ldb_ch->phy, PHY_MODE_LVDS, 0, &opts); 102 if (ret < 0) { 103 DRM_DEV_DEBUG_DRIVER(imx8qm_ldb->dev, 104 "failed to validate PHY: %d\n", ret); 105 return ret; 106 } 107 108 if (is_split) { 109 imx8qm_ldb_ch = 110 &imx8qm_ldb->channel[imx8qm_ldb->active_chno ^ 1]; 111 imx8qm_ldb_set_phy_cfg(imx8qm_ldb, di_clk, is_split, true, 112 phy_cfg); 113 ret = phy_validate(imx8qm_ldb_ch->phy, PHY_MODE_LVDS, 0, &opts); 114 if (ret < 0) { 115 DRM_DEV_DEBUG_DRIVER(imx8qm_ldb->dev, 116 "failed to validate slave PHY: %d\n", 117 ret); 118 return ret; 119 } 120 } 121 122 return ret; 123 } 124 125 static void 126 imx8qm_ldb_bridge_mode_set(struct drm_bridge *bridge, 127 const struct drm_display_mode *mode, 128 const struct drm_display_mode *adjusted_mode) 129 { 130 struct ldb_channel *ldb_ch = bridge->driver_private; 131 struct ldb *ldb = ldb_ch->ldb; 132 struct imx8qm_ldb_channel *imx8qm_ldb_ch = 133 base_to_imx8qm_ldb_channel(ldb_ch); 134 struct imx8qm_ldb *imx8qm_ldb = base_to_imx8qm_ldb(ldb); 135 struct device *dev = imx8qm_ldb->dev; 136 unsigned long di_clk = adjusted_mode->clock * 1000; 137 bool is_split = ldb_channel_is_split_link(ldb_ch); 138 union phy_configure_opts opts = { }; 139 struct phy_configure_opts_lvds *phy_cfg = &opts.lvds; 140 u32 chno = ldb_ch->chno; 141 int ret; 142 143 ret = pm_runtime_get_sync(dev); 144 if (ret < 0) 145 DRM_DEV_ERROR(dev, "failed to get runtime PM sync: %d\n", ret); 146 147 ret = phy_init(imx8qm_ldb_ch->phy); 148 if (ret < 0) 149 DRM_DEV_ERROR(dev, "failed to initialize PHY: %d\n", ret); 150 151 clk_set_rate(imx8qm_ldb->clk_bypass, di_clk); 152 clk_set_rate(imx8qm_ldb->clk_pixel, di_clk); 153 154 imx8qm_ldb_set_phy_cfg(imx8qm_ldb, di_clk, is_split, false, phy_cfg); 155 ret = phy_configure(imx8qm_ldb_ch->phy, &opts); 156 if (ret < 0) 157 DRM_DEV_ERROR(dev, "failed to configure PHY: %d\n", ret); 158 159 if (is_split) { 160 imx8qm_ldb_ch = 161 &imx8qm_ldb->channel[imx8qm_ldb->active_chno ^ 1]; 162 imx8qm_ldb_set_phy_cfg(imx8qm_ldb, di_clk, is_split, true, 163 phy_cfg); 164 ret = phy_configure(imx8qm_ldb_ch->phy, &opts); 165 if (ret < 0) 166 DRM_DEV_ERROR(dev, "failed to configure slave PHY: %d\n", 167 ret); 168 } 169 170 /* input VSYNC signal from pixel link is active low */ 171 if (ldb_ch->chno == 0 || is_split) 172 ldb->ldb_ctrl |= LDB_DI0_VS_POL_ACT_LOW; 173 if (ldb_ch->chno == 1 || is_split) 174 ldb->ldb_ctrl |= LDB_DI1_VS_POL_ACT_LOW; 175 176 switch (ldb_ch->out_bus_format) { 177 case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG: 178 break; 179 case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA: 180 case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG: 181 if (ldb_ch->chno == 0 || is_split) 182 ldb->ldb_ctrl |= LDB_CH0_DATA_WIDTH_24BIT; 183 if (ldb_ch->chno == 1 || is_split) 184 ldb->ldb_ctrl |= LDB_CH1_DATA_WIDTH_24BIT; 185 break; 186 } 187 188 ldb_bridge_mode_set_helper(bridge, mode, adjusted_mode); 189 190 if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) 191 regmap_update_bits(ldb->regmap, SS_CTRL, CH_VSYNC_M(chno), 0); 192 else if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) 193 regmap_update_bits(ldb->regmap, SS_CTRL, 194 CH_VSYNC_M(chno), CH_PVSYNC(chno)); 195 196 if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) 197 regmap_update_bits(ldb->regmap, SS_CTRL, CH_HSYNC_M(chno), 0); 198 else if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) 199 regmap_update_bits(ldb->regmap, SS_CTRL, 200 CH_HSYNC_M(chno), CH_PHSYNC(chno)); 201 } 202 203 static void imx8qm_ldb_bridge_atomic_enable(struct drm_bridge *bridge, 204 struct drm_atomic_state *state) 205 { 206 struct ldb_channel *ldb_ch = bridge->driver_private; 207 struct ldb *ldb = ldb_ch->ldb; 208 struct imx8qm_ldb_channel *imx8qm_ldb_ch = 209 base_to_imx8qm_ldb_channel(ldb_ch); 210 struct imx8qm_ldb *imx8qm_ldb = base_to_imx8qm_ldb(ldb); 211 struct device *dev = imx8qm_ldb->dev; 212 bool is_split = ldb_channel_is_split_link(ldb_ch); 213 int ret; 214 215 clk_prepare_enable(imx8qm_ldb->clk_pixel); 216 clk_prepare_enable(imx8qm_ldb->clk_bypass); 217 218 /* both DI0 and DI1 connect with pixel link, so ok to use DI0 only */ 219 if (ldb_ch->chno == 0 || is_split) { 220 ldb->ldb_ctrl &= ~LDB_CH0_MODE_EN_MASK; 221 ldb->ldb_ctrl |= LDB_CH0_MODE_EN_TO_DI0; 222 } 223 if (ldb_ch->chno == 1 || is_split) { 224 ldb->ldb_ctrl &= ~LDB_CH1_MODE_EN_MASK; 225 ldb->ldb_ctrl |= LDB_CH1_MODE_EN_TO_DI0; 226 } 227 228 if (is_split) { 229 ret = phy_power_on(imx8qm_ldb->channel[0].phy); 230 if (ret) 231 DRM_DEV_ERROR(dev, 232 "failed to power on channel0 PHY: %d\n", 233 ret); 234 235 ret = phy_power_on(imx8qm_ldb->channel[1].phy); 236 if (ret) 237 DRM_DEV_ERROR(dev, 238 "failed to power on channel1 PHY: %d\n", 239 ret); 240 } else { 241 ret = phy_power_on(imx8qm_ldb_ch->phy); 242 if (ret) 243 DRM_DEV_ERROR(dev, "failed to power on PHY: %d\n", ret); 244 } 245 246 ldb_bridge_enable_helper(bridge); 247 } 248 249 static void imx8qm_ldb_bridge_atomic_disable(struct drm_bridge *bridge, 250 struct drm_atomic_state *state) 251 { 252 struct ldb_channel *ldb_ch = bridge->driver_private; 253 struct ldb *ldb = ldb_ch->ldb; 254 struct imx8qm_ldb_channel *imx8qm_ldb_ch = 255 base_to_imx8qm_ldb_channel(ldb_ch); 256 struct imx8qm_ldb *imx8qm_ldb = base_to_imx8qm_ldb(ldb); 257 struct device *dev = imx8qm_ldb->dev; 258 bool is_split = ldb_channel_is_split_link(ldb_ch); 259 int ret; 260 261 ldb_bridge_disable_helper(bridge); 262 263 if (is_split) { 264 ret = phy_power_off(imx8qm_ldb->channel[0].phy); 265 if (ret) 266 DRM_DEV_ERROR(dev, 267 "failed to power off channel0 PHY: %d\n", 268 ret); 269 ret = phy_power_off(imx8qm_ldb->channel[1].phy); 270 if (ret) 271 DRM_DEV_ERROR(dev, 272 "failed to power off channel1 PHY: %d\n", 273 ret); 274 } else { 275 ret = phy_power_off(imx8qm_ldb_ch->phy); 276 if (ret) 277 DRM_DEV_ERROR(dev, "failed to power off PHY: %d\n", ret); 278 } 279 280 clk_disable_unprepare(imx8qm_ldb->clk_bypass); 281 clk_disable_unprepare(imx8qm_ldb->clk_pixel); 282 283 ret = pm_runtime_put(dev); 284 if (ret < 0) 285 DRM_DEV_ERROR(dev, "failed to put runtime PM: %d\n", ret); 286 } 287 288 static const u32 imx8qm_ldb_bus_output_fmts[] = { 289 MEDIA_BUS_FMT_RGB666_1X7X3_SPWG, 290 MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, 291 MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA, 292 MEDIA_BUS_FMT_FIXED, 293 }; 294 295 static bool imx8qm_ldb_bus_output_fmt_supported(u32 fmt) 296 { 297 int i; 298 299 for (i = 0; i < ARRAY_SIZE(imx8qm_ldb_bus_output_fmts); i++) { 300 if (imx8qm_ldb_bus_output_fmts[i] == fmt) 301 return true; 302 } 303 304 return false; 305 } 306 307 static u32 * 308 imx8qm_ldb_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge, 309 struct drm_bridge_state *bridge_state, 310 struct drm_crtc_state *crtc_state, 311 struct drm_connector_state *conn_state, 312 u32 output_fmt, 313 unsigned int *num_input_fmts) 314 { 315 struct drm_display_info *di; 316 const struct drm_format_info *finfo; 317 u32 *input_fmts; 318 319 if (!imx8qm_ldb_bus_output_fmt_supported(output_fmt)) 320 return NULL; 321 322 *num_input_fmts = 1; 323 324 input_fmts = kmalloc(sizeof(*input_fmts), GFP_KERNEL); 325 if (!input_fmts) 326 return NULL; 327 328 switch (output_fmt) { 329 case MEDIA_BUS_FMT_FIXED: 330 di = &conn_state->connector->display_info; 331 332 /* 333 * Look at the first bus format to determine input format. 334 * Default to MEDIA_BUS_FMT_RGB888_1X36_CPADLO, if no match. 335 */ 336 if (di->num_bus_formats) { 337 finfo = drm_format_info(di->bus_formats[0]); 338 339 input_fmts[0] = finfo->depth == 18 ? 340 MEDIA_BUS_FMT_RGB666_1X36_CPADLO : 341 MEDIA_BUS_FMT_RGB888_1X36_CPADLO; 342 } else { 343 input_fmts[0] = MEDIA_BUS_FMT_RGB888_1X36_CPADLO; 344 } 345 break; 346 case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG: 347 input_fmts[0] = MEDIA_BUS_FMT_RGB666_1X36_CPADLO; 348 break; 349 case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG: 350 case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA: 351 input_fmts[0] = MEDIA_BUS_FMT_RGB888_1X36_CPADLO; 352 break; 353 default: 354 kfree(input_fmts); 355 input_fmts = NULL; 356 break; 357 } 358 359 return input_fmts; 360 } 361 362 static u32 * 363 imx8qm_ldb_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge, 364 struct drm_bridge_state *bridge_state, 365 struct drm_crtc_state *crtc_state, 366 struct drm_connector_state *conn_state, 367 unsigned int *num_output_fmts) 368 { 369 *num_output_fmts = ARRAY_SIZE(imx8qm_ldb_bus_output_fmts); 370 return kmemdup(imx8qm_ldb_bus_output_fmts, 371 sizeof(imx8qm_ldb_bus_output_fmts), GFP_KERNEL); 372 } 373 374 static enum drm_mode_status 375 imx8qm_ldb_bridge_mode_valid(struct drm_bridge *bridge, 376 const struct drm_display_info *info, 377 const struct drm_display_mode *mode) 378 { 379 struct ldb_channel *ldb_ch = bridge->driver_private; 380 bool is_single = ldb_channel_is_single_link(ldb_ch); 381 382 if (mode->clock > 300000) 383 return MODE_CLOCK_HIGH; 384 385 if (mode->clock > 150000 && is_single) 386 return MODE_CLOCK_HIGH; 387 388 return MODE_OK; 389 } 390 391 static const struct drm_bridge_funcs imx8qm_ldb_bridge_funcs = { 392 .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, 393 .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, 394 .atomic_reset = drm_atomic_helper_bridge_reset, 395 .mode_valid = imx8qm_ldb_bridge_mode_valid, 396 .attach = ldb_bridge_attach_helper, 397 .atomic_check = imx8qm_ldb_bridge_atomic_check, 398 .mode_set = imx8qm_ldb_bridge_mode_set, 399 .atomic_enable = imx8qm_ldb_bridge_atomic_enable, 400 .atomic_disable = imx8qm_ldb_bridge_atomic_disable, 401 .atomic_get_input_bus_fmts = 402 imx8qm_ldb_bridge_atomic_get_input_bus_fmts, 403 .atomic_get_output_bus_fmts = 404 imx8qm_ldb_bridge_atomic_get_output_bus_fmts, 405 }; 406 407 static int imx8qm_ldb_get_phy(struct imx8qm_ldb *imx8qm_ldb) 408 { 409 struct imx8qm_ldb_channel *imx8qm_ldb_ch; 410 struct ldb_channel *ldb_ch; 411 struct device *dev = imx8qm_ldb->dev; 412 int i, ret; 413 414 for (i = 0; i < MAX_LDB_CHAN_NUM; i++) { 415 imx8qm_ldb_ch = &imx8qm_ldb->channel[i]; 416 ldb_ch = &imx8qm_ldb_ch->base; 417 418 if (!ldb_ch->is_available) 419 continue; 420 421 imx8qm_ldb_ch->phy = devm_of_phy_get(dev, ldb_ch->np, 422 "lvds_phy"); 423 if (IS_ERR(imx8qm_ldb_ch->phy)) { 424 ret = PTR_ERR(imx8qm_ldb_ch->phy); 425 if (ret != -EPROBE_DEFER) 426 DRM_DEV_ERROR(dev, 427 "failed to get channel%d PHY: %d\n", 428 i, ret); 429 return ret; 430 } 431 } 432 433 return 0; 434 } 435 436 static int imx8qm_ldb_probe(struct platform_device *pdev) 437 { 438 struct device *dev = &pdev->dev; 439 struct imx8qm_ldb *imx8qm_ldb; 440 struct imx8qm_ldb_channel *imx8qm_ldb_ch; 441 struct ldb *ldb; 442 struct ldb_channel *ldb_ch; 443 struct device_node *port1, *port2; 444 int pixel_order; 445 int ret, i; 446 447 imx8qm_ldb = devm_kzalloc(dev, sizeof(*imx8qm_ldb), GFP_KERNEL); 448 if (!imx8qm_ldb) 449 return -ENOMEM; 450 451 imx8qm_ldb->clk_pixel = devm_clk_get(dev, "pixel"); 452 if (IS_ERR(imx8qm_ldb->clk_pixel)) { 453 ret = PTR_ERR(imx8qm_ldb->clk_pixel); 454 if (ret != -EPROBE_DEFER) 455 DRM_DEV_ERROR(dev, 456 "failed to get pixel clock: %d\n", ret); 457 return ret; 458 } 459 460 imx8qm_ldb->clk_bypass = devm_clk_get(dev, "bypass"); 461 if (IS_ERR(imx8qm_ldb->clk_bypass)) { 462 ret = PTR_ERR(imx8qm_ldb->clk_bypass); 463 if (ret != -EPROBE_DEFER) 464 DRM_DEV_ERROR(dev, 465 "failed to get bypass clock: %d\n", ret); 466 return ret; 467 } 468 469 imx8qm_ldb->dev = dev; 470 471 ldb = &imx8qm_ldb->base; 472 ldb->dev = dev; 473 ldb->ctrl_reg = 0xe0; 474 475 for (i = 0; i < MAX_LDB_CHAN_NUM; i++) 476 ldb->channel[i] = &imx8qm_ldb->channel[i].base; 477 478 ret = ldb_init_helper(ldb); 479 if (ret) 480 return ret; 481 482 if (ldb->available_ch_cnt == 0) { 483 DRM_DEV_DEBUG_DRIVER(dev, "no available channel\n"); 484 return 0; 485 } 486 487 if (ldb->available_ch_cnt == 2) { 488 port1 = of_graph_get_port_by_id(ldb->channel[0]->np, 1); 489 port2 = of_graph_get_port_by_id(ldb->channel[1]->np, 1); 490 pixel_order = 491 drm_of_lvds_get_dual_link_pixel_order(port1, port2); 492 of_node_put(port1); 493 of_node_put(port2); 494 495 if (pixel_order != DRM_LVDS_DUAL_LINK_ODD_EVEN_PIXELS) { 496 DRM_DEV_ERROR(dev, "invalid dual link pixel order: %d\n", 497 pixel_order); 498 return -EINVAL; 499 } 500 501 imx8qm_ldb->active_chno = 0; 502 imx8qm_ldb_ch = &imx8qm_ldb->channel[0]; 503 ldb_ch = &imx8qm_ldb_ch->base; 504 ldb_ch->link_type = pixel_order; 505 } else { 506 for (i = 0; i < MAX_LDB_CHAN_NUM; i++) { 507 imx8qm_ldb_ch = &imx8qm_ldb->channel[i]; 508 ldb_ch = &imx8qm_ldb_ch->base; 509 510 if (ldb_ch->is_available) { 511 imx8qm_ldb->active_chno = ldb_ch->chno; 512 break; 513 } 514 } 515 } 516 517 ret = imx8qm_ldb_get_phy(imx8qm_ldb); 518 if (ret) 519 return ret; 520 521 ret = ldb_find_next_bridge_helper(ldb); 522 if (ret) 523 return ret; 524 525 platform_set_drvdata(pdev, imx8qm_ldb); 526 pm_runtime_enable(dev); 527 528 ldb_add_bridge_helper(ldb, &imx8qm_ldb_bridge_funcs); 529 530 return ret; 531 } 532 533 static void imx8qm_ldb_remove(struct platform_device *pdev) 534 { 535 struct imx8qm_ldb *imx8qm_ldb = platform_get_drvdata(pdev); 536 struct ldb *ldb = &imx8qm_ldb->base; 537 538 ldb_remove_bridge_helper(ldb); 539 540 pm_runtime_disable(&pdev->dev); 541 } 542 543 static int imx8qm_ldb_runtime_suspend(struct device *dev) 544 { 545 return 0; 546 } 547 548 static int imx8qm_ldb_runtime_resume(struct device *dev) 549 { 550 struct imx8qm_ldb *imx8qm_ldb = dev_get_drvdata(dev); 551 struct ldb *ldb = &imx8qm_ldb->base; 552 553 /* disable LDB by resetting the control register to POR default */ 554 regmap_write(ldb->regmap, ldb->ctrl_reg, 0); 555 556 return 0; 557 } 558 559 static const struct dev_pm_ops imx8qm_ldb_pm_ops = { 560 RUNTIME_PM_OPS(imx8qm_ldb_runtime_suspend, imx8qm_ldb_runtime_resume, NULL) 561 }; 562 563 static const struct of_device_id imx8qm_ldb_dt_ids[] = { 564 { .compatible = "fsl,imx8qm-ldb" }, 565 { /* sentinel */ } 566 }; 567 MODULE_DEVICE_TABLE(of, imx8qm_ldb_dt_ids); 568 569 static struct platform_driver imx8qm_ldb_driver = { 570 .probe = imx8qm_ldb_probe, 571 .remove = imx8qm_ldb_remove, 572 .driver = { 573 .pm = pm_ptr(&imx8qm_ldb_pm_ops), 574 .name = DRIVER_NAME, 575 .of_match_table = imx8qm_ldb_dt_ids, 576 }, 577 }; 578 module_platform_driver(imx8qm_ldb_driver); 579 580 MODULE_DESCRIPTION("i.MX8QM LVDS Display Bridge(LDB)/Pixel Mapper bridge driver"); 581 MODULE_AUTHOR("Liu Ying <victor.liu@nxp.com>"); 582 MODULE_LICENSE("GPL v2"); 583 MODULE_ALIAS("platform:" DRIVER_NAME); 584