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 204 imx8qm_ldb_bridge_atomic_enable(struct drm_bridge *bridge, 205 struct drm_bridge_state *old_bridge_state) 206 { 207 struct ldb_channel *ldb_ch = bridge->driver_private; 208 struct ldb *ldb = ldb_ch->ldb; 209 struct imx8qm_ldb_channel *imx8qm_ldb_ch = 210 base_to_imx8qm_ldb_channel(ldb_ch); 211 struct imx8qm_ldb *imx8qm_ldb = base_to_imx8qm_ldb(ldb); 212 struct device *dev = imx8qm_ldb->dev; 213 bool is_split = ldb_channel_is_split_link(ldb_ch); 214 int ret; 215 216 clk_prepare_enable(imx8qm_ldb->clk_pixel); 217 clk_prepare_enable(imx8qm_ldb->clk_bypass); 218 219 /* both DI0 and DI1 connect with pixel link, so ok to use DI0 only */ 220 if (ldb_ch->chno == 0 || is_split) { 221 ldb->ldb_ctrl &= ~LDB_CH0_MODE_EN_MASK; 222 ldb->ldb_ctrl |= LDB_CH0_MODE_EN_TO_DI0; 223 } 224 if (ldb_ch->chno == 1 || is_split) { 225 ldb->ldb_ctrl &= ~LDB_CH1_MODE_EN_MASK; 226 ldb->ldb_ctrl |= LDB_CH1_MODE_EN_TO_DI0; 227 } 228 229 if (is_split) { 230 ret = phy_power_on(imx8qm_ldb->channel[0].phy); 231 if (ret) 232 DRM_DEV_ERROR(dev, 233 "failed to power on channel0 PHY: %d\n", 234 ret); 235 236 ret = phy_power_on(imx8qm_ldb->channel[1].phy); 237 if (ret) 238 DRM_DEV_ERROR(dev, 239 "failed to power on channel1 PHY: %d\n", 240 ret); 241 } else { 242 ret = phy_power_on(imx8qm_ldb_ch->phy); 243 if (ret) 244 DRM_DEV_ERROR(dev, "failed to power on PHY: %d\n", ret); 245 } 246 247 ldb_bridge_enable_helper(bridge); 248 } 249 250 static void 251 imx8qm_ldb_bridge_atomic_disable(struct drm_bridge *bridge, 252 struct drm_bridge_state *old_bridge_state) 253 { 254 struct ldb_channel *ldb_ch = bridge->driver_private; 255 struct ldb *ldb = ldb_ch->ldb; 256 struct imx8qm_ldb_channel *imx8qm_ldb_ch = 257 base_to_imx8qm_ldb_channel(ldb_ch); 258 struct imx8qm_ldb *imx8qm_ldb = base_to_imx8qm_ldb(ldb); 259 struct device *dev = imx8qm_ldb->dev; 260 bool is_split = ldb_channel_is_split_link(ldb_ch); 261 int ret; 262 263 ldb_bridge_disable_helper(bridge); 264 265 if (is_split) { 266 ret = phy_power_off(imx8qm_ldb->channel[0].phy); 267 if (ret) 268 DRM_DEV_ERROR(dev, 269 "failed to power off channel0 PHY: %d\n", 270 ret); 271 ret = phy_power_off(imx8qm_ldb->channel[1].phy); 272 if (ret) 273 DRM_DEV_ERROR(dev, 274 "failed to power off channel1 PHY: %d\n", 275 ret); 276 } else { 277 ret = phy_power_off(imx8qm_ldb_ch->phy); 278 if (ret) 279 DRM_DEV_ERROR(dev, "failed to power off PHY: %d\n", ret); 280 } 281 282 clk_disable_unprepare(imx8qm_ldb->clk_bypass); 283 clk_disable_unprepare(imx8qm_ldb->clk_pixel); 284 285 ret = pm_runtime_put(dev); 286 if (ret < 0) 287 DRM_DEV_ERROR(dev, "failed to put runtime PM: %d\n", ret); 288 } 289 290 static const u32 imx8qm_ldb_bus_output_fmts[] = { 291 MEDIA_BUS_FMT_RGB666_1X7X3_SPWG, 292 MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, 293 MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA, 294 MEDIA_BUS_FMT_FIXED, 295 }; 296 297 static bool imx8qm_ldb_bus_output_fmt_supported(u32 fmt) 298 { 299 int i; 300 301 for (i = 0; i < ARRAY_SIZE(imx8qm_ldb_bus_output_fmts); i++) { 302 if (imx8qm_ldb_bus_output_fmts[i] == fmt) 303 return true; 304 } 305 306 return false; 307 } 308 309 static u32 * 310 imx8qm_ldb_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge, 311 struct drm_bridge_state *bridge_state, 312 struct drm_crtc_state *crtc_state, 313 struct drm_connector_state *conn_state, 314 u32 output_fmt, 315 unsigned int *num_input_fmts) 316 { 317 struct drm_display_info *di; 318 const struct drm_format_info *finfo; 319 u32 *input_fmts; 320 321 if (!imx8qm_ldb_bus_output_fmt_supported(output_fmt)) 322 return NULL; 323 324 *num_input_fmts = 1; 325 326 input_fmts = kmalloc(sizeof(*input_fmts), GFP_KERNEL); 327 if (!input_fmts) 328 return NULL; 329 330 switch (output_fmt) { 331 case MEDIA_BUS_FMT_FIXED: 332 di = &conn_state->connector->display_info; 333 334 /* 335 * Look at the first bus format to determine input format. 336 * Default to MEDIA_BUS_FMT_RGB888_1X36_CPADLO, if no match. 337 */ 338 if (di->num_bus_formats) { 339 finfo = drm_format_info(di->bus_formats[0]); 340 341 input_fmts[0] = finfo->depth == 18 ? 342 MEDIA_BUS_FMT_RGB666_1X36_CPADLO : 343 MEDIA_BUS_FMT_RGB888_1X36_CPADLO; 344 } else { 345 input_fmts[0] = MEDIA_BUS_FMT_RGB888_1X36_CPADLO; 346 } 347 break; 348 case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG: 349 input_fmts[0] = MEDIA_BUS_FMT_RGB666_1X36_CPADLO; 350 break; 351 case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG: 352 case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA: 353 input_fmts[0] = MEDIA_BUS_FMT_RGB888_1X36_CPADLO; 354 break; 355 default: 356 kfree(input_fmts); 357 input_fmts = NULL; 358 break; 359 } 360 361 return input_fmts; 362 } 363 364 static u32 * 365 imx8qm_ldb_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge, 366 struct drm_bridge_state *bridge_state, 367 struct drm_crtc_state *crtc_state, 368 struct drm_connector_state *conn_state, 369 unsigned int *num_output_fmts) 370 { 371 *num_output_fmts = ARRAY_SIZE(imx8qm_ldb_bus_output_fmts); 372 return kmemdup(imx8qm_ldb_bus_output_fmts, 373 sizeof(imx8qm_ldb_bus_output_fmts), GFP_KERNEL); 374 } 375 376 static enum drm_mode_status 377 imx8qm_ldb_bridge_mode_valid(struct drm_bridge *bridge, 378 const struct drm_display_info *info, 379 const struct drm_display_mode *mode) 380 { 381 struct ldb_channel *ldb_ch = bridge->driver_private; 382 bool is_single = ldb_channel_is_single_link(ldb_ch); 383 384 if (mode->clock > 300000) 385 return MODE_CLOCK_HIGH; 386 387 if (mode->clock > 150000 && is_single) 388 return MODE_CLOCK_HIGH; 389 390 return MODE_OK; 391 } 392 393 static const struct drm_bridge_funcs imx8qm_ldb_bridge_funcs = { 394 .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, 395 .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, 396 .atomic_reset = drm_atomic_helper_bridge_reset, 397 .mode_valid = imx8qm_ldb_bridge_mode_valid, 398 .attach = ldb_bridge_attach_helper, 399 .atomic_check = imx8qm_ldb_bridge_atomic_check, 400 .mode_set = imx8qm_ldb_bridge_mode_set, 401 .atomic_enable = imx8qm_ldb_bridge_atomic_enable, 402 .atomic_disable = imx8qm_ldb_bridge_atomic_disable, 403 .atomic_get_input_bus_fmts = 404 imx8qm_ldb_bridge_atomic_get_input_bus_fmts, 405 .atomic_get_output_bus_fmts = 406 imx8qm_ldb_bridge_atomic_get_output_bus_fmts, 407 }; 408 409 static int imx8qm_ldb_get_phy(struct imx8qm_ldb *imx8qm_ldb) 410 { 411 struct imx8qm_ldb_channel *imx8qm_ldb_ch; 412 struct ldb_channel *ldb_ch; 413 struct device *dev = imx8qm_ldb->dev; 414 int i, ret; 415 416 for (i = 0; i < MAX_LDB_CHAN_NUM; i++) { 417 imx8qm_ldb_ch = &imx8qm_ldb->channel[i]; 418 ldb_ch = &imx8qm_ldb_ch->base; 419 420 if (!ldb_ch->is_available) 421 continue; 422 423 imx8qm_ldb_ch->phy = devm_of_phy_get(dev, ldb_ch->np, 424 "lvds_phy"); 425 if (IS_ERR(imx8qm_ldb_ch->phy)) { 426 ret = PTR_ERR(imx8qm_ldb_ch->phy); 427 if (ret != -EPROBE_DEFER) 428 DRM_DEV_ERROR(dev, 429 "failed to get channel%d PHY: %d\n", 430 i, ret); 431 return ret; 432 } 433 } 434 435 return 0; 436 } 437 438 static int imx8qm_ldb_probe(struct platform_device *pdev) 439 { 440 struct device *dev = &pdev->dev; 441 struct imx8qm_ldb *imx8qm_ldb; 442 struct imx8qm_ldb_channel *imx8qm_ldb_ch; 443 struct ldb *ldb; 444 struct ldb_channel *ldb_ch; 445 struct device_node *port1, *port2; 446 int pixel_order; 447 int ret, i; 448 449 imx8qm_ldb = devm_kzalloc(dev, sizeof(*imx8qm_ldb), GFP_KERNEL); 450 if (!imx8qm_ldb) 451 return -ENOMEM; 452 453 imx8qm_ldb->clk_pixel = devm_clk_get(dev, "pixel"); 454 if (IS_ERR(imx8qm_ldb->clk_pixel)) { 455 ret = PTR_ERR(imx8qm_ldb->clk_pixel); 456 if (ret != -EPROBE_DEFER) 457 DRM_DEV_ERROR(dev, 458 "failed to get pixel clock: %d\n", ret); 459 return ret; 460 } 461 462 imx8qm_ldb->clk_bypass = devm_clk_get(dev, "bypass"); 463 if (IS_ERR(imx8qm_ldb->clk_bypass)) { 464 ret = PTR_ERR(imx8qm_ldb->clk_bypass); 465 if (ret != -EPROBE_DEFER) 466 DRM_DEV_ERROR(dev, 467 "failed to get bypass clock: %d\n", ret); 468 return ret; 469 } 470 471 imx8qm_ldb->dev = dev; 472 473 ldb = &imx8qm_ldb->base; 474 ldb->dev = dev; 475 ldb->ctrl_reg = 0xe0; 476 477 for (i = 0; i < MAX_LDB_CHAN_NUM; i++) 478 ldb->channel[i] = &imx8qm_ldb->channel[i].base; 479 480 ret = ldb_init_helper(ldb); 481 if (ret) 482 return ret; 483 484 if (ldb->available_ch_cnt == 0) { 485 DRM_DEV_DEBUG_DRIVER(dev, "no available channel\n"); 486 return 0; 487 } 488 489 if (ldb->available_ch_cnt == 2) { 490 port1 = of_graph_get_port_by_id(ldb->channel[0]->np, 1); 491 port2 = of_graph_get_port_by_id(ldb->channel[1]->np, 1); 492 pixel_order = 493 drm_of_lvds_get_dual_link_pixel_order(port1, port2); 494 of_node_put(port1); 495 of_node_put(port2); 496 497 if (pixel_order != DRM_LVDS_DUAL_LINK_ODD_EVEN_PIXELS) { 498 DRM_DEV_ERROR(dev, "invalid dual link pixel order: %d\n", 499 pixel_order); 500 return -EINVAL; 501 } 502 503 imx8qm_ldb->active_chno = 0; 504 imx8qm_ldb_ch = &imx8qm_ldb->channel[0]; 505 ldb_ch = &imx8qm_ldb_ch->base; 506 ldb_ch->link_type = pixel_order; 507 } else { 508 for (i = 0; i < MAX_LDB_CHAN_NUM; i++) { 509 imx8qm_ldb_ch = &imx8qm_ldb->channel[i]; 510 ldb_ch = &imx8qm_ldb_ch->base; 511 512 if (ldb_ch->is_available) { 513 imx8qm_ldb->active_chno = ldb_ch->chno; 514 break; 515 } 516 } 517 } 518 519 ret = imx8qm_ldb_get_phy(imx8qm_ldb); 520 if (ret) 521 return ret; 522 523 ret = ldb_find_next_bridge_helper(ldb); 524 if (ret) 525 return ret; 526 527 platform_set_drvdata(pdev, imx8qm_ldb); 528 pm_runtime_enable(dev); 529 530 ldb_add_bridge_helper(ldb, &imx8qm_ldb_bridge_funcs); 531 532 return ret; 533 } 534 535 static void imx8qm_ldb_remove(struct platform_device *pdev) 536 { 537 struct imx8qm_ldb *imx8qm_ldb = platform_get_drvdata(pdev); 538 struct ldb *ldb = &imx8qm_ldb->base; 539 540 ldb_remove_bridge_helper(ldb); 541 542 pm_runtime_disable(&pdev->dev); 543 } 544 545 static int __maybe_unused imx8qm_ldb_runtime_suspend(struct device *dev) 546 { 547 return 0; 548 } 549 550 static int __maybe_unused imx8qm_ldb_runtime_resume(struct device *dev) 551 { 552 struct imx8qm_ldb *imx8qm_ldb = dev_get_drvdata(dev); 553 struct ldb *ldb = &imx8qm_ldb->base; 554 555 /* disable LDB by resetting the control register to POR default */ 556 regmap_write(ldb->regmap, ldb->ctrl_reg, 0); 557 558 return 0; 559 } 560 561 static const struct dev_pm_ops imx8qm_ldb_pm_ops = { 562 SET_RUNTIME_PM_OPS(imx8qm_ldb_runtime_suspend, 563 imx8qm_ldb_runtime_resume, NULL) 564 }; 565 566 static const struct of_device_id imx8qm_ldb_dt_ids[] = { 567 { .compatible = "fsl,imx8qm-ldb" }, 568 { /* sentinel */ } 569 }; 570 MODULE_DEVICE_TABLE(of, imx8qm_ldb_dt_ids); 571 572 static struct platform_driver imx8qm_ldb_driver = { 573 .probe = imx8qm_ldb_probe, 574 .remove_new = imx8qm_ldb_remove, 575 .driver = { 576 .pm = &imx8qm_ldb_pm_ops, 577 .name = DRIVER_NAME, 578 .of_match_table = imx8qm_ldb_dt_ids, 579 }, 580 }; 581 module_platform_driver(imx8qm_ldb_driver); 582 583 MODULE_DESCRIPTION("i.MX8QM LVDS Display Bridge(LDB)/Pixel Mapper bridge driver"); 584 MODULE_AUTHOR("Liu Ying <victor.liu@nxp.com>"); 585 MODULE_LICENSE("GPL v2"); 586 MODULE_ALIAS("platform:" DRIVER_NAME); 587