linux/drivers/media/platform/davinci/dm644x_ccdc.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2006-2009 Texas Instruments Inc
   3 *
   4 * This program is free software; you can redistribute it and/or modify
   5 * it under the terms of the GNU General Public License as published by
   6 * the Free Software Foundation; either version 2 of the License, or
   7 * (at your option) any later version.
   8 *
   9 * This program is distributed in the hope that it will be useful,
  10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12 * GNU General Public License for more details.
  13 *
  14 * CCDC hardware module for DM6446
  15 * ------------------------------
  16 *
  17 * This module is for configuring CCD controller of DM6446 VPFE to capture
  18 * Raw yuv or Bayer RGB data from a decoder. CCDC has several modules
  19 * such as Defect Pixel Correction, Color Space Conversion etc to
  20 * pre-process the Raw Bayer RGB data, before writing it to SDRAM.
  21 * This file is named DM644x so that other variants such DM6443
  22 * may be supported using the same module.
  23 *
  24 * TODO: Test Raw bayer parameter settings and bayer capture
  25 *       Split module parameter structure to module specific ioctl structs
  26 *       investigate if enum used for user space type definition
  27 *       to be replaced by #defines or integer
  28 */
  29#include <linux/platform_device.h>
  30#include <linux/uaccess.h>
  31#include <linux/videodev2.h>
  32#include <linux/gfp.h>
  33#include <linux/err.h>
  34#include <linux/module.h>
  35
  36#include <media/davinci/dm644x_ccdc.h>
  37#include <media/davinci/vpss.h>
  38
  39#include "dm644x_ccdc_regs.h"
  40#include "ccdc_hw_device.h"
  41
  42MODULE_LICENSE("GPL");
  43MODULE_DESCRIPTION("CCDC Driver for DM6446");
  44MODULE_AUTHOR("Texas Instruments");
  45
  46static struct ccdc_oper_config {
  47        struct device *dev;
  48        /* CCDC interface type */
  49        enum vpfe_hw_if_type if_type;
  50        /* Raw Bayer configuration */
  51        struct ccdc_params_raw bayer;
  52        /* YCbCr configuration */
  53        struct ccdc_params_ycbcr ycbcr;
  54        /* ccdc base address */
  55        void __iomem *base_addr;
  56} ccdc_cfg = {
  57        /* Raw configurations */
  58        .bayer = {
  59                .pix_fmt = CCDC_PIXFMT_RAW,
  60                .frm_fmt = CCDC_FRMFMT_PROGRESSIVE,
  61                .win = CCDC_WIN_VGA,
  62                .fid_pol = VPFE_PINPOL_POSITIVE,
  63                .vd_pol = VPFE_PINPOL_POSITIVE,
  64                .hd_pol = VPFE_PINPOL_POSITIVE,
  65                .config_params = {
  66                        .data_sz = CCDC_DATA_10BITS,
  67                },
  68        },
  69        .ycbcr = {
  70                .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT,
  71                .frm_fmt = CCDC_FRMFMT_INTERLACED,
  72                .win = CCDC_WIN_PAL,
  73                .fid_pol = VPFE_PINPOL_POSITIVE,
  74                .vd_pol = VPFE_PINPOL_POSITIVE,
  75                .hd_pol = VPFE_PINPOL_POSITIVE,
  76                .bt656_enable = 1,
  77                .pix_order = CCDC_PIXORDER_CBYCRY,
  78                .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED
  79        },
  80};
  81
  82#define CCDC_MAX_RAW_YUV_FORMATS        2
  83
  84/* Raw Bayer formats */
  85static u32 ccdc_raw_bayer_pix_formats[] =
  86        {V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16};
  87
  88/* Raw YUV formats */
  89static u32 ccdc_raw_yuv_pix_formats[] =
  90        {V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV};
  91
  92/* CCDC Save/Restore context */
  93static u32 ccdc_ctx[CCDC_REG_END / sizeof(u32)];
  94
  95/* register access routines */
  96static inline u32 regr(u32 offset)
  97{
  98        return __raw_readl(ccdc_cfg.base_addr + offset);
  99}
 100
 101static inline void regw(u32 val, u32 offset)
 102{
 103        __raw_writel(val, ccdc_cfg.base_addr + offset);
 104}
 105
 106static void ccdc_enable(int flag)
 107{
 108        regw(flag, CCDC_PCR);
 109}
 110
 111static void ccdc_enable_vport(int flag)
 112{
 113        if (flag)
 114                /* enable video port */
 115                regw(CCDC_ENABLE_VIDEO_PORT, CCDC_FMTCFG);
 116        else
 117                regw(CCDC_DISABLE_VIDEO_PORT, CCDC_FMTCFG);
 118}
 119
 120/*
 121 * ccdc_setwin()
 122 * This function will configure the window size
 123 * to be capture in CCDC reg
 124 */
 125static void ccdc_setwin(struct v4l2_rect *image_win,
 126                        enum ccdc_frmfmt frm_fmt,
 127                        int ppc)
 128{
 129        int horz_start, horz_nr_pixels;
 130        int vert_start, vert_nr_lines;
 131        int val = 0, mid_img = 0;
 132
 133        dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_setwin...");
 134        /*
 135         * ppc - per pixel count. indicates how many pixels per cell
 136         * output to SDRAM. example, for ycbcr, it is one y and one c, so 2.
 137         * raw capture this is 1
 138         */
 139        horz_start = image_win->left << (ppc - 1);
 140        horz_nr_pixels = (image_win->width << (ppc - 1)) - 1;
 141        regw((horz_start << CCDC_HORZ_INFO_SPH_SHIFT) | horz_nr_pixels,
 142             CCDC_HORZ_INFO);
 143
 144        vert_start = image_win->top;
 145
 146        if (frm_fmt == CCDC_FRMFMT_INTERLACED) {
 147                vert_nr_lines = (image_win->height >> 1) - 1;
 148                vert_start >>= 1;
 149                /* Since first line doesn't have any data */
 150                vert_start += 1;
 151                /* configure VDINT0 */
 152                val = (vert_start << CCDC_VDINT_VDINT0_SHIFT);
 153                regw(val, CCDC_VDINT);
 154
 155        } else {
 156                /* Since first line doesn't have any data */
 157                vert_start += 1;
 158                vert_nr_lines = image_win->height - 1;
 159                /*
 160                 * configure VDINT0 and VDINT1. VDINT1 will be at half
 161                 * of image height
 162                 */
 163                mid_img = vert_start + (image_win->height / 2);
 164                val = (vert_start << CCDC_VDINT_VDINT0_SHIFT) |
 165                    (mid_img & CCDC_VDINT_VDINT1_MASK);
 166                regw(val, CCDC_VDINT);
 167
 168        }
 169        regw((vert_start << CCDC_VERT_START_SLV0_SHIFT) | vert_start,
 170             CCDC_VERT_START);
 171        regw(vert_nr_lines, CCDC_VERT_LINES);
 172        dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_setwin...");
 173}
 174
 175static void ccdc_readregs(void)
 176{
 177        unsigned int val = 0;
 178
 179        val = regr(CCDC_ALAW);
 180        dev_notice(ccdc_cfg.dev, "\nReading 0x%x to ALAW...\n", val);
 181        val = regr(CCDC_CLAMP);
 182        dev_notice(ccdc_cfg.dev, "\nReading 0x%x to CLAMP...\n", val);
 183        val = regr(CCDC_DCSUB);
 184        dev_notice(ccdc_cfg.dev, "\nReading 0x%x to DCSUB...\n", val);
 185        val = regr(CCDC_BLKCMP);
 186        dev_notice(ccdc_cfg.dev, "\nReading 0x%x to BLKCMP...\n", val);
 187        val = regr(CCDC_FPC_ADDR);
 188        dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FPC_ADDR...\n", val);
 189        val = regr(CCDC_FPC);
 190        dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FPC...\n", val);
 191        val = regr(CCDC_FMTCFG);
 192        dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FMTCFG...\n", val);
 193        val = regr(CCDC_COLPTN);
 194        dev_notice(ccdc_cfg.dev, "\nReading 0x%x to COLPTN...\n", val);
 195        val = regr(CCDC_FMT_HORZ);
 196        dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FMT_HORZ...\n", val);
 197        val = regr(CCDC_FMT_VERT);
 198        dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FMT_VERT...\n", val);
 199        val = regr(CCDC_HSIZE_OFF);
 200        dev_notice(ccdc_cfg.dev, "\nReading 0x%x to HSIZE_OFF...\n", val);
 201        val = regr(CCDC_SDOFST);
 202        dev_notice(ccdc_cfg.dev, "\nReading 0x%x to SDOFST...\n", val);
 203        val = regr(CCDC_VP_OUT);
 204        dev_notice(ccdc_cfg.dev, "\nReading 0x%x to VP_OUT...\n", val);
 205        val = regr(CCDC_SYN_MODE);
 206        dev_notice(ccdc_cfg.dev, "\nReading 0x%x to SYN_MODE...\n", val);
 207        val = regr(CCDC_HORZ_INFO);
 208        dev_notice(ccdc_cfg.dev, "\nReading 0x%x to HORZ_INFO...\n", val);
 209        val = regr(CCDC_VERT_START);
 210        dev_notice(ccdc_cfg.dev, "\nReading 0x%x to VERT_START...\n", val);
 211        val = regr(CCDC_VERT_LINES);
 212        dev_notice(ccdc_cfg.dev, "\nReading 0x%x to VERT_LINES...\n", val);
 213}
 214
 215static int ccdc_close(struct device *dev)
 216{
 217        return 0;
 218}
 219
 220/*
 221 * ccdc_restore_defaults()
 222 * This function will write defaults to all CCDC registers
 223 */
 224static void ccdc_restore_defaults(void)
 225{
 226        int i;
 227
 228        /* disable CCDC */
 229        ccdc_enable(0);
 230        /* set all registers to default value */
 231        for (i = 4; i <= 0x94; i += 4)
 232                regw(0,  i);
 233        regw(CCDC_NO_CULLING, CCDC_CULLING);
 234        regw(CCDC_GAMMA_BITS_11_2, CCDC_ALAW);
 235}
 236
 237static int ccdc_open(struct device *device)
 238{
 239        ccdc_restore_defaults();
 240        if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
 241                ccdc_enable_vport(1);
 242        return 0;
 243}
 244
 245static void ccdc_sbl_reset(void)
 246{
 247        vpss_clear_wbl_overflow(VPSS_PCR_CCDC_WBL_O);
 248}
 249
 250/*
 251 * ccdc_config_ycbcr()
 252 * This function will configure CCDC for YCbCr video capture
 253 */
 254static void ccdc_config_ycbcr(void)
 255{
 256        struct ccdc_params_ycbcr *params = &ccdc_cfg.ycbcr;
 257        u32 syn_mode;
 258
 259        dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_ycbcr...");
 260        /*
 261         * first restore the CCDC registers to default values
 262         * This is important since we assume default values to be set in
 263         * a lot of registers that we didn't touch
 264         */
 265        ccdc_restore_defaults();
 266
 267        /*
 268         * configure pixel format, frame format, configure video frame
 269         * format, enable output to SDRAM, enable internal timing generator
 270         * and 8bit pack mode
 271         */
 272        syn_mode = (((params->pix_fmt & CCDC_SYN_MODE_INPMOD_MASK) <<
 273                    CCDC_SYN_MODE_INPMOD_SHIFT) |
 274                    ((params->frm_fmt & CCDC_SYN_FLDMODE_MASK) <<
 275                    CCDC_SYN_FLDMODE_SHIFT) | CCDC_VDHDEN_ENABLE |
 276                    CCDC_WEN_ENABLE | CCDC_DATA_PACK_ENABLE);
 277
 278        /* setup BT.656 sync mode */
 279        if (params->bt656_enable) {
 280                regw(CCDC_REC656IF_BT656_EN, CCDC_REC656IF);
 281
 282                /*
 283                 * configure the FID, VD, HD pin polarity,
 284                 * fld,hd pol positive, vd negative, 8-bit data
 285                 */
 286                syn_mode |= CCDC_SYN_MODE_VD_POL_NEGATIVE;
 287                if (ccdc_cfg.if_type == VPFE_BT656_10BIT)
 288                        syn_mode |= CCDC_SYN_MODE_10BITS;
 289                else
 290                        syn_mode |= CCDC_SYN_MODE_8BITS;
 291        } else {
 292                /* y/c external sync mode */
 293                syn_mode |= (((params->fid_pol & CCDC_FID_POL_MASK) <<
 294                             CCDC_FID_POL_SHIFT) |
 295                             ((params->hd_pol & CCDC_HD_POL_MASK) <<
 296                             CCDC_HD_POL_SHIFT) |
 297                             ((params->vd_pol & CCDC_VD_POL_MASK) <<
 298                             CCDC_VD_POL_SHIFT));
 299        }
 300        regw(syn_mode, CCDC_SYN_MODE);
 301
 302        /* configure video window */
 303        ccdc_setwin(&params->win, params->frm_fmt, 2);
 304
 305        /*
 306         * configure the order of y cb cr in SDRAM, and disable latch
 307         * internal register on vsync
 308         */
 309        if (ccdc_cfg.if_type == VPFE_BT656_10BIT)
 310                regw((params->pix_order << CCDC_CCDCFG_Y8POS_SHIFT) |
 311                        CCDC_LATCH_ON_VSYNC_DISABLE | CCDC_CCDCFG_BW656_10BIT,
 312                        CCDC_CCDCFG);
 313        else
 314                regw((params->pix_order << CCDC_CCDCFG_Y8POS_SHIFT) |
 315                        CCDC_LATCH_ON_VSYNC_DISABLE, CCDC_CCDCFG);
 316
 317        /*
 318         * configure the horizontal line offset. This should be a
 319         * on 32 byte boundary. So clear LSB 5 bits
 320         */
 321        regw(((params->win.width * 2  + 31) & ~0x1f), CCDC_HSIZE_OFF);
 322
 323        /* configure the memory line offset */
 324        if (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED)
 325                /* two fields are interleaved in memory */
 326                regw(CCDC_SDOFST_FIELD_INTERLEAVED, CCDC_SDOFST);
 327
 328        ccdc_sbl_reset();
 329        dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_config_ycbcr...\n");
 330}
 331
 332static void ccdc_config_black_clamp(struct ccdc_black_clamp *bclamp)
 333{
 334        u32 val;
 335
 336        if (!bclamp->enable) {
 337                /* configure DCSub */
 338                val = (bclamp->dc_sub) & CCDC_BLK_DC_SUB_MASK;
 339                regw(val, CCDC_DCSUB);
 340                dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to DCSUB...\n", val);
 341                regw(CCDC_CLAMP_DEFAULT_VAL, CCDC_CLAMP);
 342                dev_dbg(ccdc_cfg.dev, "\nWriting 0x0000 to CLAMP...\n");
 343                return;
 344        }
 345        /*
 346         * Configure gain,  Start pixel, No of line to be avg,
 347         * No of pixel/line to be avg, & Enable the Black clamping
 348         */
 349        val = ((bclamp->sgain & CCDC_BLK_SGAIN_MASK) |
 350               ((bclamp->start_pixel & CCDC_BLK_ST_PXL_MASK) <<
 351                CCDC_BLK_ST_PXL_SHIFT) |
 352               ((bclamp->sample_ln & CCDC_BLK_SAMPLE_LINE_MASK) <<
 353                CCDC_BLK_SAMPLE_LINE_SHIFT) |
 354               ((bclamp->sample_pixel & CCDC_BLK_SAMPLE_LN_MASK) <<
 355                CCDC_BLK_SAMPLE_LN_SHIFT) | CCDC_BLK_CLAMP_ENABLE);
 356        regw(val, CCDC_CLAMP);
 357        dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to CLAMP...\n", val);
 358        /* If Black clamping is enable then make dcsub 0 */
 359        regw(CCDC_DCSUB_DEFAULT_VAL, CCDC_DCSUB);
 360        dev_dbg(ccdc_cfg.dev, "\nWriting 0x00000000 to DCSUB...\n");
 361}
 362
 363static void ccdc_config_black_compense(struct ccdc_black_compensation *bcomp)
 364{
 365        u32 val;
 366
 367        val = ((bcomp->b & CCDC_BLK_COMP_MASK) |
 368              ((bcomp->gb & CCDC_BLK_COMP_MASK) <<
 369               CCDC_BLK_COMP_GB_COMP_SHIFT) |
 370              ((bcomp->gr & CCDC_BLK_COMP_MASK) <<
 371               CCDC_BLK_COMP_GR_COMP_SHIFT) |
 372              ((bcomp->r & CCDC_BLK_COMP_MASK) <<
 373               CCDC_BLK_COMP_R_COMP_SHIFT));
 374        regw(val, CCDC_BLKCMP);
 375}
 376
 377/*
 378 * ccdc_config_raw()
 379 * This function will configure CCDC for Raw capture mode
 380 */
 381static void ccdc_config_raw(void)
 382{
 383        struct ccdc_params_raw *params = &ccdc_cfg.bayer;
 384        struct ccdc_config_params_raw *config_params =
 385                                &ccdc_cfg.bayer.config_params;
 386        unsigned int syn_mode = 0;
 387        unsigned int val;
 388
 389        dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_raw...");
 390
 391        /*      Reset CCDC */
 392        ccdc_restore_defaults();
 393
 394        /* Disable latching function registers on VSYNC  */
 395        regw(CCDC_LATCH_ON_VSYNC_DISABLE, CCDC_CCDCFG);
 396
 397        /*
 398         * Configure the vertical sync polarity(SYN_MODE.VDPOL),
 399         * horizontal sync polarity (SYN_MODE.HDPOL), frame id polarity
 400         * (SYN_MODE.FLDPOL), frame format(progressive or interlace),
 401         * data size(SYNMODE.DATSIZ), &pixel format (Input mode), output
 402         * SDRAM, enable internal timing generator
 403         */
 404        syn_mode =
 405                (((params->vd_pol & CCDC_VD_POL_MASK) << CCDC_VD_POL_SHIFT) |
 406                ((params->hd_pol & CCDC_HD_POL_MASK) << CCDC_HD_POL_SHIFT) |
 407                ((params->fid_pol & CCDC_FID_POL_MASK) << CCDC_FID_POL_SHIFT) |
 408                ((params->frm_fmt & CCDC_FRM_FMT_MASK) << CCDC_FRM_FMT_SHIFT) |
 409                ((config_params->data_sz & CCDC_DATA_SZ_MASK) <<
 410                CCDC_DATA_SZ_SHIFT) |
 411                ((params->pix_fmt & CCDC_PIX_FMT_MASK) << CCDC_PIX_FMT_SHIFT) |
 412                CCDC_WEN_ENABLE | CCDC_VDHDEN_ENABLE);
 413
 414        /* Enable and configure aLaw register if needed */
 415        if (config_params->alaw.enable) {
 416                val = ((config_params->alaw.gamma_wd &
 417                      CCDC_ALAW_GAMMA_WD_MASK) | CCDC_ALAW_ENABLE);
 418                regw(val, CCDC_ALAW);
 419                dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to ALAW...\n", val);
 420        }
 421
 422        /* Configure video window */
 423        ccdc_setwin(&params->win, params->frm_fmt, CCDC_PPC_RAW);
 424
 425        /* Configure Black Clamp */
 426        ccdc_config_black_clamp(&config_params->blk_clamp);
 427
 428        /* Configure Black level compensation */
 429        ccdc_config_black_compense(&config_params->blk_comp);
 430
 431        /* If data size is 8 bit then pack the data */
 432        if ((config_params->data_sz == CCDC_DATA_8BITS) ||
 433             config_params->alaw.enable)
 434                syn_mode |= CCDC_DATA_PACK_ENABLE;
 435
 436        /* disable video port */
 437        val = CCDC_DISABLE_VIDEO_PORT;
 438
 439        if (config_params->data_sz == CCDC_DATA_8BITS)
 440                val |= (CCDC_DATA_10BITS & CCDC_FMTCFG_VPIN_MASK)
 441                    << CCDC_FMTCFG_VPIN_SHIFT;
 442        else
 443                val |= (config_params->data_sz & CCDC_FMTCFG_VPIN_MASK)
 444                    << CCDC_FMTCFG_VPIN_SHIFT;
 445        /* Write value in FMTCFG */
 446        regw(val, CCDC_FMTCFG);
 447
 448        dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FMTCFG...\n", val);
 449        /* Configure the color pattern according to mt9t001 sensor */
 450        regw(CCDC_COLPTN_VAL, CCDC_COLPTN);
 451
 452        dev_dbg(ccdc_cfg.dev, "\nWriting 0xBB11BB11 to COLPTN...\n");
 453        /*
 454         * Configure Data formatter(Video port) pixel selection
 455         * (FMT_HORZ, FMT_VERT)
 456         */
 457        val = ((params->win.left & CCDC_FMT_HORZ_FMTSPH_MASK) <<
 458              CCDC_FMT_HORZ_FMTSPH_SHIFT) |
 459              (params->win.width & CCDC_FMT_HORZ_FMTLNH_MASK);
 460        regw(val, CCDC_FMT_HORZ);
 461
 462        dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FMT_HORZ...\n", val);
 463        val = (params->win.top & CCDC_FMT_VERT_FMTSLV_MASK)
 464            << CCDC_FMT_VERT_FMTSLV_SHIFT;
 465        if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE)
 466                val |= (params->win.height) & CCDC_FMT_VERT_FMTLNV_MASK;
 467        else
 468                val |= (params->win.height >> 1) & CCDC_FMT_VERT_FMTLNV_MASK;
 469
 470        dev_dbg(ccdc_cfg.dev, "\nparams->win.height  0x%x ...\n",
 471               params->win.height);
 472        regw(val, CCDC_FMT_VERT);
 473
 474        dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FMT_VERT...\n", val);
 475
 476        dev_dbg(ccdc_cfg.dev, "\nbelow regw(val, FMT_VERT)...");
 477
 478        /*
 479         * Configure Horizontal offset register. If pack 8 is enabled then
 480         * 1 pixel will take 1 byte
 481         */
 482        if ((config_params->data_sz == CCDC_DATA_8BITS) ||
 483            config_params->alaw.enable)
 484                regw((params->win.width + CCDC_32BYTE_ALIGN_VAL) &
 485                    CCDC_HSIZE_OFF_MASK, CCDC_HSIZE_OFF);
 486        else
 487                /* else one pixel will take 2 byte */
 488                regw(((params->win.width * CCDC_TWO_BYTES_PER_PIXEL) +
 489                    CCDC_32BYTE_ALIGN_VAL) & CCDC_HSIZE_OFF_MASK,
 490                    CCDC_HSIZE_OFF);
 491
 492        /* Set value for SDOFST */
 493        if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) {
 494                if (params->image_invert_enable) {
 495                        /* For intelace inverse mode */
 496                        regw(CCDC_INTERLACED_IMAGE_INVERT, CCDC_SDOFST);
 497                        dev_dbg(ccdc_cfg.dev, "\nWriting 0x4B6D to SDOFST..\n");
 498                }
 499
 500                else {
 501                        /* For intelace non inverse mode */
 502                        regw(CCDC_INTERLACED_NO_IMAGE_INVERT, CCDC_SDOFST);
 503                        dev_dbg(ccdc_cfg.dev, "\nWriting 0x0249 to SDOFST..\n");
 504                }
 505        } else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) {
 506                regw(CCDC_PROGRESSIVE_NO_IMAGE_INVERT, CCDC_SDOFST);
 507                dev_dbg(ccdc_cfg.dev, "\nWriting 0x0000 to SDOFST...\n");
 508        }
 509
 510        /*
 511         * Configure video port pixel selection (VPOUT)
 512         * Here -1 is to make the height value less than FMT_VERT.FMTLNV
 513         */
 514        if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE)
 515                val = (((params->win.height - 1) & CCDC_VP_OUT_VERT_NUM_MASK))
 516                    << CCDC_VP_OUT_VERT_NUM_SHIFT;
 517        else
 518                val =
 519                    ((((params->win.height >> CCDC_INTERLACED_HEIGHT_SHIFT) -
 520                     1) & CCDC_VP_OUT_VERT_NUM_MASK)) <<
 521                    CCDC_VP_OUT_VERT_NUM_SHIFT;
 522
 523        val |= ((((params->win.width))) & CCDC_VP_OUT_HORZ_NUM_MASK)
 524            << CCDC_VP_OUT_HORZ_NUM_SHIFT;
 525        val |= (params->win.left) & CCDC_VP_OUT_HORZ_ST_MASK;
 526        regw(val, CCDC_VP_OUT);
 527
 528        dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to VP_OUT...\n", val);
 529        regw(syn_mode, CCDC_SYN_MODE);
 530        dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to SYN_MODE...\n", syn_mode);
 531
 532        ccdc_sbl_reset();
 533        dev_dbg(ccdc_cfg.dev, "\nend of ccdc_config_raw...");
 534        ccdc_readregs();
 535}
 536
 537static int ccdc_configure(void)
 538{
 539        if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
 540                ccdc_config_raw();
 541        else
 542                ccdc_config_ycbcr();
 543        return 0;
 544}
 545
 546static int ccdc_set_buftype(enum ccdc_buftype buf_type)
 547{
 548        if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
 549                ccdc_cfg.bayer.buf_type = buf_type;
 550        else
 551                ccdc_cfg.ycbcr.buf_type = buf_type;
 552        return 0;
 553}
 554
 555static enum ccdc_buftype ccdc_get_buftype(void)
 556{
 557        if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
 558                return ccdc_cfg.bayer.buf_type;
 559        return ccdc_cfg.ycbcr.buf_type;
 560}
 561
 562static int ccdc_enum_pix(u32 *pix, int i)
 563{
 564        int ret = -EINVAL;
 565        if (ccdc_cfg.if_type == VPFE_RAW_BAYER) {
 566                if (i < ARRAY_SIZE(ccdc_raw_bayer_pix_formats)) {
 567                        *pix = ccdc_raw_bayer_pix_formats[i];
 568                        ret = 0;
 569                }
 570        } else {
 571                if (i < ARRAY_SIZE(ccdc_raw_yuv_pix_formats)) {
 572                        *pix = ccdc_raw_yuv_pix_formats[i];
 573                        ret = 0;
 574                }
 575        }
 576        return ret;
 577}
 578
 579static int ccdc_set_pixel_format(u32 pixfmt)
 580{
 581        if (ccdc_cfg.if_type == VPFE_RAW_BAYER) {
 582                ccdc_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW;
 583                if (pixfmt == V4L2_PIX_FMT_SBGGR8)
 584                        ccdc_cfg.bayer.config_params.alaw.enable = 1;
 585                else if (pixfmt != V4L2_PIX_FMT_SBGGR16)
 586                        return -EINVAL;
 587        } else {
 588                if (pixfmt == V4L2_PIX_FMT_YUYV)
 589                        ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR;
 590                else if (pixfmt == V4L2_PIX_FMT_UYVY)
 591                        ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;
 592                else
 593                        return -EINVAL;
 594        }
 595        return 0;
 596}
 597
 598static u32 ccdc_get_pixel_format(void)
 599{
 600        struct ccdc_a_law *alaw = &ccdc_cfg.bayer.config_params.alaw;
 601        u32 pixfmt;
 602
 603        if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
 604                if (alaw->enable)
 605                        pixfmt = V4L2_PIX_FMT_SBGGR8;
 606                else
 607                        pixfmt = V4L2_PIX_FMT_SBGGR16;
 608        else {
 609                if (ccdc_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR)
 610                        pixfmt = V4L2_PIX_FMT_YUYV;
 611                else
 612                        pixfmt = V4L2_PIX_FMT_UYVY;
 613        }
 614        return pixfmt;
 615}
 616
 617static int ccdc_set_image_window(struct v4l2_rect *win)
 618{
 619        if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
 620                ccdc_cfg.bayer.win = *win;
 621        else
 622                ccdc_cfg.ycbcr.win = *win;
 623        return 0;
 624}
 625
 626static void ccdc_get_image_window(struct v4l2_rect *win)
 627{
 628        if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
 629                *win = ccdc_cfg.bayer.win;
 630        else
 631                *win = ccdc_cfg.ycbcr.win;
 632}
 633
 634static unsigned int ccdc_get_line_length(void)
 635{
 636        struct ccdc_config_params_raw *config_params =
 637                                &ccdc_cfg.bayer.config_params;
 638        unsigned int len;
 639
 640        if (ccdc_cfg.if_type == VPFE_RAW_BAYER) {
 641                if ((config_params->alaw.enable) ||
 642                    (config_params->data_sz == CCDC_DATA_8BITS))
 643                        len = ccdc_cfg.bayer.win.width;
 644                else
 645                        len = ccdc_cfg.bayer.win.width * 2;
 646        } else
 647                len = ccdc_cfg.ycbcr.win.width * 2;
 648        return ALIGN(len, 32);
 649}
 650
 651static int ccdc_set_frame_format(enum ccdc_frmfmt frm_fmt)
 652{
 653        if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
 654                ccdc_cfg.bayer.frm_fmt = frm_fmt;
 655        else
 656                ccdc_cfg.ycbcr.frm_fmt = frm_fmt;
 657        return 0;
 658}
 659
 660static enum ccdc_frmfmt ccdc_get_frame_format(void)
 661{
 662        if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
 663                return ccdc_cfg.bayer.frm_fmt;
 664        else
 665                return ccdc_cfg.ycbcr.frm_fmt;
 666}
 667
 668static int ccdc_getfid(void)
 669{
 670        return (regr(CCDC_SYN_MODE) >> 15) & 1;
 671}
 672
 673/* misc operations */
 674static inline void ccdc_setfbaddr(unsigned long addr)
 675{
 676        regw(addr & 0xffffffe0, CCDC_SDR_ADDR);
 677}
 678
 679static int ccdc_set_hw_if_params(struct vpfe_hw_if_param *params)
 680{
 681        ccdc_cfg.if_type = params->if_type;
 682
 683        switch (params->if_type) {
 684        case VPFE_BT656:
 685        case VPFE_YCBCR_SYNC_16:
 686        case VPFE_YCBCR_SYNC_8:
 687        case VPFE_BT656_10BIT:
 688                ccdc_cfg.ycbcr.vd_pol = params->vdpol;
 689                ccdc_cfg.ycbcr.hd_pol = params->hdpol;
 690                break;
 691        default:
 692                /* TODO add support for raw bayer here */
 693                return -EINVAL;
 694        }
 695        return 0;
 696}
 697
 698static void ccdc_save_context(void)
 699{
 700        ccdc_ctx[CCDC_PCR >> 2] = regr(CCDC_PCR);
 701        ccdc_ctx[CCDC_SYN_MODE >> 2] = regr(CCDC_SYN_MODE);
 702        ccdc_ctx[CCDC_HD_VD_WID >> 2] = regr(CCDC_HD_VD_WID);
 703        ccdc_ctx[CCDC_PIX_LINES >> 2] = regr(CCDC_PIX_LINES);
 704        ccdc_ctx[CCDC_HORZ_INFO >> 2] = regr(CCDC_HORZ_INFO);
 705        ccdc_ctx[CCDC_VERT_START >> 2] = regr(CCDC_VERT_START);
 706        ccdc_ctx[CCDC_VERT_LINES >> 2] = regr(CCDC_VERT_LINES);
 707        ccdc_ctx[CCDC_CULLING >> 2] = regr(CCDC_CULLING);
 708        ccdc_ctx[CCDC_HSIZE_OFF >> 2] = regr(CCDC_HSIZE_OFF);
 709        ccdc_ctx[CCDC_SDOFST >> 2] = regr(CCDC_SDOFST);
 710        ccdc_ctx[CCDC_SDR_ADDR >> 2] = regr(CCDC_SDR_ADDR);
 711        ccdc_ctx[CCDC_CLAMP >> 2] = regr(CCDC_CLAMP);
 712        ccdc_ctx[CCDC_DCSUB >> 2] = regr(CCDC_DCSUB);
 713        ccdc_ctx[CCDC_COLPTN >> 2] = regr(CCDC_COLPTN);
 714        ccdc_ctx[CCDC_BLKCMP >> 2] = regr(CCDC_BLKCMP);
 715        ccdc_ctx[CCDC_FPC >> 2] = regr(CCDC_FPC);
 716        ccdc_ctx[CCDC_FPC_ADDR >> 2] = regr(CCDC_FPC_ADDR);
 717        ccdc_ctx[CCDC_VDINT >> 2] = regr(CCDC_VDINT);
 718        ccdc_ctx[CCDC_ALAW >> 2] = regr(CCDC_ALAW);
 719        ccdc_ctx[CCDC_REC656IF >> 2] = regr(CCDC_REC656IF);
 720        ccdc_ctx[CCDC_CCDCFG >> 2] = regr(CCDC_CCDCFG);
 721        ccdc_ctx[CCDC_FMTCFG >> 2] = regr(CCDC_FMTCFG);
 722        ccdc_ctx[CCDC_FMT_HORZ >> 2] = regr(CCDC_FMT_HORZ);
 723        ccdc_ctx[CCDC_FMT_VERT >> 2] = regr(CCDC_FMT_VERT);
 724        ccdc_ctx[CCDC_FMT_ADDR0 >> 2] = regr(CCDC_FMT_ADDR0);
 725        ccdc_ctx[CCDC_FMT_ADDR1 >> 2] = regr(CCDC_FMT_ADDR1);
 726        ccdc_ctx[CCDC_FMT_ADDR2 >> 2] = regr(CCDC_FMT_ADDR2);
 727        ccdc_ctx[CCDC_FMT_ADDR3 >> 2] = regr(CCDC_FMT_ADDR3);
 728        ccdc_ctx[CCDC_FMT_ADDR4 >> 2] = regr(CCDC_FMT_ADDR4);
 729        ccdc_ctx[CCDC_FMT_ADDR5 >> 2] = regr(CCDC_FMT_ADDR5);
 730        ccdc_ctx[CCDC_FMT_ADDR6 >> 2] = regr(CCDC_FMT_ADDR6);
 731        ccdc_ctx[CCDC_FMT_ADDR7 >> 2] = regr(CCDC_FMT_ADDR7);
 732        ccdc_ctx[CCDC_PRGEVEN_0 >> 2] = regr(CCDC_PRGEVEN_0);
 733        ccdc_ctx[CCDC_PRGEVEN_1 >> 2] = regr(CCDC_PRGEVEN_1);
 734        ccdc_ctx[CCDC_PRGODD_0 >> 2] = regr(CCDC_PRGODD_0);
 735        ccdc_ctx[CCDC_PRGODD_1 >> 2] = regr(CCDC_PRGODD_1);
 736        ccdc_ctx[CCDC_VP_OUT >> 2] = regr(CCDC_VP_OUT);
 737}
 738
 739static void ccdc_restore_context(void)
 740{
 741        regw(ccdc_ctx[CCDC_SYN_MODE >> 2], CCDC_SYN_MODE);
 742        regw(ccdc_ctx[CCDC_HD_VD_WID >> 2], CCDC_HD_VD_WID);
 743        regw(ccdc_ctx[CCDC_PIX_LINES >> 2], CCDC_PIX_LINES);
 744        regw(ccdc_ctx[CCDC_HORZ_INFO >> 2], CCDC_HORZ_INFO);
 745        regw(ccdc_ctx[CCDC_VERT_START >> 2], CCDC_VERT_START);
 746        regw(ccdc_ctx[CCDC_VERT_LINES >> 2], CCDC_VERT_LINES);
 747        regw(ccdc_ctx[CCDC_CULLING >> 2], CCDC_CULLING);
 748        regw(ccdc_ctx[CCDC_HSIZE_OFF >> 2], CCDC_HSIZE_OFF);
 749        regw(ccdc_ctx[CCDC_SDOFST >> 2], CCDC_SDOFST);
 750        regw(ccdc_ctx[CCDC_SDR_ADDR >> 2], CCDC_SDR_ADDR);
 751        regw(ccdc_ctx[CCDC_CLAMP >> 2], CCDC_CLAMP);
 752        regw(ccdc_ctx[CCDC_DCSUB >> 2], CCDC_DCSUB);
 753        regw(ccdc_ctx[CCDC_COLPTN >> 2], CCDC_COLPTN);
 754        regw(ccdc_ctx[CCDC_BLKCMP >> 2], CCDC_BLKCMP);
 755        regw(ccdc_ctx[CCDC_FPC >> 2], CCDC_FPC);
 756        regw(ccdc_ctx[CCDC_FPC_ADDR >> 2], CCDC_FPC_ADDR);
 757        regw(ccdc_ctx[CCDC_VDINT >> 2], CCDC_VDINT);
 758        regw(ccdc_ctx[CCDC_ALAW >> 2], CCDC_ALAW);
 759        regw(ccdc_ctx[CCDC_REC656IF >> 2], CCDC_REC656IF);
 760        regw(ccdc_ctx[CCDC_CCDCFG >> 2], CCDC_CCDCFG);
 761        regw(ccdc_ctx[CCDC_FMTCFG >> 2], CCDC_FMTCFG);
 762        regw(ccdc_ctx[CCDC_FMT_HORZ >> 2], CCDC_FMT_HORZ);
 763        regw(ccdc_ctx[CCDC_FMT_VERT >> 2], CCDC_FMT_VERT);
 764        regw(ccdc_ctx[CCDC_FMT_ADDR0 >> 2], CCDC_FMT_ADDR0);
 765        regw(ccdc_ctx[CCDC_FMT_ADDR1 >> 2], CCDC_FMT_ADDR1);
 766        regw(ccdc_ctx[CCDC_FMT_ADDR2 >> 2], CCDC_FMT_ADDR2);
 767        regw(ccdc_ctx[CCDC_FMT_ADDR3 >> 2], CCDC_FMT_ADDR3);
 768        regw(ccdc_ctx[CCDC_FMT_ADDR4 >> 2], CCDC_FMT_ADDR4);
 769        regw(ccdc_ctx[CCDC_FMT_ADDR5 >> 2], CCDC_FMT_ADDR5);
 770        regw(ccdc_ctx[CCDC_FMT_ADDR6 >> 2], CCDC_FMT_ADDR6);
 771        regw(ccdc_ctx[CCDC_FMT_ADDR7 >> 2], CCDC_FMT_ADDR7);
 772        regw(ccdc_ctx[CCDC_PRGEVEN_0 >> 2], CCDC_PRGEVEN_0);
 773        regw(ccdc_ctx[CCDC_PRGEVEN_1 >> 2], CCDC_PRGEVEN_1);
 774        regw(ccdc_ctx[CCDC_PRGODD_0 >> 2], CCDC_PRGODD_0);
 775        regw(ccdc_ctx[CCDC_PRGODD_1 >> 2], CCDC_PRGODD_1);
 776        regw(ccdc_ctx[CCDC_VP_OUT >> 2], CCDC_VP_OUT);
 777        regw(ccdc_ctx[CCDC_PCR >> 2], CCDC_PCR);
 778}
 779static struct ccdc_hw_device ccdc_hw_dev = {
 780        .name = "DM6446 CCDC",
 781        .owner = THIS_MODULE,
 782        .hw_ops = {
 783                .open = ccdc_open,
 784                .close = ccdc_close,
 785                .reset = ccdc_sbl_reset,
 786                .enable = ccdc_enable,
 787                .set_hw_if_params = ccdc_set_hw_if_params,
 788                .configure = ccdc_configure,
 789                .set_buftype = ccdc_set_buftype,
 790                .get_buftype = ccdc_get_buftype,
 791                .enum_pix = ccdc_enum_pix,
 792                .set_pixel_format = ccdc_set_pixel_format,
 793                .get_pixel_format = ccdc_get_pixel_format,
 794                .set_frame_format = ccdc_set_frame_format,
 795                .get_frame_format = ccdc_get_frame_format,
 796                .set_image_window = ccdc_set_image_window,
 797                .get_image_window = ccdc_get_image_window,
 798                .get_line_length = ccdc_get_line_length,
 799                .setfbaddr = ccdc_setfbaddr,
 800                .getfid = ccdc_getfid,
 801        },
 802};
 803
 804static int dm644x_ccdc_probe(struct platform_device *pdev)
 805{
 806        struct resource *res;
 807        int status = 0;
 808
 809        /*
 810         * first try to register with vpfe. If not correct platform, then we
 811         * don't have to iomap
 812         */
 813        status = vpfe_register_ccdc_device(&ccdc_hw_dev);
 814        if (status < 0)
 815                return status;
 816
 817        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 818        if (!res) {
 819                status = -ENODEV;
 820                goto fail_nores;
 821        }
 822
 823        res = request_mem_region(res->start, resource_size(res), res->name);
 824        if (!res) {
 825                status = -EBUSY;
 826                goto fail_nores;
 827        }
 828
 829        ccdc_cfg.base_addr = ioremap_nocache(res->start, resource_size(res));
 830        if (!ccdc_cfg.base_addr) {
 831                status = -ENOMEM;
 832                goto fail_nomem;
 833        }
 834
 835        ccdc_cfg.dev = &pdev->dev;
 836        printk(KERN_NOTICE "%s is registered with vpfe.\n", ccdc_hw_dev.name);
 837        return 0;
 838fail_nomem:
 839        release_mem_region(res->start, resource_size(res));
 840fail_nores:
 841        vpfe_unregister_ccdc_device(&ccdc_hw_dev);
 842        return status;
 843}
 844
 845static int dm644x_ccdc_remove(struct platform_device *pdev)
 846{
 847        struct resource *res;
 848
 849        iounmap(ccdc_cfg.base_addr);
 850        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 851        if (res)
 852                release_mem_region(res->start, resource_size(res));
 853        vpfe_unregister_ccdc_device(&ccdc_hw_dev);
 854        return 0;
 855}
 856
 857static int dm644x_ccdc_suspend(struct device *dev)
 858{
 859        /* Save CCDC context */
 860        ccdc_save_context();
 861        /* Disable CCDC */
 862        ccdc_enable(0);
 863
 864        return 0;
 865}
 866
 867static int dm644x_ccdc_resume(struct device *dev)
 868{
 869        /* Restore CCDC context */
 870        ccdc_restore_context();
 871
 872        return 0;
 873}
 874
 875static const struct dev_pm_ops dm644x_ccdc_pm_ops = {
 876        .suspend = dm644x_ccdc_suspend,
 877        .resume = dm644x_ccdc_resume,
 878};
 879
 880static struct platform_driver dm644x_ccdc_driver = {
 881        .driver = {
 882                .name   = "dm644x_ccdc",
 883                .pm = &dm644x_ccdc_pm_ops,
 884        },
 885        .remove = dm644x_ccdc_remove,
 886        .probe = dm644x_ccdc_probe,
 887};
 888
 889module_platform_driver(dm644x_ccdc_driver);
 890