linux/drivers/media/video/s5p-fimc/fimc-core.c
<<
>>
Prefs
   1/*
   2 * Samsung S5P/EXYNOS4 SoC series FIMC (CAMIF) driver
   3 *
   4 * Copyright (C) 2010-2012 Samsung Electronics Co., Ltd.
   5 * Sylwester Nawrocki <s.nawrocki@samsung.com>
   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/device.h>
  20#include <linux/platform_device.h>
  21#include <linux/pm_runtime.h>
  22#include <linux/list.h>
  23#include <linux/io.h>
  24#include <linux/slab.h>
  25#include <linux/clk.h>
  26#include <media/v4l2-ioctl.h>
  27#include <media/videobuf2-core.h>
  28#include <media/videobuf2-dma-contig.h>
  29
  30#include "fimc-core.h"
  31#include "fimc-reg.h"
  32#include "fimc-mdevice.h"
  33
  34static char *fimc_clocks[MAX_FIMC_CLOCKS] = {
  35        "sclk_fimc", "fimc"
  36};
  37
  38static struct fimc_fmt fimc_formats[] = {
  39        {
  40                .name           = "RGB565",
  41                .fourcc         = V4L2_PIX_FMT_RGB565,
  42                .depth          = { 16 },
  43                .color          = FIMC_FMT_RGB565,
  44                .memplanes      = 1,
  45                .colplanes      = 1,
  46                .flags          = FMT_FLAGS_M2M,
  47        }, {
  48                .name           = "BGR666",
  49                .fourcc         = V4L2_PIX_FMT_BGR666,
  50                .depth          = { 32 },
  51                .color          = FIMC_FMT_RGB666,
  52                .memplanes      = 1,
  53                .colplanes      = 1,
  54                .flags          = FMT_FLAGS_M2M,
  55        }, {
  56                .name           = "ARGB8888, 32 bpp",
  57                .fourcc         = V4L2_PIX_FMT_RGB32,
  58                .depth          = { 32 },
  59                .color          = FIMC_FMT_RGB888,
  60                .memplanes      = 1,
  61                .colplanes      = 1,
  62                .flags          = FMT_FLAGS_M2M | FMT_HAS_ALPHA,
  63        }, {
  64                .name           = "ARGB1555",
  65                .fourcc         = V4L2_PIX_FMT_RGB555,
  66                .depth          = { 16 },
  67                .color          = FIMC_FMT_RGB555,
  68                .memplanes      = 1,
  69                .colplanes      = 1,
  70                .flags          = FMT_FLAGS_M2M_OUT | FMT_HAS_ALPHA,
  71        }, {
  72                .name           = "ARGB4444",
  73                .fourcc         = V4L2_PIX_FMT_RGB444,
  74                .depth          = { 16 },
  75                .color          = FIMC_FMT_RGB444,
  76                .memplanes      = 1,
  77                .colplanes      = 1,
  78                .flags          = FMT_FLAGS_M2M_OUT | FMT_HAS_ALPHA,
  79        }, {
  80                .name           = "YUV 4:2:2 packed, YCbYCr",
  81                .fourcc         = V4L2_PIX_FMT_YUYV,
  82                .depth          = { 16 },
  83                .color          = FIMC_FMT_YCBYCR422,
  84                .memplanes      = 1,
  85                .colplanes      = 1,
  86                .mbus_code      = V4L2_MBUS_FMT_YUYV8_2X8,
  87                .flags          = FMT_FLAGS_M2M | FMT_FLAGS_CAM,
  88        }, {
  89                .name           = "YUV 4:2:2 packed, CbYCrY",
  90                .fourcc         = V4L2_PIX_FMT_UYVY,
  91                .depth          = { 16 },
  92                .color          = FIMC_FMT_CBYCRY422,
  93                .memplanes      = 1,
  94                .colplanes      = 1,
  95                .mbus_code      = V4L2_MBUS_FMT_UYVY8_2X8,
  96                .flags          = FMT_FLAGS_M2M | FMT_FLAGS_CAM,
  97        }, {
  98                .name           = "YUV 4:2:2 packed, CrYCbY",
  99                .fourcc         = V4L2_PIX_FMT_VYUY,
 100                .depth          = { 16 },
 101                .color          = FIMC_FMT_CRYCBY422,
 102                .memplanes      = 1,
 103                .colplanes      = 1,
 104                .mbus_code      = V4L2_MBUS_FMT_VYUY8_2X8,
 105                .flags          = FMT_FLAGS_M2M | FMT_FLAGS_CAM,
 106        }, {
 107                .name           = "YUV 4:2:2 packed, YCrYCb",
 108                .fourcc         = V4L2_PIX_FMT_YVYU,
 109                .depth          = { 16 },
 110                .color          = FIMC_FMT_YCRYCB422,
 111                .memplanes      = 1,
 112                .colplanes      = 1,
 113                .mbus_code      = V4L2_MBUS_FMT_YVYU8_2X8,
 114                .flags          = FMT_FLAGS_M2M | FMT_FLAGS_CAM,
 115        }, {
 116                .name           = "YUV 4:2:2 planar, Y/Cb/Cr",
 117                .fourcc         = V4L2_PIX_FMT_YUV422P,
 118                .depth          = { 12 },
 119                .color          = FIMC_FMT_YCBYCR422,
 120                .memplanes      = 1,
 121                .colplanes      = 3,
 122                .flags          = FMT_FLAGS_M2M,
 123        }, {
 124                .name           = "YUV 4:2:2 planar, Y/CbCr",
 125                .fourcc         = V4L2_PIX_FMT_NV16,
 126                .depth          = { 16 },
 127                .color          = FIMC_FMT_YCBYCR422,
 128                .memplanes      = 1,
 129                .colplanes      = 2,
 130                .flags          = FMT_FLAGS_M2M,
 131        }, {
 132                .name           = "YUV 4:2:2 planar, Y/CrCb",
 133                .fourcc         = V4L2_PIX_FMT_NV61,
 134                .depth          = { 16 },
 135                .color          = FIMC_FMT_YCRYCB422,
 136                .memplanes      = 1,
 137                .colplanes      = 2,
 138                .flags          = FMT_FLAGS_M2M,
 139        }, {
 140                .name           = "YUV 4:2:0 planar, YCbCr",
 141                .fourcc         = V4L2_PIX_FMT_YUV420,
 142                .depth          = { 12 },
 143                .color          = FIMC_FMT_YCBCR420,
 144                .memplanes      = 1,
 145                .colplanes      = 3,
 146                .flags          = FMT_FLAGS_M2M,
 147        }, {
 148                .name           = "YUV 4:2:0 planar, Y/CbCr",
 149                .fourcc         = V4L2_PIX_FMT_NV12,
 150                .depth          = { 12 },
 151                .color          = FIMC_FMT_YCBCR420,
 152                .memplanes      = 1,
 153                .colplanes      = 2,
 154                .flags          = FMT_FLAGS_M2M,
 155        }, {
 156                .name           = "YUV 4:2:0 non-contig. 2p, Y/CbCr",
 157                .fourcc         = V4L2_PIX_FMT_NV12M,
 158                .color          = FIMC_FMT_YCBCR420,
 159                .depth          = { 8, 4 },
 160                .memplanes      = 2,
 161                .colplanes      = 2,
 162                .flags          = FMT_FLAGS_M2M,
 163        }, {
 164                .name           = "YUV 4:2:0 non-contig. 3p, Y/Cb/Cr",
 165                .fourcc         = V4L2_PIX_FMT_YUV420M,
 166                .color          = FIMC_FMT_YCBCR420,
 167                .depth          = { 8, 2, 2 },
 168                .memplanes      = 3,
 169                .colplanes      = 3,
 170                .flags          = FMT_FLAGS_M2M,
 171        }, {
 172                .name           = "YUV 4:2:0 non-contig. 2p, tiled",
 173                .fourcc         = V4L2_PIX_FMT_NV12MT,
 174                .color          = FIMC_FMT_YCBCR420,
 175                .depth          = { 8, 4 },
 176                .memplanes      = 2,
 177                .colplanes      = 2,
 178                .flags          = FMT_FLAGS_M2M,
 179        }, {
 180                .name           = "JPEG encoded data",
 181                .fourcc         = V4L2_PIX_FMT_JPEG,
 182                .color          = FIMC_FMT_JPEG,
 183                .depth          = { 8 },
 184                .memplanes      = 1,
 185                .colplanes      = 1,
 186                .mbus_code      = V4L2_MBUS_FMT_JPEG_1X8,
 187                .flags          = FMT_FLAGS_CAM,
 188        },
 189};
 190
 191struct fimc_fmt *fimc_get_format(unsigned int index)
 192{
 193        if (index >= ARRAY_SIZE(fimc_formats))
 194                return NULL;
 195
 196        return &fimc_formats[index];
 197}
 198
 199int fimc_check_scaler_ratio(struct fimc_ctx *ctx, int sw, int sh,
 200                            int dw, int dh, int rotation)
 201{
 202        if (rotation == 90 || rotation == 270)
 203                swap(dw, dh);
 204
 205        if (!ctx->scaler.enabled)
 206                return (sw == dw && sh == dh) ? 0 : -EINVAL;
 207
 208        if ((sw >= SCALER_MAX_HRATIO * dw) || (sh >= SCALER_MAX_VRATIO * dh))
 209                return -EINVAL;
 210
 211        return 0;
 212}
 213
 214static int fimc_get_scaler_factor(u32 src, u32 tar, u32 *ratio, u32 *shift)
 215{
 216        u32 sh = 6;
 217
 218        if (src >= 64 * tar)
 219                return -EINVAL;
 220
 221        while (sh--) {
 222                u32 tmp = 1 << sh;
 223                if (src >= tar * tmp) {
 224                        *shift = sh, *ratio = tmp;
 225                        return 0;
 226                }
 227        }
 228        *shift = 0, *ratio = 1;
 229        return 0;
 230}
 231
 232int fimc_set_scaler_info(struct fimc_ctx *ctx)
 233{
 234        struct fimc_variant *variant = ctx->fimc_dev->variant;
 235        struct device *dev = &ctx->fimc_dev->pdev->dev;
 236        struct fimc_scaler *sc = &ctx->scaler;
 237        struct fimc_frame *s_frame = &ctx->s_frame;
 238        struct fimc_frame *d_frame = &ctx->d_frame;
 239        int tx, ty, sx, sy;
 240        int ret;
 241
 242        if (ctx->rotation == 90 || ctx->rotation == 270) {
 243                ty = d_frame->width;
 244                tx = d_frame->height;
 245        } else {
 246                tx = d_frame->width;
 247                ty = d_frame->height;
 248        }
 249        if (tx <= 0 || ty <= 0) {
 250                dev_err(dev, "Invalid target size: %dx%d", tx, ty);
 251                return -EINVAL;
 252        }
 253
 254        sx = s_frame->width;
 255        sy = s_frame->height;
 256        if (sx <= 0 || sy <= 0) {
 257                dev_err(dev, "Invalid source size: %dx%d", sx, sy);
 258                return -EINVAL;
 259        }
 260        sc->real_width = sx;
 261        sc->real_height = sy;
 262
 263        ret = fimc_get_scaler_factor(sx, tx, &sc->pre_hratio, &sc->hfactor);
 264        if (ret)
 265                return ret;
 266
 267        ret = fimc_get_scaler_factor(sy, ty,  &sc->pre_vratio, &sc->vfactor);
 268        if (ret)
 269                return ret;
 270
 271        sc->pre_dst_width = sx / sc->pre_hratio;
 272        sc->pre_dst_height = sy / sc->pre_vratio;
 273
 274        if (variant->has_mainscaler_ext) {
 275                sc->main_hratio = (sx << 14) / (tx << sc->hfactor);
 276                sc->main_vratio = (sy << 14) / (ty << sc->vfactor);
 277        } else {
 278                sc->main_hratio = (sx << 8) / (tx << sc->hfactor);
 279                sc->main_vratio = (sy << 8) / (ty << sc->vfactor);
 280
 281        }
 282
 283        sc->scaleup_h = (tx >= sx) ? 1 : 0;
 284        sc->scaleup_v = (ty >= sy) ? 1 : 0;
 285
 286        /* check to see if input and output size/format differ */
 287        if (s_frame->fmt->color == d_frame->fmt->color
 288                && s_frame->width == d_frame->width
 289                && s_frame->height == d_frame->height)
 290                sc->copy_mode = 1;
 291        else
 292                sc->copy_mode = 0;
 293
 294        return 0;
 295}
 296
 297static irqreturn_t fimc_irq_handler(int irq, void *priv)
 298{
 299        struct fimc_dev *fimc = priv;
 300        struct fimc_ctx *ctx;
 301
 302        fimc_hw_clear_irq(fimc);
 303
 304        spin_lock(&fimc->slock);
 305
 306        if (test_and_clear_bit(ST_M2M_PEND, &fimc->state)) {
 307                if (test_and_clear_bit(ST_M2M_SUSPENDING, &fimc->state)) {
 308                        set_bit(ST_M2M_SUSPENDED, &fimc->state);
 309                        wake_up(&fimc->irq_queue);
 310                        goto out;
 311                }
 312                ctx = v4l2_m2m_get_curr_priv(fimc->m2m.m2m_dev);
 313                if (ctx != NULL) {
 314                        spin_unlock(&fimc->slock);
 315                        fimc_m2m_job_finish(ctx, VB2_BUF_STATE_DONE);
 316
 317                        if (ctx->state & FIMC_CTX_SHUT) {
 318                                ctx->state &= ~FIMC_CTX_SHUT;
 319                                wake_up(&fimc->irq_queue);
 320                        }
 321                        return IRQ_HANDLED;
 322                }
 323        } else if (test_bit(ST_CAPT_PEND, &fimc->state)) {
 324                int last_buf = test_bit(ST_CAPT_JPEG, &fimc->state) &&
 325                                fimc->vid_cap.reqbufs_count == 1;
 326                fimc_capture_irq_handler(fimc, !last_buf);
 327        }
 328out:
 329        spin_unlock(&fimc->slock);
 330        return IRQ_HANDLED;
 331}
 332
 333/* The color format (colplanes, memplanes) must be already configured. */
 334int fimc_prepare_addr(struct fimc_ctx *ctx, struct vb2_buffer *vb,
 335                      struct fimc_frame *frame, struct fimc_addr *paddr)
 336{
 337        int ret = 0;
 338        u32 pix_size;
 339
 340        if (vb == NULL || frame == NULL)
 341                return -EINVAL;
 342
 343        pix_size = frame->width * frame->height;
 344
 345        dbg("memplanes= %d, colplanes= %d, pix_size= %d",
 346                frame->fmt->memplanes, frame->fmt->colplanes, pix_size);
 347
 348        paddr->y = vb2_dma_contig_plane_dma_addr(vb, 0);
 349
 350        if (frame->fmt->memplanes == 1) {
 351                switch (frame->fmt->colplanes) {
 352                case 1:
 353                        paddr->cb = 0;
 354                        paddr->cr = 0;
 355                        break;
 356                case 2:
 357                        /* decompose Y into Y/Cb */
 358                        paddr->cb = (u32)(paddr->y + pix_size);
 359                        paddr->cr = 0;
 360                        break;
 361                case 3:
 362                        paddr->cb = (u32)(paddr->y + pix_size);
 363                        /* decompose Y into Y/Cb/Cr */
 364                        if (FIMC_FMT_YCBCR420 == frame->fmt->color)
 365                                paddr->cr = (u32)(paddr->cb
 366                                                + (pix_size >> 2));
 367                        else /* 422 */
 368                                paddr->cr = (u32)(paddr->cb
 369                                                + (pix_size >> 1));
 370                        break;
 371                default:
 372                        return -EINVAL;
 373                }
 374        } else {
 375                if (frame->fmt->memplanes >= 2)
 376                        paddr->cb = vb2_dma_contig_plane_dma_addr(vb, 1);
 377
 378                if (frame->fmt->memplanes == 3)
 379                        paddr->cr = vb2_dma_contig_plane_dma_addr(vb, 2);
 380        }
 381
 382        dbg("PHYS_ADDR: y= 0x%X  cb= 0x%X cr= 0x%X ret= %d",
 383            paddr->y, paddr->cb, paddr->cr, ret);
 384
 385        return ret;
 386}
 387
 388/* Set order for 1 and 2 plane YCBCR 4:2:2 formats. */
 389void fimc_set_yuv_order(struct fimc_ctx *ctx)
 390{
 391        /* The one only mode supported in SoC. */
 392        ctx->in_order_2p = FIMC_REG_CIOCTRL_ORDER422_2P_LSB_CRCB;
 393        ctx->out_order_2p = FIMC_REG_CIOCTRL_ORDER422_2P_LSB_CRCB;
 394
 395        /* Set order for 1 plane input formats. */
 396        switch (ctx->s_frame.fmt->color) {
 397        case FIMC_FMT_YCRYCB422:
 398                ctx->in_order_1p = FIMC_REG_MSCTRL_ORDER422_CBYCRY;
 399                break;
 400        case FIMC_FMT_CBYCRY422:
 401                ctx->in_order_1p = FIMC_REG_MSCTRL_ORDER422_YCRYCB;
 402                break;
 403        case FIMC_FMT_CRYCBY422:
 404                ctx->in_order_1p = FIMC_REG_MSCTRL_ORDER422_YCBYCR;
 405                break;
 406        case FIMC_FMT_YCBYCR422:
 407        default:
 408                ctx->in_order_1p = FIMC_REG_MSCTRL_ORDER422_CRYCBY;
 409                break;
 410        }
 411        dbg("ctx->in_order_1p= %d", ctx->in_order_1p);
 412
 413        switch (ctx->d_frame.fmt->color) {
 414        case FIMC_FMT_YCRYCB422:
 415                ctx->out_order_1p = FIMC_REG_CIOCTRL_ORDER422_CBYCRY;
 416                break;
 417        case FIMC_FMT_CBYCRY422:
 418                ctx->out_order_1p = FIMC_REG_CIOCTRL_ORDER422_YCRYCB;
 419                break;
 420        case FIMC_FMT_CRYCBY422:
 421                ctx->out_order_1p = FIMC_REG_CIOCTRL_ORDER422_YCBYCR;
 422                break;
 423        case FIMC_FMT_YCBYCR422:
 424        default:
 425                ctx->out_order_1p = FIMC_REG_CIOCTRL_ORDER422_CRYCBY;
 426                break;
 427        }
 428        dbg("ctx->out_order_1p= %d", ctx->out_order_1p);
 429}
 430
 431void fimc_prepare_dma_offset(struct fimc_ctx *ctx, struct fimc_frame *f)
 432{
 433        struct fimc_variant *variant = ctx->fimc_dev->variant;
 434        u32 i, depth = 0;
 435
 436        for (i = 0; i < f->fmt->colplanes; i++)
 437                depth += f->fmt->depth[i];
 438
 439        f->dma_offset.y_h = f->offs_h;
 440        if (!variant->pix_hoff)
 441                f->dma_offset.y_h *= (depth >> 3);
 442
 443        f->dma_offset.y_v = f->offs_v;
 444
 445        f->dma_offset.cb_h = f->offs_h;
 446        f->dma_offset.cb_v = f->offs_v;
 447
 448        f->dma_offset.cr_h = f->offs_h;
 449        f->dma_offset.cr_v = f->offs_v;
 450
 451        if (!variant->pix_hoff) {
 452                if (f->fmt->colplanes == 3) {
 453                        f->dma_offset.cb_h >>= 1;
 454                        f->dma_offset.cr_h >>= 1;
 455                }
 456                if (f->fmt->color == FIMC_FMT_YCBCR420) {
 457                        f->dma_offset.cb_v >>= 1;
 458                        f->dma_offset.cr_v >>= 1;
 459                }
 460        }
 461
 462        dbg("in_offset: color= %d, y_h= %d, y_v= %d",
 463            f->fmt->color, f->dma_offset.y_h, f->dma_offset.y_v);
 464}
 465
 466int fimc_set_color_effect(struct fimc_ctx *ctx, enum v4l2_colorfx colorfx)
 467{
 468        struct fimc_effect *effect = &ctx->effect;
 469
 470        switch (colorfx) {
 471        case V4L2_COLORFX_NONE:
 472                effect->type = FIMC_REG_CIIMGEFF_FIN_BYPASS;
 473                break;
 474        case V4L2_COLORFX_BW:
 475                effect->type = FIMC_REG_CIIMGEFF_FIN_ARBITRARY;
 476                effect->pat_cb = 128;
 477                effect->pat_cr = 128;
 478                break;
 479        case V4L2_COLORFX_SEPIA:
 480                effect->type = FIMC_REG_CIIMGEFF_FIN_ARBITRARY;
 481                effect->pat_cb = 115;
 482                effect->pat_cr = 145;
 483                break;
 484        case V4L2_COLORFX_NEGATIVE:
 485                effect->type = FIMC_REG_CIIMGEFF_FIN_NEGATIVE;
 486                break;
 487        case V4L2_COLORFX_EMBOSS:
 488                effect->type = FIMC_REG_CIIMGEFF_FIN_EMBOSSING;
 489                break;
 490        case V4L2_COLORFX_ART_FREEZE:
 491                effect->type = FIMC_REG_CIIMGEFF_FIN_ARTFREEZE;
 492                break;
 493        case V4L2_COLORFX_SILHOUETTE:
 494                effect->type = FIMC_REG_CIIMGEFF_FIN_SILHOUETTE;
 495                break;
 496        case V4L2_COLORFX_SET_CBCR:
 497                effect->type = FIMC_REG_CIIMGEFF_FIN_ARBITRARY;
 498                effect->pat_cb = ctx->ctrls.colorfx_cbcr->val >> 8;
 499                effect->pat_cr = ctx->ctrls.colorfx_cbcr->val & 0xff;
 500                break;
 501        default:
 502                return -EINVAL;
 503        }
 504
 505        return 0;
 506}
 507
 508/*
 509 * V4L2 controls handling
 510 */
 511#define ctrl_to_ctx(__ctrl) \
 512        container_of((__ctrl)->handler, struct fimc_ctx, ctrls.handler)
 513
 514static int __fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_ctrl *ctrl)
 515{
 516        struct fimc_dev *fimc = ctx->fimc_dev;
 517        struct fimc_variant *variant = fimc->variant;
 518        unsigned int flags = FIMC_DST_FMT | FIMC_SRC_FMT;
 519        int ret = 0;
 520
 521        if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE)
 522                return 0;
 523
 524        switch (ctrl->id) {
 525        case V4L2_CID_HFLIP:
 526                ctx->hflip = ctrl->val;
 527                break;
 528
 529        case V4L2_CID_VFLIP:
 530                ctx->vflip = ctrl->val;
 531                break;
 532
 533        case V4L2_CID_ROTATE:
 534                if (fimc_capture_pending(fimc) ||
 535                    (ctx->state & flags) == flags) {
 536                        ret = fimc_check_scaler_ratio(ctx, ctx->s_frame.width,
 537                                        ctx->s_frame.height, ctx->d_frame.width,
 538                                        ctx->d_frame.height, ctrl->val);
 539                        if (ret)
 540                                return -EINVAL;
 541                }
 542                if ((ctrl->val == 90 || ctrl->val == 270) &&
 543                    !variant->has_out_rot)
 544                        return -EINVAL;
 545
 546                ctx->rotation = ctrl->val;
 547                break;
 548
 549        case V4L2_CID_ALPHA_COMPONENT:
 550                ctx->d_frame.alpha = ctrl->val;
 551                break;
 552
 553        case V4L2_CID_COLORFX:
 554                ret = fimc_set_color_effect(ctx, ctrl->val);
 555                if (ret)
 556                        return ret;
 557                break;
 558        }
 559
 560        ctx->state |= FIMC_PARAMS;
 561        set_bit(ST_CAPT_APPLY_CFG, &fimc->state);
 562        return 0;
 563}
 564
 565static int fimc_s_ctrl(struct v4l2_ctrl *ctrl)
 566{
 567        struct fimc_ctx *ctx = ctrl_to_ctx(ctrl);
 568        unsigned long flags;
 569        int ret;
 570
 571        spin_lock_irqsave(&ctx->fimc_dev->slock, flags);
 572        ret = __fimc_s_ctrl(ctx, ctrl);
 573        spin_unlock_irqrestore(&ctx->fimc_dev->slock, flags);
 574
 575        return ret;
 576}
 577
 578static const struct v4l2_ctrl_ops fimc_ctrl_ops = {
 579        .s_ctrl = fimc_s_ctrl,
 580};
 581
 582int fimc_ctrls_create(struct fimc_ctx *ctx)
 583{
 584        struct fimc_variant *variant = ctx->fimc_dev->variant;
 585        unsigned int max_alpha = fimc_get_alpha_mask(ctx->d_frame.fmt);
 586        struct fimc_ctrls *ctrls = &ctx->ctrls;
 587        struct v4l2_ctrl_handler *handler = &ctrls->handler;
 588
 589        if (ctx->ctrls.ready)
 590                return 0;
 591
 592        v4l2_ctrl_handler_init(handler, 6);
 593
 594        ctrls->rotate = v4l2_ctrl_new_std(handler, &fimc_ctrl_ops,
 595                                        V4L2_CID_ROTATE, 0, 270, 90, 0);
 596        ctrls->hflip = v4l2_ctrl_new_std(handler, &fimc_ctrl_ops,
 597                                        V4L2_CID_HFLIP, 0, 1, 1, 0);
 598        ctrls->vflip = v4l2_ctrl_new_std(handler, &fimc_ctrl_ops,
 599                                        V4L2_CID_VFLIP, 0, 1, 1, 0);
 600
 601        if (variant->has_alpha)
 602                ctrls->alpha = v4l2_ctrl_new_std(handler, &fimc_ctrl_ops,
 603                                        V4L2_CID_ALPHA_COMPONENT,
 604                                        0, max_alpha, 1, 0);
 605        else
 606                ctrls->alpha = NULL;
 607
 608        ctrls->colorfx = v4l2_ctrl_new_std_menu(handler, &fimc_ctrl_ops,
 609                                V4L2_CID_COLORFX, V4L2_COLORFX_SET_CBCR,
 610                                ~0x983f, V4L2_COLORFX_NONE);
 611
 612        ctrls->colorfx_cbcr = v4l2_ctrl_new_std(handler, &fimc_ctrl_ops,
 613                                V4L2_CID_COLORFX_CBCR, 0, 0xffff, 1, 0);
 614
 615        ctx->effect.type = FIMC_REG_CIIMGEFF_FIN_BYPASS;
 616
 617        if (!handler->error) {
 618                v4l2_ctrl_cluster(2, &ctrls->colorfx);
 619                ctrls->ready = true;
 620        }
 621
 622        return handler->error;
 623}
 624
 625void fimc_ctrls_delete(struct fimc_ctx *ctx)
 626{
 627        struct fimc_ctrls *ctrls = &ctx->ctrls;
 628
 629        if (ctrls->ready) {
 630                v4l2_ctrl_handler_free(&ctrls->handler);
 631                ctrls->ready = false;
 632                ctrls->alpha = NULL;
 633        }
 634}
 635
 636void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active)
 637{
 638        unsigned int has_alpha = ctx->d_frame.fmt->flags & FMT_HAS_ALPHA;
 639        struct fimc_ctrls *ctrls = &ctx->ctrls;
 640
 641        if (!ctrls->ready)
 642                return;
 643
 644        mutex_lock(ctrls->handler.lock);
 645        v4l2_ctrl_activate(ctrls->rotate, active);
 646        v4l2_ctrl_activate(ctrls->hflip, active);
 647        v4l2_ctrl_activate(ctrls->vflip, active);
 648        v4l2_ctrl_activate(ctrls->colorfx, active);
 649        if (ctrls->alpha)
 650                v4l2_ctrl_activate(ctrls->alpha, active && has_alpha);
 651
 652        if (active) {
 653                fimc_set_color_effect(ctx, ctrls->colorfx->cur.val);
 654                ctx->rotation = ctrls->rotate->val;
 655                ctx->hflip    = ctrls->hflip->val;
 656                ctx->vflip    = ctrls->vflip->val;
 657        } else {
 658                ctx->effect.type = FIMC_REG_CIIMGEFF_FIN_BYPASS;
 659                ctx->rotation = 0;
 660                ctx->hflip    = 0;
 661                ctx->vflip    = 0;
 662        }
 663        mutex_unlock(ctrls->handler.lock);
 664}
 665
 666/* Update maximum value of the alpha color control */
 667void fimc_alpha_ctrl_update(struct fimc_ctx *ctx)
 668{
 669        struct fimc_dev *fimc = ctx->fimc_dev;
 670        struct v4l2_ctrl *ctrl = ctx->ctrls.alpha;
 671
 672        if (ctrl == NULL || !fimc->variant->has_alpha)
 673                return;
 674
 675        v4l2_ctrl_lock(ctrl);
 676        ctrl->maximum = fimc_get_alpha_mask(ctx->d_frame.fmt);
 677
 678        if (ctrl->cur.val > ctrl->maximum)
 679                ctrl->cur.val = ctrl->maximum;
 680
 681        v4l2_ctrl_unlock(ctrl);
 682}
 683
 684int fimc_fill_format(struct fimc_frame *frame, struct v4l2_format *f)
 685{
 686        struct v4l2_pix_format_mplane *pixm = &f->fmt.pix_mp;
 687        int i;
 688
 689        pixm->width = frame->o_width;
 690        pixm->height = frame->o_height;
 691        pixm->field = V4L2_FIELD_NONE;
 692        pixm->pixelformat = frame->fmt->fourcc;
 693        pixm->colorspace = V4L2_COLORSPACE_JPEG;
 694        pixm->num_planes = frame->fmt->memplanes;
 695
 696        for (i = 0; i < pixm->num_planes; ++i) {
 697                int bpl = frame->f_width;
 698                if (frame->fmt->colplanes == 1) /* packed formats */
 699                        bpl = (bpl * frame->fmt->depth[0]) / 8;
 700                pixm->plane_fmt[i].bytesperline = bpl;
 701                pixm->plane_fmt[i].sizeimage = (frame->o_width *
 702                        frame->o_height * frame->fmt->depth[i]) / 8;
 703        }
 704        return 0;
 705}
 706
 707void fimc_fill_frame(struct fimc_frame *frame, struct v4l2_format *f)
 708{
 709        struct v4l2_pix_format_mplane *pixm = &f->fmt.pix_mp;
 710
 711        frame->f_width  = pixm->plane_fmt[0].bytesperline;
 712        if (frame->fmt->colplanes == 1)
 713                frame->f_width = (frame->f_width * 8) / frame->fmt->depth[0];
 714        frame->f_height = pixm->height;
 715        frame->width    = pixm->width;
 716        frame->height   = pixm->height;
 717        frame->o_width  = pixm->width;
 718        frame->o_height = pixm->height;
 719        frame->offs_h   = 0;
 720        frame->offs_v   = 0;
 721}
 722
 723/**
 724 * fimc_adjust_mplane_format - adjust bytesperline/sizeimage for each plane
 725 * @fmt: fimc pixel format description (input)
 726 * @width: requested pixel width
 727 * @height: requested pixel height
 728 * @pix: multi-plane format to adjust
 729 */
 730void fimc_adjust_mplane_format(struct fimc_fmt *fmt, u32 width, u32 height,
 731                               struct v4l2_pix_format_mplane *pix)
 732{
 733        u32 bytesperline = 0;
 734        int i;
 735
 736        pix->colorspace = V4L2_COLORSPACE_JPEG;
 737        pix->field = V4L2_FIELD_NONE;
 738        pix->num_planes = fmt->memplanes;
 739        pix->pixelformat = fmt->fourcc;
 740        pix->height = height;
 741        pix->width = width;
 742
 743        for (i = 0; i < pix->num_planes; ++i) {
 744                struct v4l2_plane_pix_format *plane_fmt = &pix->plane_fmt[i];
 745                u32 bpl = plane_fmt->bytesperline;
 746
 747                if (fmt->colplanes > 1 && (bpl == 0 || bpl < pix->width))
 748                        bpl = pix->width; /* Planar */
 749
 750                if (fmt->colplanes == 1 && /* Packed */
 751                    (bpl == 0 || ((bpl * 8) / fmt->depth[i]) < pix->width))
 752                        bpl = (pix->width * fmt->depth[0]) / 8;
 753
 754                if (i == 0) /* Same bytesperline for each plane. */
 755                        bytesperline = bpl;
 756
 757                plane_fmt->bytesperline = bytesperline;
 758                plane_fmt->sizeimage = max((pix->width * pix->height *
 759                                   fmt->depth[i]) / 8, plane_fmt->sizeimage);
 760        }
 761}
 762
 763/**
 764 * fimc_find_format - lookup fimc color format by fourcc or media bus format
 765 * @pixelformat: fourcc to match, ignored if null
 766 * @mbus_code: media bus code to match, ignored if null
 767 * @mask: the color flags to match
 768 * @index: offset in the fimc_formats array, ignored if negative
 769 */
 770struct fimc_fmt *fimc_find_format(const u32 *pixelformat, const u32 *mbus_code,
 771                                  unsigned int mask, int index)
 772{
 773        struct fimc_fmt *fmt, *def_fmt = NULL;
 774        unsigned int i;
 775        int id = 0;
 776
 777        if (index >= (int)ARRAY_SIZE(fimc_formats))
 778                return NULL;
 779
 780        for (i = 0; i < ARRAY_SIZE(fimc_formats); ++i) {
 781                fmt = &fimc_formats[i];
 782                if (!(fmt->flags & mask))
 783                        continue;
 784                if (pixelformat && fmt->fourcc == *pixelformat)
 785                        return fmt;
 786                if (mbus_code && fmt->mbus_code == *mbus_code)
 787                        return fmt;
 788                if (index == id)
 789                        def_fmt = fmt;
 790                id++;
 791        }
 792        return def_fmt;
 793}
 794
 795static void fimc_clk_put(struct fimc_dev *fimc)
 796{
 797        int i;
 798        for (i = 0; i < MAX_FIMC_CLOCKS; i++) {
 799                if (IS_ERR_OR_NULL(fimc->clock[i]))
 800                        continue;
 801                clk_unprepare(fimc->clock[i]);
 802                clk_put(fimc->clock[i]);
 803                fimc->clock[i] = NULL;
 804        }
 805}
 806
 807static int fimc_clk_get(struct fimc_dev *fimc)
 808{
 809        int i, ret;
 810
 811        for (i = 0; i < MAX_FIMC_CLOCKS; i++) {
 812                fimc->clock[i] = clk_get(&fimc->pdev->dev, fimc_clocks[i]);
 813                if (IS_ERR(fimc->clock[i]))
 814                        goto err;
 815                ret = clk_prepare(fimc->clock[i]);
 816                if (ret < 0) {
 817                        clk_put(fimc->clock[i]);
 818                        fimc->clock[i] = NULL;
 819                        goto err;
 820                }
 821        }
 822        return 0;
 823err:
 824        fimc_clk_put(fimc);
 825        dev_err(&fimc->pdev->dev, "failed to get clock: %s\n",
 826                fimc_clocks[i]);
 827        return -ENXIO;
 828}
 829
 830static int fimc_m2m_suspend(struct fimc_dev *fimc)
 831{
 832        unsigned long flags;
 833        int timeout;
 834
 835        spin_lock_irqsave(&fimc->slock, flags);
 836        if (!fimc_m2m_pending(fimc)) {
 837                spin_unlock_irqrestore(&fimc->slock, flags);
 838                return 0;
 839        }
 840        clear_bit(ST_M2M_SUSPENDED, &fimc->state);
 841        set_bit(ST_M2M_SUSPENDING, &fimc->state);
 842        spin_unlock_irqrestore(&fimc->slock, flags);
 843
 844        timeout = wait_event_timeout(fimc->irq_queue,
 845                             test_bit(ST_M2M_SUSPENDED, &fimc->state),
 846                             FIMC_SHUTDOWN_TIMEOUT);
 847
 848        clear_bit(ST_M2M_SUSPENDING, &fimc->state);
 849        return timeout == 0 ? -EAGAIN : 0;
 850}
 851
 852static int fimc_m2m_resume(struct fimc_dev *fimc)
 853{
 854        unsigned long flags;
 855
 856        spin_lock_irqsave(&fimc->slock, flags);
 857        /* Clear for full H/W setup in first run after resume */
 858        fimc->m2m.ctx = NULL;
 859        spin_unlock_irqrestore(&fimc->slock, flags);
 860
 861        if (test_and_clear_bit(ST_M2M_SUSPENDED, &fimc->state))
 862                fimc_m2m_job_finish(fimc->m2m.ctx,
 863                                    VB2_BUF_STATE_ERROR);
 864        return 0;
 865}
 866
 867static int fimc_probe(struct platform_device *pdev)
 868{
 869        struct fimc_drvdata *drv_data = fimc_get_drvdata(pdev);
 870        struct s5p_platform_fimc *pdata;
 871        struct fimc_dev *fimc;
 872        struct resource *res;
 873        int ret = 0;
 874
 875        if (pdev->id >= drv_data->num_entities) {
 876                dev_err(&pdev->dev, "Invalid platform device id: %d\n",
 877                        pdev->id);
 878                return -EINVAL;
 879        }
 880
 881        fimc = devm_kzalloc(&pdev->dev, sizeof(*fimc), GFP_KERNEL);
 882        if (!fimc)
 883                return -ENOMEM;
 884
 885        fimc->id = pdev->id;
 886
 887        fimc->variant = drv_data->variant[fimc->id];
 888        fimc->pdev = pdev;
 889        pdata = pdev->dev.platform_data;
 890        fimc->pdata = pdata;
 891
 892        init_waitqueue_head(&fimc->irq_queue);
 893        spin_lock_init(&fimc->slock);
 894        mutex_init(&fimc->lock);
 895
 896        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 897        fimc->regs = devm_request_and_ioremap(&pdev->dev, res);
 898        if (fimc->regs == NULL) {
 899                dev_err(&pdev->dev, "Failed to obtain io memory\n");
 900                return -ENOENT;
 901        }
 902
 903        res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 904        if (res == NULL) {
 905                dev_err(&pdev->dev, "Failed to get IRQ resource\n");
 906                return -ENXIO;
 907        }
 908
 909        ret = fimc_clk_get(fimc);
 910        if (ret)
 911                return ret;
 912        clk_set_rate(fimc->clock[CLK_BUS], drv_data->lclk_frequency);
 913        clk_enable(fimc->clock[CLK_BUS]);
 914
 915        ret = devm_request_irq(&pdev->dev, res->start, fimc_irq_handler,
 916                               0, dev_name(&pdev->dev), fimc);
 917        if (ret) {
 918                dev_err(&pdev->dev, "failed to install irq (%d)\n", ret);
 919                goto err_clk;
 920        }
 921
 922        ret = fimc_initialize_capture_subdev(fimc);
 923        if (ret)
 924                goto err_clk;
 925
 926        platform_set_drvdata(pdev, fimc);
 927        pm_runtime_enable(&pdev->dev);
 928        ret = pm_runtime_get_sync(&pdev->dev);
 929        if (ret < 0)
 930                goto err_sd;
 931        /* Initialize contiguous memory allocator */
 932        fimc->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
 933        if (IS_ERR(fimc->alloc_ctx)) {
 934                ret = PTR_ERR(fimc->alloc_ctx);
 935                goto err_pm;
 936        }
 937
 938        dev_dbg(&pdev->dev, "FIMC.%d registered successfully\n", fimc->id);
 939
 940        pm_runtime_put(&pdev->dev);
 941        return 0;
 942err_pm:
 943        pm_runtime_put(&pdev->dev);
 944err_sd:
 945        fimc_unregister_capture_subdev(fimc);
 946err_clk:
 947        fimc_clk_put(fimc);
 948        return ret;
 949}
 950
 951static int fimc_runtime_resume(struct device *dev)
 952{
 953        struct fimc_dev *fimc = dev_get_drvdata(dev);
 954
 955        dbg("fimc%d: state: 0x%lx", fimc->id, fimc->state);
 956
 957        /* Enable clocks and perform basic initalization */
 958        clk_enable(fimc->clock[CLK_GATE]);
 959        fimc_hw_reset(fimc);
 960
 961        /* Resume the capture or mem-to-mem device */
 962        if (fimc_capture_busy(fimc))
 963                return fimc_capture_resume(fimc);
 964
 965        return fimc_m2m_resume(fimc);
 966}
 967
 968static int fimc_runtime_suspend(struct device *dev)
 969{
 970        struct fimc_dev *fimc = dev_get_drvdata(dev);
 971        int ret = 0;
 972
 973        if (fimc_capture_busy(fimc))
 974                ret = fimc_capture_suspend(fimc);
 975        else
 976                ret = fimc_m2m_suspend(fimc);
 977        if (!ret)
 978                clk_disable(fimc->clock[CLK_GATE]);
 979
 980        dbg("fimc%d: state: 0x%lx", fimc->id, fimc->state);
 981        return ret;
 982}
 983
 984#ifdef CONFIG_PM_SLEEP
 985static int fimc_resume(struct device *dev)
 986{
 987        struct fimc_dev *fimc = dev_get_drvdata(dev);
 988        unsigned long flags;
 989
 990        dbg("fimc%d: state: 0x%lx", fimc->id, fimc->state);
 991
 992        /* Do not resume if the device was idle before system suspend */
 993        spin_lock_irqsave(&fimc->slock, flags);
 994        if (!test_and_clear_bit(ST_LPM, &fimc->state) ||
 995            (!fimc_m2m_active(fimc) && !fimc_capture_busy(fimc))) {
 996                spin_unlock_irqrestore(&fimc->slock, flags);
 997                return 0;
 998        }
 999        fimc_hw_reset(fimc);
1000        spin_unlock_irqrestore(&fimc->slock, flags);
1001
1002        if (fimc_capture_busy(fimc))
1003                return fimc_capture_resume(fimc);
1004
1005        return fimc_m2m_resume(fimc);
1006}
1007
1008static int fimc_suspend(struct device *dev)
1009{
1010        struct fimc_dev *fimc = dev_get_drvdata(dev);
1011
1012        dbg("fimc%d: state: 0x%lx", fimc->id, fimc->state);
1013
1014        if (test_and_set_bit(ST_LPM, &fimc->state))
1015                return 0;
1016        if (fimc_capture_busy(fimc))
1017                return fimc_capture_suspend(fimc);
1018
1019        return fimc_m2m_suspend(fimc);
1020}
1021#endif /* CONFIG_PM_SLEEP */
1022
1023static int __devexit fimc_remove(struct platform_device *pdev)
1024{
1025        struct fimc_dev *fimc = platform_get_drvdata(pdev);
1026
1027        pm_runtime_disable(&pdev->dev);
1028        pm_runtime_set_suspended(&pdev->dev);
1029
1030        fimc_unregister_capture_subdev(fimc);
1031        vb2_dma_contig_cleanup_ctx(fimc->alloc_ctx);
1032
1033        clk_disable(fimc->clock[CLK_BUS]);
1034        fimc_clk_put(fimc);
1035
1036        dev_info(&pdev->dev, "driver unloaded\n");
1037        return 0;
1038}
1039
1040/* Image pixel limits, similar across several FIMC HW revisions. */
1041static struct fimc_pix_limit s5p_pix_limit[4] = {
1042        [0] = {
1043                .scaler_en_w    = 3264,
1044                .scaler_dis_w   = 8192,
1045                .in_rot_en_h    = 1920,
1046                .in_rot_dis_w   = 8192,
1047                .out_rot_en_w   = 1920,
1048                .out_rot_dis_w  = 4224,
1049        },
1050        [1] = {
1051                .scaler_en_w    = 4224,
1052                .scaler_dis_w   = 8192,
1053                .in_rot_en_h    = 1920,
1054                .in_rot_dis_w   = 8192,
1055                .out_rot_en_w   = 1920,
1056                .out_rot_dis_w  = 4224,
1057        },
1058        [2] = {
1059                .scaler_en_w    = 1920,
1060                .scaler_dis_w   = 8192,
1061                .in_rot_en_h    = 1280,
1062                .in_rot_dis_w   = 8192,
1063                .out_rot_en_w   = 1280,
1064                .out_rot_dis_w  = 1920,
1065        },
1066        [3] = {
1067                .scaler_en_w    = 1920,
1068                .scaler_dis_w   = 8192,
1069                .in_rot_en_h    = 1366,
1070                .in_rot_dis_w   = 8192,
1071                .out_rot_en_w   = 1366,
1072                .out_rot_dis_w  = 1920,
1073        },
1074};
1075
1076static struct fimc_variant fimc0_variant_s5p = {
1077        .has_inp_rot     = 1,
1078        .has_out_rot     = 1,
1079        .has_cam_if      = 1,
1080        .min_inp_pixsize = 16,
1081        .min_out_pixsize = 16,
1082        .hor_offs_align  = 8,
1083        .min_vsize_align = 16,
1084        .out_buf_count   = 4,
1085        .pix_limit       = &s5p_pix_limit[0],
1086};
1087
1088static struct fimc_variant fimc2_variant_s5p = {
1089        .has_cam_if      = 1,
1090        .min_inp_pixsize = 16,
1091        .min_out_pixsize = 16,
1092        .hor_offs_align  = 8,
1093        .min_vsize_align = 16,
1094        .out_buf_count   = 4,
1095        .pix_limit       = &s5p_pix_limit[1],
1096};
1097
1098static struct fimc_variant fimc0_variant_s5pv210 = {
1099        .pix_hoff        = 1,
1100        .has_inp_rot     = 1,
1101        .has_out_rot     = 1,
1102        .has_cam_if      = 1,
1103        .min_inp_pixsize = 16,
1104        .min_out_pixsize = 16,
1105        .hor_offs_align  = 8,
1106        .min_vsize_align = 16,
1107        .out_buf_count   = 4,
1108        .pix_limit       = &s5p_pix_limit[1],
1109};
1110
1111static struct fimc_variant fimc1_variant_s5pv210 = {
1112        .pix_hoff        = 1,
1113        .has_inp_rot     = 1,
1114        .has_out_rot     = 1,
1115        .has_cam_if      = 1,
1116        .has_mainscaler_ext = 1,
1117        .min_inp_pixsize = 16,
1118        .min_out_pixsize = 16,
1119        .hor_offs_align  = 1,
1120        .min_vsize_align = 1,
1121        .out_buf_count   = 4,
1122        .pix_limit       = &s5p_pix_limit[2],
1123};
1124
1125static struct fimc_variant fimc2_variant_s5pv210 = {
1126        .has_cam_if      = 1,
1127        .pix_hoff        = 1,
1128        .min_inp_pixsize = 16,
1129        .min_out_pixsize = 16,
1130        .hor_offs_align  = 8,
1131        .min_vsize_align = 16,
1132        .out_buf_count   = 4,
1133        .pix_limit       = &s5p_pix_limit[2],
1134};
1135
1136static struct fimc_variant fimc0_variant_exynos4 = {
1137        .pix_hoff        = 1,
1138        .has_inp_rot     = 1,
1139        .has_out_rot     = 1,
1140        .has_cam_if      = 1,
1141        .has_cistatus2   = 1,
1142        .has_mainscaler_ext = 1,
1143        .has_alpha       = 1,
1144        .min_inp_pixsize = 16,
1145        .min_out_pixsize = 16,
1146        .hor_offs_align  = 2,
1147        .min_vsize_align = 1,
1148        .out_buf_count   = 32,
1149        .pix_limit       = &s5p_pix_limit[1],
1150};
1151
1152static struct fimc_variant fimc3_variant_exynos4 = {
1153        .pix_hoff        = 1,
1154        .has_cam_if      = 1,
1155        .has_cistatus2   = 1,
1156        .has_mainscaler_ext = 1,
1157        .has_alpha       = 1,
1158        .min_inp_pixsize = 16,
1159        .min_out_pixsize = 16,
1160        .hor_offs_align  = 2,
1161        .min_vsize_align = 1,
1162        .out_buf_count   = 32,
1163        .pix_limit       = &s5p_pix_limit[3],
1164};
1165
1166/* S5PC100 */
1167static struct fimc_drvdata fimc_drvdata_s5p = {
1168        .variant = {
1169                [0] = &fimc0_variant_s5p,
1170                [1] = &fimc0_variant_s5p,
1171                [2] = &fimc2_variant_s5p,
1172        },
1173        .num_entities = 3,
1174        .lclk_frequency = 133000000UL,
1175};
1176
1177/* S5PV210, S5PC110 */
1178static struct fimc_drvdata fimc_drvdata_s5pv210 = {
1179        .variant = {
1180                [0] = &fimc0_variant_s5pv210,
1181                [1] = &fimc1_variant_s5pv210,
1182                [2] = &fimc2_variant_s5pv210,
1183        },
1184        .num_entities = 3,
1185        .lclk_frequency = 166000000UL,
1186};
1187
1188/* EXYNOS4210, S5PV310, S5PC210 */
1189static struct fimc_drvdata fimc_drvdata_exynos4 = {
1190        .variant = {
1191                [0] = &fimc0_variant_exynos4,
1192                [1] = &fimc0_variant_exynos4,
1193                [2] = &fimc0_variant_exynos4,
1194                [3] = &fimc3_variant_exynos4,
1195        },
1196        .num_entities = 4,
1197        .lclk_frequency = 166000000UL,
1198};
1199
1200static struct platform_device_id fimc_driver_ids[] = {
1201        {
1202                .name           = "s5p-fimc",
1203                .driver_data    = (unsigned long)&fimc_drvdata_s5p,
1204        }, {
1205                .name           = "s5pv210-fimc",
1206                .driver_data    = (unsigned long)&fimc_drvdata_s5pv210,
1207        }, {
1208                .name           = "exynos4-fimc",
1209                .driver_data    = (unsigned long)&fimc_drvdata_exynos4,
1210        },
1211        {},
1212};
1213MODULE_DEVICE_TABLE(platform, fimc_driver_ids);
1214
1215static const struct dev_pm_ops fimc_pm_ops = {
1216        SET_SYSTEM_SLEEP_PM_OPS(fimc_suspend, fimc_resume)
1217        SET_RUNTIME_PM_OPS(fimc_runtime_suspend, fimc_runtime_resume, NULL)
1218};
1219
1220static struct platform_driver fimc_driver = {
1221        .probe          = fimc_probe,
1222        .remove         = __devexit_p(fimc_remove),
1223        .id_table       = fimc_driver_ids,
1224        .driver = {
1225                .name   = FIMC_MODULE_NAME,
1226                .owner  = THIS_MODULE,
1227                .pm     = &fimc_pm_ops,
1228        }
1229};
1230
1231int __init fimc_register_driver(void)
1232{
1233        return platform_driver_register(&fimc_driver);
1234}
1235
1236void __exit fimc_unregister_driver(void)
1237{
1238        platform_driver_unregister(&fimc_driver);
1239}
1240