1 /* 2 * Copyright (C) 2015 Free Electrons 3 * Copyright (C) 2015 NextThing Co 4 * 5 * Maxime Ripard <maxime.ripard@free-electrons.com> 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License as 9 * published by the Free Software Foundation; either version 2 of 10 * the License, or (at your option) any later version. 11 */ 12 13 #include <drm/drmP.h> 14 #include <drm/drm_atomic_helper.h> 15 #include <drm/drm_crtc.h> 16 #include <drm/drm_crtc_helper.h> 17 #include <drm/drm_modes.h> 18 #include <drm/drm_panel.h> 19 20 #include <linux/component.h> 21 #include <linux/ioport.h> 22 #include <linux/of_address.h> 23 #include <linux/of_graph.h> 24 #include <linux/of_irq.h> 25 #include <linux/regmap.h> 26 #include <linux/reset.h> 27 28 #include "sun4i_crtc.h" 29 #include "sun4i_dotclock.h" 30 #include "sun4i_drv.h" 31 #include "sun4i_rgb.h" 32 #include "sun4i_tcon.h" 33 34 void sun4i_tcon_disable(struct sun4i_tcon *tcon) 35 { 36 DRM_DEBUG_DRIVER("Disabling TCON\n"); 37 38 /* Disable the TCON */ 39 regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG, 40 SUN4I_TCON_GCTL_TCON_ENABLE, 0); 41 } 42 EXPORT_SYMBOL(sun4i_tcon_disable); 43 44 void sun4i_tcon_enable(struct sun4i_tcon *tcon) 45 { 46 DRM_DEBUG_DRIVER("Enabling TCON\n"); 47 48 /* Enable the TCON */ 49 regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG, 50 SUN4I_TCON_GCTL_TCON_ENABLE, 51 SUN4I_TCON_GCTL_TCON_ENABLE); 52 } 53 EXPORT_SYMBOL(sun4i_tcon_enable); 54 55 void sun4i_tcon_channel_disable(struct sun4i_tcon *tcon, int channel) 56 { 57 /* Disable the TCON's channel */ 58 if (channel == 0) { 59 regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG, 60 SUN4I_TCON0_CTL_TCON_ENABLE, 0); 61 clk_disable_unprepare(tcon->dclk); 62 return; 63 } 64 65 WARN_ON(!tcon->has_channel_1); 66 regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG, 67 SUN4I_TCON1_CTL_TCON_ENABLE, 0); 68 clk_disable_unprepare(tcon->sclk1); 69 } 70 EXPORT_SYMBOL(sun4i_tcon_channel_disable); 71 72 void sun4i_tcon_channel_enable(struct sun4i_tcon *tcon, int channel) 73 { 74 /* Enable the TCON's channel */ 75 if (channel == 0) { 76 regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG, 77 SUN4I_TCON0_CTL_TCON_ENABLE, 78 SUN4I_TCON0_CTL_TCON_ENABLE); 79 clk_prepare_enable(tcon->dclk); 80 return; 81 } 82 83 WARN_ON(!tcon->has_channel_1); 84 regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG, 85 SUN4I_TCON1_CTL_TCON_ENABLE, 86 SUN4I_TCON1_CTL_TCON_ENABLE); 87 clk_prepare_enable(tcon->sclk1); 88 } 89 EXPORT_SYMBOL(sun4i_tcon_channel_enable); 90 91 void sun4i_tcon_enable_vblank(struct sun4i_tcon *tcon, bool enable) 92 { 93 u32 mask, val = 0; 94 95 DRM_DEBUG_DRIVER("%sabling VBLANK interrupt\n", enable ? "En" : "Dis"); 96 97 mask = SUN4I_TCON_GINT0_VBLANK_ENABLE(0) | 98 SUN4I_TCON_GINT0_VBLANK_ENABLE(1); 99 100 if (enable) 101 val = mask; 102 103 regmap_update_bits(tcon->regs, SUN4I_TCON_GINT0_REG, mask, val); 104 } 105 EXPORT_SYMBOL(sun4i_tcon_enable_vblank); 106 107 static int sun4i_tcon_get_clk_delay(struct drm_display_mode *mode, 108 int channel) 109 { 110 int delay = mode->vtotal - mode->vdisplay; 111 112 if (mode->flags & DRM_MODE_FLAG_INTERLACE) 113 delay /= 2; 114 115 if (channel == 1) 116 delay -= 2; 117 118 delay = min(delay, 30); 119 120 DRM_DEBUG_DRIVER("TCON %d clock delay %u\n", channel, delay); 121 122 return delay; 123 } 124 125 void sun4i_tcon0_mode_set(struct sun4i_tcon *tcon, 126 struct drm_display_mode *mode) 127 { 128 unsigned int bp, hsync, vsync; 129 u8 clk_delay; 130 u32 val = 0; 131 132 /* Adjust clock delay */ 133 clk_delay = sun4i_tcon_get_clk_delay(mode, 0); 134 regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG, 135 SUN4I_TCON0_CTL_CLK_DELAY_MASK, 136 SUN4I_TCON0_CTL_CLK_DELAY(clk_delay)); 137 138 /* Set the resolution */ 139 regmap_write(tcon->regs, SUN4I_TCON0_BASIC0_REG, 140 SUN4I_TCON0_BASIC0_X(mode->crtc_hdisplay) | 141 SUN4I_TCON0_BASIC0_Y(mode->crtc_vdisplay)); 142 143 /* 144 * This is called a backporch in the register documentation, 145 * but it really is the front porch + hsync 146 */ 147 bp = mode->crtc_htotal - mode->crtc_hsync_start; 148 DRM_DEBUG_DRIVER("Setting horizontal total %d, backporch %d\n", 149 mode->crtc_htotal, bp); 150 151 /* Set horizontal display timings */ 152 regmap_write(tcon->regs, SUN4I_TCON0_BASIC1_REG, 153 SUN4I_TCON0_BASIC1_H_TOTAL(mode->crtc_htotal) | 154 SUN4I_TCON0_BASIC1_H_BACKPORCH(bp)); 155 156 /* 157 * This is called a backporch in the register documentation, 158 * but it really is the front porch + hsync 159 */ 160 bp = mode->crtc_vtotal - mode->crtc_vsync_start; 161 DRM_DEBUG_DRIVER("Setting vertical total %d, backporch %d\n", 162 mode->crtc_vtotal, bp); 163 164 /* Set vertical display timings */ 165 regmap_write(tcon->regs, SUN4I_TCON0_BASIC2_REG, 166 SUN4I_TCON0_BASIC2_V_TOTAL(mode->crtc_vtotal) | 167 SUN4I_TCON0_BASIC2_V_BACKPORCH(bp)); 168 169 /* Set Hsync and Vsync length */ 170 hsync = mode->crtc_hsync_end - mode->crtc_hsync_start; 171 vsync = mode->crtc_vsync_end - mode->crtc_vsync_start; 172 DRM_DEBUG_DRIVER("Setting HSYNC %d, VSYNC %d\n", hsync, vsync); 173 regmap_write(tcon->regs, SUN4I_TCON0_BASIC3_REG, 174 SUN4I_TCON0_BASIC3_V_SYNC(vsync) | 175 SUN4I_TCON0_BASIC3_H_SYNC(hsync)); 176 177 /* Setup the polarity of the various signals */ 178 if (!(mode->flags & DRM_MODE_FLAG_PHSYNC)) 179 val |= SUN4I_TCON0_IO_POL_HSYNC_POSITIVE; 180 181 if (!(mode->flags & DRM_MODE_FLAG_PVSYNC)) 182 val |= SUN4I_TCON0_IO_POL_VSYNC_POSITIVE; 183 184 regmap_update_bits(tcon->regs, SUN4I_TCON0_IO_POL_REG, 185 SUN4I_TCON0_IO_POL_HSYNC_POSITIVE | SUN4I_TCON0_IO_POL_VSYNC_POSITIVE, 186 val); 187 188 /* Map output pins to channel 0 */ 189 regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG, 190 SUN4I_TCON_GCTL_IOMAP_MASK, 191 SUN4I_TCON_GCTL_IOMAP_TCON0); 192 193 /* Enable the output on the pins */ 194 regmap_write(tcon->regs, SUN4I_TCON0_IO_TRI_REG, 0); 195 } 196 EXPORT_SYMBOL(sun4i_tcon0_mode_set); 197 198 void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon, 199 struct drm_display_mode *mode) 200 { 201 unsigned int bp, hsync, vsync; 202 u8 clk_delay; 203 u32 val; 204 205 WARN_ON(!tcon->has_channel_1); 206 207 /* Adjust clock delay */ 208 clk_delay = sun4i_tcon_get_clk_delay(mode, 1); 209 regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG, 210 SUN4I_TCON1_CTL_CLK_DELAY_MASK, 211 SUN4I_TCON1_CTL_CLK_DELAY(clk_delay)); 212 213 /* Set interlaced mode */ 214 if (mode->flags & DRM_MODE_FLAG_INTERLACE) 215 val = SUN4I_TCON1_CTL_INTERLACE_ENABLE; 216 else 217 val = 0; 218 regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG, 219 SUN4I_TCON1_CTL_INTERLACE_ENABLE, 220 val); 221 222 /* Set the input resolution */ 223 regmap_write(tcon->regs, SUN4I_TCON1_BASIC0_REG, 224 SUN4I_TCON1_BASIC0_X(mode->crtc_hdisplay) | 225 SUN4I_TCON1_BASIC0_Y(mode->crtc_vdisplay)); 226 227 /* Set the upscaling resolution */ 228 regmap_write(tcon->regs, SUN4I_TCON1_BASIC1_REG, 229 SUN4I_TCON1_BASIC1_X(mode->crtc_hdisplay) | 230 SUN4I_TCON1_BASIC1_Y(mode->crtc_vdisplay)); 231 232 /* Set the output resolution */ 233 regmap_write(tcon->regs, SUN4I_TCON1_BASIC2_REG, 234 SUN4I_TCON1_BASIC2_X(mode->crtc_hdisplay) | 235 SUN4I_TCON1_BASIC2_Y(mode->crtc_vdisplay)); 236 237 /* Set horizontal display timings */ 238 bp = mode->crtc_htotal - mode->crtc_hsync_end; 239 DRM_DEBUG_DRIVER("Setting horizontal total %d, backporch %d\n", 240 mode->htotal, bp); 241 regmap_write(tcon->regs, SUN4I_TCON1_BASIC3_REG, 242 SUN4I_TCON1_BASIC3_H_TOTAL(mode->crtc_htotal) | 243 SUN4I_TCON1_BASIC3_H_BACKPORCH(bp)); 244 245 /* Set vertical display timings */ 246 bp = mode->crtc_vtotal - mode->crtc_vsync_end; 247 DRM_DEBUG_DRIVER("Setting vertical total %d, backporch %d\n", 248 mode->vtotal, bp); 249 regmap_write(tcon->regs, SUN4I_TCON1_BASIC4_REG, 250 SUN4I_TCON1_BASIC4_V_TOTAL(mode->vtotal) | 251 SUN4I_TCON1_BASIC4_V_BACKPORCH(bp)); 252 253 /* Set Hsync and Vsync length */ 254 hsync = mode->crtc_hsync_end - mode->crtc_hsync_start; 255 vsync = mode->crtc_vsync_end - mode->crtc_vsync_start; 256 DRM_DEBUG_DRIVER("Setting HSYNC %d, VSYNC %d\n", hsync, vsync); 257 regmap_write(tcon->regs, SUN4I_TCON1_BASIC5_REG, 258 SUN4I_TCON1_BASIC5_V_SYNC(vsync) | 259 SUN4I_TCON1_BASIC5_H_SYNC(hsync)); 260 261 /* Map output pins to channel 1 */ 262 regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG, 263 SUN4I_TCON_GCTL_IOMAP_MASK, 264 SUN4I_TCON_GCTL_IOMAP_TCON1); 265 266 /* 267 * FIXME: Undocumented bits 268 */ 269 if (tcon->has_mux) 270 regmap_write(tcon->regs, SUN4I_TCON_MUX_CTRL_REG, 1); 271 } 272 EXPORT_SYMBOL(sun4i_tcon1_mode_set); 273 274 static void sun4i_tcon_finish_page_flip(struct drm_device *dev, 275 struct sun4i_crtc *scrtc) 276 { 277 unsigned long flags; 278 279 spin_lock_irqsave(&dev->event_lock, flags); 280 if (scrtc->event) { 281 drm_crtc_send_vblank_event(&scrtc->crtc, scrtc->event); 282 drm_crtc_vblank_put(&scrtc->crtc); 283 scrtc->event = NULL; 284 } 285 spin_unlock_irqrestore(&dev->event_lock, flags); 286 } 287 288 static irqreturn_t sun4i_tcon_handler(int irq, void *private) 289 { 290 struct sun4i_tcon *tcon = private; 291 struct drm_device *drm = tcon->drm; 292 struct sun4i_drv *drv = drm->dev_private; 293 struct sun4i_crtc *scrtc = drv->crtc; 294 unsigned int status; 295 296 regmap_read(tcon->regs, SUN4I_TCON_GINT0_REG, &status); 297 298 if (!(status & (SUN4I_TCON_GINT0_VBLANK_INT(0) | 299 SUN4I_TCON_GINT0_VBLANK_INT(1)))) 300 return IRQ_NONE; 301 302 drm_crtc_handle_vblank(&scrtc->crtc); 303 sun4i_tcon_finish_page_flip(drm, scrtc); 304 305 /* Acknowledge the interrupt */ 306 regmap_update_bits(tcon->regs, SUN4I_TCON_GINT0_REG, 307 SUN4I_TCON_GINT0_VBLANK_INT(0) | 308 SUN4I_TCON_GINT0_VBLANK_INT(1), 309 0); 310 311 return IRQ_HANDLED; 312 } 313 314 static int sun4i_tcon_init_clocks(struct device *dev, 315 struct sun4i_tcon *tcon) 316 { 317 tcon->clk = devm_clk_get(dev, "ahb"); 318 if (IS_ERR(tcon->clk)) { 319 dev_err(dev, "Couldn't get the TCON bus clock\n"); 320 return PTR_ERR(tcon->clk); 321 } 322 clk_prepare_enable(tcon->clk); 323 324 tcon->sclk0 = devm_clk_get(dev, "tcon-ch0"); 325 if (IS_ERR(tcon->sclk0)) { 326 dev_err(dev, "Couldn't get the TCON channel 0 clock\n"); 327 return PTR_ERR(tcon->sclk0); 328 } 329 330 if (tcon->has_channel_1) { 331 tcon->sclk1 = devm_clk_get(dev, "tcon-ch1"); 332 if (IS_ERR(tcon->sclk1)) { 333 dev_err(dev, "Couldn't get the TCON channel 1 clock\n"); 334 return PTR_ERR(tcon->sclk1); 335 } 336 } 337 338 return sun4i_dclk_create(dev, tcon); 339 } 340 341 static void sun4i_tcon_free_clocks(struct sun4i_tcon *tcon) 342 { 343 sun4i_dclk_free(tcon); 344 clk_disable_unprepare(tcon->clk); 345 } 346 347 static int sun4i_tcon_init_irq(struct device *dev, 348 struct sun4i_tcon *tcon) 349 { 350 struct platform_device *pdev = to_platform_device(dev); 351 int irq, ret; 352 353 irq = platform_get_irq(pdev, 0); 354 if (irq < 0) { 355 dev_err(dev, "Couldn't retrieve the TCON interrupt\n"); 356 return irq; 357 } 358 359 ret = devm_request_irq(dev, irq, sun4i_tcon_handler, 0, 360 dev_name(dev), tcon); 361 if (ret) { 362 dev_err(dev, "Couldn't request the IRQ\n"); 363 return ret; 364 } 365 366 return 0; 367 } 368 369 static struct regmap_config sun4i_tcon_regmap_config = { 370 .reg_bits = 32, 371 .val_bits = 32, 372 .reg_stride = 4, 373 .max_register = 0x800, 374 }; 375 376 static int sun4i_tcon_init_regmap(struct device *dev, 377 struct sun4i_tcon *tcon) 378 { 379 struct platform_device *pdev = to_platform_device(dev); 380 struct resource *res; 381 void __iomem *regs; 382 383 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 384 regs = devm_ioremap_resource(dev, res); 385 if (IS_ERR(regs)) 386 return PTR_ERR(regs); 387 388 tcon->regs = devm_regmap_init_mmio(dev, regs, 389 &sun4i_tcon_regmap_config); 390 if (IS_ERR(tcon->regs)) { 391 dev_err(dev, "Couldn't create the TCON regmap\n"); 392 return PTR_ERR(tcon->regs); 393 } 394 395 /* Make sure the TCON is disabled and all IRQs are off */ 396 regmap_write(tcon->regs, SUN4I_TCON_GCTL_REG, 0); 397 regmap_write(tcon->regs, SUN4I_TCON_GINT0_REG, 0); 398 regmap_write(tcon->regs, SUN4I_TCON_GINT1_REG, 0); 399 400 /* Disable IO lines and set them to tristate */ 401 regmap_write(tcon->regs, SUN4I_TCON0_IO_TRI_REG, ~0); 402 regmap_write(tcon->regs, SUN4I_TCON1_IO_TRI_REG, ~0); 403 404 return 0; 405 } 406 407 struct drm_panel *sun4i_tcon_find_panel(struct device_node *node) 408 { 409 struct device_node *port, *remote, *child; 410 struct device_node *end_node = NULL; 411 412 /* Inputs are listed first, then outputs */ 413 port = of_graph_get_port_by_id(node, 1); 414 415 /* 416 * Our first output is the RGB interface where the panel will 417 * be connected. 418 */ 419 for_each_child_of_node(port, child) { 420 u32 reg; 421 422 of_property_read_u32(child, "reg", ®); 423 if (reg == 0) 424 end_node = child; 425 } 426 427 if (!end_node) { 428 DRM_DEBUG_DRIVER("Missing panel endpoint\n"); 429 return ERR_PTR(-ENODEV); 430 } 431 432 remote = of_graph_get_remote_port_parent(end_node); 433 if (!remote) { 434 DRM_DEBUG_DRIVER("Unable to parse remote node\n"); 435 return ERR_PTR(-EINVAL); 436 } 437 438 return of_drm_find_panel(remote) ?: ERR_PTR(-EPROBE_DEFER); 439 } 440 441 struct drm_bridge *sun4i_tcon_find_bridge(struct device_node *node) 442 { 443 struct device_node *port, *remote, *child; 444 struct device_node *end_node = NULL; 445 446 /* Inputs are listed first, then outputs */ 447 port = of_graph_get_port_by_id(node, 1); 448 449 /* 450 * Our first output is the RGB interface where the panel will 451 * be connected. 452 */ 453 for_each_child_of_node(port, child) { 454 u32 reg; 455 456 of_property_read_u32(child, "reg", ®); 457 if (reg == 0) 458 end_node = child; 459 } 460 461 if (!end_node) { 462 DRM_DEBUG_DRIVER("Missing bridge endpoint\n"); 463 return ERR_PTR(-ENODEV); 464 } 465 466 remote = of_graph_get_remote_port_parent(end_node); 467 if (!remote) { 468 DRM_DEBUG_DRIVER("Enable to parse remote node\n"); 469 return ERR_PTR(-EINVAL); 470 } 471 472 return of_drm_find_bridge(remote) ?: ERR_PTR(-EPROBE_DEFER); 473 } 474 475 static int sun4i_tcon_bind(struct device *dev, struct device *master, 476 void *data) 477 { 478 struct drm_device *drm = data; 479 struct sun4i_drv *drv = drm->dev_private; 480 struct sun4i_tcon *tcon; 481 int ret; 482 483 tcon = devm_kzalloc(dev, sizeof(*tcon), GFP_KERNEL); 484 if (!tcon) 485 return -ENOMEM; 486 dev_set_drvdata(dev, tcon); 487 drv->tcon = tcon; 488 tcon->drm = drm; 489 tcon->dev = dev; 490 491 if (of_device_is_compatible(dev->of_node, "allwinner,sun5i-a13-tcon")) { 492 tcon->has_mux = true; 493 tcon->has_channel_1 = true; 494 } else { 495 tcon->has_mux = false; 496 tcon->has_channel_1 = false; 497 } 498 499 tcon->lcd_rst = devm_reset_control_get(dev, "lcd"); 500 if (IS_ERR(tcon->lcd_rst)) { 501 dev_err(dev, "Couldn't get our reset line\n"); 502 return PTR_ERR(tcon->lcd_rst); 503 } 504 505 /* Make sure our TCON is reset */ 506 if (!reset_control_status(tcon->lcd_rst)) 507 reset_control_assert(tcon->lcd_rst); 508 509 ret = reset_control_deassert(tcon->lcd_rst); 510 if (ret) { 511 dev_err(dev, "Couldn't deassert our reset line\n"); 512 return ret; 513 } 514 515 ret = sun4i_tcon_init_regmap(dev, tcon); 516 if (ret) { 517 dev_err(dev, "Couldn't init our TCON regmap\n"); 518 goto err_assert_reset; 519 } 520 521 ret = sun4i_tcon_init_clocks(dev, tcon); 522 if (ret) { 523 dev_err(dev, "Couldn't init our TCON clocks\n"); 524 goto err_assert_reset; 525 } 526 527 ret = sun4i_tcon_init_irq(dev, tcon); 528 if (ret) { 529 dev_err(dev, "Couldn't init our TCON interrupts\n"); 530 goto err_free_clocks; 531 } 532 533 ret = sun4i_rgb_init(drm); 534 if (ret < 0) 535 goto err_free_clocks; 536 537 return 0; 538 539 err_free_clocks: 540 sun4i_tcon_free_clocks(tcon); 541 err_assert_reset: 542 reset_control_assert(tcon->lcd_rst); 543 return ret; 544 } 545 546 static void sun4i_tcon_unbind(struct device *dev, struct device *master, 547 void *data) 548 { 549 struct sun4i_tcon *tcon = dev_get_drvdata(dev); 550 551 sun4i_tcon_free_clocks(tcon); 552 } 553 554 static struct component_ops sun4i_tcon_ops = { 555 .bind = sun4i_tcon_bind, 556 .unbind = sun4i_tcon_unbind, 557 }; 558 559 static int sun4i_tcon_probe(struct platform_device *pdev) 560 { 561 struct device_node *node = pdev->dev.of_node; 562 struct drm_bridge *bridge; 563 struct drm_panel *panel; 564 565 /* 566 * Neither the bridge or the panel is ready. 567 * Defer the probe. 568 */ 569 panel = sun4i_tcon_find_panel(node); 570 bridge = sun4i_tcon_find_bridge(node); 571 572 /* 573 * If we don't have a panel endpoint, just go on 574 */ 575 if ((PTR_ERR(panel) == -EPROBE_DEFER) && 576 (PTR_ERR(bridge) == -EPROBE_DEFER)) { 577 DRM_DEBUG_DRIVER("Still waiting for our panel/bridge. Deferring...\n"); 578 return -EPROBE_DEFER; 579 } 580 581 return component_add(&pdev->dev, &sun4i_tcon_ops); 582 } 583 584 static int sun4i_tcon_remove(struct platform_device *pdev) 585 { 586 component_del(&pdev->dev, &sun4i_tcon_ops); 587 588 return 0; 589 } 590 591 static const struct of_device_id sun4i_tcon_of_table[] = { 592 { .compatible = "allwinner,sun5i-a13-tcon" }, 593 { .compatible = "allwinner,sun8i-a33-tcon" }, 594 { } 595 }; 596 MODULE_DEVICE_TABLE(of, sun4i_tcon_of_table); 597 598 static struct platform_driver sun4i_tcon_platform_driver = { 599 .probe = sun4i_tcon_probe, 600 .remove = sun4i_tcon_remove, 601 .driver = { 602 .name = "sun4i-tcon", 603 .of_match_table = sun4i_tcon_of_table, 604 }, 605 }; 606 module_platform_driver(sun4i_tcon_platform_driver); 607 608 MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>"); 609 MODULE_DESCRIPTION("Allwinner A10 Timing Controller Driver"); 610 MODULE_LICENSE("GPL"); 611