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