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