Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.14 622 lines 17 kB view raw
1/* 2 * i.MX drm driver - LVDS display bridge 3 * 4 * Copyright (C) 2012 Sascha Hauer, Pengutronix 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * as published by the Free Software Foundation; either version 2 9 * of the License, or (at your option) any later version. 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 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 * MA 02110-1301, USA. 19 */ 20 21#include <linux/module.h> 22#include <linux/clk.h> 23#include <drm/drmP.h> 24#include <drm/drm_fb_helper.h> 25#include <drm/drm_crtc_helper.h> 26#include <linux/mfd/syscon.h> 27#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h> 28#include <linux/of_address.h> 29#include <linux/of_device.h> 30#include <video/of_videomode.h> 31#include <linux/regmap.h> 32#include <linux/videodev2.h> 33 34#include "imx-drm.h" 35 36#define DRIVER_NAME "imx-ldb" 37 38#define LDB_CH0_MODE_EN_TO_DI0 (1 << 0) 39#define LDB_CH0_MODE_EN_TO_DI1 (3 << 0) 40#define LDB_CH0_MODE_EN_MASK (3 << 0) 41#define LDB_CH1_MODE_EN_TO_DI0 (1 << 2) 42#define LDB_CH1_MODE_EN_TO_DI1 (3 << 2) 43#define LDB_CH1_MODE_EN_MASK (3 << 2) 44#define LDB_SPLIT_MODE_EN (1 << 4) 45#define LDB_DATA_WIDTH_CH0_24 (1 << 5) 46#define LDB_BIT_MAP_CH0_JEIDA (1 << 6) 47#define LDB_DATA_WIDTH_CH1_24 (1 << 7) 48#define LDB_BIT_MAP_CH1_JEIDA (1 << 8) 49#define LDB_DI0_VS_POL_ACT_LOW (1 << 9) 50#define LDB_DI1_VS_POL_ACT_LOW (1 << 10) 51#define LDB_BGREF_RMODE_INT (1 << 15) 52 53#define con_to_imx_ldb_ch(x) container_of(x, struct imx_ldb_channel, connector) 54#define enc_to_imx_ldb_ch(x) container_of(x, struct imx_ldb_channel, encoder) 55 56struct imx_ldb; 57 58struct imx_ldb_channel { 59 struct imx_ldb *ldb; 60 struct drm_connector connector; 61 struct imx_drm_connector *imx_drm_connector; 62 struct drm_encoder encoder; 63 struct imx_drm_encoder *imx_drm_encoder; 64 int chno; 65 void *edid; 66 int edid_len; 67 struct drm_display_mode mode; 68 int mode_valid; 69}; 70 71struct bus_mux { 72 int reg; 73 int shift; 74 int mask; 75}; 76 77struct imx_ldb { 78 struct regmap *regmap; 79 struct device *dev; 80 struct imx_ldb_channel channel[2]; 81 struct clk *clk[2]; /* our own clock */ 82 struct clk *clk_sel[4]; /* parent of display clock */ 83 struct clk *clk_pll[2]; /* upstream clock we can adjust */ 84 u32 ldb_ctrl; 85 const struct bus_mux *lvds_mux; 86}; 87 88static enum drm_connector_status imx_ldb_connector_detect( 89 struct drm_connector *connector, bool force) 90{ 91 return connector_status_connected; 92} 93 94static void imx_ldb_connector_destroy(struct drm_connector *connector) 95{ 96 /* do not free here */ 97} 98 99static int imx_ldb_connector_get_modes(struct drm_connector *connector) 100{ 101 struct imx_ldb_channel *imx_ldb_ch = con_to_imx_ldb_ch(connector); 102 int num_modes = 0; 103 104 if (imx_ldb_ch->edid) { 105 drm_mode_connector_update_edid_property(connector, 106 imx_ldb_ch->edid); 107 num_modes = drm_add_edid_modes(connector, imx_ldb_ch->edid); 108 } 109 110 if (imx_ldb_ch->mode_valid) { 111 struct drm_display_mode *mode; 112 113 mode = drm_mode_create(connector->dev); 114 drm_mode_copy(mode, &imx_ldb_ch->mode); 115 mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; 116 drm_mode_probed_add(connector, mode); 117 num_modes++; 118 } 119 120 return num_modes; 121} 122 123static int imx_ldb_connector_mode_valid(struct drm_connector *connector, 124 struct drm_display_mode *mode) 125{ 126 return 0; 127} 128 129static struct drm_encoder *imx_ldb_connector_best_encoder( 130 struct drm_connector *connector) 131{ 132 struct imx_ldb_channel *imx_ldb_ch = con_to_imx_ldb_ch(connector); 133 134 return &imx_ldb_ch->encoder; 135} 136 137static void imx_ldb_encoder_dpms(struct drm_encoder *encoder, int mode) 138{ 139} 140 141static bool imx_ldb_encoder_mode_fixup(struct drm_encoder *encoder, 142 const struct drm_display_mode *mode, 143 struct drm_display_mode *adjusted_mode) 144{ 145 return true; 146} 147 148static void imx_ldb_set_clock(struct imx_ldb *ldb, int mux, int chno, 149 unsigned long serial_clk, unsigned long di_clk) 150{ 151 int ret; 152 153 dev_dbg(ldb->dev, "%s: now: %ld want: %ld\n", __func__, 154 clk_get_rate(ldb->clk_pll[chno]), serial_clk); 155 clk_set_rate(ldb->clk_pll[chno], serial_clk); 156 157 dev_dbg(ldb->dev, "%s after: %ld\n", __func__, 158 clk_get_rate(ldb->clk_pll[chno])); 159 160 dev_dbg(ldb->dev, "%s: now: %ld want: %ld\n", __func__, 161 clk_get_rate(ldb->clk[chno]), 162 (long int)di_clk); 163 clk_set_rate(ldb->clk[chno], di_clk); 164 165 dev_dbg(ldb->dev, "%s after: %ld\n", __func__, 166 clk_get_rate(ldb->clk[chno])); 167 168 /* set display clock mux to LDB input clock */ 169 ret = clk_set_parent(ldb->clk_sel[mux], ldb->clk[chno]); 170 if (ret) 171 dev_err(ldb->dev, "unable to set di%d parent clock to ldb_di%d\n", mux, chno); 172} 173 174static void imx_ldb_encoder_prepare(struct drm_encoder *encoder) 175{ 176 struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder); 177 struct imx_ldb *ldb = imx_ldb_ch->ldb; 178 struct drm_display_mode *mode = &encoder->crtc->mode; 179 u32 pixel_fmt; 180 unsigned long serial_clk; 181 unsigned long di_clk = mode->clock * 1000; 182 int mux = imx_drm_encoder_get_mux_id(imx_ldb_ch->imx_drm_encoder, 183 encoder->crtc); 184 185 if (ldb->ldb_ctrl & LDB_SPLIT_MODE_EN) { 186 /* dual channel LVDS mode */ 187 serial_clk = 3500UL * mode->clock; 188 imx_ldb_set_clock(ldb, mux, 0, serial_clk, di_clk); 189 imx_ldb_set_clock(ldb, mux, 1, serial_clk, di_clk); 190 } else { 191 serial_clk = 7000UL * mode->clock; 192 imx_ldb_set_clock(ldb, mux, imx_ldb_ch->chno, serial_clk, di_clk); 193 } 194 195 switch (imx_ldb_ch->chno) { 196 case 0: 197 pixel_fmt = (ldb->ldb_ctrl & LDB_DATA_WIDTH_CH0_24) ? 198 V4L2_PIX_FMT_RGB24 : V4L2_PIX_FMT_BGR666; 199 break; 200 case 1: 201 pixel_fmt = (ldb->ldb_ctrl & LDB_DATA_WIDTH_CH1_24) ? 202 V4L2_PIX_FMT_RGB24 : V4L2_PIX_FMT_BGR666; 203 break; 204 default: 205 dev_err(ldb->dev, "unable to config di%d panel format\n", 206 imx_ldb_ch->chno); 207 pixel_fmt = V4L2_PIX_FMT_RGB24; 208 } 209 210 imx_drm_crtc_panel_format(encoder->crtc, DRM_MODE_ENCODER_LVDS, 211 pixel_fmt); 212} 213 214static void imx_ldb_encoder_commit(struct drm_encoder *encoder) 215{ 216 struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder); 217 struct imx_ldb *ldb = imx_ldb_ch->ldb; 218 int dual = ldb->ldb_ctrl & LDB_SPLIT_MODE_EN; 219 int mux = imx_drm_encoder_get_mux_id(imx_ldb_ch->imx_drm_encoder, 220 encoder->crtc); 221 222 if (dual) { 223 clk_prepare_enable(ldb->clk[0]); 224 clk_prepare_enable(ldb->clk[1]); 225 } 226 227 if (imx_ldb_ch == &ldb->channel[0] || dual) { 228 ldb->ldb_ctrl &= ~LDB_CH0_MODE_EN_MASK; 229 if (mux == 0 || ldb->lvds_mux) 230 ldb->ldb_ctrl |= LDB_CH0_MODE_EN_TO_DI0; 231 else if (mux == 1) 232 ldb->ldb_ctrl |= LDB_CH0_MODE_EN_TO_DI1; 233 } 234 if (imx_ldb_ch == &ldb->channel[1] || dual) { 235 ldb->ldb_ctrl &= ~LDB_CH1_MODE_EN_MASK; 236 if (mux == 1 || ldb->lvds_mux) 237 ldb->ldb_ctrl |= LDB_CH1_MODE_EN_TO_DI1; 238 else if (mux == 0) 239 ldb->ldb_ctrl |= LDB_CH1_MODE_EN_TO_DI0; 240 } 241 242 if (ldb->lvds_mux) { 243 const struct bus_mux *lvds_mux = NULL; 244 245 if (imx_ldb_ch == &ldb->channel[0]) 246 lvds_mux = &ldb->lvds_mux[0]; 247 else if (imx_ldb_ch == &ldb->channel[1]) 248 lvds_mux = &ldb->lvds_mux[1]; 249 250 regmap_update_bits(ldb->regmap, lvds_mux->reg, lvds_mux->mask, 251 mux << lvds_mux->shift); 252 } 253 254 regmap_write(ldb->regmap, IOMUXC_GPR2, ldb->ldb_ctrl); 255} 256 257static void imx_ldb_encoder_mode_set(struct drm_encoder *encoder, 258 struct drm_display_mode *mode, 259 struct drm_display_mode *adjusted_mode) 260{ 261 struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder); 262 struct imx_ldb *ldb = imx_ldb_ch->ldb; 263 int dual = ldb->ldb_ctrl & LDB_SPLIT_MODE_EN; 264 265 if (mode->clock > 170000) { 266 dev_warn(ldb->dev, 267 "%s: mode exceeds 170 MHz pixel clock\n", __func__); 268 } 269 if (mode->clock > 85000 && !dual) { 270 dev_warn(ldb->dev, 271 "%s: mode exceeds 85 MHz pixel clock\n", __func__); 272 } 273 274 /* FIXME - assumes straight connections DI0 --> CH0, DI1 --> CH1 */ 275 if (imx_ldb_ch == &ldb->channel[0]) { 276 if (mode->flags & DRM_MODE_FLAG_NVSYNC) 277 ldb->ldb_ctrl |= LDB_DI0_VS_POL_ACT_LOW; 278 else if (mode->flags & DRM_MODE_FLAG_PVSYNC) 279 ldb->ldb_ctrl &= ~LDB_DI0_VS_POL_ACT_LOW; 280 } 281 if (imx_ldb_ch == &ldb->channel[1]) { 282 if (mode->flags & DRM_MODE_FLAG_NVSYNC) 283 ldb->ldb_ctrl |= LDB_DI1_VS_POL_ACT_LOW; 284 else if (mode->flags & DRM_MODE_FLAG_PVSYNC) 285 ldb->ldb_ctrl &= ~LDB_DI1_VS_POL_ACT_LOW; 286 } 287} 288 289static void imx_ldb_encoder_disable(struct drm_encoder *encoder) 290{ 291 struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder); 292 struct imx_ldb *ldb = imx_ldb_ch->ldb; 293 294 /* 295 * imx_ldb_encoder_disable is called by 296 * drm_helper_disable_unused_functions without 297 * the encoder being enabled before. 298 */ 299 if (imx_ldb_ch == &ldb->channel[0] && 300 (ldb->ldb_ctrl & LDB_CH0_MODE_EN_MASK) == 0) 301 return; 302 else if (imx_ldb_ch == &ldb->channel[1] && 303 (ldb->ldb_ctrl & LDB_CH1_MODE_EN_MASK) == 0) 304 return; 305 306 if (imx_ldb_ch == &ldb->channel[0]) 307 ldb->ldb_ctrl &= ~LDB_CH0_MODE_EN_MASK; 308 else if (imx_ldb_ch == &ldb->channel[1]) 309 ldb->ldb_ctrl &= ~LDB_CH1_MODE_EN_MASK; 310 311 regmap_write(ldb->regmap, IOMUXC_GPR2, ldb->ldb_ctrl); 312 313 if (ldb->ldb_ctrl & LDB_SPLIT_MODE_EN) { 314 clk_disable_unprepare(ldb->clk[0]); 315 clk_disable_unprepare(ldb->clk[1]); 316 } 317} 318 319static void imx_ldb_encoder_destroy(struct drm_encoder *encoder) 320{ 321 /* do not free here */ 322} 323 324static struct drm_connector_funcs imx_ldb_connector_funcs = { 325 .dpms = drm_helper_connector_dpms, 326 .fill_modes = drm_helper_probe_single_connector_modes, 327 .detect = imx_ldb_connector_detect, 328 .destroy = imx_ldb_connector_destroy, 329}; 330 331static struct drm_connector_helper_funcs imx_ldb_connector_helper_funcs = { 332 .get_modes = imx_ldb_connector_get_modes, 333 .best_encoder = imx_ldb_connector_best_encoder, 334 .mode_valid = imx_ldb_connector_mode_valid, 335}; 336 337static struct drm_encoder_funcs imx_ldb_encoder_funcs = { 338 .destroy = imx_ldb_encoder_destroy, 339}; 340 341static struct drm_encoder_helper_funcs imx_ldb_encoder_helper_funcs = { 342 .dpms = imx_ldb_encoder_dpms, 343 .mode_fixup = imx_ldb_encoder_mode_fixup, 344 .prepare = imx_ldb_encoder_prepare, 345 .commit = imx_ldb_encoder_commit, 346 .mode_set = imx_ldb_encoder_mode_set, 347 .disable = imx_ldb_encoder_disable, 348}; 349 350static int imx_ldb_get_clk(struct imx_ldb *ldb, int chno) 351{ 352 char clkname[16]; 353 354 sprintf(clkname, "di%d", chno); 355 ldb->clk[chno] = devm_clk_get(ldb->dev, clkname); 356 if (IS_ERR(ldb->clk[chno])) 357 return PTR_ERR(ldb->clk[chno]); 358 359 sprintf(clkname, "di%d_pll", chno); 360 ldb->clk_pll[chno] = devm_clk_get(ldb->dev, clkname); 361 362 return PTR_ERR_OR_ZERO(ldb->clk_pll[chno]); 363} 364 365static int imx_ldb_register(struct imx_ldb_channel *imx_ldb_ch) 366{ 367 int ret; 368 struct imx_ldb *ldb = imx_ldb_ch->ldb; 369 370 ret = imx_ldb_get_clk(ldb, imx_ldb_ch->chno); 371 if (ret) 372 return ret; 373 if (ldb->ldb_ctrl & LDB_SPLIT_MODE_EN) { 374 ret |= imx_ldb_get_clk(ldb, 1); 375 if (ret) 376 return ret; 377 } 378 379 imx_ldb_ch->connector.funcs = &imx_ldb_connector_funcs; 380 imx_ldb_ch->encoder.funcs = &imx_ldb_encoder_funcs; 381 382 imx_ldb_ch->encoder.encoder_type = DRM_MODE_ENCODER_LVDS; 383 imx_ldb_ch->connector.connector_type = DRM_MODE_CONNECTOR_LVDS; 384 385 drm_encoder_helper_add(&imx_ldb_ch->encoder, 386 &imx_ldb_encoder_helper_funcs); 387 ret = imx_drm_add_encoder(&imx_ldb_ch->encoder, 388 &imx_ldb_ch->imx_drm_encoder, THIS_MODULE); 389 if (ret) { 390 dev_err(ldb->dev, "adding encoder failed with %d\n", ret); 391 return ret; 392 } 393 394 drm_connector_helper_add(&imx_ldb_ch->connector, 395 &imx_ldb_connector_helper_funcs); 396 397 ret = imx_drm_add_connector(&imx_ldb_ch->connector, 398 &imx_ldb_ch->imx_drm_connector, THIS_MODULE); 399 if (ret) { 400 imx_drm_remove_encoder(imx_ldb_ch->imx_drm_encoder); 401 dev_err(ldb->dev, "adding connector failed with %d\n", ret); 402 return ret; 403 } 404 405 drm_mode_connector_attach_encoder(&imx_ldb_ch->connector, 406 &imx_ldb_ch->encoder); 407 408 return 0; 409} 410 411enum { 412 LVDS_BIT_MAP_SPWG, 413 LVDS_BIT_MAP_JEIDA 414}; 415 416static const char * const imx_ldb_bit_mappings[] = { 417 [LVDS_BIT_MAP_SPWG] = "spwg", 418 [LVDS_BIT_MAP_JEIDA] = "jeida", 419}; 420 421static const int of_get_data_mapping(struct device_node *np) 422{ 423 const char *bm; 424 int ret, i; 425 426 ret = of_property_read_string(np, "fsl,data-mapping", &bm); 427 if (ret < 0) 428 return ret; 429 430 for (i = 0; i < ARRAY_SIZE(imx_ldb_bit_mappings); i++) 431 if (!strcasecmp(bm, imx_ldb_bit_mappings[i])) 432 return i; 433 434 return -EINVAL; 435} 436 437static struct bus_mux imx6q_lvds_mux[2] = { 438 { 439 .reg = IOMUXC_GPR3, 440 .shift = 6, 441 .mask = IMX6Q_GPR3_LVDS0_MUX_CTL_MASK, 442 }, { 443 .reg = IOMUXC_GPR3, 444 .shift = 8, 445 .mask = IMX6Q_GPR3_LVDS1_MUX_CTL_MASK, 446 } 447}; 448 449/* 450 * For a device declaring compatible = "fsl,imx6q-ldb", "fsl,imx53-ldb", 451 * of_match_device will walk through this list and take the first entry 452 * matching any of its compatible values. Therefore, the more generic 453 * entries (in this case fsl,imx53-ldb) need to be ordered last. 454 */ 455static const struct of_device_id imx_ldb_dt_ids[] = { 456 { .compatible = "fsl,imx6q-ldb", .data = imx6q_lvds_mux, }, 457 { .compatible = "fsl,imx53-ldb", .data = NULL, }, 458 { } 459}; 460MODULE_DEVICE_TABLE(of, imx_ldb_dt_ids); 461 462static int imx_ldb_probe(struct platform_device *pdev) 463{ 464 struct device_node *np = pdev->dev.of_node; 465 const struct of_device_id *of_id = 466 of_match_device(imx_ldb_dt_ids, &pdev->dev); 467 struct device_node *child; 468 const u8 *edidp; 469 struct imx_ldb *imx_ldb; 470 int datawidth; 471 int mapping; 472 int dual; 473 int ret; 474 int i; 475 476 imx_ldb = devm_kzalloc(&pdev->dev, sizeof(*imx_ldb), GFP_KERNEL); 477 if (!imx_ldb) 478 return -ENOMEM; 479 480 imx_ldb->regmap = syscon_regmap_lookup_by_phandle(np, "gpr"); 481 if (IS_ERR(imx_ldb->regmap)) { 482 dev_err(&pdev->dev, "failed to get parent regmap\n"); 483 return PTR_ERR(imx_ldb->regmap); 484 } 485 486 imx_ldb->dev = &pdev->dev; 487 488 if (of_id) 489 imx_ldb->lvds_mux = of_id->data; 490 491 dual = of_property_read_bool(np, "fsl,dual-channel"); 492 if (dual) 493 imx_ldb->ldb_ctrl |= LDB_SPLIT_MODE_EN; 494 495 /* 496 * There are three different possible clock mux configurations: 497 * i.MX53: ipu1_di0_sel, ipu1_di1_sel 498 * i.MX6q: ipu1_di0_sel, ipu1_di1_sel, ipu2_di0_sel, ipu2_di1_sel 499 * i.MX6dl: ipu1_di0_sel, ipu1_di1_sel, lcdif_sel 500 * Map them all to di0_sel...di3_sel. 501 */ 502 for (i = 0; i < 4; i++) { 503 char clkname[16]; 504 505 sprintf(clkname, "di%d_sel", i); 506 imx_ldb->clk_sel[i] = devm_clk_get(imx_ldb->dev, clkname); 507 if (IS_ERR(imx_ldb->clk_sel[i])) { 508 ret = PTR_ERR(imx_ldb->clk_sel[i]); 509 imx_ldb->clk_sel[i] = NULL; 510 break; 511 } 512 } 513 if (i == 0) 514 return ret; 515 516 for_each_child_of_node(np, child) { 517 struct imx_ldb_channel *channel; 518 519 ret = of_property_read_u32(child, "reg", &i); 520 if (ret || i < 0 || i > 1) 521 return -EINVAL; 522 523 if (dual && i > 0) { 524 dev_warn(&pdev->dev, "dual-channel mode, ignoring second output\n"); 525 continue; 526 } 527 528 if (!of_device_is_available(child)) 529 continue; 530 531 channel = &imx_ldb->channel[i]; 532 channel->ldb = imx_ldb; 533 channel->chno = i; 534 535 edidp = of_get_property(child, "edid", &channel->edid_len); 536 if (edidp) { 537 channel->edid = kmemdup(edidp, channel->edid_len, 538 GFP_KERNEL); 539 } else { 540 ret = of_get_drm_display_mode(child, &channel->mode, 0); 541 if (!ret) 542 channel->mode_valid = 1; 543 } 544 545 ret = of_property_read_u32(child, "fsl,data-width", &datawidth); 546 if (ret) 547 datawidth = 0; 548 else if (datawidth != 18 && datawidth != 24) 549 return -EINVAL; 550 551 mapping = of_get_data_mapping(child); 552 switch (mapping) { 553 case LVDS_BIT_MAP_SPWG: 554 if (datawidth == 24) { 555 if (i == 0 || dual) 556 imx_ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH0_24; 557 if (i == 1 || dual) 558 imx_ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH1_24; 559 } 560 break; 561 case LVDS_BIT_MAP_JEIDA: 562 if (datawidth == 18) { 563 dev_err(&pdev->dev, "JEIDA standard only supported in 24 bit\n"); 564 return -EINVAL; 565 } 566 if (i == 0 || dual) 567 imx_ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH0_24 | LDB_BIT_MAP_CH0_JEIDA; 568 if (i == 1 || dual) 569 imx_ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH1_24 | LDB_BIT_MAP_CH1_JEIDA; 570 break; 571 default: 572 dev_err(&pdev->dev, "data mapping not specified or invalid\n"); 573 return -EINVAL; 574 } 575 576 ret = imx_ldb_register(channel); 577 if (ret) 578 return ret; 579 580 imx_drm_encoder_add_possible_crtcs(channel->imx_drm_encoder, child); 581 } 582 583 platform_set_drvdata(pdev, imx_ldb); 584 585 return 0; 586} 587 588static int imx_ldb_remove(struct platform_device *pdev) 589{ 590 struct imx_ldb *imx_ldb = platform_get_drvdata(pdev); 591 int i; 592 593 for (i = 0; i < 2; i++) { 594 struct imx_ldb_channel *channel = &imx_ldb->channel[i]; 595 struct drm_connector *connector = &channel->connector; 596 struct drm_encoder *encoder = &channel->encoder; 597 598 drm_mode_connector_detach_encoder(connector, encoder); 599 600 imx_drm_remove_connector(channel->imx_drm_connector); 601 imx_drm_remove_encoder(channel->imx_drm_encoder); 602 } 603 604 return 0; 605} 606 607static struct platform_driver imx_ldb_driver = { 608 .probe = imx_ldb_probe, 609 .remove = imx_ldb_remove, 610 .driver = { 611 .of_match_table = imx_ldb_dt_ids, 612 .name = DRIVER_NAME, 613 .owner = THIS_MODULE, 614 }, 615}; 616 617module_platform_driver(imx_ldb_driver); 618 619MODULE_DESCRIPTION("i.MX LVDS driver"); 620MODULE_AUTHOR("Sascha Hauer, Pengutronix"); 621MODULE_LICENSE("GPL"); 622MODULE_ALIAS("platform:" DRIVER_NAME);