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