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