linux/drivers/media/platform/exynos-gsc/gsc-core.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2011 - 2012 Samsung Electronics Co., Ltd.
   3 *              http://www.samsung.com
   4 *
   5 * Samsung EXYNOS5 SoC series G-Scaler driver
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License as published
   9 * by the Free Software Foundation, either version 2 of the License,
  10 * or (at your option) any later version.
  11 */
  12
  13#include <linux/module.h>
  14#include <linux/kernel.h>
  15#include <linux/types.h>
  16#include <linux/errno.h>
  17#include <linux/bug.h>
  18#include <linux/interrupt.h>
  19#include <linux/workqueue.h>
  20#include <linux/device.h>
  21#include <linux/platform_device.h>
  22#include <linux/list.h>
  23#include <linux/io.h>
  24#include <linux/slab.h>
  25#include <linux/clk.h>
  26#include <linux/of.h>
  27#include <media/v4l2-ioctl.h>
  28
  29#include "gsc-core.h"
  30
  31#define GSC_CLOCK_GATE_NAME     "gscl"
  32
  33static const struct gsc_fmt gsc_formats[] = {
  34        {
  35                .name           = "RGB565",
  36                .pixelformat    = V4L2_PIX_FMT_RGB565X,
  37                .depth          = { 16 },
  38                .color          = GSC_RGB,
  39                .num_planes     = 1,
  40                .num_comp       = 1,
  41        }, {
  42                .name           = "XRGB-8-8-8-8, 32 bpp",
  43                .pixelformat    = V4L2_PIX_FMT_RGB32,
  44                .depth          = { 32 },
  45                .color          = GSC_RGB,
  46                .num_planes     = 1,
  47                .num_comp       = 1,
  48        }, {
  49                .name           = "YUV 4:2:2 packed, YCbYCr",
  50                .pixelformat    = V4L2_PIX_FMT_YUYV,
  51                .depth          = { 16 },
  52                .color          = GSC_YUV422,
  53                .yorder         = GSC_LSB_Y,
  54                .corder         = GSC_CBCR,
  55                .num_planes     = 1,
  56                .num_comp       = 1,
  57                .mbus_code      = MEDIA_BUS_FMT_YUYV8_2X8,
  58        }, {
  59                .name           = "YUV 4:2:2 packed, CbYCrY",
  60                .pixelformat    = V4L2_PIX_FMT_UYVY,
  61                .depth          = { 16 },
  62                .color          = GSC_YUV422,
  63                .yorder         = GSC_LSB_C,
  64                .corder         = GSC_CBCR,
  65                .num_planes     = 1,
  66                .num_comp       = 1,
  67                .mbus_code      = MEDIA_BUS_FMT_UYVY8_2X8,
  68        }, {
  69                .name           = "YUV 4:2:2 packed, CrYCbY",
  70                .pixelformat    = V4L2_PIX_FMT_VYUY,
  71                .depth          = { 16 },
  72                .color          = GSC_YUV422,
  73                .yorder         = GSC_LSB_C,
  74                .corder         = GSC_CRCB,
  75                .num_planes     = 1,
  76                .num_comp       = 1,
  77                .mbus_code      = MEDIA_BUS_FMT_VYUY8_2X8,
  78        }, {
  79                .name           = "YUV 4:2:2 packed, YCrYCb",
  80                .pixelformat    = V4L2_PIX_FMT_YVYU,
  81                .depth          = { 16 },
  82                .color          = GSC_YUV422,
  83                .yorder         = GSC_LSB_Y,
  84                .corder         = GSC_CRCB,
  85                .num_planes     = 1,
  86                .num_comp       = 1,
  87                .mbus_code      = MEDIA_BUS_FMT_YVYU8_2X8,
  88        }, {
  89                .name           = "YUV 4:4:4 planar, YCbYCr",
  90                .pixelformat    = V4L2_PIX_FMT_YUV32,
  91                .depth          = { 32 },
  92                .color          = GSC_YUV444,
  93                .yorder         = GSC_LSB_Y,
  94                .corder         = GSC_CBCR,
  95                .num_planes     = 1,
  96                .num_comp       = 1,
  97        }, {
  98                .name           = "YUV 4:2:2 planar, Y/Cb/Cr",
  99                .pixelformat    = V4L2_PIX_FMT_YUV422P,
 100                .depth          = { 16 },
 101                .color          = GSC_YUV422,
 102                .yorder         = GSC_LSB_Y,
 103                .corder         = GSC_CBCR,
 104                .num_planes     = 1,
 105                .num_comp       = 3,
 106        }, {
 107                .name           = "YUV 4:2:2 planar, Y/CbCr",
 108                .pixelformat    = V4L2_PIX_FMT_NV16,
 109                .depth          = { 16 },
 110                .color          = GSC_YUV422,
 111                .yorder         = GSC_LSB_Y,
 112                .corder         = GSC_CBCR,
 113                .num_planes     = 1,
 114                .num_comp       = 2,
 115        }, {
 116                .name           = "YUV 4:2:2 planar, Y/CrCb",
 117                .pixelformat    = V4L2_PIX_FMT_NV61,
 118                .depth          = { 16 },
 119                .color          = GSC_YUV422,
 120                .yorder         = GSC_LSB_Y,
 121                .corder         = GSC_CRCB,
 122                .num_planes     = 1,
 123                .num_comp       = 2,
 124        }, {
 125                .name           = "YUV 4:2:0 planar, YCbCr",
 126                .pixelformat    = V4L2_PIX_FMT_YUV420,
 127                .depth          = { 12 },
 128                .color          = GSC_YUV420,
 129                .yorder         = GSC_LSB_Y,
 130                .corder         = GSC_CBCR,
 131                .num_planes     = 1,
 132                .num_comp       = 3,
 133        }, {
 134                .name           = "YUV 4:2:0 planar, YCrCb",
 135                .pixelformat    = V4L2_PIX_FMT_YVU420,
 136                .depth          = { 12 },
 137                .color          = GSC_YUV420,
 138                .yorder         = GSC_LSB_Y,
 139                .corder         = GSC_CRCB,
 140                .num_planes     = 1,
 141                .num_comp       = 3,
 142
 143        }, {
 144                .name           = "YUV 4:2:0 planar, Y/CbCr",
 145                .pixelformat    = V4L2_PIX_FMT_NV12,
 146                .depth          = { 12 },
 147                .color          = GSC_YUV420,
 148                .yorder         = GSC_LSB_Y,
 149                .corder         = GSC_CBCR,
 150                .num_planes     = 1,
 151                .num_comp       = 2,
 152        }, {
 153                .name           = "YUV 4:2:0 planar, Y/CrCb",
 154                .pixelformat    = V4L2_PIX_FMT_NV21,
 155                .depth          = { 12 },
 156                .color          = GSC_YUV420,
 157                .yorder         = GSC_LSB_Y,
 158                .corder         = GSC_CRCB,
 159                .num_planes     = 1,
 160                .num_comp       = 2,
 161        }, {
 162                .name           = "YUV 4:2:0 non-contig. 2p, Y/CbCr",
 163                .pixelformat    = V4L2_PIX_FMT_NV12M,
 164                .depth          = { 8, 4 },
 165                .color          = GSC_YUV420,
 166                .yorder         = GSC_LSB_Y,
 167                .corder         = GSC_CBCR,
 168                .num_planes     = 2,
 169                .num_comp       = 2,
 170        }, {
 171                .name           = "YUV 4:2:0 non-contig. 3p, Y/Cb/Cr",
 172                .pixelformat    = V4L2_PIX_FMT_YUV420M,
 173                .depth          = { 8, 2, 2 },
 174                .color          = GSC_YUV420,
 175                .yorder         = GSC_LSB_Y,
 176                .corder         = GSC_CBCR,
 177                .num_planes     = 3,
 178                .num_comp       = 3,
 179        }, {
 180                .name           = "YUV 4:2:0 non-contig. 3p, Y/Cr/Cb",
 181                .pixelformat    = V4L2_PIX_FMT_YVU420M,
 182                .depth          = { 8, 2, 2 },
 183                .color          = GSC_YUV420,
 184                .yorder         = GSC_LSB_Y,
 185                .corder         = GSC_CRCB,
 186                .num_planes     = 3,
 187                .num_comp       = 3,
 188        }, {
 189                .name           = "YUV 4:2:0 n.c. 2p, Y/CbCr tiled",
 190                .pixelformat    = V4L2_PIX_FMT_NV12MT_16X16,
 191                .depth          = { 8, 4 },
 192                .color          = GSC_YUV420,
 193                .yorder         = GSC_LSB_Y,
 194                .corder         = GSC_CBCR,
 195                .num_planes     = 2,
 196                .num_comp       = 2,
 197        }
 198};
 199
 200const struct gsc_fmt *get_format(int index)
 201{
 202        if (index >= ARRAY_SIZE(gsc_formats))
 203                return NULL;
 204
 205        return (struct gsc_fmt *)&gsc_formats[index];
 206}
 207
 208const struct gsc_fmt *find_fmt(u32 *pixelformat, u32 *mbus_code, u32 index)
 209{
 210        const struct gsc_fmt *fmt, *def_fmt = NULL;
 211        unsigned int i;
 212
 213        if (index >= ARRAY_SIZE(gsc_formats))
 214                return NULL;
 215
 216        for (i = 0; i < ARRAY_SIZE(gsc_formats); ++i) {
 217                fmt = get_format(i);
 218                if (pixelformat && fmt->pixelformat == *pixelformat)
 219                        return fmt;
 220                if (mbus_code && fmt->mbus_code == *mbus_code)
 221                        return fmt;
 222                if (index == i)
 223                        def_fmt = fmt;
 224        }
 225        return def_fmt;
 226
 227}
 228
 229void gsc_set_frame_size(struct gsc_frame *frame, int width, int height)
 230{
 231        frame->f_width  = width;
 232        frame->f_height = height;
 233        frame->crop.width = width;
 234        frame->crop.height = height;
 235        frame->crop.left = 0;
 236        frame->crop.top = 0;
 237}
 238
 239int gsc_cal_prescaler_ratio(struct gsc_variant *var, u32 src, u32 dst,
 240                                                                u32 *ratio)
 241{
 242        if ((dst > src) || (dst >= src / var->poly_sc_down_max)) {
 243                *ratio = 1;
 244                return 0;
 245        }
 246
 247        if ((src / var->poly_sc_down_max / var->pre_sc_down_max) > dst) {
 248                pr_err("Exceeded maximum downscaling ratio (1/16))");
 249                return -EINVAL;
 250        }
 251
 252        *ratio = (dst > (src / 8)) ? 2 : 4;
 253
 254        return 0;
 255}
 256
 257void gsc_get_prescaler_shfactor(u32 hratio, u32 vratio, u32 *sh)
 258{
 259        if (hratio == 4 && vratio == 4)
 260                *sh = 4;
 261        else if ((hratio == 4 && vratio == 2) ||
 262                 (hratio == 2 && vratio == 4))
 263                *sh = 3;
 264        else if ((hratio == 4 && vratio == 1) ||
 265                 (hratio == 1 && vratio == 4) ||
 266                 (hratio == 2 && vratio == 2))
 267                *sh = 2;
 268        else if (hratio == 1 && vratio == 1)
 269                *sh = 0;
 270        else
 271                *sh = 1;
 272}
 273
 274void gsc_check_src_scale_info(struct gsc_variant *var,
 275                                struct gsc_frame *s_frame, u32 *wratio,
 276                                 u32 tx, u32 ty, u32 *hratio)
 277{
 278        int remainder = 0, walign, halign;
 279
 280        if (is_yuv420(s_frame->fmt->color)) {
 281                walign = GSC_SC_ALIGN_4;
 282                halign = GSC_SC_ALIGN_4;
 283        } else if (is_yuv422(s_frame->fmt->color)) {
 284                walign = GSC_SC_ALIGN_4;
 285                halign = GSC_SC_ALIGN_2;
 286        } else {
 287                walign = GSC_SC_ALIGN_2;
 288                halign = GSC_SC_ALIGN_2;
 289        }
 290
 291        remainder = s_frame->crop.width % (*wratio * walign);
 292        if (remainder) {
 293                s_frame->crop.width -= remainder;
 294                gsc_cal_prescaler_ratio(var, s_frame->crop.width, tx, wratio);
 295                pr_info("cropped src width size is recalculated from %d to %d",
 296                        s_frame->crop.width + remainder, s_frame->crop.width);
 297        }
 298
 299        remainder = s_frame->crop.height % (*hratio * halign);
 300        if (remainder) {
 301                s_frame->crop.height -= remainder;
 302                gsc_cal_prescaler_ratio(var, s_frame->crop.height, ty, hratio);
 303                pr_info("cropped src height size is recalculated from %d to %d",
 304                        s_frame->crop.height + remainder, s_frame->crop.height);
 305        }
 306}
 307
 308int gsc_enum_fmt_mplane(struct v4l2_fmtdesc *f)
 309{
 310        const struct gsc_fmt *fmt;
 311
 312        fmt = find_fmt(NULL, NULL, f->index);
 313        if (!fmt)
 314                return -EINVAL;
 315
 316        strlcpy(f->description, fmt->name, sizeof(f->description));
 317        f->pixelformat = fmt->pixelformat;
 318
 319        return 0;
 320}
 321
 322static int get_plane_info(struct gsc_frame *frm, u32 addr, u32 *index, u32 *ret_addr)
 323{
 324        if (frm->addr.y == addr) {
 325                *index = 0;
 326                *ret_addr = frm->addr.y;
 327        } else if (frm->addr.cb == addr) {
 328                *index = 1;
 329                *ret_addr = frm->addr.cb;
 330        } else if (frm->addr.cr == addr) {
 331                *index = 2;
 332                *ret_addr = frm->addr.cr;
 333        } else {
 334                pr_err("Plane address is wrong");
 335                return -EINVAL;
 336        }
 337        return 0;
 338}
 339
 340void gsc_set_prefbuf(struct gsc_dev *gsc, struct gsc_frame *frm)
 341{
 342        u32 f_chk_addr, f_chk_len, s_chk_addr, s_chk_len;
 343        f_chk_addr = f_chk_len = s_chk_addr = s_chk_len = 0;
 344
 345        f_chk_addr = frm->addr.y;
 346        f_chk_len = frm->payload[0];
 347        if (frm->fmt->num_planes == 2) {
 348                s_chk_addr = frm->addr.cb;
 349                s_chk_len = frm->payload[1];
 350        } else if (frm->fmt->num_planes == 3) {
 351                u32 low_addr, low_plane, mid_addr, mid_plane;
 352                u32 high_addr, high_plane;
 353                u32 t_min, t_max;
 354
 355                t_min = min3(frm->addr.y, frm->addr.cb, frm->addr.cr);
 356                if (get_plane_info(frm, t_min, &low_plane, &low_addr))
 357                        return;
 358                t_max = max3(frm->addr.y, frm->addr.cb, frm->addr.cr);
 359                if (get_plane_info(frm, t_max, &high_plane, &high_addr))
 360                        return;
 361
 362                mid_plane = 3 - (low_plane + high_plane);
 363                if (mid_plane == 0)
 364                        mid_addr = frm->addr.y;
 365                else if (mid_plane == 1)
 366                        mid_addr = frm->addr.cb;
 367                else if (mid_plane == 2)
 368                        mid_addr = frm->addr.cr;
 369                else
 370                        return;
 371
 372                f_chk_addr = low_addr;
 373                if (mid_addr + frm->payload[mid_plane] - low_addr >
 374                    high_addr + frm->payload[high_plane] - mid_addr) {
 375                        f_chk_len = frm->payload[low_plane];
 376                        s_chk_addr = mid_addr;
 377                        s_chk_len = high_addr +
 378                                        frm->payload[high_plane] - mid_addr;
 379                } else {
 380                        f_chk_len = mid_addr +
 381                                        frm->payload[mid_plane] - low_addr;
 382                        s_chk_addr = high_addr;
 383                        s_chk_len = frm->payload[high_plane];
 384                }
 385        }
 386        pr_debug("f_addr = 0x%08x, f_len = %d, s_addr = 0x%08x, s_len = %d\n",
 387                        f_chk_addr, f_chk_len, s_chk_addr, s_chk_len);
 388}
 389
 390int gsc_try_fmt_mplane(struct gsc_ctx *ctx, struct v4l2_format *f)
 391{
 392        struct gsc_dev *gsc = ctx->gsc_dev;
 393        struct gsc_variant *variant = gsc->variant;
 394        struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
 395        const struct gsc_fmt *fmt;
 396        u32 max_w, max_h, mod_x, mod_y;
 397        u32 min_w, min_h, tmp_w, tmp_h;
 398        int i;
 399
 400        pr_debug("user put w: %d, h: %d", pix_mp->width, pix_mp->height);
 401
 402        fmt = find_fmt(&pix_mp->pixelformat, NULL, 0);
 403        if (!fmt) {
 404                pr_err("pixelformat format (0x%X) invalid\n",
 405                                                pix_mp->pixelformat);
 406                return -EINVAL;
 407        }
 408
 409        if (pix_mp->field == V4L2_FIELD_ANY)
 410                pix_mp->field = V4L2_FIELD_NONE;
 411        else if (pix_mp->field != V4L2_FIELD_NONE) {
 412                pr_err("Not supported field order(%d)\n", pix_mp->field);
 413                return -EINVAL;
 414        }
 415
 416        max_w = variant->pix_max->target_rot_dis_w;
 417        max_h = variant->pix_max->target_rot_dis_h;
 418
 419        mod_x = ffs(variant->pix_align->org_w) - 1;
 420        if (is_yuv420(fmt->color))
 421                mod_y = ffs(variant->pix_align->org_h) - 1;
 422        else
 423                mod_y = ffs(variant->pix_align->org_h) - 2;
 424
 425        if (V4L2_TYPE_IS_OUTPUT(f->type)) {
 426                min_w = variant->pix_min->org_w;
 427                min_h = variant->pix_min->org_h;
 428        } else {
 429                min_w = variant->pix_min->target_rot_dis_w;
 430                min_h = variant->pix_min->target_rot_dis_h;
 431        }
 432
 433        pr_debug("mod_x: %d, mod_y: %d, max_w: %d, max_h = %d",
 434                        mod_x, mod_y, max_w, max_h);
 435
 436        /* To check if image size is modified to adjust parameter against
 437           hardware abilities */
 438        tmp_w = pix_mp->width;
 439        tmp_h = pix_mp->height;
 440
 441        v4l_bound_align_image(&pix_mp->width, min_w, max_w, mod_x,
 442                &pix_mp->height, min_h, max_h, mod_y, 0);
 443        if (tmp_w != pix_mp->width || tmp_h != pix_mp->height)
 444                pr_info("Image size has been modified from %dx%d to %dx%d",
 445                         tmp_w, tmp_h, pix_mp->width, pix_mp->height);
 446
 447        pix_mp->num_planes = fmt->num_planes;
 448
 449        if (pix_mp->width >= 1280) /* HD */
 450                pix_mp->colorspace = V4L2_COLORSPACE_REC709;
 451        else /* SD */
 452                pix_mp->colorspace = V4L2_COLORSPACE_SMPTE170M;
 453
 454
 455        for (i = 0; i < pix_mp->num_planes; ++i) {
 456                int bpl = (pix_mp->width * fmt->depth[i]) >> 3;
 457                pix_mp->plane_fmt[i].bytesperline = bpl;
 458                pix_mp->plane_fmt[i].sizeimage = bpl * pix_mp->height;
 459
 460                pr_debug("[%d]: bpl: %d, sizeimage: %d",
 461                                i, bpl, pix_mp->plane_fmt[i].sizeimage);
 462        }
 463
 464        return 0;
 465}
 466
 467int gsc_g_fmt_mplane(struct gsc_ctx *ctx, struct v4l2_format *f)
 468{
 469        struct gsc_frame *frame;
 470        struct v4l2_pix_format_mplane *pix_mp;
 471        int i;
 472
 473        frame = ctx_get_frame(ctx, f->type);
 474        if (IS_ERR(frame))
 475                return PTR_ERR(frame);
 476
 477        pix_mp = &f->fmt.pix_mp;
 478
 479        pix_mp->width           = frame->f_width;
 480        pix_mp->height          = frame->f_height;
 481        pix_mp->field           = V4L2_FIELD_NONE;
 482        pix_mp->pixelformat     = frame->fmt->pixelformat;
 483        pix_mp->colorspace      = V4L2_COLORSPACE_REC709;
 484        pix_mp->num_planes      = frame->fmt->num_planes;
 485
 486        for (i = 0; i < pix_mp->num_planes; ++i) {
 487                pix_mp->plane_fmt[i].bytesperline = (frame->f_width *
 488                        frame->fmt->depth[i]) / 8;
 489                pix_mp->plane_fmt[i].sizeimage =
 490                         pix_mp->plane_fmt[i].bytesperline * frame->f_height;
 491        }
 492
 493        return 0;
 494}
 495
 496void gsc_check_crop_change(u32 tmp_w, u32 tmp_h, u32 *w, u32 *h)
 497{
 498        if (tmp_w != *w || tmp_h != *h) {
 499                pr_info("Cropped size has been modified from %dx%d to %dx%d",
 500                                                        *w, *h, tmp_w, tmp_h);
 501                *w = tmp_w;
 502                *h = tmp_h;
 503        }
 504}
 505
 506int gsc_g_crop(struct gsc_ctx *ctx, struct v4l2_crop *cr)
 507{
 508        struct gsc_frame *frame;
 509
 510        frame = ctx_get_frame(ctx, cr->type);
 511        if (IS_ERR(frame))
 512                return PTR_ERR(frame);
 513
 514        cr->c = frame->crop;
 515
 516        return 0;
 517}
 518
 519int gsc_try_crop(struct gsc_ctx *ctx, struct v4l2_crop *cr)
 520{
 521        struct gsc_frame *f;
 522        struct gsc_dev *gsc = ctx->gsc_dev;
 523        struct gsc_variant *variant = gsc->variant;
 524        u32 mod_x = 0, mod_y = 0, tmp_w, tmp_h;
 525        u32 min_w, min_h, max_w, max_h;
 526
 527        if (cr->c.top < 0 || cr->c.left < 0) {
 528                pr_err("doesn't support negative values for top & left\n");
 529                return -EINVAL;
 530        }
 531        pr_debug("user put w: %d, h: %d", cr->c.width, cr->c.height);
 532
 533        if (cr->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
 534                f = &ctx->d_frame;
 535        else if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
 536                f = &ctx->s_frame;
 537        else
 538                return -EINVAL;
 539
 540        max_w = f->f_width;
 541        max_h = f->f_height;
 542        tmp_w = cr->c.width;
 543        tmp_h = cr->c.height;
 544
 545        if (V4L2_TYPE_IS_OUTPUT(cr->type)) {
 546                if ((is_yuv422(f->fmt->color) && f->fmt->num_comp == 1) ||
 547                    is_rgb(f->fmt->color))
 548                        min_w = 32;
 549                else
 550                        min_w = 64;
 551                if ((is_yuv422(f->fmt->color) && f->fmt->num_comp == 3) ||
 552                    is_yuv420(f->fmt->color))
 553                        min_h = 32;
 554                else
 555                        min_h = 16;
 556        } else {
 557                if (is_yuv420(f->fmt->color) || is_yuv422(f->fmt->color))
 558                        mod_x = ffs(variant->pix_align->target_w) - 1;
 559                if (is_yuv420(f->fmt->color))
 560                        mod_y = ffs(variant->pix_align->target_h) - 1;
 561                if (ctx->gsc_ctrls.rotate->val == 90 ||
 562                    ctx->gsc_ctrls.rotate->val == 270) {
 563                        max_w = f->f_height;
 564                        max_h = f->f_width;
 565                        min_w = variant->pix_min->target_rot_en_w;
 566                        min_h = variant->pix_min->target_rot_en_h;
 567                        tmp_w = cr->c.height;
 568                        tmp_h = cr->c.width;
 569                } else {
 570                        min_w = variant->pix_min->target_rot_dis_w;
 571                        min_h = variant->pix_min->target_rot_dis_h;
 572                }
 573        }
 574        pr_debug("mod_x: %d, mod_y: %d, min_w: %d, min_h = %d",
 575                                        mod_x, mod_y, min_w, min_h);
 576        pr_debug("tmp_w : %d, tmp_h : %d", tmp_w, tmp_h);
 577
 578        v4l_bound_align_image(&tmp_w, min_w, max_w, mod_x,
 579                              &tmp_h, min_h, max_h, mod_y, 0);
 580
 581        if (!V4L2_TYPE_IS_OUTPUT(cr->type) &&
 582                (ctx->gsc_ctrls.rotate->val == 90 ||
 583                ctx->gsc_ctrls.rotate->val == 270))
 584                gsc_check_crop_change(tmp_h, tmp_w,
 585                                        &cr->c.width, &cr->c.height);
 586        else
 587                gsc_check_crop_change(tmp_w, tmp_h,
 588                                        &cr->c.width, &cr->c.height);
 589
 590
 591        /* adjust left/top if cropping rectangle is out of bounds */
 592        /* Need to add code to algin left value with 2's multiple */
 593        if (cr->c.left + tmp_w > max_w)
 594                cr->c.left = max_w - tmp_w;
 595        if (cr->c.top + tmp_h > max_h)
 596                cr->c.top = max_h - tmp_h;
 597
 598        if ((is_yuv420(f->fmt->color) || is_yuv422(f->fmt->color)) &&
 599                cr->c.left & 1)
 600                        cr->c.left -= 1;
 601
 602        pr_debug("Aligned l:%d, t:%d, w:%d, h:%d, f_w: %d, f_h: %d",
 603            cr->c.left, cr->c.top, cr->c.width, cr->c.height, max_w, max_h);
 604
 605        return 0;
 606}
 607
 608int gsc_check_scaler_ratio(struct gsc_variant *var, int sw, int sh, int dw,
 609                           int dh, int rot, int out_path)
 610{
 611        int tmp_w, tmp_h, sc_down_max;
 612
 613        if (out_path == GSC_DMA)
 614                sc_down_max = var->sc_down_max;
 615        else
 616                sc_down_max = var->local_sc_down;
 617
 618        if (rot == 90 || rot == 270) {
 619                tmp_w = dh;
 620                tmp_h = dw;
 621        } else {
 622                tmp_w = dw;
 623                tmp_h = dh;
 624        }
 625
 626        if ((sw / tmp_w) > sc_down_max ||
 627            (sh / tmp_h) > sc_down_max ||
 628            (tmp_w / sw) > var->sc_up_max ||
 629            (tmp_h / sh) > var->sc_up_max)
 630                return -EINVAL;
 631
 632        return 0;
 633}
 634
 635int gsc_set_scaler_info(struct gsc_ctx *ctx)
 636{
 637        struct gsc_scaler *sc = &ctx->scaler;
 638        struct gsc_frame *s_frame = &ctx->s_frame;
 639        struct gsc_frame *d_frame = &ctx->d_frame;
 640        struct gsc_variant *variant = ctx->gsc_dev->variant;
 641        struct device *dev = &ctx->gsc_dev->pdev->dev;
 642        int tx, ty;
 643        int ret;
 644
 645        ret = gsc_check_scaler_ratio(variant, s_frame->crop.width,
 646                s_frame->crop.height, d_frame->crop.width, d_frame->crop.height,
 647                ctx->gsc_ctrls.rotate->val, ctx->out_path);
 648        if (ret) {
 649                pr_err("out of scaler range");
 650                return ret;
 651        }
 652
 653        if (ctx->gsc_ctrls.rotate->val == 90 ||
 654            ctx->gsc_ctrls.rotate->val == 270) {
 655                ty = d_frame->crop.width;
 656                tx = d_frame->crop.height;
 657        } else {
 658                tx = d_frame->crop.width;
 659                ty = d_frame->crop.height;
 660        }
 661
 662        if (tx <= 0 || ty <= 0) {
 663                dev_err(dev, "Invalid target size: %dx%d", tx, ty);
 664                return -EINVAL;
 665        }
 666
 667        ret = gsc_cal_prescaler_ratio(variant, s_frame->crop.width,
 668                                      tx, &sc->pre_hratio);
 669        if (ret) {
 670                pr_err("Horizontal scale ratio is out of range");
 671                return ret;
 672        }
 673
 674        ret = gsc_cal_prescaler_ratio(variant, s_frame->crop.height,
 675                                      ty, &sc->pre_vratio);
 676        if (ret) {
 677                pr_err("Vertical scale ratio is out of range");
 678                return ret;
 679        }
 680
 681        gsc_check_src_scale_info(variant, s_frame, &sc->pre_hratio,
 682                                 tx, ty, &sc->pre_vratio);
 683
 684        gsc_get_prescaler_shfactor(sc->pre_hratio, sc->pre_vratio,
 685                                   &sc->pre_shfactor);
 686
 687        sc->main_hratio = (s_frame->crop.width << 16) / tx;
 688        sc->main_vratio = (s_frame->crop.height << 16) / ty;
 689
 690        pr_debug("scaler input/output size : sx = %d, sy = %d, tx = %d, ty = %d",
 691                        s_frame->crop.width, s_frame->crop.height, tx, ty);
 692        pr_debug("scaler ratio info : pre_shfactor : %d, pre_h : %d",
 693                        sc->pre_shfactor, sc->pre_hratio);
 694        pr_debug("pre_v :%d, main_h : %d, main_v : %d",
 695                        sc->pre_vratio, sc->main_hratio, sc->main_vratio);
 696
 697        return 0;
 698}
 699
 700static int __gsc_s_ctrl(struct gsc_ctx *ctx, struct v4l2_ctrl *ctrl)
 701{
 702        struct gsc_dev *gsc = ctx->gsc_dev;
 703        struct gsc_variant *variant = gsc->variant;
 704        unsigned int flags = GSC_DST_FMT | GSC_SRC_FMT;
 705        int ret = 0;
 706
 707        if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE)
 708                return 0;
 709
 710        switch (ctrl->id) {
 711        case V4L2_CID_HFLIP:
 712                ctx->hflip = ctrl->val;
 713                break;
 714
 715        case V4L2_CID_VFLIP:
 716                ctx->vflip = ctrl->val;
 717                break;
 718
 719        case V4L2_CID_ROTATE:
 720                if ((ctx->state & flags) == flags) {
 721                        ret = gsc_check_scaler_ratio(variant,
 722                                        ctx->s_frame.crop.width,
 723                                        ctx->s_frame.crop.height,
 724                                        ctx->d_frame.crop.width,
 725                                        ctx->d_frame.crop.height,
 726                                        ctx->gsc_ctrls.rotate->val,
 727                                        ctx->out_path);
 728
 729                        if (ret)
 730                                return -EINVAL;
 731                }
 732
 733                ctx->rotation = ctrl->val;
 734                break;
 735
 736        case V4L2_CID_ALPHA_COMPONENT:
 737                ctx->d_frame.alpha = ctrl->val;
 738                break;
 739        }
 740
 741        ctx->state |= GSC_PARAMS;
 742        return 0;
 743}
 744
 745static int gsc_s_ctrl(struct v4l2_ctrl *ctrl)
 746{
 747        struct gsc_ctx *ctx = ctrl_to_ctx(ctrl);
 748        unsigned long flags;
 749        int ret;
 750
 751        spin_lock_irqsave(&ctx->gsc_dev->slock, flags);
 752        ret = __gsc_s_ctrl(ctx, ctrl);
 753        spin_unlock_irqrestore(&ctx->gsc_dev->slock, flags);
 754
 755        return ret;
 756}
 757
 758static const struct v4l2_ctrl_ops gsc_ctrl_ops = {
 759        .s_ctrl = gsc_s_ctrl,
 760};
 761
 762int gsc_ctrls_create(struct gsc_ctx *ctx)
 763{
 764        if (ctx->ctrls_rdy) {
 765                pr_err("Control handler of this context was created already");
 766                return 0;
 767        }
 768
 769        v4l2_ctrl_handler_init(&ctx->ctrl_handler, GSC_MAX_CTRL_NUM);
 770
 771        ctx->gsc_ctrls.rotate = v4l2_ctrl_new_std(&ctx->ctrl_handler,
 772                                &gsc_ctrl_ops, V4L2_CID_ROTATE, 0, 270, 90, 0);
 773        ctx->gsc_ctrls.hflip = v4l2_ctrl_new_std(&ctx->ctrl_handler,
 774                                &gsc_ctrl_ops, V4L2_CID_HFLIP, 0, 1, 1, 0);
 775        ctx->gsc_ctrls.vflip = v4l2_ctrl_new_std(&ctx->ctrl_handler,
 776                                &gsc_ctrl_ops, V4L2_CID_VFLIP, 0, 1, 1, 0);
 777        ctx->gsc_ctrls.global_alpha = v4l2_ctrl_new_std(&ctx->ctrl_handler,
 778                        &gsc_ctrl_ops, V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 0);
 779
 780        ctx->ctrls_rdy = ctx->ctrl_handler.error == 0;
 781
 782        if (ctx->ctrl_handler.error) {
 783                int err = ctx->ctrl_handler.error;
 784                v4l2_ctrl_handler_free(&ctx->ctrl_handler);
 785                pr_err("Failed to create G-Scaler control handlers");
 786                return err;
 787        }
 788
 789        return 0;
 790}
 791
 792void gsc_ctrls_delete(struct gsc_ctx *ctx)
 793{
 794        if (ctx->ctrls_rdy) {
 795                v4l2_ctrl_handler_free(&ctx->ctrl_handler);
 796                ctx->ctrls_rdy = false;
 797        }
 798}
 799
 800/* The color format (num_comp, num_planes) must be already configured. */
 801int gsc_prepare_addr(struct gsc_ctx *ctx, struct vb2_buffer *vb,
 802                        struct gsc_frame *frame, struct gsc_addr *addr)
 803{
 804        int ret = 0;
 805        u32 pix_size;
 806
 807        if ((vb == NULL) || (frame == NULL))
 808                return -EINVAL;
 809
 810        pix_size = frame->f_width * frame->f_height;
 811
 812        pr_debug("num_planes= %d, num_comp= %d, pix_size= %d",
 813                frame->fmt->num_planes, frame->fmt->num_comp, pix_size);
 814
 815        addr->y = vb2_dma_contig_plane_dma_addr(vb, 0);
 816
 817        if (frame->fmt->num_planes == 1) {
 818                switch (frame->fmt->num_comp) {
 819                case 1:
 820                        addr->cb = 0;
 821                        addr->cr = 0;
 822                        break;
 823                case 2:
 824                        /* decompose Y into Y/Cb */
 825                        addr->cb = (dma_addr_t)(addr->y + pix_size);
 826                        addr->cr = 0;
 827                        break;
 828                case 3:
 829                        /* decompose Y into Y/Cb/Cr */
 830                        addr->cb = (dma_addr_t)(addr->y + pix_size);
 831                        if (GSC_YUV420 == frame->fmt->color)
 832                                addr->cr = (dma_addr_t)(addr->cb
 833                                                + (pix_size >> 2));
 834                        else /* 422 */
 835                                addr->cr = (dma_addr_t)(addr->cb
 836                                                + (pix_size >> 1));
 837                        break;
 838                default:
 839                        pr_err("Invalid the number of color planes");
 840                        return -EINVAL;
 841                }
 842        } else {
 843                if (frame->fmt->num_planes >= 2)
 844                        addr->cb = vb2_dma_contig_plane_dma_addr(vb, 1);
 845
 846                if (frame->fmt->num_planes == 3)
 847                        addr->cr = vb2_dma_contig_plane_dma_addr(vb, 2);
 848        }
 849
 850        if ((frame->fmt->pixelformat == V4L2_PIX_FMT_VYUY) ||
 851                (frame->fmt->pixelformat == V4L2_PIX_FMT_YVYU) ||
 852                (frame->fmt->pixelformat == V4L2_PIX_FMT_NV61) ||
 853                (frame->fmt->pixelformat == V4L2_PIX_FMT_YVU420) ||
 854                (frame->fmt->pixelformat == V4L2_PIX_FMT_NV21) ||
 855                (frame->fmt->pixelformat == V4L2_PIX_FMT_YVU420M))
 856                swap(addr->cb, addr->cr);
 857
 858        pr_debug("ADDR: y= %pad  cb= %pad cr= %pad ret= %d",
 859                &addr->y, &addr->cb, &addr->cr, ret);
 860
 861        return ret;
 862}
 863
 864static irqreturn_t gsc_irq_handler(int irq, void *priv)
 865{
 866        struct gsc_dev *gsc = priv;
 867        struct gsc_ctx *ctx;
 868        int gsc_irq;
 869
 870        gsc_irq = gsc_hw_get_irq_status(gsc);
 871        gsc_hw_clear_irq(gsc, gsc_irq);
 872
 873        if (gsc_irq == GSC_IRQ_OVERRUN) {
 874                pr_err("Local path input over-run interrupt has occurred!\n");
 875                return IRQ_HANDLED;
 876        }
 877
 878        spin_lock(&gsc->slock);
 879
 880        if (test_and_clear_bit(ST_M2M_PEND, &gsc->state)) {
 881
 882                gsc_hw_enable_control(gsc, false);
 883
 884                if (test_and_clear_bit(ST_M2M_SUSPENDING, &gsc->state)) {
 885                        set_bit(ST_M2M_SUSPENDED, &gsc->state);
 886                        wake_up(&gsc->irq_queue);
 887                        goto isr_unlock;
 888                }
 889                ctx = v4l2_m2m_get_curr_priv(gsc->m2m.m2m_dev);
 890
 891                if (!ctx || !ctx->m2m_ctx)
 892                        goto isr_unlock;
 893
 894                spin_unlock(&gsc->slock);
 895                gsc_m2m_job_finish(ctx, VB2_BUF_STATE_DONE);
 896
 897                /* wake_up job_abort, stop_streaming */
 898                if (ctx->state & GSC_CTX_STOP_REQ) {
 899                        ctx->state &= ~GSC_CTX_STOP_REQ;
 900                        wake_up(&gsc->irq_queue);
 901                }
 902                return IRQ_HANDLED;
 903        }
 904
 905isr_unlock:
 906        spin_unlock(&gsc->slock);
 907        return IRQ_HANDLED;
 908}
 909
 910static struct gsc_pix_max gsc_v_100_max = {
 911        .org_scaler_bypass_w    = 8192,
 912        .org_scaler_bypass_h    = 8192,
 913        .org_scaler_input_w     = 4800,
 914        .org_scaler_input_h     = 3344,
 915        .real_rot_dis_w         = 4800,
 916        .real_rot_dis_h         = 3344,
 917        .real_rot_en_w          = 2047,
 918        .real_rot_en_h          = 2047,
 919        .target_rot_dis_w       = 4800,
 920        .target_rot_dis_h       = 3344,
 921        .target_rot_en_w        = 2016,
 922        .target_rot_en_h        = 2016,
 923};
 924
 925static struct gsc_pix_min gsc_v_100_min = {
 926        .org_w                  = 64,
 927        .org_h                  = 32,
 928        .real_w                 = 64,
 929        .real_h                 = 32,
 930        .target_rot_dis_w       = 64,
 931        .target_rot_dis_h       = 32,
 932        .target_rot_en_w        = 32,
 933        .target_rot_en_h        = 16,
 934};
 935
 936static struct gsc_pix_align gsc_v_100_align = {
 937        .org_h                  = 16,
 938        .org_w                  = 16, /* yuv420 : 16, others : 8 */
 939        .offset_h               = 2,  /* yuv420/422 : 2, others : 1 */
 940        .real_w                 = 16, /* yuv420/422 : 4~16, others : 2~8 */
 941        .real_h                 = 16, /* yuv420 : 4~16, others : 1 */
 942        .target_w               = 2,  /* yuv420/422 : 2, others : 1 */
 943        .target_h               = 2,  /* yuv420 : 2, others : 1 */
 944};
 945
 946static struct gsc_variant gsc_v_100_variant = {
 947        .pix_max                = &gsc_v_100_max,
 948        .pix_min                = &gsc_v_100_min,
 949        .pix_align              = &gsc_v_100_align,
 950        .in_buf_cnt             = 32,
 951        .out_buf_cnt            = 32,
 952        .sc_up_max              = 8,
 953        .sc_down_max            = 16,
 954        .poly_sc_down_max       = 4,
 955        .pre_sc_down_max        = 4,
 956        .local_sc_down          = 2,
 957};
 958
 959static struct gsc_driverdata gsc_v_100_drvdata = {
 960        .variant = {
 961                [0] = &gsc_v_100_variant,
 962                [1] = &gsc_v_100_variant,
 963                [2] = &gsc_v_100_variant,
 964                [3] = &gsc_v_100_variant,
 965        },
 966        .num_entities = 4,
 967        .lclk_frequency = 266000000UL,
 968};
 969
 970static const struct of_device_id exynos_gsc_match[] = {
 971        {
 972                .compatible = "samsung,exynos5-gsc",
 973                .data = &gsc_v_100_drvdata,
 974        },
 975        {},
 976};
 977MODULE_DEVICE_TABLE(of, exynos_gsc_match);
 978
 979static void *gsc_get_drv_data(struct platform_device *pdev)
 980{
 981        struct gsc_driverdata *driver_data = NULL;
 982        const struct of_device_id *match;
 983
 984        match = of_match_node(exynos_gsc_match, pdev->dev.of_node);
 985        if (match)
 986                driver_data = (struct gsc_driverdata *)match->data;
 987
 988        return driver_data;
 989}
 990
 991static void gsc_clk_put(struct gsc_dev *gsc)
 992{
 993        if (!IS_ERR(gsc->clock))
 994                clk_unprepare(gsc->clock);
 995}
 996
 997static int gsc_clk_get(struct gsc_dev *gsc)
 998{
 999        int ret;
1000
1001        dev_dbg(&gsc->pdev->dev, "gsc_clk_get Called\n");
1002
1003        gsc->clock = devm_clk_get(&gsc->pdev->dev, GSC_CLOCK_GATE_NAME);
1004        if (IS_ERR(gsc->clock)) {
1005                dev_err(&gsc->pdev->dev, "failed to get clock~~~: %s\n",
1006                        GSC_CLOCK_GATE_NAME);
1007                return PTR_ERR(gsc->clock);
1008        }
1009
1010        ret = clk_prepare(gsc->clock);
1011        if (ret < 0) {
1012                dev_err(&gsc->pdev->dev, "clock prepare failed for clock: %s\n",
1013                        GSC_CLOCK_GATE_NAME);
1014                gsc->clock = ERR_PTR(-EINVAL);
1015                return ret;
1016        }
1017
1018        return 0;
1019}
1020
1021static int gsc_m2m_suspend(struct gsc_dev *gsc)
1022{
1023        unsigned long flags;
1024        int timeout;
1025
1026        spin_lock_irqsave(&gsc->slock, flags);
1027        if (!gsc_m2m_pending(gsc)) {
1028                spin_unlock_irqrestore(&gsc->slock, flags);
1029                return 0;
1030        }
1031        clear_bit(ST_M2M_SUSPENDED, &gsc->state);
1032        set_bit(ST_M2M_SUSPENDING, &gsc->state);
1033        spin_unlock_irqrestore(&gsc->slock, flags);
1034
1035        timeout = wait_event_timeout(gsc->irq_queue,
1036                             test_bit(ST_M2M_SUSPENDED, &gsc->state),
1037                             GSC_SHUTDOWN_TIMEOUT);
1038
1039        clear_bit(ST_M2M_SUSPENDING, &gsc->state);
1040        return timeout == 0 ? -EAGAIN : 0;
1041}
1042
1043static int gsc_m2m_resume(struct gsc_dev *gsc)
1044{
1045        struct gsc_ctx *ctx;
1046        unsigned long flags;
1047
1048        spin_lock_irqsave(&gsc->slock, flags);
1049        /* Clear for full H/W setup in first run after resume */
1050        ctx = gsc->m2m.ctx;
1051        gsc->m2m.ctx = NULL;
1052        spin_unlock_irqrestore(&gsc->slock, flags);
1053
1054        if (test_and_clear_bit(ST_M2M_SUSPENDED, &gsc->state))
1055                gsc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR);
1056
1057        return 0;
1058}
1059
1060static int gsc_probe(struct platform_device *pdev)
1061{
1062        struct gsc_dev *gsc;
1063        struct resource *res;
1064        struct gsc_driverdata *drv_data = gsc_get_drv_data(pdev);
1065        struct device *dev = &pdev->dev;
1066        int ret;
1067
1068        gsc = devm_kzalloc(dev, sizeof(struct gsc_dev), GFP_KERNEL);
1069        if (!gsc)
1070                return -ENOMEM;
1071
1072        ret = of_alias_get_id(pdev->dev.of_node, "gsc");
1073        if (ret < 0)
1074                return ret;
1075
1076        gsc->id = ret;
1077        if (gsc->id >= drv_data->num_entities) {
1078                dev_err(dev, "Invalid platform device id: %d\n", gsc->id);
1079                return -EINVAL;
1080        }
1081
1082        gsc->variant = drv_data->variant[gsc->id];
1083        gsc->pdev = pdev;
1084
1085        init_waitqueue_head(&gsc->irq_queue);
1086        spin_lock_init(&gsc->slock);
1087        mutex_init(&gsc->lock);
1088        gsc->clock = ERR_PTR(-EINVAL);
1089
1090        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1091        gsc->regs = devm_ioremap_resource(dev, res);
1092        if (IS_ERR(gsc->regs))
1093                return PTR_ERR(gsc->regs);
1094
1095        res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
1096        if (!res) {
1097                dev_err(dev, "failed to get IRQ resource\n");
1098                return -ENXIO;
1099        }
1100
1101        ret = gsc_clk_get(gsc);
1102        if (ret)
1103                return ret;
1104
1105        ret = devm_request_irq(dev, res->start, gsc_irq_handler,
1106                                0, pdev->name, gsc);
1107        if (ret) {
1108                dev_err(dev, "failed to install irq (%d)\n", ret);
1109                goto err_clk;
1110        }
1111
1112        ret = v4l2_device_register(dev, &gsc->v4l2_dev);
1113        if (ret)
1114                goto err_clk;
1115
1116        ret = gsc_register_m2m_device(gsc);
1117        if (ret)
1118                goto err_v4l2;
1119
1120        platform_set_drvdata(pdev, gsc);
1121        pm_runtime_enable(dev);
1122        ret = pm_runtime_get_sync(&pdev->dev);
1123        if (ret < 0)
1124                goto err_m2m;
1125
1126        vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32));
1127
1128        dev_dbg(dev, "gsc-%d registered successfully\n", gsc->id);
1129
1130        pm_runtime_put(dev);
1131        return 0;
1132
1133err_m2m:
1134        gsc_unregister_m2m_device(gsc);
1135err_v4l2:
1136        v4l2_device_unregister(&gsc->v4l2_dev);
1137err_clk:
1138        gsc_clk_put(gsc);
1139        return ret;
1140}
1141
1142static int gsc_remove(struct platform_device *pdev)
1143{
1144        struct gsc_dev *gsc = platform_get_drvdata(pdev);
1145
1146        gsc_unregister_m2m_device(gsc);
1147        v4l2_device_unregister(&gsc->v4l2_dev);
1148
1149        vb2_dma_contig_clear_max_seg_size(&pdev->dev);
1150        pm_runtime_disable(&pdev->dev);
1151        gsc_clk_put(gsc);
1152
1153        dev_dbg(&pdev->dev, "%s driver unloaded\n", pdev->name);
1154        return 0;
1155}
1156
1157static int gsc_runtime_resume(struct device *dev)
1158{
1159        struct gsc_dev *gsc = dev_get_drvdata(dev);
1160        int ret = 0;
1161
1162        pr_debug("gsc%d: state: 0x%lx", gsc->id, gsc->state);
1163
1164        ret = clk_enable(gsc->clock);
1165        if (ret)
1166                return ret;
1167
1168        gsc_hw_set_sw_reset(gsc);
1169        gsc_wait_reset(gsc);
1170
1171        return gsc_m2m_resume(gsc);
1172}
1173
1174static int gsc_runtime_suspend(struct device *dev)
1175{
1176        struct gsc_dev *gsc = dev_get_drvdata(dev);
1177        int ret = 0;
1178
1179        ret = gsc_m2m_suspend(gsc);
1180        if (!ret)
1181                clk_disable(gsc->clock);
1182
1183        pr_debug("gsc%d: state: 0x%lx", gsc->id, gsc->state);
1184        return ret;
1185}
1186
1187static int gsc_resume(struct device *dev)
1188{
1189        struct gsc_dev *gsc = dev_get_drvdata(dev);
1190        unsigned long flags;
1191
1192        pr_debug("gsc%d: state: 0x%lx", gsc->id, gsc->state);
1193
1194        /* Do not resume if the device was idle before system suspend */
1195        spin_lock_irqsave(&gsc->slock, flags);
1196        if (!test_and_clear_bit(ST_SUSPEND, &gsc->state) ||
1197            !gsc_m2m_opened(gsc)) {
1198                spin_unlock_irqrestore(&gsc->slock, flags);
1199                return 0;
1200        }
1201        spin_unlock_irqrestore(&gsc->slock, flags);
1202
1203        if (!pm_runtime_suspended(dev))
1204                return gsc_runtime_resume(dev);
1205
1206        return 0;
1207}
1208
1209static int gsc_suspend(struct device *dev)
1210{
1211        struct gsc_dev *gsc = dev_get_drvdata(dev);
1212
1213        pr_debug("gsc%d: state: 0x%lx", gsc->id, gsc->state);
1214
1215        if (test_and_set_bit(ST_SUSPEND, &gsc->state))
1216                return 0;
1217
1218        if (!pm_runtime_suspended(dev))
1219                return gsc_runtime_suspend(dev);
1220
1221        return 0;
1222}
1223
1224static const struct dev_pm_ops gsc_pm_ops = {
1225        .suspend                = gsc_suspend,
1226        .resume                 = gsc_resume,
1227        .runtime_suspend        = gsc_runtime_suspend,
1228        .runtime_resume         = gsc_runtime_resume,
1229};
1230
1231static struct platform_driver gsc_driver = {
1232        .probe          = gsc_probe,
1233        .remove         = gsc_remove,
1234        .driver = {
1235                .name   = GSC_MODULE_NAME,
1236                .pm     = &gsc_pm_ops,
1237                .of_match_table = exynos_gsc_match,
1238        }
1239};
1240
1241module_platform_driver(gsc_driver);
1242
1243MODULE_AUTHOR("Hyunwong Kim <khw0178.kim@samsung.com>");
1244MODULE_DESCRIPTION("Samsung EXYNOS5 Soc series G-Scaler driver");
1245MODULE_LICENSE("GPL");
1246