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