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