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