linux/drivers/gpu/drm/exynos/exynos_drm_vidi.c
<<
>>
Prefs
   1/* exynos_drm_vidi.c
   2 *
   3 * Copyright (C) 2012 Samsung Electronics Co.Ltd
   4 * Authors:
   5 *      Inki Dae <inki.dae@samsung.com>
   6 *
   7 * This program is free software; you can redistribute  it and/or modify it
   8 * under  the terms of  the GNU General  Public License as published by the
   9 * Free Software Foundation;  either version 2 of the  License, or (at your
  10 * option) any later version.
  11 *
  12 */
  13#include <drm/drmP.h>
  14
  15#include <linux/kernel.h>
  16#include <linux/module.h>
  17#include <linux/platform_device.h>
  18
  19#include <drm/exynos_drm.h>
  20
  21#include <drm/drm_edid.h>
  22#include <drm/drm_crtc_helper.h>
  23
  24#include "exynos_drm_drv.h"
  25#include "exynos_drm_crtc.h"
  26#include "exynos_drm_encoder.h"
  27
  28/* vidi has totally three virtual windows. */
  29#define WINDOWS_NR              3
  30
  31#define get_vidi_context(dev)   platform_get_drvdata(to_platform_device(dev))
  32
  33struct vidi_win_data {
  34        unsigned int            offset_x;
  35        unsigned int            offset_y;
  36        unsigned int            ovl_width;
  37        unsigned int            ovl_height;
  38        unsigned int            fb_width;
  39        unsigned int            fb_height;
  40        unsigned int            bpp;
  41        dma_addr_t              dma_addr;
  42        unsigned int            buf_offsize;
  43        unsigned int            line_size;      /* bytes */
  44        bool                    enabled;
  45};
  46
  47struct vidi_context {
  48        struct exynos_drm_subdrv        subdrv;
  49        struct drm_crtc                 *crtc;
  50        struct vidi_win_data            win_data[WINDOWS_NR];
  51        struct edid                     *raw_edid;
  52        unsigned int                    clkdiv;
  53        unsigned int                    default_win;
  54        unsigned long                   irq_flags;
  55        unsigned int                    connected;
  56        bool                            vblank_on;
  57        bool                            suspended;
  58        bool                            direct_vblank;
  59        struct work_struct              work;
  60        struct mutex                    lock;
  61};
  62
  63static const char fake_edid_info[] = {
  64        0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x4c, 0x2d, 0x05, 0x05,
  65        0x00, 0x00, 0x00, 0x00, 0x30, 0x12, 0x01, 0x03, 0x80, 0x10, 0x09, 0x78,
  66        0x0a, 0xee, 0x91, 0xa3, 0x54, 0x4c, 0x99, 0x26, 0x0f, 0x50, 0x54, 0xbd,
  67        0xee, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
  68        0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x66, 0x21, 0x50, 0xb0, 0x51, 0x00,
  69        0x1b, 0x30, 0x40, 0x70, 0x36, 0x00, 0xa0, 0x5a, 0x00, 0x00, 0x00, 0x1e,
  70        0x01, 0x1d, 0x00, 0x72, 0x51, 0xd0, 0x1e, 0x20, 0x6e, 0x28, 0x55, 0x00,
  71        0xa0, 0x5a, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x18,
  72        0x4b, 0x1a, 0x44, 0x17, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
  73        0x00, 0x00, 0x00, 0xfc, 0x00, 0x53, 0x41, 0x4d, 0x53, 0x55, 0x4e, 0x47,
  74        0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, 0xbc, 0x02, 0x03, 0x1e, 0xf1,
  75        0x46, 0x84, 0x05, 0x03, 0x10, 0x20, 0x22, 0x23, 0x09, 0x07, 0x07, 0x83,
  76        0x01, 0x00, 0x00, 0xe2, 0x00, 0x0f, 0x67, 0x03, 0x0c, 0x00, 0x10, 0x00,
  77        0xb8, 0x2d, 0x01, 0x1d, 0x80, 0x18, 0x71, 0x1c, 0x16, 0x20, 0x58, 0x2c,
  78        0x25, 0x00, 0xa0, 0x5a, 0x00, 0x00, 0x00, 0x9e, 0x8c, 0x0a, 0xd0, 0x8a,
  79        0x20, 0xe0, 0x2d, 0x10, 0x10, 0x3e, 0x96, 0x00, 0xa0, 0x5a, 0x00, 0x00,
  80        0x00, 0x18, 0x02, 0x3a, 0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c,
  81        0x45, 0x00, 0xa0, 0x5a, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00,
  82        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  83        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  84        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  85        0x00, 0x00, 0x00, 0x06
  86};
  87
  88static bool vidi_display_is_connected(struct device *dev)
  89{
  90        struct vidi_context *ctx = get_vidi_context(dev);
  91
  92        DRM_DEBUG_KMS("%s\n", __FILE__);
  93
  94        /*
  95         * connection request would come from user side
  96         * to do hotplug through specific ioctl.
  97         */
  98        return ctx->connected ? true : false;
  99}
 100
 101static struct edid *vidi_get_edid(struct device *dev,
 102                        struct drm_connector *connector)
 103{
 104        struct vidi_context *ctx = get_vidi_context(dev);
 105        struct edid *edid;
 106        int edid_len;
 107
 108        DRM_DEBUG_KMS("%s\n", __FILE__);
 109
 110        /*
 111         * the edid data comes from user side and it would be set
 112         * to ctx->raw_edid through specific ioctl.
 113         */
 114        if (!ctx->raw_edid) {
 115                DRM_DEBUG_KMS("raw_edid is null.\n");
 116                return ERR_PTR(-EFAULT);
 117        }
 118
 119        edid_len = (1 + ctx->raw_edid->extensions) * EDID_LENGTH;
 120        edid = kmemdup(ctx->raw_edid, edid_len, GFP_KERNEL);
 121        if (!edid) {
 122                DRM_DEBUG_KMS("failed to allocate edid\n");
 123                return ERR_PTR(-ENOMEM);
 124        }
 125
 126        return edid;
 127}
 128
 129static void *vidi_get_panel(struct device *dev)
 130{
 131        DRM_DEBUG_KMS("%s\n", __FILE__);
 132
 133        /* TODO. */
 134
 135        return NULL;
 136}
 137
 138static int vidi_check_timing(struct device *dev, void *timing)
 139{
 140        DRM_DEBUG_KMS("%s\n", __FILE__);
 141
 142        /* TODO. */
 143
 144        return 0;
 145}
 146
 147static int vidi_display_power_on(struct device *dev, int mode)
 148{
 149        DRM_DEBUG_KMS("%s\n", __FILE__);
 150
 151        /* TODO */
 152
 153        return 0;
 154}
 155
 156static struct exynos_drm_display_ops vidi_display_ops = {
 157        .type = EXYNOS_DISPLAY_TYPE_VIDI,
 158        .is_connected = vidi_display_is_connected,
 159        .get_edid = vidi_get_edid,
 160        .get_panel = vidi_get_panel,
 161        .check_timing = vidi_check_timing,
 162        .power_on = vidi_display_power_on,
 163};
 164
 165static void vidi_dpms(struct device *subdrv_dev, int mode)
 166{
 167        struct vidi_context *ctx = get_vidi_context(subdrv_dev);
 168
 169        DRM_DEBUG_KMS("%s, %d\n", __FILE__, mode);
 170
 171        mutex_lock(&ctx->lock);
 172
 173        switch (mode) {
 174        case DRM_MODE_DPMS_ON:
 175                /* TODO. */
 176                break;
 177        case DRM_MODE_DPMS_STANDBY:
 178        case DRM_MODE_DPMS_SUSPEND:
 179        case DRM_MODE_DPMS_OFF:
 180                /* TODO. */
 181                break;
 182        default:
 183                DRM_DEBUG_KMS("unspecified mode %d\n", mode);
 184                break;
 185        }
 186
 187        mutex_unlock(&ctx->lock);
 188}
 189
 190static void vidi_apply(struct device *subdrv_dev)
 191{
 192        struct vidi_context *ctx = get_vidi_context(subdrv_dev);
 193        struct exynos_drm_manager *mgr = ctx->subdrv.manager;
 194        struct exynos_drm_manager_ops *mgr_ops = mgr->ops;
 195        struct exynos_drm_overlay_ops *ovl_ops = mgr->overlay_ops;
 196        struct vidi_win_data *win_data;
 197        int i;
 198
 199        DRM_DEBUG_KMS("%s\n", __FILE__);
 200
 201        for (i = 0; i < WINDOWS_NR; i++) {
 202                win_data = &ctx->win_data[i];
 203                if (win_data->enabled && (ovl_ops && ovl_ops->commit))
 204                        ovl_ops->commit(subdrv_dev, i);
 205        }
 206
 207        if (mgr_ops && mgr_ops->commit)
 208                mgr_ops->commit(subdrv_dev);
 209}
 210
 211static void vidi_commit(struct device *dev)
 212{
 213        struct vidi_context *ctx = get_vidi_context(dev);
 214
 215        DRM_DEBUG_KMS("%s\n", __FILE__);
 216
 217        if (ctx->suspended)
 218                return;
 219}
 220
 221static int vidi_enable_vblank(struct device *dev)
 222{
 223        struct vidi_context *ctx = get_vidi_context(dev);
 224
 225        DRM_DEBUG_KMS("%s\n", __FILE__);
 226
 227        if (ctx->suspended)
 228                return -EPERM;
 229
 230        if (!test_and_set_bit(0, &ctx->irq_flags))
 231                ctx->vblank_on = true;
 232
 233        ctx->direct_vblank = true;
 234
 235        /*
 236         * in case of page flip request, vidi_finish_pageflip function
 237         * will not be called because direct_vblank is true and then
 238         * that function will be called by overlay_ops->commit callback
 239         */
 240        schedule_work(&ctx->work);
 241
 242        return 0;
 243}
 244
 245static void vidi_disable_vblank(struct device *dev)
 246{
 247        struct vidi_context *ctx = get_vidi_context(dev);
 248
 249        DRM_DEBUG_KMS("%s\n", __FILE__);
 250
 251        if (ctx->suspended)
 252                return;
 253
 254        if (test_and_clear_bit(0, &ctx->irq_flags))
 255                ctx->vblank_on = false;
 256}
 257
 258static struct exynos_drm_manager_ops vidi_manager_ops = {
 259        .dpms = vidi_dpms,
 260        .apply = vidi_apply,
 261        .commit = vidi_commit,
 262        .enable_vblank = vidi_enable_vblank,
 263        .disable_vblank = vidi_disable_vblank,
 264};
 265
 266static void vidi_win_mode_set(struct device *dev,
 267                              struct exynos_drm_overlay *overlay)
 268{
 269        struct vidi_context *ctx = get_vidi_context(dev);
 270        struct vidi_win_data *win_data;
 271        int win;
 272        unsigned long offset;
 273
 274        DRM_DEBUG_KMS("%s\n", __FILE__);
 275
 276        if (!overlay) {
 277                dev_err(dev, "overlay is NULL\n");
 278                return;
 279        }
 280
 281        win = overlay->zpos;
 282        if (win == DEFAULT_ZPOS)
 283                win = ctx->default_win;
 284
 285        if (win < 0 || win > WINDOWS_NR)
 286                return;
 287
 288        offset = overlay->fb_x * (overlay->bpp >> 3);
 289        offset += overlay->fb_y * overlay->pitch;
 290
 291        DRM_DEBUG_KMS("offset = 0x%lx, pitch = %x\n", offset, overlay->pitch);
 292
 293        win_data = &ctx->win_data[win];
 294
 295        win_data->offset_x = overlay->crtc_x;
 296        win_data->offset_y = overlay->crtc_y;
 297        win_data->ovl_width = overlay->crtc_width;
 298        win_data->ovl_height = overlay->crtc_height;
 299        win_data->fb_width = overlay->fb_width;
 300        win_data->fb_height = overlay->fb_height;
 301        win_data->dma_addr = overlay->dma_addr[0] + offset;
 302        win_data->bpp = overlay->bpp;
 303        win_data->buf_offsize = (overlay->fb_width - overlay->crtc_width) *
 304                                (overlay->bpp >> 3);
 305        win_data->line_size = overlay->crtc_width * (overlay->bpp >> 3);
 306
 307        /*
 308         * some parts of win_data should be transferred to user side
 309         * through specific ioctl.
 310         */
 311
 312        DRM_DEBUG_KMS("offset_x = %d, offset_y = %d\n",
 313                        win_data->offset_x, win_data->offset_y);
 314        DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
 315                        win_data->ovl_width, win_data->ovl_height);
 316        DRM_DEBUG_KMS("paddr = 0x%lx\n", (unsigned long)win_data->dma_addr);
 317        DRM_DEBUG_KMS("fb_width = %d, crtc_width = %d\n",
 318                        overlay->fb_width, overlay->crtc_width);
 319}
 320
 321static void vidi_win_commit(struct device *dev, int zpos)
 322{
 323        struct vidi_context *ctx = get_vidi_context(dev);
 324        struct vidi_win_data *win_data;
 325        int win = zpos;
 326
 327        DRM_DEBUG_KMS("%s\n", __FILE__);
 328
 329        if (ctx->suspended)
 330                return;
 331
 332        if (win == DEFAULT_ZPOS)
 333                win = ctx->default_win;
 334
 335        if (win < 0 || win > WINDOWS_NR)
 336                return;
 337
 338        win_data = &ctx->win_data[win];
 339
 340        win_data->enabled = true;
 341
 342        DRM_DEBUG_KMS("dma_addr = 0x%x\n", win_data->dma_addr);
 343
 344        if (ctx->vblank_on)
 345                schedule_work(&ctx->work);
 346}
 347
 348static void vidi_win_disable(struct device *dev, int zpos)
 349{
 350        struct vidi_context *ctx = get_vidi_context(dev);
 351        struct vidi_win_data *win_data;
 352        int win = zpos;
 353
 354        DRM_DEBUG_KMS("%s\n", __FILE__);
 355
 356        if (win == DEFAULT_ZPOS)
 357                win = ctx->default_win;
 358
 359        if (win < 0 || win > WINDOWS_NR)
 360                return;
 361
 362        win_data = &ctx->win_data[win];
 363        win_data->enabled = false;
 364
 365        /* TODO. */
 366}
 367
 368static struct exynos_drm_overlay_ops vidi_overlay_ops = {
 369        .mode_set = vidi_win_mode_set,
 370        .commit = vidi_win_commit,
 371        .disable = vidi_win_disable,
 372};
 373
 374static struct exynos_drm_manager vidi_manager = {
 375        .pipe           = -1,
 376        .ops            = &vidi_manager_ops,
 377        .overlay_ops    = &vidi_overlay_ops,
 378        .display_ops    = &vidi_display_ops,
 379};
 380
 381static void vidi_fake_vblank_handler(struct work_struct *work)
 382{
 383        struct vidi_context *ctx = container_of(work, struct vidi_context,
 384                                        work);
 385        struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
 386        struct exynos_drm_manager *manager = subdrv->manager;
 387
 388        if (manager->pipe < 0)
 389                return;
 390
 391        /* refresh rate is about 50Hz. */
 392        usleep_range(16000, 20000);
 393
 394        mutex_lock(&ctx->lock);
 395
 396        if (ctx->direct_vblank) {
 397                drm_handle_vblank(subdrv->drm_dev, manager->pipe);
 398                ctx->direct_vblank = false;
 399                mutex_unlock(&ctx->lock);
 400                return;
 401        }
 402
 403        mutex_unlock(&ctx->lock);
 404
 405        exynos_drm_crtc_finish_pageflip(subdrv->drm_dev, manager->pipe);
 406}
 407
 408static int vidi_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
 409{
 410        DRM_DEBUG_KMS("%s\n", __FILE__);
 411
 412        /*
 413         * enable drm irq mode.
 414         * - with irq_enabled = 1, we can use the vblank feature.
 415         *
 416         * P.S. note that we wouldn't use drm irq handler but
 417         *      just specific driver own one instead because
 418         *      drm framework supports only one irq handler.
 419         */
 420        drm_dev->irq_enabled = 1;
 421
 422        /*
 423         * with vblank_disable_allowed = 1, vblank interrupt will be disabled
 424         * by drm timer once a current process gives up ownership of
 425         * vblank event.(after drm_vblank_put function is called)
 426         */
 427        drm_dev->vblank_disable_allowed = 1;
 428
 429        return 0;
 430}
 431
 432static void vidi_subdrv_remove(struct drm_device *drm_dev, struct device *dev)
 433{
 434        DRM_DEBUG_KMS("%s\n", __FILE__);
 435
 436        /* TODO. */
 437}
 438
 439static int vidi_power_on(struct vidi_context *ctx, bool enable)
 440{
 441        struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
 442        struct device *dev = subdrv->dev;
 443
 444        DRM_DEBUG_KMS("%s\n", __FILE__);
 445
 446        if (enable != false && enable != true)
 447                return -EINVAL;
 448
 449        if (enable) {
 450                ctx->suspended = false;
 451
 452                /* if vblank was enabled status, enable it again. */
 453                if (test_and_clear_bit(0, &ctx->irq_flags))
 454                        vidi_enable_vblank(dev);
 455
 456                vidi_apply(dev);
 457        } else {
 458                ctx->suspended = true;
 459        }
 460
 461        return 0;
 462}
 463
 464static int vidi_show_connection(struct device *dev,
 465                                struct device_attribute *attr, char *buf)
 466{
 467        int rc;
 468        struct vidi_context *ctx = get_vidi_context(dev);
 469
 470        mutex_lock(&ctx->lock);
 471
 472        rc = sprintf(buf, "%d\n", ctx->connected);
 473
 474        mutex_unlock(&ctx->lock);
 475
 476        return rc;
 477}
 478
 479static int vidi_store_connection(struct device *dev,
 480                                struct device_attribute *attr,
 481                                const char *buf, size_t len)
 482{
 483        struct vidi_context *ctx = get_vidi_context(dev);
 484        int ret;
 485
 486        DRM_DEBUG_KMS("%s\n", __FILE__);
 487
 488        ret = kstrtoint(buf, 0, &ctx->connected);
 489        if (ret)
 490                return ret;
 491
 492        if (ctx->connected > 1)
 493                return -EINVAL;
 494
 495        /* use fake edid data for test. */
 496        if (!ctx->raw_edid)
 497                ctx->raw_edid = (struct edid *)fake_edid_info;
 498
 499        /* if raw_edid isn't same as fake data then it can't be tested. */
 500        if (ctx->raw_edid != (struct edid *)fake_edid_info) {
 501                DRM_DEBUG_KMS("edid data is not fake data.\n");
 502                return -EINVAL;
 503        }
 504
 505        DRM_DEBUG_KMS("requested connection.\n");
 506
 507        drm_helper_hpd_irq_event(ctx->subdrv.drm_dev);
 508
 509        return len;
 510}
 511
 512static DEVICE_ATTR(connection, 0644, vidi_show_connection,
 513                        vidi_store_connection);
 514
 515int vidi_connection_ioctl(struct drm_device *drm_dev, void *data,
 516                                struct drm_file *file_priv)
 517{
 518        struct vidi_context *ctx = NULL;
 519        struct drm_encoder *encoder;
 520        struct exynos_drm_manager *manager;
 521        struct exynos_drm_display_ops *display_ops;
 522        struct drm_exynos_vidi_connection *vidi = data;
 523        int edid_len;
 524
 525        DRM_DEBUG_KMS("%s\n", __FILE__);
 526
 527        if (!vidi) {
 528                DRM_DEBUG_KMS("user data for vidi is null.\n");
 529                return -EINVAL;
 530        }
 531
 532        if (vidi->connection > 1) {
 533                DRM_DEBUG_KMS("connection should be 0 or 1.\n");
 534                return -EINVAL;
 535        }
 536
 537        list_for_each_entry(encoder, &drm_dev->mode_config.encoder_list,
 538                                                                head) {
 539                manager = exynos_drm_get_manager(encoder);
 540                display_ops = manager->display_ops;
 541
 542                if (display_ops->type == EXYNOS_DISPLAY_TYPE_VIDI) {
 543                        ctx = get_vidi_context(manager->dev);
 544                        break;
 545                }
 546        }
 547
 548        if (!ctx) {
 549                DRM_DEBUG_KMS("not found virtual device type encoder.\n");
 550                return -EINVAL;
 551        }
 552
 553        if (ctx->connected == vidi->connection) {
 554                DRM_DEBUG_KMS("same connection request.\n");
 555                return -EINVAL;
 556        }
 557
 558        if (vidi->connection) {
 559                struct edid *raw_edid  = (struct edid *)(uint32_t)vidi->edid;
 560                if (!drm_edid_is_valid(raw_edid)) {
 561                        DRM_DEBUG_KMS("edid data is invalid.\n");
 562                        return -EINVAL;
 563                }
 564                edid_len = (1 + raw_edid->extensions) * EDID_LENGTH;
 565                ctx->raw_edid = kmemdup(raw_edid, edid_len, GFP_KERNEL);
 566                if (!ctx->raw_edid) {
 567                        DRM_DEBUG_KMS("failed to allocate raw_edid.\n");
 568                        return -ENOMEM;
 569                }
 570        } else {
 571                /*
 572                 * with connection = 0, free raw_edid
 573                 * only if raw edid data isn't same as fake data.
 574                 */
 575                if (ctx->raw_edid && ctx->raw_edid !=
 576                                (struct edid *)fake_edid_info) {
 577                        kfree(ctx->raw_edid);
 578                        ctx->raw_edid = NULL;
 579                }
 580        }
 581
 582        ctx->connected = vidi->connection;
 583        drm_helper_hpd_irq_event(ctx->subdrv.drm_dev);
 584
 585        return 0;
 586}
 587
 588static int vidi_probe(struct platform_device *pdev)
 589{
 590        struct device *dev = &pdev->dev;
 591        struct vidi_context *ctx;
 592        struct exynos_drm_subdrv *subdrv;
 593        int ret;
 594
 595        DRM_DEBUG_KMS("%s\n", __FILE__);
 596
 597        ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
 598        if (!ctx)
 599                return -ENOMEM;
 600
 601        ctx->default_win = 0;
 602
 603        INIT_WORK(&ctx->work, vidi_fake_vblank_handler);
 604
 605        subdrv = &ctx->subdrv;
 606        subdrv->dev = dev;
 607        subdrv->manager = &vidi_manager;
 608        subdrv->probe = vidi_subdrv_probe;
 609        subdrv->remove = vidi_subdrv_remove;
 610
 611        mutex_init(&ctx->lock);
 612
 613        platform_set_drvdata(pdev, ctx);
 614
 615        ret = device_create_file(dev, &dev_attr_connection);
 616        if (ret < 0)
 617                DRM_INFO("failed to create connection sysfs.\n");
 618
 619        exynos_drm_subdrv_register(subdrv);
 620
 621        return 0;
 622}
 623
 624static int vidi_remove(struct platform_device *pdev)
 625{
 626        struct vidi_context *ctx = platform_get_drvdata(pdev);
 627
 628        DRM_DEBUG_KMS("%s\n", __FILE__);
 629
 630        exynos_drm_subdrv_unregister(&ctx->subdrv);
 631
 632        if (ctx->raw_edid != (struct edid *)fake_edid_info) {
 633                kfree(ctx->raw_edid);
 634                ctx->raw_edid = NULL;
 635        }
 636
 637        return 0;
 638}
 639
 640#ifdef CONFIG_PM_SLEEP
 641static int vidi_suspend(struct device *dev)
 642{
 643        struct vidi_context *ctx = get_vidi_context(dev);
 644
 645        return vidi_power_on(ctx, false);
 646}
 647
 648static int vidi_resume(struct device *dev)
 649{
 650        struct vidi_context *ctx = get_vidi_context(dev);
 651
 652        return vidi_power_on(ctx, true);
 653}
 654#endif
 655
 656static const struct dev_pm_ops vidi_pm_ops = {
 657        SET_SYSTEM_SLEEP_PM_OPS(vidi_suspend, vidi_resume)
 658};
 659
 660struct platform_driver vidi_driver = {
 661        .probe          = vidi_probe,
 662        .remove         = vidi_remove,
 663        .driver         = {
 664                .name   = "exynos-drm-vidi",
 665                .owner  = THIS_MODULE,
 666                .pm     = &vidi_pm_ops,
 667        },
 668};
 669