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