linux/drivers/gpu/drm/tilcdc/tilcdc_drv.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2012 Texas Instruments
   3 * Author: Rob Clark <robdclark@gmail.com>
   4 *
   5 * This program is free software; you can redistribute it and/or modify it
   6 * under the terms of the GNU General Public License version 2 as published by
   7 * the Free Software Foundation.
   8 *
   9 * This program is distributed in the hope that it will be useful, but WITHOUT
  10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  12 * more details.
  13 *
  14 * You should have received a copy of the GNU General Public License along with
  15 * this program.  If not, see <http://www.gnu.org/licenses/>.
  16 */
  17
  18/* LCDC DRM driver, based on da8xx-fb */
  19
  20#include "tilcdc_drv.h"
  21#include "tilcdc_regs.h"
  22#include "tilcdc_tfp410.h"
  23#include "tilcdc_slave.h"
  24#include "tilcdc_panel.h"
  25
  26#include "drm_fb_helper.h"
  27
  28static LIST_HEAD(module_list);
  29static bool slave_probing;
  30
  31void tilcdc_module_init(struct tilcdc_module *mod, const char *name,
  32                const struct tilcdc_module_ops *funcs)
  33{
  34        mod->name = name;
  35        mod->funcs = funcs;
  36        INIT_LIST_HEAD(&mod->list);
  37        list_add(&mod->list, &module_list);
  38}
  39
  40void tilcdc_module_cleanup(struct tilcdc_module *mod)
  41{
  42        list_del(&mod->list);
  43}
  44
  45void tilcdc_slave_probedefer(bool defered)
  46{
  47        slave_probing = defered;
  48}
  49
  50static struct of_device_id tilcdc_of_match[];
  51
  52static struct drm_framebuffer *tilcdc_fb_create(struct drm_device *dev,
  53                struct drm_file *file_priv, struct drm_mode_fb_cmd2 *mode_cmd)
  54{
  55        return drm_fb_cma_create(dev, file_priv, mode_cmd);
  56}
  57
  58static void tilcdc_fb_output_poll_changed(struct drm_device *dev)
  59{
  60        struct tilcdc_drm_private *priv = dev->dev_private;
  61        if (priv->fbdev)
  62                drm_fbdev_cma_hotplug_event(priv->fbdev);
  63}
  64
  65static const struct drm_mode_config_funcs mode_config_funcs = {
  66        .fb_create = tilcdc_fb_create,
  67        .output_poll_changed = tilcdc_fb_output_poll_changed,
  68};
  69
  70static int modeset_init(struct drm_device *dev)
  71{
  72        struct tilcdc_drm_private *priv = dev->dev_private;
  73        struct tilcdc_module *mod;
  74
  75        drm_mode_config_init(dev);
  76
  77        priv->crtc = tilcdc_crtc_create(dev);
  78
  79        list_for_each_entry(mod, &module_list, list) {
  80                DBG("loading module: %s", mod->name);
  81                mod->funcs->modeset_init(mod, dev);
  82        }
  83
  84        if ((priv->num_encoders == 0) || (priv->num_connectors == 0)) {
  85                /* oh nos! */
  86                dev_err(dev->dev, "no encoders/connectors found\n");
  87                drm_mode_config_cleanup(dev);
  88                return -ENXIO;
  89        }
  90
  91        dev->mode_config.min_width = 0;
  92        dev->mode_config.min_height = 0;
  93        dev->mode_config.max_width = tilcdc_crtc_max_width(priv->crtc);
  94        dev->mode_config.max_height = 2048;
  95        dev->mode_config.funcs = &mode_config_funcs;
  96
  97        return 0;
  98}
  99
 100#ifdef CONFIG_CPU_FREQ
 101static int cpufreq_transition(struct notifier_block *nb,
 102                                     unsigned long val, void *data)
 103{
 104        struct tilcdc_drm_private *priv = container_of(nb,
 105                        struct tilcdc_drm_private, freq_transition);
 106        if (val == CPUFREQ_POSTCHANGE) {
 107                if (priv->lcd_fck_rate != clk_get_rate(priv->clk)) {
 108                        priv->lcd_fck_rate = clk_get_rate(priv->clk);
 109                        tilcdc_crtc_update_clk(priv->crtc);
 110                }
 111        }
 112
 113        return 0;
 114}
 115#endif
 116
 117/*
 118 * DRM operations:
 119 */
 120
 121static int tilcdc_unload(struct drm_device *dev)
 122{
 123        struct tilcdc_drm_private *priv = dev->dev_private;
 124
 125        drm_fbdev_cma_fini(priv->fbdev);
 126        drm_kms_helper_poll_fini(dev);
 127        drm_mode_config_cleanup(dev);
 128        drm_vblank_cleanup(dev);
 129
 130        pm_runtime_get_sync(dev->dev);
 131        drm_irq_uninstall(dev);
 132        pm_runtime_put_sync(dev->dev);
 133
 134#ifdef CONFIG_CPU_FREQ
 135        cpufreq_unregister_notifier(&priv->freq_transition,
 136                        CPUFREQ_TRANSITION_NOTIFIER);
 137#endif
 138
 139        if (priv->clk)
 140                clk_put(priv->clk);
 141
 142        if (priv->mmio)
 143                iounmap(priv->mmio);
 144
 145        flush_workqueue(priv->wq);
 146        destroy_workqueue(priv->wq);
 147
 148        dev->dev_private = NULL;
 149
 150        pm_runtime_disable(dev->dev);
 151
 152        kfree(priv);
 153
 154        return 0;
 155}
 156
 157static int tilcdc_load(struct drm_device *dev, unsigned long flags)
 158{
 159        struct platform_device *pdev = dev->platformdev;
 160        struct device_node *node = pdev->dev.of_node;
 161        struct tilcdc_drm_private *priv;
 162        struct tilcdc_module *mod;
 163        struct resource *res;
 164        u32 bpp = 0;
 165        int ret;
 166
 167        priv = kzalloc(sizeof(*priv), GFP_KERNEL);
 168        if (!priv) {
 169                dev_err(dev->dev, "failed to allocate private data\n");
 170                return -ENOMEM;
 171        }
 172
 173        dev->dev_private = priv;
 174
 175        priv->wq = alloc_ordered_workqueue("tilcdc", 0);
 176        if (!priv->wq) {
 177                ret = -ENOMEM;
 178                goto fail_free_priv;
 179        }
 180
 181        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 182        if (!res) {
 183                dev_err(dev->dev, "failed to get memory resource\n");
 184                ret = -EINVAL;
 185                goto fail_free_wq;
 186        }
 187
 188        priv->mmio = ioremap_nocache(res->start, resource_size(res));
 189        if (!priv->mmio) {
 190                dev_err(dev->dev, "failed to ioremap\n");
 191                ret = -ENOMEM;
 192                goto fail_free_wq;
 193        }
 194
 195        priv->clk = clk_get(dev->dev, "fck");
 196        if (IS_ERR(priv->clk)) {
 197                dev_err(dev->dev, "failed to get functional clock\n");
 198                ret = -ENODEV;
 199                goto fail_iounmap;
 200        }
 201
 202        priv->disp_clk = clk_get(dev->dev, "dpll_disp_ck");
 203        if (IS_ERR(priv->clk)) {
 204                dev_err(dev->dev, "failed to get display clock\n");
 205                ret = -ENODEV;
 206                goto fail_put_clk;
 207        }
 208
 209#ifdef CONFIG_CPU_FREQ
 210        priv->lcd_fck_rate = clk_get_rate(priv->clk);
 211        priv->freq_transition.notifier_call = cpufreq_transition;
 212        ret = cpufreq_register_notifier(&priv->freq_transition,
 213                        CPUFREQ_TRANSITION_NOTIFIER);
 214        if (ret) {
 215                dev_err(dev->dev, "failed to register cpufreq notifier\n");
 216                goto fail_put_disp_clk;
 217        }
 218#endif
 219
 220        if (of_property_read_u32(node, "max-bandwidth", &priv->max_bandwidth))
 221                priv->max_bandwidth = TILCDC_DEFAULT_MAX_BANDWIDTH;
 222
 223        DBG("Maximum Bandwidth Value %d", priv->max_bandwidth);
 224
 225        if (of_property_read_u32(node, "ti,max-width", &priv->max_width))
 226                priv->max_width = TILCDC_DEFAULT_MAX_WIDTH;
 227
 228        DBG("Maximum Horizontal Pixel Width Value %dpixels", priv->max_width);
 229
 230        if (of_property_read_u32(node, "ti,max-pixelclock",
 231                                        &priv->max_pixelclock))
 232                priv->max_pixelclock = TILCDC_DEFAULT_MAX_PIXELCLOCK;
 233
 234        DBG("Maximum Pixel Clock Value %dKHz", priv->max_pixelclock);
 235
 236        pm_runtime_enable(dev->dev);
 237
 238        /* Determine LCD IP Version */
 239        pm_runtime_get_sync(dev->dev);
 240        switch (tilcdc_read(dev, LCDC_PID_REG)) {
 241        case 0x4c100102:
 242                priv->rev = 1;
 243                break;
 244        case 0x4f200800:
 245        case 0x4f201000:
 246                priv->rev = 2;
 247                break;
 248        default:
 249                dev_warn(dev->dev, "Unknown PID Reg value 0x%08x, "
 250                                "defaulting to LCD revision 1\n",
 251                                tilcdc_read(dev, LCDC_PID_REG));
 252                priv->rev = 1;
 253                break;
 254        }
 255
 256        pm_runtime_put_sync(dev->dev);
 257
 258        ret = modeset_init(dev);
 259        if (ret < 0) {
 260                dev_err(dev->dev, "failed to initialize mode setting\n");
 261                goto fail_cpufreq_unregister;
 262        }
 263
 264        ret = drm_vblank_init(dev, 1);
 265        if (ret < 0) {
 266                dev_err(dev->dev, "failed to initialize vblank\n");
 267                goto fail_mode_config_cleanup;
 268        }
 269
 270        pm_runtime_get_sync(dev->dev);
 271        ret = drm_irq_install(dev, platform_get_irq(dev->platformdev, 0));
 272        pm_runtime_put_sync(dev->dev);
 273        if (ret < 0) {
 274                dev_err(dev->dev, "failed to install IRQ handler\n");
 275                goto fail_vblank_cleanup;
 276        }
 277
 278        platform_set_drvdata(pdev, dev);
 279
 280
 281        list_for_each_entry(mod, &module_list, list) {
 282                DBG("%s: preferred_bpp: %d", mod->name, mod->preferred_bpp);
 283                bpp = mod->preferred_bpp;
 284                if (bpp > 0)
 285                        break;
 286        }
 287
 288        priv->fbdev = drm_fbdev_cma_init(dev, bpp,
 289                        dev->mode_config.num_crtc,
 290                        dev->mode_config.num_connector);
 291        if (IS_ERR(priv->fbdev)) {
 292                ret = PTR_ERR(priv->fbdev);
 293                goto fail_irq_uninstall;
 294        }
 295
 296        drm_kms_helper_poll_init(dev);
 297
 298        return 0;
 299
 300fail_irq_uninstall:
 301        pm_runtime_get_sync(dev->dev);
 302        drm_irq_uninstall(dev);
 303        pm_runtime_put_sync(dev->dev);
 304
 305fail_vblank_cleanup:
 306        drm_vblank_cleanup(dev);
 307
 308fail_mode_config_cleanup:
 309        drm_mode_config_cleanup(dev);
 310
 311fail_cpufreq_unregister:
 312        pm_runtime_disable(dev->dev);
 313#ifdef CONFIG_CPU_FREQ
 314        cpufreq_unregister_notifier(&priv->freq_transition,
 315                        CPUFREQ_TRANSITION_NOTIFIER);
 316fail_put_disp_clk:
 317        clk_put(priv->disp_clk);
 318#endif
 319
 320fail_put_clk:
 321        clk_put(priv->clk);
 322
 323fail_iounmap:
 324        iounmap(priv->mmio);
 325
 326fail_free_wq:
 327        flush_workqueue(priv->wq);
 328        destroy_workqueue(priv->wq);
 329
 330fail_free_priv:
 331        dev->dev_private = NULL;
 332        kfree(priv);
 333        return ret;
 334}
 335
 336static void tilcdc_preclose(struct drm_device *dev, struct drm_file *file)
 337{
 338        struct tilcdc_drm_private *priv = dev->dev_private;
 339
 340        tilcdc_crtc_cancel_page_flip(priv->crtc, file);
 341}
 342
 343static void tilcdc_lastclose(struct drm_device *dev)
 344{
 345        struct tilcdc_drm_private *priv = dev->dev_private;
 346        drm_fbdev_cma_restore_mode(priv->fbdev);
 347}
 348
 349static irqreturn_t tilcdc_irq(int irq, void *arg)
 350{
 351        struct drm_device *dev = arg;
 352        struct tilcdc_drm_private *priv = dev->dev_private;
 353        return tilcdc_crtc_irq(priv->crtc);
 354}
 355
 356static void tilcdc_irq_preinstall(struct drm_device *dev)
 357{
 358        tilcdc_clear_irqstatus(dev, 0xffffffff);
 359}
 360
 361static int tilcdc_irq_postinstall(struct drm_device *dev)
 362{
 363        struct tilcdc_drm_private *priv = dev->dev_private;
 364
 365        /* enable FIFO underflow irq: */
 366        if (priv->rev == 1)
 367                tilcdc_set(dev, LCDC_RASTER_CTRL_REG, LCDC_V1_UNDERFLOW_INT_ENA);
 368        else
 369                tilcdc_set(dev, LCDC_INT_ENABLE_SET_REG, LCDC_V2_UNDERFLOW_INT_ENA);
 370
 371        return 0;
 372}
 373
 374static void tilcdc_irq_uninstall(struct drm_device *dev)
 375{
 376        struct tilcdc_drm_private *priv = dev->dev_private;
 377
 378        /* disable irqs that we might have enabled: */
 379        if (priv->rev == 1) {
 380                tilcdc_clear(dev, LCDC_RASTER_CTRL_REG,
 381                                LCDC_V1_UNDERFLOW_INT_ENA | LCDC_V1_PL_INT_ENA);
 382                tilcdc_clear(dev, LCDC_DMA_CTRL_REG, LCDC_V1_END_OF_FRAME_INT_ENA);
 383        } else {
 384                tilcdc_clear(dev, LCDC_INT_ENABLE_SET_REG,
 385                        LCDC_V2_UNDERFLOW_INT_ENA | LCDC_V2_PL_INT_ENA |
 386                        LCDC_V2_END_OF_FRAME0_INT_ENA | LCDC_V2_END_OF_FRAME1_INT_ENA |
 387                        LCDC_FRAME_DONE);
 388        }
 389
 390}
 391
 392static void enable_vblank(struct drm_device *dev, bool enable)
 393{
 394        struct tilcdc_drm_private *priv = dev->dev_private;
 395        u32 reg, mask;
 396
 397        if (priv->rev == 1) {
 398                reg = LCDC_DMA_CTRL_REG;
 399                mask = LCDC_V1_END_OF_FRAME_INT_ENA;
 400        } else {
 401                reg = LCDC_INT_ENABLE_SET_REG;
 402                mask = LCDC_V2_END_OF_FRAME0_INT_ENA |
 403                        LCDC_V2_END_OF_FRAME1_INT_ENA | LCDC_FRAME_DONE;
 404        }
 405
 406        if (enable)
 407                tilcdc_set(dev, reg, mask);
 408        else
 409                tilcdc_clear(dev, reg, mask);
 410}
 411
 412static int tilcdc_enable_vblank(struct drm_device *dev, int crtc)
 413{
 414        enable_vblank(dev, true);
 415        return 0;
 416}
 417
 418static void tilcdc_disable_vblank(struct drm_device *dev, int crtc)
 419{
 420        enable_vblank(dev, false);
 421}
 422
 423#if defined(CONFIG_DEBUG_FS) || defined(CONFIG_PM_SLEEP)
 424static const struct {
 425        const char *name;
 426        uint8_t  rev;
 427        uint8_t  save;
 428        uint32_t reg;
 429} registers[] =         {
 430#define REG(rev, save, reg) { #reg, rev, save, reg }
 431                /* exists in revision 1: */
 432                REG(1, false, LCDC_PID_REG),
 433                REG(1, true,  LCDC_CTRL_REG),
 434                REG(1, false, LCDC_STAT_REG),
 435                REG(1, true,  LCDC_RASTER_CTRL_REG),
 436                REG(1, true,  LCDC_RASTER_TIMING_0_REG),
 437                REG(1, true,  LCDC_RASTER_TIMING_1_REG),
 438                REG(1, true,  LCDC_RASTER_TIMING_2_REG),
 439                REG(1, true,  LCDC_DMA_CTRL_REG),
 440                REG(1, true,  LCDC_DMA_FB_BASE_ADDR_0_REG),
 441                REG(1, true,  LCDC_DMA_FB_CEILING_ADDR_0_REG),
 442                REG(1, true,  LCDC_DMA_FB_BASE_ADDR_1_REG),
 443                REG(1, true,  LCDC_DMA_FB_CEILING_ADDR_1_REG),
 444                /* new in revision 2: */
 445                REG(2, false, LCDC_RAW_STAT_REG),
 446                REG(2, false, LCDC_MASKED_STAT_REG),
 447                REG(2, false, LCDC_INT_ENABLE_SET_REG),
 448                REG(2, false, LCDC_INT_ENABLE_CLR_REG),
 449                REG(2, false, LCDC_END_OF_INT_IND_REG),
 450                REG(2, true,  LCDC_CLK_ENABLE_REG),
 451                REG(2, true,  LCDC_INT_ENABLE_SET_REG),
 452#undef REG
 453};
 454#endif
 455
 456#ifdef CONFIG_DEBUG_FS
 457static int tilcdc_regs_show(struct seq_file *m, void *arg)
 458{
 459        struct drm_info_node *node = (struct drm_info_node *) m->private;
 460        struct drm_device *dev = node->minor->dev;
 461        struct tilcdc_drm_private *priv = dev->dev_private;
 462        unsigned i;
 463
 464        pm_runtime_get_sync(dev->dev);
 465
 466        seq_printf(m, "revision: %d\n", priv->rev);
 467
 468        for (i = 0; i < ARRAY_SIZE(registers); i++)
 469                if (priv->rev >= registers[i].rev)
 470                        seq_printf(m, "%s:\t %08x\n", registers[i].name,
 471                                        tilcdc_read(dev, registers[i].reg));
 472
 473        pm_runtime_put_sync(dev->dev);
 474
 475        return 0;
 476}
 477
 478static int tilcdc_mm_show(struct seq_file *m, void *arg)
 479{
 480        struct drm_info_node *node = (struct drm_info_node *) m->private;
 481        struct drm_device *dev = node->minor->dev;
 482        return drm_mm_dump_table(m, &dev->vma_offset_manager->vm_addr_space_mm);
 483}
 484
 485static struct drm_info_list tilcdc_debugfs_list[] = {
 486                { "regs", tilcdc_regs_show, 0 },
 487                { "mm",   tilcdc_mm_show,   0 },
 488                { "fb",   drm_fb_cma_debugfs_show, 0 },
 489};
 490
 491static int tilcdc_debugfs_init(struct drm_minor *minor)
 492{
 493        struct drm_device *dev = minor->dev;
 494        struct tilcdc_module *mod;
 495        int ret;
 496
 497        ret = drm_debugfs_create_files(tilcdc_debugfs_list,
 498                        ARRAY_SIZE(tilcdc_debugfs_list),
 499                        minor->debugfs_root, minor);
 500
 501        list_for_each_entry(mod, &module_list, list)
 502                if (mod->funcs->debugfs_init)
 503                        mod->funcs->debugfs_init(mod, minor);
 504
 505        if (ret) {
 506                dev_err(dev->dev, "could not install tilcdc_debugfs_list\n");
 507                return ret;
 508        }
 509
 510        return ret;
 511}
 512
 513static void tilcdc_debugfs_cleanup(struct drm_minor *minor)
 514{
 515        struct tilcdc_module *mod;
 516        drm_debugfs_remove_files(tilcdc_debugfs_list,
 517                        ARRAY_SIZE(tilcdc_debugfs_list), minor);
 518
 519        list_for_each_entry(mod, &module_list, list)
 520                if (mod->funcs->debugfs_cleanup)
 521                        mod->funcs->debugfs_cleanup(mod, minor);
 522}
 523#endif
 524
 525static const struct file_operations fops = {
 526        .owner              = THIS_MODULE,
 527        .open               = drm_open,
 528        .release            = drm_release,
 529        .unlocked_ioctl     = drm_ioctl,
 530#ifdef CONFIG_COMPAT
 531        .compat_ioctl       = drm_compat_ioctl,
 532#endif
 533        .poll               = drm_poll,
 534        .read               = drm_read,
 535        .llseek             = no_llseek,
 536        .mmap               = drm_gem_cma_mmap,
 537};
 538
 539static struct drm_driver tilcdc_driver = {
 540        .driver_features    = DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET,
 541        .load               = tilcdc_load,
 542        .unload             = tilcdc_unload,
 543        .preclose           = tilcdc_preclose,
 544        .lastclose          = tilcdc_lastclose,
 545        .set_busid          = drm_platform_set_busid,
 546        .irq_handler        = tilcdc_irq,
 547        .irq_preinstall     = tilcdc_irq_preinstall,
 548        .irq_postinstall    = tilcdc_irq_postinstall,
 549        .irq_uninstall      = tilcdc_irq_uninstall,
 550        .get_vblank_counter = drm_vblank_count,
 551        .enable_vblank      = tilcdc_enable_vblank,
 552        .disable_vblank     = tilcdc_disable_vblank,
 553        .gem_free_object    = drm_gem_cma_free_object,
 554        .gem_vm_ops         = &drm_gem_cma_vm_ops,
 555        .dumb_create        = drm_gem_cma_dumb_create,
 556        .dumb_map_offset    = drm_gem_cma_dumb_map_offset,
 557        .dumb_destroy       = drm_gem_dumb_destroy,
 558#ifdef CONFIG_DEBUG_FS
 559        .debugfs_init       = tilcdc_debugfs_init,
 560        .debugfs_cleanup    = tilcdc_debugfs_cleanup,
 561#endif
 562        .fops               = &fops,
 563        .name               = "tilcdc",
 564        .desc               = "TI LCD Controller DRM",
 565        .date               = "20121205",
 566        .major              = 1,
 567        .minor              = 0,
 568};
 569
 570/*
 571 * Power management:
 572 */
 573
 574#ifdef CONFIG_PM_SLEEP
 575static int tilcdc_pm_suspend(struct device *dev)
 576{
 577        struct drm_device *ddev = dev_get_drvdata(dev);
 578        struct tilcdc_drm_private *priv = ddev->dev_private;
 579        unsigned i, n = 0;
 580
 581        drm_kms_helper_poll_disable(ddev);
 582
 583        /* Save register state: */
 584        for (i = 0; i < ARRAY_SIZE(registers); i++)
 585                if (registers[i].save && (priv->rev >= registers[i].rev))
 586                        priv->saved_register[n++] = tilcdc_read(ddev, registers[i].reg);
 587
 588        return 0;
 589}
 590
 591static int tilcdc_pm_resume(struct device *dev)
 592{
 593        struct drm_device *ddev = dev_get_drvdata(dev);
 594        struct tilcdc_drm_private *priv = ddev->dev_private;
 595        unsigned i, n = 0;
 596
 597        /* Restore register state: */
 598        for (i = 0; i < ARRAY_SIZE(registers); i++)
 599                if (registers[i].save && (priv->rev >= registers[i].rev))
 600                        tilcdc_write(ddev, registers[i].reg, priv->saved_register[n++]);
 601
 602        drm_kms_helper_poll_enable(ddev);
 603
 604        return 0;
 605}
 606#endif
 607
 608static const struct dev_pm_ops tilcdc_pm_ops = {
 609        SET_SYSTEM_SLEEP_PM_OPS(tilcdc_pm_suspend, tilcdc_pm_resume)
 610};
 611
 612/*
 613 * Platform driver:
 614 */
 615
 616static int tilcdc_pdev_probe(struct platform_device *pdev)
 617{
 618        /* bail out early if no DT data: */
 619        if (!pdev->dev.of_node) {
 620                dev_err(&pdev->dev, "device-tree data is missing\n");
 621                return -ENXIO;
 622        }
 623
 624        /* defer probing if slave is in deferred probing */
 625        if (slave_probing == true)
 626                return -EPROBE_DEFER;
 627
 628        return drm_platform_init(&tilcdc_driver, pdev);
 629}
 630
 631static int tilcdc_pdev_remove(struct platform_device *pdev)
 632{
 633        drm_put_dev(platform_get_drvdata(pdev));
 634
 635        return 0;
 636}
 637
 638static struct of_device_id tilcdc_of_match[] = {
 639                { .compatible = "ti,am33xx-tilcdc", },
 640                { },
 641};
 642MODULE_DEVICE_TABLE(of, tilcdc_of_match);
 643
 644static struct platform_driver tilcdc_platform_driver = {
 645        .probe      = tilcdc_pdev_probe,
 646        .remove     = tilcdc_pdev_remove,
 647        .driver     = {
 648                .owner  = THIS_MODULE,
 649                .name   = "tilcdc",
 650                .pm     = &tilcdc_pm_ops,
 651                .of_match_table = tilcdc_of_match,
 652        },
 653};
 654
 655static int __init tilcdc_drm_init(void)
 656{
 657        DBG("init");
 658        tilcdc_tfp410_init();
 659        tilcdc_slave_init();
 660        tilcdc_panel_init();
 661        return platform_driver_register(&tilcdc_platform_driver);
 662}
 663
 664static void __exit tilcdc_drm_fini(void)
 665{
 666        DBG("fini");
 667        platform_driver_unregister(&tilcdc_platform_driver);
 668        tilcdc_panel_fini();
 669        tilcdc_slave_fini();
 670        tilcdc_tfp410_fini();
 671}
 672
 673module_init(tilcdc_drm_init);
 674module_exit(tilcdc_drm_fini);
 675
 676MODULE_AUTHOR("Rob Clark <robdclark@gmail.com");
 677MODULE_DESCRIPTION("TI LCD Controller DRM Driver");
 678MODULE_LICENSE("GPL");
 679