linux/drivers/media/platform/davinci/dm355_ccdc.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2005-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 DM355
  15 * ------------------------------
  16 *
  17 * This module is for configuring DM355 CCD controller of 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 Bayer RGB data, before writing it to SDRAM.
  21 *
  22 * TODO: 1) Raw bayer parameter settings and bayer capture
  23 *       2) Split module parameter structure to module specific ioctl structs
  24 *       3) add support for lense shading correction
  25 *       4) investigate if enum used for user space type definition
  26 *          to be replaced by #defines or integer
  27 */
  28#include <linux/platform_device.h>
  29#include <linux/uaccess.h>
  30#include <linux/videodev2.h>
  31#include <linux/err.h>
  32#include <linux/module.h>
  33
  34#include <media/davinci/dm355_ccdc.h>
  35#include <media/davinci/vpss.h>
  36
  37#include "dm355_ccdc_regs.h"
  38#include "ccdc_hw_device.h"
  39
  40MODULE_LICENSE("GPL");
  41MODULE_DESCRIPTION("CCDC Driver for DM355");
  42MODULE_AUTHOR("Texas Instruments");
  43
  44static struct ccdc_oper_config {
  45        struct device *dev;
  46        /* CCDC interface type */
  47        enum vpfe_hw_if_type if_type;
  48        /* Raw Bayer configuration */
  49        struct ccdc_params_raw bayer;
  50        /* YCbCr configuration */
  51        struct ccdc_params_ycbcr ycbcr;
  52        /* ccdc base address */
  53        void __iomem *base_addr;
  54} ccdc_cfg = {
  55        /* Raw configurations */
  56        .bayer = {
  57                .pix_fmt = CCDC_PIXFMT_RAW,
  58                .frm_fmt = CCDC_FRMFMT_PROGRESSIVE,
  59                .win = CCDC_WIN_VGA,
  60                .fid_pol = VPFE_PINPOL_POSITIVE,
  61                .vd_pol = VPFE_PINPOL_POSITIVE,
  62                .hd_pol = VPFE_PINPOL_POSITIVE,
  63                .gain = {
  64                        .r_ye = 256,
  65                        .gb_g = 256,
  66                        .gr_cy = 256,
  67                        .b_mg = 256
  68                },
  69                .config_params = {
  70                        .datasft = 2,
  71                        .mfilt1 = CCDC_NO_MEDIAN_FILTER1,
  72                        .mfilt2 = CCDC_NO_MEDIAN_FILTER2,
  73                        .alaw = {
  74                                .gamma_wd = 2,
  75                        },
  76                        .blk_clamp = {
  77                                .sample_pixel = 1,
  78                                .dc_sub = 25
  79                        },
  80                        .col_pat_field0 = {
  81                                .olop = CCDC_GREEN_BLUE,
  82                                .olep = CCDC_BLUE,
  83                                .elop = CCDC_RED,
  84                                .elep = CCDC_GREEN_RED
  85                        },
  86                        .col_pat_field1 = {
  87                                .olop = CCDC_GREEN_BLUE,
  88                                .olep = CCDC_BLUE,
  89                                .elop = CCDC_RED,
  90                                .elep = CCDC_GREEN_RED
  91                        },
  92                },
  93        },
  94        /* YCbCr configuration */
  95        .ycbcr = {
  96                .win = CCDC_WIN_PAL,
  97                .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT,
  98                .frm_fmt = CCDC_FRMFMT_INTERLACED,
  99                .fid_pol = VPFE_PINPOL_POSITIVE,
 100                .vd_pol = VPFE_PINPOL_POSITIVE,
 101                .hd_pol = VPFE_PINPOL_POSITIVE,
 102                .bt656_enable = 1,
 103                .pix_order = CCDC_PIXORDER_CBYCRY,
 104                .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED
 105        },
 106};
 107
 108
 109/* Raw Bayer formats */
 110static u32 ccdc_raw_bayer_pix_formats[] =
 111                {V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16};
 112
 113/* Raw YUV formats */
 114static u32 ccdc_raw_yuv_pix_formats[] =
 115                {V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV};
 116
 117/* register access routines */
 118static inline u32 regr(u32 offset)
 119{
 120        return __raw_readl(ccdc_cfg.base_addr + offset);
 121}
 122
 123static inline void regw(u32 val, u32 offset)
 124{
 125        __raw_writel(val, ccdc_cfg.base_addr + offset);
 126}
 127
 128static void ccdc_enable(int en)
 129{
 130        unsigned int temp;
 131        temp = regr(SYNCEN);
 132        temp &= (~CCDC_SYNCEN_VDHDEN_MASK);
 133        temp |= (en & CCDC_SYNCEN_VDHDEN_MASK);
 134        regw(temp, SYNCEN);
 135}
 136
 137static void ccdc_enable_output_to_sdram(int en)
 138{
 139        unsigned int temp;
 140        temp = regr(SYNCEN);
 141        temp &= (~(CCDC_SYNCEN_WEN_MASK));
 142        temp |= ((en << CCDC_SYNCEN_WEN_SHIFT) & CCDC_SYNCEN_WEN_MASK);
 143        regw(temp, SYNCEN);
 144}
 145
 146static void ccdc_config_gain_offset(void)
 147{
 148        /* configure gain */
 149        regw(ccdc_cfg.bayer.gain.r_ye, RYEGAIN);
 150        regw(ccdc_cfg.bayer.gain.gr_cy, GRCYGAIN);
 151        regw(ccdc_cfg.bayer.gain.gb_g, GBGGAIN);
 152        regw(ccdc_cfg.bayer.gain.b_mg, BMGGAIN);
 153        /* configure offset */
 154        regw(ccdc_cfg.bayer.ccdc_offset, OFFSET);
 155}
 156
 157/*
 158 * ccdc_restore_defaults()
 159 * This function restore power on defaults in the ccdc registers
 160 */
 161static int ccdc_restore_defaults(void)
 162{
 163        int i;
 164
 165        dev_dbg(ccdc_cfg.dev, "\nstarting ccdc_restore_defaults...");
 166        /* set all registers to zero */
 167        for (i = 0; i <= CCDC_REG_LAST; i += 4)
 168                regw(0, i);
 169
 170        /* now override the values with power on defaults in registers */
 171        regw(MODESET_DEFAULT, MODESET);
 172        /* no culling support */
 173        regw(CULH_DEFAULT, CULH);
 174        regw(CULV_DEFAULT, CULV);
 175        /* Set default Gain and Offset */
 176        ccdc_cfg.bayer.gain.r_ye = GAIN_DEFAULT;
 177        ccdc_cfg.bayer.gain.gb_g = GAIN_DEFAULT;
 178        ccdc_cfg.bayer.gain.gr_cy = GAIN_DEFAULT;
 179        ccdc_cfg.bayer.gain.b_mg = GAIN_DEFAULT;
 180        ccdc_config_gain_offset();
 181        regw(OUTCLIP_DEFAULT, OUTCLIP);
 182        regw(LSCCFG2_DEFAULT, LSCCFG2);
 183        /* select ccdc input */
 184        if (vpss_select_ccdc_source(VPSS_CCDCIN)) {
 185                dev_dbg(ccdc_cfg.dev, "\ncouldn't select ccdc input source");
 186                return -EFAULT;
 187        }
 188        /* select ccdc clock */
 189        if (vpss_enable_clock(VPSS_CCDC_CLOCK, 1) < 0) {
 190                dev_dbg(ccdc_cfg.dev, "\ncouldn't enable ccdc clock");
 191                return -EFAULT;
 192        }
 193        dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_restore_defaults...");
 194        return 0;
 195}
 196
 197static int ccdc_open(struct device *device)
 198{
 199        return ccdc_restore_defaults();
 200}
 201
 202static int ccdc_close(struct device *device)
 203{
 204        /* disable clock */
 205        vpss_enable_clock(VPSS_CCDC_CLOCK, 0);
 206        /* do nothing for now */
 207        return 0;
 208}
 209/*
 210 * ccdc_setwin()
 211 * This function will configure the window size to
 212 * be capture in CCDC reg.
 213 */
 214static void ccdc_setwin(struct v4l2_rect *image_win,
 215                        enum ccdc_frmfmt frm_fmt, int ppc)
 216{
 217        int horz_start, horz_nr_pixels;
 218        int vert_start, vert_nr_lines;
 219        int mid_img = 0;
 220
 221        dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_setwin...");
 222
 223        /*
 224         * ppc - per pixel count. indicates how many pixels per cell
 225         * output to SDRAM. example, for ycbcr, it is one y and one c, so 2.
 226         * raw capture this is 1
 227         */
 228        horz_start = image_win->left << (ppc - 1);
 229        horz_nr_pixels = ((image_win->width) << (ppc - 1)) - 1;
 230
 231        /* Writing the horizontal info into the registers */
 232        regw(horz_start, SPH);
 233        regw(horz_nr_pixels, NPH);
 234        vert_start = image_win->top;
 235
 236        if (frm_fmt == CCDC_FRMFMT_INTERLACED) {
 237                vert_nr_lines = (image_win->height >> 1) - 1;
 238                vert_start >>= 1;
 239                /* Since first line doesn't have any data */
 240                vert_start += 1;
 241                /* configure VDINT0 and VDINT1 */
 242                regw(vert_start, VDINT0);
 243        } else {
 244                /* Since first line doesn't have any data */
 245                vert_start += 1;
 246                vert_nr_lines = image_win->height - 1;
 247                /* configure VDINT0 and VDINT1 */
 248                mid_img = vert_start + (image_win->height / 2);
 249                regw(vert_start, VDINT0);
 250                regw(mid_img, VDINT1);
 251        }
 252        regw(vert_start & CCDC_START_VER_ONE_MASK, SLV0);
 253        regw(vert_start & CCDC_START_VER_TWO_MASK, SLV1);
 254        regw(vert_nr_lines & CCDC_NUM_LINES_VER, NLV);
 255        dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_setwin...");
 256}
 257
 258/* This function will configure CCDC for YCbCr video capture */
 259static void ccdc_config_ycbcr(void)
 260{
 261        struct ccdc_params_ycbcr *params = &ccdc_cfg.ycbcr;
 262        u32 temp;
 263
 264        /* first set the CCDC power on defaults values in all registers */
 265        dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_ycbcr...");
 266        ccdc_restore_defaults();
 267
 268        /* configure pixel format & video frame format */
 269        temp = (((params->pix_fmt & CCDC_INPUT_MODE_MASK) <<
 270                CCDC_INPUT_MODE_SHIFT) |
 271                ((params->frm_fmt & CCDC_FRM_FMT_MASK) <<
 272                CCDC_FRM_FMT_SHIFT));
 273
 274        /* setup BT.656 sync mode */
 275        if (params->bt656_enable) {
 276                regw(CCDC_REC656IF_BT656_EN, REC656IF);
 277                /*
 278                 * configure the FID, VD, HD pin polarity fld,hd pol positive,
 279                 * vd negative, 8-bit pack mode
 280                 */
 281                temp |= CCDC_VD_POL_NEGATIVE;
 282        } else {                /* y/c external sync mode */
 283                temp |= (((params->fid_pol & CCDC_FID_POL_MASK) <<
 284                        CCDC_FID_POL_SHIFT) |
 285                        ((params->hd_pol & CCDC_HD_POL_MASK) <<
 286                        CCDC_HD_POL_SHIFT) |
 287                        ((params->vd_pol & CCDC_VD_POL_MASK) <<
 288                        CCDC_VD_POL_SHIFT));
 289        }
 290
 291        /* pack the data to 8-bit */
 292        temp |= CCDC_DATA_PACK_ENABLE;
 293
 294        regw(temp, MODESET);
 295
 296        /* configure video window */
 297        ccdc_setwin(&params->win, params->frm_fmt, 2);
 298
 299        /* configure the order of y cb cr in SD-RAM */
 300        temp = (params->pix_order << CCDC_Y8POS_SHIFT);
 301        temp |= CCDC_LATCH_ON_VSYNC_DISABLE | CCDC_CCDCFG_FIDMD_NO_LATCH_VSYNC;
 302        regw(temp, CCDCFG);
 303
 304        /*
 305         * configure the horizontal line offset. This is done by rounding up
 306         * width to a multiple of 16 pixels and multiply by two to account for
 307         * y:cb:cr 4:2:2 data
 308         */
 309        regw(((params->win.width * 2 + 31) >> 5), HSIZE);
 310
 311        /* configure the memory line offset */
 312        if (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED) {
 313                /* two fields are interleaved in memory */
 314                regw(CCDC_SDOFST_FIELD_INTERLEAVED, SDOFST);
 315        }
 316
 317        dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_config_ycbcr...\n");
 318}
 319
 320/*
 321 * ccdc_config_black_clamp()
 322 * configure parameters for Optical Black Clamp
 323 */
 324static void ccdc_config_black_clamp(struct ccdc_black_clamp *bclamp)
 325{
 326        u32 val;
 327
 328        if (!bclamp->b_clamp_enable) {
 329                /* configure DCSub */
 330                regw(bclamp->dc_sub & CCDC_BLK_DC_SUB_MASK, DCSUB);
 331                regw(0x0000, CLAMP);
 332                return;
 333        }
 334        /* Enable the Black clamping, set sample lines and pixels */
 335        val = (bclamp->start_pixel & CCDC_BLK_ST_PXL_MASK) |
 336              ((bclamp->sample_pixel & CCDC_BLK_SAMPLE_LN_MASK) <<
 337                CCDC_BLK_SAMPLE_LN_SHIFT) | CCDC_BLK_CLAMP_ENABLE;
 338        regw(val, CLAMP);
 339
 340        /* If Black clamping is enable then make dcsub 0 */
 341        val = (bclamp->sample_ln & CCDC_NUM_LINE_CALC_MASK)
 342                        << CCDC_NUM_LINE_CALC_SHIFT;
 343        regw(val, DCSUB);
 344}
 345
 346/*
 347 * ccdc_config_black_compense()
 348 * configure parameters for Black Compensation
 349 */
 350static void ccdc_config_black_compense(struct ccdc_black_compensation *bcomp)
 351{
 352        u32 val;
 353
 354        val = (bcomp->b & CCDC_BLK_COMP_MASK) |
 355                ((bcomp->gb & CCDC_BLK_COMP_MASK) <<
 356                CCDC_BLK_COMP_GB_COMP_SHIFT);
 357        regw(val, BLKCMP1);
 358
 359        val = ((bcomp->gr & CCDC_BLK_COMP_MASK) <<
 360                CCDC_BLK_COMP_GR_COMP_SHIFT) |
 361                ((bcomp->r & CCDC_BLK_COMP_MASK) <<
 362                CCDC_BLK_COMP_R_COMP_SHIFT);
 363        regw(val, BLKCMP0);
 364}
 365
 366/*
 367 * ccdc_write_dfc_entry()
 368 * write an entry in the dfc table.
 369 */
 370static int ccdc_write_dfc_entry(int index, struct ccdc_vertical_dft *dfc)
 371{
 372/* TODO This is to be re-visited and adjusted */
 373#define DFC_WRITE_WAIT_COUNT    1000
 374        u32 val, count = DFC_WRITE_WAIT_COUNT;
 375
 376        regw(dfc->dft_corr_vert[index], DFCMEM0);
 377        regw(dfc->dft_corr_horz[index], DFCMEM1);
 378        regw(dfc->dft_corr_sub1[index], DFCMEM2);
 379        regw(dfc->dft_corr_sub2[index], DFCMEM3);
 380        regw(dfc->dft_corr_sub3[index], DFCMEM4);
 381        /* set WR bit to write */
 382        val = regr(DFCMEMCTL) | CCDC_DFCMEMCTL_DFCMWR_MASK;
 383        regw(val, DFCMEMCTL);
 384
 385        /*
 386         * Assume, it is very short. If we get an error, we need to
 387         * adjust this value
 388         */
 389        while (regr(DFCMEMCTL) & CCDC_DFCMEMCTL_DFCMWR_MASK)
 390                count--;
 391        /*
 392         * TODO We expect the count to be non-zero to be successful. Adjust
 393         * the count if write requires more time
 394         */
 395
 396        if (count) {
 397                dev_err(ccdc_cfg.dev, "defect table write timeout !!!\n");
 398                return -1;
 399        }
 400        return 0;
 401}
 402
 403/*
 404 * ccdc_config_vdfc()
 405 * configure parameters for Vertical Defect Correction
 406 */
 407static int ccdc_config_vdfc(struct ccdc_vertical_dft *dfc)
 408{
 409        u32 val;
 410        int i;
 411
 412        /* Configure General Defect Correction. The table used is from IPIPE */
 413        val = dfc->gen_dft_en & CCDC_DFCCTL_GDFCEN_MASK;
 414
 415        /* Configure Vertical Defect Correction if needed */
 416        if (!dfc->ver_dft_en) {
 417                /* Enable only General Defect Correction */
 418                regw(val, DFCCTL);
 419                return 0;
 420        }
 421
 422        if (dfc->table_size > CCDC_DFT_TABLE_SIZE)
 423                return -EINVAL;
 424
 425        val |= CCDC_DFCCTL_VDFC_DISABLE;
 426        val |= (dfc->dft_corr_ctl.vdfcsl & CCDC_DFCCTL_VDFCSL_MASK) <<
 427                CCDC_DFCCTL_VDFCSL_SHIFT;
 428        val |= (dfc->dft_corr_ctl.vdfcuda & CCDC_DFCCTL_VDFCUDA_MASK) <<
 429                CCDC_DFCCTL_VDFCUDA_SHIFT;
 430        val |= (dfc->dft_corr_ctl.vdflsft & CCDC_DFCCTL_VDFLSFT_MASK) <<
 431                CCDC_DFCCTL_VDFLSFT_SHIFT;
 432        regw(val , DFCCTL);
 433
 434        /* clear address ptr to offset 0 */
 435        val = CCDC_DFCMEMCTL_DFCMARST_MASK << CCDC_DFCMEMCTL_DFCMARST_SHIFT;
 436
 437        /* write defect table entries */
 438        for (i = 0; i < dfc->table_size; i++) {
 439                /* increment address for non zero index */
 440                if (i != 0)
 441                        val = CCDC_DFCMEMCTL_INC_ADDR;
 442                regw(val, DFCMEMCTL);
 443                if (ccdc_write_dfc_entry(i, dfc) < 0)
 444                        return -EFAULT;
 445        }
 446
 447        /* update saturation level and enable dfc */
 448        regw(dfc->saturation_ctl & CCDC_VDC_DFCVSAT_MASK, DFCVSAT);
 449        val = regr(DFCCTL) | (CCDC_DFCCTL_VDFCEN_MASK <<
 450                        CCDC_DFCCTL_VDFCEN_SHIFT);
 451        regw(val, DFCCTL);
 452        return 0;
 453}
 454
 455/*
 456 * ccdc_config_csc()
 457 * configure parameters for color space conversion
 458 * Each register CSCM0-7 has two values in S8Q5 format.
 459 */
 460static void ccdc_config_csc(struct ccdc_csc *csc)
 461{
 462        u32 val1 = 0, val2;
 463        int i;
 464
 465        if (!csc->enable)
 466                return;
 467
 468        /* Enable the CSC sub-module */
 469        regw(CCDC_CSC_ENABLE, CSCCTL);
 470
 471        /* Converting the co-eff as per the format of the register */
 472        for (i = 0; i < CCDC_CSC_COEFF_TABLE_SIZE; i++) {
 473                if ((i % 2) == 0) {
 474                        /* CSCM - LSB */
 475                        val1 = (csc->coeff[i].integer &
 476                                CCDC_CSC_COEF_INTEG_MASK)
 477                                << CCDC_CSC_COEF_INTEG_SHIFT;
 478                        /*
 479                         * convert decimal part to binary. Use 2 decimal
 480                         * precision, user values range from .00 - 0.99
 481                         */
 482                        val1 |= (((csc->coeff[i].decimal &
 483                                CCDC_CSC_COEF_DECIMAL_MASK) *
 484                                CCDC_CSC_DEC_MAX) / 100);
 485                } else {
 486
 487                        /* CSCM - MSB */
 488                        val2 = (csc->coeff[i].integer &
 489                                CCDC_CSC_COEF_INTEG_MASK)
 490                                << CCDC_CSC_COEF_INTEG_SHIFT;
 491                        val2 |= (((csc->coeff[i].decimal &
 492                                 CCDC_CSC_COEF_DECIMAL_MASK) *
 493                                 CCDC_CSC_DEC_MAX) / 100);
 494                        val2 <<= CCDC_CSCM_MSB_SHIFT;
 495                        val2 |= val1;
 496                        regw(val2, (CSCM0 + ((i - 1) << 1)));
 497                }
 498        }
 499}
 500
 501/*
 502 * ccdc_config_color_patterns()
 503 * configure parameters for color patterns
 504 */
 505static void ccdc_config_color_patterns(struct ccdc_col_pat *pat0,
 506                                       struct ccdc_col_pat *pat1)
 507{
 508        u32 val;
 509
 510        val = (pat0->olop | (pat0->olep << 2) | (pat0->elop << 4) |
 511                (pat0->elep << 6) | (pat1->olop << 8) | (pat1->olep << 10) |
 512                (pat1->elop << 12) | (pat1->elep << 14));
 513        regw(val, COLPTN);
 514}
 515
 516/* This function will configure CCDC for Raw mode image capture */
 517static int ccdc_config_raw(void)
 518{
 519        struct ccdc_params_raw *params = &ccdc_cfg.bayer;
 520        struct ccdc_config_params_raw *config_params =
 521                                        &ccdc_cfg.bayer.config_params;
 522        unsigned int val;
 523
 524        dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_raw...");
 525
 526        /* restore power on defaults to register */
 527        ccdc_restore_defaults();
 528
 529        /* CCDCFG register:
 530         * set CCD Not to swap input since input is RAW data
 531         * set FID detection function to Latch at V-Sync
 532         * set WENLOG - ccdc valid area to AND
 533         * set TRGSEL to WENBIT
 534         * set EXTRG to DISABLE
 535         * disable latching function on VSYNC - shadowed registers
 536         */
 537        regw(CCDC_YCINSWP_RAW | CCDC_CCDCFG_FIDMD_LATCH_VSYNC |
 538             CCDC_CCDCFG_WENLOG_AND | CCDC_CCDCFG_TRGSEL_WEN |
 539             CCDC_CCDCFG_EXTRG_DISABLE | CCDC_LATCH_ON_VSYNC_DISABLE, CCDCFG);
 540
 541        /*
 542         * Set VDHD direction to input,  input type to raw input
 543         * normal data polarity, do not use external WEN
 544         */
 545        val = (CCDC_VDHDOUT_INPUT | CCDC_RAW_IP_MODE | CCDC_DATAPOL_NORMAL |
 546                CCDC_EXWEN_DISABLE);
 547
 548        /*
 549         * Configure the vertical sync polarity (MODESET.VDPOL), horizontal
 550         * sync polarity (MODESET.HDPOL), field id polarity (MODESET.FLDPOL),
 551         * frame format(progressive or interlace), & pixel format (Input mode)
 552         */
 553        val |= (((params->vd_pol & CCDC_VD_POL_MASK) << CCDC_VD_POL_SHIFT) |
 554                ((params->hd_pol & CCDC_HD_POL_MASK) << CCDC_HD_POL_SHIFT) |
 555                ((params->fid_pol & CCDC_FID_POL_MASK) << CCDC_FID_POL_SHIFT) |
 556                ((params->frm_fmt & CCDC_FRM_FMT_MASK) << CCDC_FRM_FMT_SHIFT) |
 557                ((params->pix_fmt & CCDC_PIX_FMT_MASK) << CCDC_PIX_FMT_SHIFT));
 558
 559        /* set pack for alaw compression */
 560        if ((config_params->data_sz == CCDC_DATA_8BITS) ||
 561             config_params->alaw.enable)
 562                val |= CCDC_DATA_PACK_ENABLE;
 563
 564        /* Configure for LPF */
 565        if (config_params->lpf_enable)
 566                val |= (config_params->lpf_enable & CCDC_LPF_MASK) <<
 567                        CCDC_LPF_SHIFT;
 568
 569        /* Configure the data shift */
 570        val |= (config_params->datasft & CCDC_DATASFT_MASK) <<
 571                CCDC_DATASFT_SHIFT;
 572        regw(val , MODESET);
 573        dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to MODESET...\n", val);
 574
 575        /* Configure the Median Filter threshold */
 576        regw((config_params->med_filt_thres) & CCDC_MED_FILT_THRESH, MEDFILT);
 577
 578        /* Configure GAMMAWD register. defaur 11-2, and Mosaic cfa pattern */
 579        val = CCDC_GAMMA_BITS_11_2 << CCDC_GAMMAWD_INPUT_SHIFT |
 580                CCDC_CFA_MOSAIC;
 581
 582        /* Enable and configure aLaw register if needed */
 583        if (config_params->alaw.enable) {
 584                val |= (CCDC_ALAW_ENABLE |
 585                        ((config_params->alaw.gamma_wd &
 586                        CCDC_ALAW_GAMMA_WD_MASK) <<
 587                        CCDC_GAMMAWD_INPUT_SHIFT));
 588        }
 589
 590        /* Configure Median filter1 & filter2 */
 591        val |= ((config_params->mfilt1 << CCDC_MFILT1_SHIFT) |
 592                (config_params->mfilt2 << CCDC_MFILT2_SHIFT));
 593
 594        regw(val, GAMMAWD);
 595        dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to GAMMAWD...\n", val);
 596
 597        /* configure video window */
 598        ccdc_setwin(&params->win, params->frm_fmt, 1);
 599
 600        /* Optical Clamp Averaging */
 601        ccdc_config_black_clamp(&config_params->blk_clamp);
 602
 603        /* Black level compensation */
 604        ccdc_config_black_compense(&config_params->blk_comp);
 605
 606        /* Vertical Defect Correction if needed */
 607        if (ccdc_config_vdfc(&config_params->vertical_dft) < 0)
 608                return -EFAULT;
 609
 610        /* color space conversion */
 611        ccdc_config_csc(&config_params->csc);
 612
 613        /* color pattern */
 614        ccdc_config_color_patterns(&config_params->col_pat_field0,
 615                                   &config_params->col_pat_field1);
 616
 617        /* Configure the Gain  & offset control */
 618        ccdc_config_gain_offset();
 619
 620        dev_dbg(ccdc_cfg.dev, "\nWriting %x to COLPTN...\n", val);
 621
 622        /* Configure DATAOFST  register */
 623        val = (config_params->data_offset.horz_offset & CCDC_DATAOFST_MASK) <<
 624                CCDC_DATAOFST_H_SHIFT;
 625        val |= (config_params->data_offset.vert_offset & CCDC_DATAOFST_MASK) <<
 626                CCDC_DATAOFST_V_SHIFT;
 627        regw(val, DATAOFST);
 628
 629        /* configuring HSIZE register */
 630        val = (params->horz_flip_enable & CCDC_HSIZE_FLIP_MASK) <<
 631                CCDC_HSIZE_FLIP_SHIFT;
 632
 633        /* If pack 8 is enable then 1 pixel will take 1 byte */
 634        if ((config_params->data_sz == CCDC_DATA_8BITS) ||
 635             config_params->alaw.enable) {
 636                val |= (((params->win.width) + 31) >> 5) &
 637                        CCDC_HSIZE_VAL_MASK;
 638
 639                /* adjust to multiple of 32 */
 640                dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to HSIZE...\n",
 641                       (((params->win.width) + 31) >> 5) &
 642                        CCDC_HSIZE_VAL_MASK);
 643        } else {
 644                /* else one pixel will take 2 byte */
 645                val |= (((params->win.width * 2) + 31) >> 5) &
 646                        CCDC_HSIZE_VAL_MASK;
 647
 648                dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to HSIZE...\n",
 649                       (((params->win.width * 2) + 31) >> 5) &
 650                        CCDC_HSIZE_VAL_MASK);
 651        }
 652        regw(val, HSIZE);
 653
 654        /* Configure SDOFST register */
 655        if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) {
 656                if (params->image_invert_enable) {
 657                        /* For interlace inverse mode */
 658                        regw(CCDC_SDOFST_INTERLACE_INVERSE, SDOFST);
 659                        dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n",
 660                                CCDC_SDOFST_INTERLACE_INVERSE);
 661                } else {
 662                        /* For interlace non inverse mode */
 663                        regw(CCDC_SDOFST_INTERLACE_NORMAL, SDOFST);
 664                        dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n",
 665                                CCDC_SDOFST_INTERLACE_NORMAL);
 666                }
 667        } else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) {
 668                if (params->image_invert_enable) {
 669                        /* For progessive inverse mode */
 670                        regw(CCDC_SDOFST_PROGRESSIVE_INVERSE, SDOFST);
 671                        dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n",
 672                                CCDC_SDOFST_PROGRESSIVE_INVERSE);
 673                } else {
 674                        /* For progessive non inverse mode */
 675                        regw(CCDC_SDOFST_PROGRESSIVE_NORMAL, SDOFST);
 676                        dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n",
 677                                CCDC_SDOFST_PROGRESSIVE_NORMAL);
 678                }
 679        }
 680        dev_dbg(ccdc_cfg.dev, "\nend of ccdc_config_raw...");
 681        return 0;
 682}
 683
 684static int ccdc_configure(void)
 685{
 686        if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
 687                return ccdc_config_raw();
 688        else
 689                ccdc_config_ycbcr();
 690        return 0;
 691}
 692
 693static int ccdc_set_buftype(enum ccdc_buftype buf_type)
 694{
 695        if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
 696                ccdc_cfg.bayer.buf_type = buf_type;
 697        else
 698                ccdc_cfg.ycbcr.buf_type = buf_type;
 699        return 0;
 700}
 701static enum ccdc_buftype ccdc_get_buftype(void)
 702{
 703        if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
 704                return ccdc_cfg.bayer.buf_type;
 705        return ccdc_cfg.ycbcr.buf_type;
 706}
 707
 708static int ccdc_enum_pix(u32 *pix, int i)
 709{
 710        int ret = -EINVAL;
 711        if (ccdc_cfg.if_type == VPFE_RAW_BAYER) {
 712                if (i < ARRAY_SIZE(ccdc_raw_bayer_pix_formats)) {
 713                        *pix = ccdc_raw_bayer_pix_formats[i];
 714                        ret = 0;
 715                }
 716        } else {
 717                if (i < ARRAY_SIZE(ccdc_raw_yuv_pix_formats)) {
 718                        *pix = ccdc_raw_yuv_pix_formats[i];
 719                        ret = 0;
 720                }
 721        }
 722        return ret;
 723}
 724
 725static int ccdc_set_pixel_format(u32 pixfmt)
 726{
 727        struct ccdc_a_law *alaw = &ccdc_cfg.bayer.config_params.alaw;
 728
 729        if (ccdc_cfg.if_type == VPFE_RAW_BAYER) {
 730                ccdc_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW;
 731                if (pixfmt == V4L2_PIX_FMT_SBGGR8)
 732                        alaw->enable = 1;
 733                else if (pixfmt != V4L2_PIX_FMT_SBGGR16)
 734                        return -EINVAL;
 735        } else {
 736                if (pixfmt == V4L2_PIX_FMT_YUYV)
 737                        ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR;
 738                else if (pixfmt == V4L2_PIX_FMT_UYVY)
 739                        ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;
 740                else
 741                        return -EINVAL;
 742        }
 743        return 0;
 744}
 745static u32 ccdc_get_pixel_format(void)
 746{
 747        struct ccdc_a_law *alaw = &ccdc_cfg.bayer.config_params.alaw;
 748        u32 pixfmt;
 749
 750        if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
 751                if (alaw->enable)
 752                        pixfmt = V4L2_PIX_FMT_SBGGR8;
 753                else
 754                        pixfmt = V4L2_PIX_FMT_SBGGR16;
 755        else {
 756                if (ccdc_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR)
 757                        pixfmt = V4L2_PIX_FMT_YUYV;
 758                else
 759                        pixfmt = V4L2_PIX_FMT_UYVY;
 760        }
 761        return pixfmt;
 762}
 763static int ccdc_set_image_window(struct v4l2_rect *win)
 764{
 765        if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
 766                ccdc_cfg.bayer.win = *win;
 767        else
 768                ccdc_cfg.ycbcr.win = *win;
 769        return 0;
 770}
 771
 772static void ccdc_get_image_window(struct v4l2_rect *win)
 773{
 774        if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
 775                *win = ccdc_cfg.bayer.win;
 776        else
 777                *win = ccdc_cfg.ycbcr.win;
 778}
 779
 780static unsigned int ccdc_get_line_length(void)
 781{
 782        struct ccdc_config_params_raw *config_params =
 783                                &ccdc_cfg.bayer.config_params;
 784        unsigned int len;
 785
 786        if (ccdc_cfg.if_type == VPFE_RAW_BAYER) {
 787                if ((config_params->alaw.enable) ||
 788                    (config_params->data_sz == CCDC_DATA_8BITS))
 789                        len = ccdc_cfg.bayer.win.width;
 790                else
 791                        len = ccdc_cfg.bayer.win.width * 2;
 792        } else
 793                len = ccdc_cfg.ycbcr.win.width * 2;
 794        return ALIGN(len, 32);
 795}
 796
 797static int ccdc_set_frame_format(enum ccdc_frmfmt frm_fmt)
 798{
 799        if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
 800                ccdc_cfg.bayer.frm_fmt = frm_fmt;
 801        else
 802                ccdc_cfg.ycbcr.frm_fmt = frm_fmt;
 803        return 0;
 804}
 805
 806static enum ccdc_frmfmt ccdc_get_frame_format(void)
 807{
 808        if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
 809                return ccdc_cfg.bayer.frm_fmt;
 810        else
 811                return ccdc_cfg.ycbcr.frm_fmt;
 812}
 813
 814static int ccdc_getfid(void)
 815{
 816        return  (regr(MODESET) >> 15) & 1;
 817}
 818
 819/* misc operations */
 820static inline void ccdc_setfbaddr(unsigned long addr)
 821{
 822        regw((addr >> 21) & 0x007f, STADRH);
 823        regw((addr >> 5) & 0x0ffff, STADRL);
 824}
 825
 826static int ccdc_set_hw_if_params(struct vpfe_hw_if_param *params)
 827{
 828        ccdc_cfg.if_type = params->if_type;
 829
 830        switch (params->if_type) {
 831        case VPFE_BT656:
 832        case VPFE_YCBCR_SYNC_16:
 833        case VPFE_YCBCR_SYNC_8:
 834                ccdc_cfg.ycbcr.vd_pol = params->vdpol;
 835                ccdc_cfg.ycbcr.hd_pol = params->hdpol;
 836                break;
 837        default:
 838                /* TODO add support for raw bayer here */
 839                return -EINVAL;
 840        }
 841        return 0;
 842}
 843
 844static const struct ccdc_hw_device ccdc_hw_dev = {
 845        .name = "DM355 CCDC",
 846        .owner = THIS_MODULE,
 847        .hw_ops = {
 848                .open = ccdc_open,
 849                .close = ccdc_close,
 850                .enable = ccdc_enable,
 851                .enable_out_to_sdram = ccdc_enable_output_to_sdram,
 852                .set_hw_if_params = ccdc_set_hw_if_params,
 853                .configure = ccdc_configure,
 854                .set_buftype = ccdc_set_buftype,
 855                .get_buftype = ccdc_get_buftype,
 856                .enum_pix = ccdc_enum_pix,
 857                .set_pixel_format = ccdc_set_pixel_format,
 858                .get_pixel_format = ccdc_get_pixel_format,
 859                .set_frame_format = ccdc_set_frame_format,
 860                .get_frame_format = ccdc_get_frame_format,
 861                .set_image_window = ccdc_set_image_window,
 862                .get_image_window = ccdc_get_image_window,
 863                .get_line_length = ccdc_get_line_length,
 864                .setfbaddr = ccdc_setfbaddr,
 865                .getfid = ccdc_getfid,
 866        },
 867};
 868
 869static int dm355_ccdc_probe(struct platform_device *pdev)
 870{
 871        void (*setup_pinmux)(void);
 872        struct resource *res;
 873        int status = 0;
 874
 875        /*
 876         * first try to register with vpfe. If not correct platform, then we
 877         * don't have to iomap
 878         */
 879        status = vpfe_register_ccdc_device(&ccdc_hw_dev);
 880        if (status < 0)
 881                return status;
 882
 883        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 884        if (!res) {
 885                status = -ENODEV;
 886                goto fail_nores;
 887        }
 888
 889        res = request_mem_region(res->start, resource_size(res), res->name);
 890        if (!res) {
 891                status = -EBUSY;
 892                goto fail_nores;
 893        }
 894
 895        ccdc_cfg.base_addr = ioremap_nocache(res->start, resource_size(res));
 896        if (!ccdc_cfg.base_addr) {
 897                status = -ENOMEM;
 898                goto fail_nomem;
 899        }
 900
 901        /* Platform data holds setup_pinmux function ptr */
 902        if (NULL == pdev->dev.platform_data) {
 903                status = -ENODEV;
 904                goto fail_nomap;
 905        }
 906        setup_pinmux = pdev->dev.platform_data;
 907        /*
 908         * setup Mux configuration for ccdc which may be different for
 909         * different SoCs using this CCDC
 910         */
 911        setup_pinmux();
 912        ccdc_cfg.dev = &pdev->dev;
 913        printk(KERN_NOTICE "%s is registered with vpfe.\n", ccdc_hw_dev.name);
 914        return 0;
 915fail_nomap:
 916        iounmap(ccdc_cfg.base_addr);
 917fail_nomem:
 918        release_mem_region(res->start, resource_size(res));
 919fail_nores:
 920        vpfe_unregister_ccdc_device(&ccdc_hw_dev);
 921        return status;
 922}
 923
 924static int dm355_ccdc_remove(struct platform_device *pdev)
 925{
 926        struct resource *res;
 927
 928        iounmap(ccdc_cfg.base_addr);
 929        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 930        if (res)
 931                release_mem_region(res->start, resource_size(res));
 932        vpfe_unregister_ccdc_device(&ccdc_hw_dev);
 933        return 0;
 934}
 935
 936static struct platform_driver dm355_ccdc_driver = {
 937        .driver = {
 938                .name   = "dm355_ccdc",
 939        },
 940        .remove = dm355_ccdc_remove,
 941        .probe = dm355_ccdc_probe,
 942};
 943
 944module_platform_driver(dm355_ccdc_driver);
 945