1 /*
2  * Copyright (C) 2008-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  * Image Sensor Interface (ISIF) driver
19  *
20  * This driver is for configuring the ISIF IP available on DM365 or any other
21  * TI SoCs. This is used for capturing yuv or bayer video or image data
22  * from a decoder or sensor. This IP is similar to the CCDC IP on DM355
23  * and DM6446, but with enhanced or additional ip blocks. The driver
24  * configures the ISIF upon commands from the vpfe bridge driver through
25  * ccdc_hw_device interface.
26  *
27  * TODO: 1) Raw bayer parameter settings and bayer capture
28  *	 2) Add support for control ioctl
29  */
30 #include <linux/delay.h>
31 #include <linux/platform_device.h>
32 #include <linux/uaccess.h>
33 #include <linux/io.h>
34 #include <linux/videodev2.h>
35 #include <linux/clk.h>
36 #include <linux/err.h>
37 #include <linux/module.h>
38 
39 #include <mach/mux.h>
40 
41 #include <media/davinci/isif.h>
42 #include <media/davinci/vpss.h>
43 
44 #include "isif_regs.h"
45 #include "ccdc_hw_device.h"
46 
47 /* Defaults for module configuration parameters */
48 static struct isif_config_params_raw isif_config_defaults = {
49 	.linearize = {
50 		.en = 0,
51 		.corr_shft = ISIF_NO_SHIFT,
52 		.scale_fact = {1, 0},
53 	},
54 	.df_csc = {
55 		.df_or_csc = 0,
56 		.csc = {
57 			.en = 0,
58 		},
59 	},
60 	.dfc = {
61 		.en = 0,
62 	},
63 	.bclamp = {
64 		.en = 0,
65 	},
66 	.gain_offset = {
67 		.gain = {
68 			.r_ye = {1, 0},
69 			.gr_cy = {1, 0},
70 			.gb_g = {1, 0},
71 			.b_mg = {1, 0},
72 		},
73 	},
74 	.culling = {
75 		.hcpat_odd = 0xff,
76 		.hcpat_even = 0xff,
77 		.vcpat = 0xff,
78 	},
79 	.compress = {
80 		.alg = ISIF_ALAW,
81 	},
82 };
83 
84 /* ISIF operation configuration */
85 static struct isif_oper_config {
86 	struct device *dev;
87 	enum vpfe_hw_if_type if_type;
88 	struct isif_ycbcr_config ycbcr;
89 	struct isif_params_raw bayer;
90 	enum isif_data_pack data_pack;
91 	/* Master clock */
92 	struct clk *mclk;
93 	/* ISIF base address */
94 	void __iomem *base_addr;
95 	/* ISIF Linear Table 0 */
96 	void __iomem *linear_tbl0_addr;
97 	/* ISIF Linear Table 1 */
98 	void __iomem *linear_tbl1_addr;
99 } isif_cfg = {
100 	.ycbcr = {
101 		.pix_fmt = CCDC_PIXFMT_YCBCR_8BIT,
102 		.frm_fmt = CCDC_FRMFMT_INTERLACED,
103 		.win = ISIF_WIN_NTSC,
104 		.fid_pol = VPFE_PINPOL_POSITIVE,
105 		.vd_pol = VPFE_PINPOL_POSITIVE,
106 		.hd_pol = VPFE_PINPOL_POSITIVE,
107 		.pix_order = CCDC_PIXORDER_CBYCRY,
108 		.buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED,
109 	},
110 	.bayer = {
111 		.pix_fmt = CCDC_PIXFMT_RAW,
112 		.frm_fmt = CCDC_FRMFMT_PROGRESSIVE,
113 		.win = ISIF_WIN_VGA,
114 		.fid_pol = VPFE_PINPOL_POSITIVE,
115 		.vd_pol = VPFE_PINPOL_POSITIVE,
116 		.hd_pol = VPFE_PINPOL_POSITIVE,
117 		.gain = {
118 			.r_ye = {1, 0},
119 			.gr_cy = {1, 0},
120 			.gb_g = {1, 0},
121 			.b_mg = {1, 0},
122 		},
123 		.cfa_pat = ISIF_CFA_PAT_MOSAIC,
124 		.data_msb = ISIF_BIT_MSB_11,
125 		.config_params = {
126 			.data_shift = ISIF_NO_SHIFT,
127 			.col_pat_field0 = {
128 				.olop = ISIF_GREEN_BLUE,
129 				.olep = ISIF_BLUE,
130 				.elop = ISIF_RED,
131 				.elep = ISIF_GREEN_RED,
132 			},
133 			.col_pat_field1 = {
134 				.olop = ISIF_GREEN_BLUE,
135 				.olep = ISIF_BLUE,
136 				.elop = ISIF_RED,
137 				.elep = ISIF_GREEN_RED,
138 			},
139 			.test_pat_gen = 0,
140 		},
141 	},
142 	.data_pack = ISIF_DATA_PACK8,
143 };
144 
145 /* Raw Bayer formats */
146 static const u32 isif_raw_bayer_pix_formats[] = {
147 	V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16};
148 
149 /* Raw YUV formats */
150 static const u32 isif_raw_yuv_pix_formats[] = {
151 	V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV};
152 
153 /* register access routines */
regr(u32 offset)154 static inline u32 regr(u32 offset)
155 {
156 	return __raw_readl(isif_cfg.base_addr + offset);
157 }
158 
regw(u32 val,u32 offset)159 static inline void regw(u32 val, u32 offset)
160 {
161 	__raw_writel(val, isif_cfg.base_addr + offset);
162 }
163 
164 /* reg_modify() - read, modify and write register */
reg_modify(u32 mask,u32 val,u32 offset)165 static inline u32 reg_modify(u32 mask, u32 val, u32 offset)
166 {
167 	u32 new_val = (regr(offset) & ~mask) | (val & mask);
168 
169 	regw(new_val, offset);
170 	return new_val;
171 }
172 
regw_lin_tbl(u32 val,u32 offset,int i)173 static inline void regw_lin_tbl(u32 val, u32 offset, int i)
174 {
175 	if (!i)
176 		__raw_writel(val, isif_cfg.linear_tbl0_addr + offset);
177 	else
178 		__raw_writel(val, isif_cfg.linear_tbl1_addr + offset);
179 }
180 
isif_disable_all_modules(void)181 static void isif_disable_all_modules(void)
182 {
183 	/* disable BC */
184 	regw(0, CLAMPCFG);
185 	/* disable vdfc */
186 	regw(0, DFCCTL);
187 	/* disable CSC */
188 	regw(0, CSCCTL);
189 	/* disable linearization */
190 	regw(0, LINCFG0);
191 	/* disable other modules here as they are supported */
192 }
193 
isif_enable(int en)194 static void isif_enable(int en)
195 {
196 	if (!en) {
197 		/* Before disable isif, disable all ISIF modules */
198 		isif_disable_all_modules();
199 		/*
200 		 * wait for next VD. Assume lowest scan rate is 12 Hz. So
201 		 * 100 msec delay is good enough
202 		 */
203 		msleep(100);
204 	}
205 	reg_modify(ISIF_SYNCEN_VDHDEN_MASK, en, SYNCEN);
206 }
207 
isif_enable_output_to_sdram(int en)208 static void isif_enable_output_to_sdram(int en)
209 {
210 	reg_modify(ISIF_SYNCEN_WEN_MASK, en << ISIF_SYNCEN_WEN_SHIFT, SYNCEN);
211 }
212 
isif_config_culling(struct isif_cul * cul)213 static void isif_config_culling(struct isif_cul *cul)
214 {
215 	u32 val;
216 
217 	/* Horizontal pattern */
218 	val = (cul->hcpat_even << CULL_PAT_EVEN_LINE_SHIFT) | cul->hcpat_odd;
219 	regw(val, CULH);
220 
221 	/* vertical pattern */
222 	regw(cul->vcpat, CULV);
223 
224 	/* LPF */
225 	reg_modify(ISIF_LPF_MASK << ISIF_LPF_SHIFT,
226 		  cul->en_lpf << ISIF_LPF_SHIFT, MODESET);
227 }
228 
isif_config_gain_offset(void)229 static void isif_config_gain_offset(void)
230 {
231 	struct isif_gain_offsets_adj *gain_off_p =
232 		&isif_cfg.bayer.config_params.gain_offset;
233 	u32 val;
234 
235 	val = (!!gain_off_p->gain_sdram_en << GAIN_SDRAM_EN_SHIFT) |
236 	      (!!gain_off_p->gain_ipipe_en << GAIN_IPIPE_EN_SHIFT) |
237 	      (!!gain_off_p->gain_h3a_en << GAIN_H3A_EN_SHIFT) |
238 	      (!!gain_off_p->offset_sdram_en << OFST_SDRAM_EN_SHIFT) |
239 	      (!!gain_off_p->offset_ipipe_en << OFST_IPIPE_EN_SHIFT) |
240 	      (!!gain_off_p->offset_h3a_en << OFST_H3A_EN_SHIFT);
241 
242 	reg_modify(GAIN_OFFSET_EN_MASK, val, CGAMMAWD);
243 
244 	val = (gain_off_p->gain.r_ye.integer << GAIN_INTEGER_SHIFT) |
245 	       gain_off_p->gain.r_ye.decimal;
246 	regw(val, CRGAIN);
247 
248 	val = (gain_off_p->gain.gr_cy.integer << GAIN_INTEGER_SHIFT) |
249 	       gain_off_p->gain.gr_cy.decimal;
250 	regw(val, CGRGAIN);
251 
252 	val = (gain_off_p->gain.gb_g.integer << GAIN_INTEGER_SHIFT) |
253 	       gain_off_p->gain.gb_g.decimal;
254 	regw(val, CGBGAIN);
255 
256 	val = (gain_off_p->gain.b_mg.integer << GAIN_INTEGER_SHIFT) |
257 	       gain_off_p->gain.b_mg.decimal;
258 	regw(val, CBGAIN);
259 
260 	regw(gain_off_p->offset, COFSTA);
261 }
262 
isif_restore_defaults(void)263 static void isif_restore_defaults(void)
264 {
265 	enum vpss_ccdc_source_sel source = VPSS_CCDCIN;
266 
267 	dev_dbg(isif_cfg.dev, "\nstarting isif_restore_defaults...");
268 	isif_cfg.bayer.config_params = isif_config_defaults;
269 	/* Enable clock to ISIF, IPIPEIF and BL */
270 	vpss_enable_clock(VPSS_CCDC_CLOCK, 1);
271 	vpss_enable_clock(VPSS_IPIPEIF_CLOCK, 1);
272 	vpss_enable_clock(VPSS_BL_CLOCK, 1);
273 	/* Set default offset and gain */
274 	isif_config_gain_offset();
275 	vpss_select_ccdc_source(source);
276 	dev_dbg(isif_cfg.dev, "\nEnd of isif_restore_defaults...");
277 }
278 
isif_open(struct device * device)279 static int isif_open(struct device *device)
280 {
281 	isif_restore_defaults();
282 	return 0;
283 }
284 
285 /* This function will configure the window size to be capture in ISIF reg */
isif_setwin(struct v4l2_rect * image_win,enum ccdc_frmfmt frm_fmt,int ppc)286 static void isif_setwin(struct v4l2_rect *image_win,
287 			enum ccdc_frmfmt frm_fmt, int ppc)
288 {
289 	int horz_start, horz_nr_pixels;
290 	int vert_start, vert_nr_lines;
291 	int mid_img = 0;
292 
293 	dev_dbg(isif_cfg.dev, "\nStarting isif_setwin...");
294 	/*
295 	 * ppc - per pixel count. indicates how many pixels per cell
296 	 * output to SDRAM. example, for ycbcr, it is one y and one c, so 2.
297 	 * raw capture this is 1
298 	 */
299 	horz_start = image_win->left << (ppc - 1);
300 	horz_nr_pixels = ((image_win->width) << (ppc - 1)) - 1;
301 
302 	/* Writing the horizontal info into the registers */
303 	regw(horz_start & START_PX_HOR_MASK, SPH);
304 	regw(horz_nr_pixels & NUM_PX_HOR_MASK, LNH);
305 	vert_start = image_win->top;
306 
307 	if (frm_fmt == CCDC_FRMFMT_INTERLACED) {
308 		vert_nr_lines = (image_win->height >> 1) - 1;
309 		vert_start >>= 1;
310 		/* To account for VD since line 0 doesn't have any data */
311 		vert_start += 1;
312 	} else {
313 		/* To account for VD since line 0 doesn't have any data */
314 		vert_start += 1;
315 		vert_nr_lines = image_win->height - 1;
316 		/* configure VDINT0 and VDINT1 */
317 		mid_img = vert_start + (image_win->height / 2);
318 		regw(mid_img, VDINT1);
319 	}
320 
321 	regw(0, VDINT0);
322 	regw(vert_start & START_VER_ONE_MASK, SLV0);
323 	regw(vert_start & START_VER_TWO_MASK, SLV1);
324 	regw(vert_nr_lines & NUM_LINES_VER, LNV);
325 }
326 
isif_config_bclamp(struct isif_black_clamp * bc)327 static void isif_config_bclamp(struct isif_black_clamp *bc)
328 {
329 	u32 val;
330 
331 	/*
332 	 * DC Offset is always added to image data irrespective of bc enable
333 	 * status
334 	 */
335 	regw(bc->dc_offset, CLDCOFST);
336 
337 	if (bc->en) {
338 		val = bc->bc_mode_color << ISIF_BC_MODE_COLOR_SHIFT;
339 
340 		/* Enable BC and horizontal clamp caculation paramaters */
341 		val = val | 1 | (bc->horz.mode << ISIF_HORZ_BC_MODE_SHIFT);
342 
343 		regw(val, CLAMPCFG);
344 
345 		if (bc->horz.mode != ISIF_HORZ_BC_DISABLE) {
346 			/*
347 			 * Window count for calculation
348 			 * Base window selection
349 			 * pixel limit
350 			 * Horizontal size of window
351 			 * vertical size of the window
352 			 * Horizontal start position of the window
353 			 * Vertical start position of the window
354 			 */
355 			val = bc->horz.win_count_calc |
356 			      ((!!bc->horz.base_win_sel_calc) <<
357 				ISIF_HORZ_BC_WIN_SEL_SHIFT) |
358 			      ((!!bc->horz.clamp_pix_limit) <<
359 				ISIF_HORZ_BC_PIX_LIMIT_SHIFT) |
360 			      (bc->horz.win_h_sz_calc <<
361 				ISIF_HORZ_BC_WIN_H_SIZE_SHIFT) |
362 			      (bc->horz.win_v_sz_calc <<
363 				ISIF_HORZ_BC_WIN_V_SIZE_SHIFT);
364 			regw(val, CLHWIN0);
365 
366 			regw(bc->horz.win_start_h_calc, CLHWIN1);
367 			regw(bc->horz.win_start_v_calc, CLHWIN2);
368 		}
369 
370 		/* vertical clamp caculation paramaters */
371 
372 		/* Reset clamp value sel for previous line */
373 		val |=
374 		(bc->vert.reset_val_sel << ISIF_VERT_BC_RST_VAL_SEL_SHIFT) |
375 		(bc->vert.line_ave_coef << ISIF_VERT_BC_LINE_AVE_COEF_SHIFT);
376 		regw(val, CLVWIN0);
377 
378 		/* Optical Black horizontal start position */
379 		regw(bc->vert.ob_start_h, CLVWIN1);
380 		/* Optical Black vertical start position */
381 		regw(bc->vert.ob_start_v, CLVWIN2);
382 		/* Optical Black vertical size for calculation */
383 		regw(bc->vert.ob_v_sz_calc, CLVWIN3);
384 		/* Vertical start position for BC subtraction */
385 		regw(bc->vert_start_sub, CLSV);
386 	}
387 }
388 
isif_config_linearization(struct isif_linearize * linearize)389 static void isif_config_linearization(struct isif_linearize *linearize)
390 {
391 	u32 val, i;
392 
393 	if (!linearize->en) {
394 		regw(0, LINCFG0);
395 		return;
396 	}
397 
398 	/* shift value for correction & enable linearization (set lsb) */
399 	val = (linearize->corr_shft << ISIF_LIN_CORRSFT_SHIFT) | 1;
400 	regw(val, LINCFG0);
401 
402 	/* Scale factor */
403 	val = ((!!linearize->scale_fact.integer) <<
404 	       ISIF_LIN_SCALE_FACT_INTEG_SHIFT) |
405 	       linearize->scale_fact.decimal;
406 	regw(val, LINCFG1);
407 
408 	for (i = 0; i < ISIF_LINEAR_TAB_SIZE; i++) {
409 		if (i % 2)
410 			regw_lin_tbl(linearize->table[i], ((i >> 1) << 2), 1);
411 		else
412 			regw_lin_tbl(linearize->table[i], ((i >> 1) << 2), 0);
413 	}
414 }
415 
isif_config_dfc(struct isif_dfc * vdfc)416 static int isif_config_dfc(struct isif_dfc *vdfc)
417 {
418 	/* initialize retries to loop for max ~ 250 usec */
419 	u32 val, count, retries = loops_per_jiffy / (4000/HZ);
420 	int i;
421 
422 	if (!vdfc->en)
423 		return 0;
424 
425 	/* Correction mode */
426 	val = (vdfc->corr_mode << ISIF_VDFC_CORR_MOD_SHIFT);
427 
428 	/* Correct whole line or partial */
429 	if (vdfc->corr_whole_line)
430 		val |= 1 << ISIF_VDFC_CORR_WHOLE_LN_SHIFT;
431 
432 	/* level shift value */
433 	val |= vdfc->def_level_shift << ISIF_VDFC_LEVEL_SHFT_SHIFT;
434 
435 	regw(val, DFCCTL);
436 
437 	/* Defect saturation level */
438 	regw(vdfc->def_sat_level, VDFSATLV);
439 
440 	regw(vdfc->table[0].pos_vert, DFCMEM0);
441 	regw(vdfc->table[0].pos_horz, DFCMEM1);
442 	if (vdfc->corr_mode == ISIF_VDFC_NORMAL ||
443 	    vdfc->corr_mode == ISIF_VDFC_HORZ_INTERPOL_IF_SAT) {
444 		regw(vdfc->table[0].level_at_pos, DFCMEM2);
445 		regw(vdfc->table[0].level_up_pixels, DFCMEM3);
446 		regw(vdfc->table[0].level_low_pixels, DFCMEM4);
447 	}
448 
449 	/* set DFCMARST and set DFCMWR */
450 	val = regr(DFCMEMCTL) | (1 << ISIF_DFCMEMCTL_DFCMARST_SHIFT) | 1;
451 	regw(val, DFCMEMCTL);
452 
453 	count = retries;
454 	while (count && (regr(DFCMEMCTL) & 0x1))
455 		count--;
456 
457 	if (!count) {
458 		dev_dbg(isif_cfg.dev, "defect table write timeout !!!\n");
459 		return -1;
460 	}
461 
462 	for (i = 1; i < vdfc->num_vdefects; i++) {
463 		regw(vdfc->table[i].pos_vert, DFCMEM0);
464 		regw(vdfc->table[i].pos_horz, DFCMEM1);
465 		if (vdfc->corr_mode == ISIF_VDFC_NORMAL ||
466 		    vdfc->corr_mode == ISIF_VDFC_HORZ_INTERPOL_IF_SAT) {
467 			regw(vdfc->table[i].level_at_pos, DFCMEM2);
468 			regw(vdfc->table[i].level_up_pixels, DFCMEM3);
469 			regw(vdfc->table[i].level_low_pixels, DFCMEM4);
470 		}
471 		val = regr(DFCMEMCTL);
472 		/* clear DFCMARST and set DFCMWR */
473 		val &= ~BIT(ISIF_DFCMEMCTL_DFCMARST_SHIFT);
474 		val |= 1;
475 		regw(val, DFCMEMCTL);
476 
477 		count = retries;
478 		while (count && (regr(DFCMEMCTL) & 0x1))
479 			count--;
480 
481 		if (!count) {
482 			dev_err(isif_cfg.dev,
483 				"defect table write timeout !!!\n");
484 			return -1;
485 		}
486 	}
487 	if (vdfc->num_vdefects < ISIF_VDFC_TABLE_SIZE) {
488 		/* Extra cycle needed */
489 		regw(0, DFCMEM0);
490 		regw(0x1FFF, DFCMEM1);
491 		regw(1, DFCMEMCTL);
492 	}
493 
494 	/* enable VDFC */
495 	reg_modify((1 << ISIF_VDFC_EN_SHIFT), (1 << ISIF_VDFC_EN_SHIFT),
496 		   DFCCTL);
497 	return 0;
498 }
499 
isif_config_csc(struct isif_df_csc * df_csc)500 static void isif_config_csc(struct isif_df_csc *df_csc)
501 {
502 	u32 val1 = 0, val2 = 0, i;
503 
504 	if (!df_csc->csc.en) {
505 		regw(0, CSCCTL);
506 		return;
507 	}
508 	for (i = 0; i < ISIF_CSC_NUM_COEFF; i++) {
509 		if ((i % 2) == 0) {
510 			/* CSCM - LSB */
511 			val1 = (df_csc->csc.coeff[i].integer <<
512 				ISIF_CSC_COEF_INTEG_SHIFT) |
513 				df_csc->csc.coeff[i].decimal;
514 		} else {
515 
516 			/* CSCM - MSB */
517 			val2 = (df_csc->csc.coeff[i].integer <<
518 				ISIF_CSC_COEF_INTEG_SHIFT) |
519 				df_csc->csc.coeff[i].decimal;
520 			val2 <<= ISIF_CSCM_MSB_SHIFT;
521 			val2 |= val1;
522 			regw(val2, (CSCM0 + ((i - 1) << 1)));
523 		}
524 	}
525 
526 	/* program the active area */
527 	regw(df_csc->start_pix, FMTSPH);
528 	/*
529 	 * one extra pixel as required for CSC. Actually number of
530 	 * pixel - 1 should be configured in this register. So we
531 	 * need to subtract 1 before writing to FMTSPH, but we will
532 	 * not do this since csc requires one extra pixel
533 	 */
534 	regw(df_csc->num_pixels, FMTLNH);
535 	regw(df_csc->start_line, FMTSLV);
536 	/*
537 	 * one extra line as required for CSC. See reason documented for
538 	 * num_pixels
539 	 */
540 	regw(df_csc->num_lines, FMTLNV);
541 
542 	/* Enable CSC */
543 	regw(1, CSCCTL);
544 }
545 
isif_config_raw(void)546 static int isif_config_raw(void)
547 {
548 	struct isif_params_raw *params = &isif_cfg.bayer;
549 	struct isif_config_params_raw *module_params =
550 		&isif_cfg.bayer.config_params;
551 	struct vpss_pg_frame_size frame_size;
552 	struct vpss_sync_pol sync;
553 	u32 val;
554 
555 	dev_dbg(isif_cfg.dev, "\nStarting isif_config_raw..\n");
556 
557 	/*
558 	 * Configure CCDCFG register:-
559 	 * Set CCD Not to swap input since input is RAW data
560 	 * Set FID detection function to Latch at V-Sync
561 	 * Set WENLOG - isif valid area
562 	 * Set TRGSEL
563 	 * Set EXTRG
564 	 * Packed to 8 or 16 bits
565 	 */
566 
567 	val = ISIF_YCINSWP_RAW | ISIF_CCDCFG_FIDMD_LATCH_VSYNC |
568 		ISIF_CCDCFG_WENLOG_AND | ISIF_CCDCFG_TRGSEL_WEN |
569 		ISIF_CCDCFG_EXTRG_DISABLE | isif_cfg.data_pack;
570 
571 	dev_dbg(isif_cfg.dev, "Writing 0x%x to ...CCDCFG \n", val);
572 	regw(val, CCDCFG);
573 
574 	/*
575 	 * Configure the vertical sync polarity(MODESET.VDPOL)
576 	 * Configure the horizontal sync polarity (MODESET.HDPOL)
577 	 * Configure frame id polarity (MODESET.FLDPOL)
578 	 * Configure data polarity
579 	 * Configure External WEN Selection
580 	 * Configure frame format(progressive or interlace)
581 	 * Configure pixel format (Input mode)
582 	 * Configure the data shift
583 	 */
584 
585 	val = ISIF_VDHDOUT_INPUT | (params->vd_pol << ISIF_VD_POL_SHIFT) |
586 		(params->hd_pol << ISIF_HD_POL_SHIFT) |
587 		(params->fid_pol << ISIF_FID_POL_SHIFT) |
588 		(ISIF_DATAPOL_NORMAL << ISIF_DATAPOL_SHIFT) |
589 		(ISIF_EXWEN_DISABLE << ISIF_EXWEN_SHIFT) |
590 		(params->frm_fmt << ISIF_FRM_FMT_SHIFT) |
591 		(params->pix_fmt << ISIF_INPUT_SHIFT) |
592 		(params->config_params.data_shift << ISIF_DATASFT_SHIFT);
593 
594 	regw(val, MODESET);
595 	dev_dbg(isif_cfg.dev, "Writing 0x%x to MODESET...\n", val);
596 
597 	/*
598 	 * Configure GAMMAWD register
599 	 * CFA pattern setting
600 	 */
601 	val = params->cfa_pat << ISIF_GAMMAWD_CFA_SHIFT;
602 
603 	/* Gamma msb */
604 	if (module_params->compress.alg == ISIF_ALAW)
605 		val |= ISIF_ALAW_ENABLE;
606 
607 	val |= (params->data_msb << ISIF_ALAW_GAMA_WD_SHIFT);
608 	regw(val, CGAMMAWD);
609 
610 	/* Configure DPCM compression settings */
611 	if (module_params->compress.alg == ISIF_DPCM) {
612 		val =  BIT(ISIF_DPCM_EN_SHIFT) |
613 		       (module_params->compress.pred <<
614 		       ISIF_DPCM_PREDICTOR_SHIFT);
615 	}
616 
617 	regw(val, MISC);
618 
619 	/* Configure Gain & Offset */
620 	isif_config_gain_offset();
621 
622 	/* Configure Color pattern */
623 	val = (params->config_params.col_pat_field0.olop) |
624 	      (params->config_params.col_pat_field0.olep << 2) |
625 	      (params->config_params.col_pat_field0.elop << 4) |
626 	      (params->config_params.col_pat_field0.elep << 6) |
627 	      (params->config_params.col_pat_field1.olop << 8) |
628 	      (params->config_params.col_pat_field1.olep << 10) |
629 	      (params->config_params.col_pat_field1.elop << 12) |
630 	      (params->config_params.col_pat_field1.elep << 14);
631 	regw(val, CCOLP);
632 	dev_dbg(isif_cfg.dev, "Writing %x to CCOLP ...\n", val);
633 
634 	/* Configure HSIZE register  */
635 	val = (!!params->horz_flip_en) << ISIF_HSIZE_FLIP_SHIFT;
636 
637 	/* calculate line offset in 32 bytes based on pack value */
638 	if (isif_cfg.data_pack == ISIF_PACK_8BIT)
639 		val |= ((params->win.width + 31) >> 5);
640 	else if (isif_cfg.data_pack == ISIF_PACK_12BIT)
641 		val |= (((params->win.width +
642 		       (params->win.width >> 2)) + 31) >> 5);
643 	else
644 		val |= (((params->win.width * 2) + 31) >> 5);
645 	regw(val, HSIZE);
646 
647 	/* Configure SDOFST register  */
648 	if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) {
649 		if (params->image_invert_en) {
650 			/* For interlace inverse mode */
651 			regw(0x4B6D, SDOFST);
652 			dev_dbg(isif_cfg.dev, "Writing 0x4B6D to SDOFST...\n");
653 		} else {
654 			/* For interlace non inverse mode */
655 			regw(0x0B6D, SDOFST);
656 			dev_dbg(isif_cfg.dev, "Writing 0x0B6D to SDOFST...\n");
657 		}
658 	} else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) {
659 		if (params->image_invert_en) {
660 			/* For progressive inverse mode */
661 			regw(0x4000, SDOFST);
662 			dev_dbg(isif_cfg.dev, "Writing 0x4000 to SDOFST...\n");
663 		} else {
664 			/* For progressive non inverse mode */
665 			regw(0x0000, SDOFST);
666 			dev_dbg(isif_cfg.dev, "Writing 0x0000 to SDOFST...\n");
667 		}
668 	}
669 
670 	/* Configure video window */
671 	isif_setwin(&params->win, params->frm_fmt, 1);
672 
673 	/* Configure Black Clamp */
674 	isif_config_bclamp(&module_params->bclamp);
675 
676 	/* Configure Vertical Defection Pixel Correction */
677 	if (isif_config_dfc(&module_params->dfc) < 0)
678 		return -EFAULT;
679 
680 	if (!module_params->df_csc.df_or_csc)
681 		/* Configure Color Space Conversion */
682 		isif_config_csc(&module_params->df_csc);
683 
684 	isif_config_linearization(&module_params->linearize);
685 
686 	/* Configure Culling */
687 	isif_config_culling(&module_params->culling);
688 
689 	/* Configure horizontal and vertical offsets(DFC,LSC,Gain) */
690 	regw(module_params->horz_offset, DATAHOFST);
691 	regw(module_params->vert_offset, DATAVOFST);
692 
693 	/* Setup test pattern if enabled */
694 	if (params->config_params.test_pat_gen) {
695 		/* Use the HD/VD pol settings from user */
696 		sync.ccdpg_hdpol = params->hd_pol;
697 		sync.ccdpg_vdpol = params->vd_pol;
698 		dm365_vpss_set_sync_pol(sync);
699 		frame_size.hlpfr = isif_cfg.bayer.win.width;
700 		frame_size.pplen = isif_cfg.bayer.win.height;
701 		dm365_vpss_set_pg_frame_size(frame_size);
702 		vpss_select_ccdc_source(VPSS_PGLPBK);
703 	}
704 
705 	dev_dbg(isif_cfg.dev, "\nEnd of isif_config_ycbcr...\n");
706 	return 0;
707 }
708 
isif_set_buftype(enum ccdc_buftype buf_type)709 static int isif_set_buftype(enum ccdc_buftype buf_type)
710 {
711 	if (isif_cfg.if_type == VPFE_RAW_BAYER)
712 		isif_cfg.bayer.buf_type = buf_type;
713 	else
714 		isif_cfg.ycbcr.buf_type = buf_type;
715 
716 	return 0;
717 
718 }
isif_get_buftype(void)719 static enum ccdc_buftype isif_get_buftype(void)
720 {
721 	if (isif_cfg.if_type == VPFE_RAW_BAYER)
722 		return isif_cfg.bayer.buf_type;
723 
724 	return isif_cfg.ycbcr.buf_type;
725 }
726 
isif_enum_pix(u32 * pix,int i)727 static int isif_enum_pix(u32 *pix, int i)
728 {
729 	int ret = -EINVAL;
730 
731 	if (isif_cfg.if_type == VPFE_RAW_BAYER) {
732 		if (i < ARRAY_SIZE(isif_raw_bayer_pix_formats)) {
733 			*pix = isif_raw_bayer_pix_formats[i];
734 			ret = 0;
735 		}
736 	} else {
737 		if (i < ARRAY_SIZE(isif_raw_yuv_pix_formats)) {
738 			*pix = isif_raw_yuv_pix_formats[i];
739 			ret = 0;
740 		}
741 	}
742 
743 	return ret;
744 }
745 
isif_set_pixel_format(unsigned int pixfmt)746 static int isif_set_pixel_format(unsigned int pixfmt)
747 {
748 	if (isif_cfg.if_type == VPFE_RAW_BAYER) {
749 		if (pixfmt == V4L2_PIX_FMT_SBGGR8) {
750 			if ((isif_cfg.bayer.config_params.compress.alg !=
751 			     ISIF_ALAW) &&
752 			    (isif_cfg.bayer.config_params.compress.alg !=
753 			     ISIF_DPCM)) {
754 				dev_dbg(isif_cfg.dev,
755 					"Either configure A-Law or DPCM\n");
756 				return -EINVAL;
757 			}
758 			isif_cfg.data_pack = ISIF_PACK_8BIT;
759 		} else if (pixfmt == V4L2_PIX_FMT_SBGGR16) {
760 			isif_cfg.bayer.config_params.compress.alg =
761 					ISIF_NO_COMPRESSION;
762 			isif_cfg.data_pack = ISIF_PACK_16BIT;
763 		} else
764 			return -EINVAL;
765 		isif_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW;
766 	} else {
767 		if (pixfmt == V4L2_PIX_FMT_YUYV)
768 			isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR;
769 		else if (pixfmt == V4L2_PIX_FMT_UYVY)
770 			isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;
771 		else
772 			return -EINVAL;
773 		isif_cfg.data_pack = ISIF_PACK_8BIT;
774 	}
775 	return 0;
776 }
777 
isif_get_pixel_format(void)778 static u32 isif_get_pixel_format(void)
779 {
780 	u32 pixfmt;
781 
782 	if (isif_cfg.if_type == VPFE_RAW_BAYER)
783 		if (isif_cfg.bayer.config_params.compress.alg == ISIF_ALAW ||
784 		    isif_cfg.bayer.config_params.compress.alg == ISIF_DPCM)
785 			pixfmt = V4L2_PIX_FMT_SBGGR8;
786 		else
787 			pixfmt = V4L2_PIX_FMT_SBGGR16;
788 	else {
789 		if (isif_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR)
790 			pixfmt = V4L2_PIX_FMT_YUYV;
791 		else
792 			pixfmt = V4L2_PIX_FMT_UYVY;
793 	}
794 	return pixfmt;
795 }
796 
isif_set_image_window(struct v4l2_rect * win)797 static int isif_set_image_window(struct v4l2_rect *win)
798 {
799 	if (isif_cfg.if_type == VPFE_RAW_BAYER) {
800 		isif_cfg.bayer.win.top = win->top;
801 		isif_cfg.bayer.win.left = win->left;
802 		isif_cfg.bayer.win.width = win->width;
803 		isif_cfg.bayer.win.height = win->height;
804 	} else {
805 		isif_cfg.ycbcr.win.top = win->top;
806 		isif_cfg.ycbcr.win.left = win->left;
807 		isif_cfg.ycbcr.win.width = win->width;
808 		isif_cfg.ycbcr.win.height = win->height;
809 	}
810 	return 0;
811 }
812 
isif_get_image_window(struct v4l2_rect * win)813 static void isif_get_image_window(struct v4l2_rect *win)
814 {
815 	if (isif_cfg.if_type == VPFE_RAW_BAYER)
816 		*win = isif_cfg.bayer.win;
817 	else
818 		*win = isif_cfg.ycbcr.win;
819 }
820 
isif_get_line_length(void)821 static unsigned int isif_get_line_length(void)
822 {
823 	unsigned int len;
824 
825 	if (isif_cfg.if_type == VPFE_RAW_BAYER) {
826 		if (isif_cfg.data_pack == ISIF_PACK_8BIT)
827 			len = ((isif_cfg.bayer.win.width));
828 		else if (isif_cfg.data_pack == ISIF_PACK_12BIT)
829 			len = (((isif_cfg.bayer.win.width * 2) +
830 				 (isif_cfg.bayer.win.width >> 2)));
831 		else
832 			len = (((isif_cfg.bayer.win.width * 2)));
833 	} else
834 		len = (((isif_cfg.ycbcr.win.width * 2)));
835 	return ALIGN(len, 32);
836 }
837 
isif_set_frame_format(enum ccdc_frmfmt frm_fmt)838 static int isif_set_frame_format(enum ccdc_frmfmt frm_fmt)
839 {
840 	if (isif_cfg.if_type == VPFE_RAW_BAYER)
841 		isif_cfg.bayer.frm_fmt = frm_fmt;
842 	else
843 		isif_cfg.ycbcr.frm_fmt = frm_fmt;
844 	return 0;
845 }
isif_get_frame_format(void)846 static enum ccdc_frmfmt isif_get_frame_format(void)
847 {
848 	if (isif_cfg.if_type == VPFE_RAW_BAYER)
849 		return isif_cfg.bayer.frm_fmt;
850 	return isif_cfg.ycbcr.frm_fmt;
851 }
852 
isif_getfid(void)853 static int isif_getfid(void)
854 {
855 	return (regr(MODESET) >> 15) & 0x1;
856 }
857 
858 /* misc operations */
isif_setfbaddr(unsigned long addr)859 static void isif_setfbaddr(unsigned long addr)
860 {
861 	regw((addr >> 21) & 0x07ff, CADU);
862 	regw((addr >> 5) & 0x0ffff, CADL);
863 }
864 
isif_set_hw_if_params(struct vpfe_hw_if_param * params)865 static int isif_set_hw_if_params(struct vpfe_hw_if_param *params)
866 {
867 	isif_cfg.if_type = params->if_type;
868 
869 	switch (params->if_type) {
870 	case VPFE_BT656:
871 	case VPFE_BT656_10BIT:
872 	case VPFE_YCBCR_SYNC_8:
873 		isif_cfg.ycbcr.pix_fmt = CCDC_PIXFMT_YCBCR_8BIT;
874 		isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;
875 		break;
876 	case VPFE_BT1120:
877 	case VPFE_YCBCR_SYNC_16:
878 		isif_cfg.ycbcr.pix_fmt = CCDC_PIXFMT_YCBCR_16BIT;
879 		isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;
880 		break;
881 	case VPFE_RAW_BAYER:
882 		isif_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW;
883 		break;
884 	default:
885 		dev_dbg(isif_cfg.dev, "Invalid interface type\n");
886 		return -EINVAL;
887 	}
888 
889 	return 0;
890 }
891 
892 /* This function will configure ISIF for YCbCr parameters. */
isif_config_ycbcr(void)893 static int isif_config_ycbcr(void)
894 {
895 	struct isif_ycbcr_config *params = &isif_cfg.ycbcr;
896 	struct vpss_pg_frame_size frame_size;
897 	u32 modeset = 0, ccdcfg = 0;
898 	struct vpss_sync_pol sync;
899 
900 	dev_dbg(isif_cfg.dev, "\nStarting isif_config_ycbcr...");
901 
902 	/* configure pixel format or input mode */
903 	modeset = modeset | (params->pix_fmt << ISIF_INPUT_SHIFT) |
904 		  (params->frm_fmt << ISIF_FRM_FMT_SHIFT) |
905 		  (params->fid_pol << ISIF_FID_POL_SHIFT) |
906 		  (params->hd_pol << ISIF_HD_POL_SHIFT) |
907 		  (params->vd_pol << ISIF_VD_POL_SHIFT);
908 
909 	/* pack the data to 8-bit ISIFCFG */
910 	switch (isif_cfg.if_type) {
911 	case VPFE_BT656:
912 		if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) {
913 			dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n");
914 			return -EINVAL;
915 		}
916 		modeset |= (VPFE_PINPOL_NEGATIVE << ISIF_VD_POL_SHIFT);
917 		regw(3, REC656IF);
918 		ccdcfg = ccdcfg | ISIF_DATA_PACK8 | ISIF_YCINSWP_YCBCR;
919 		break;
920 	case VPFE_BT656_10BIT:
921 		if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) {
922 			dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n");
923 			return -EINVAL;
924 		}
925 		/* setup BT.656, embedded sync  */
926 		regw(3, REC656IF);
927 		/* enable 10 bit mode in ccdcfg */
928 		ccdcfg = ccdcfg | ISIF_DATA_PACK8 | ISIF_YCINSWP_YCBCR |
929 			ISIF_BW656_ENABLE;
930 		break;
931 	case VPFE_BT1120:
932 		if (params->pix_fmt != CCDC_PIXFMT_YCBCR_16BIT) {
933 			dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n");
934 			return -EINVAL;
935 		}
936 		regw(3, REC656IF);
937 		break;
938 
939 	case VPFE_YCBCR_SYNC_8:
940 		ccdcfg |= ISIF_DATA_PACK8;
941 		ccdcfg |= ISIF_YCINSWP_YCBCR;
942 		if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) {
943 			dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n");
944 			return -EINVAL;
945 		}
946 		break;
947 	case VPFE_YCBCR_SYNC_16:
948 		if (params->pix_fmt != CCDC_PIXFMT_YCBCR_16BIT) {
949 			dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n");
950 			return -EINVAL;
951 		}
952 		break;
953 	default:
954 		/* should never come here */
955 		dev_dbg(isif_cfg.dev, "Invalid interface type\n");
956 		return -EINVAL;
957 	}
958 
959 	regw(modeset, MODESET);
960 
961 	/* Set up pix order */
962 	ccdcfg |= params->pix_order << ISIF_PIX_ORDER_SHIFT;
963 
964 	regw(ccdcfg, CCDCFG);
965 
966 	/* configure video window */
967 	if ((isif_cfg.if_type == VPFE_BT1120) ||
968 	    (isif_cfg.if_type == VPFE_YCBCR_SYNC_16))
969 		isif_setwin(&params->win, params->frm_fmt, 1);
970 	else
971 		isif_setwin(&params->win, params->frm_fmt, 2);
972 
973 	/*
974 	 * configure the horizontal line offset
975 	 * this is done by rounding up width to a multiple of 16 pixels
976 	 * and multiply by two to account for y:cb:cr 4:2:2 data
977 	 */
978 	regw(((((params->win.width * 2) + 31) & 0xffffffe0) >> 5), HSIZE);
979 
980 	/* configure the memory line offset */
981 	if ((params->frm_fmt == CCDC_FRMFMT_INTERLACED) &&
982 	    (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED))
983 		/* two fields are interleaved in memory */
984 		regw(0x00000249, SDOFST);
985 
986 	/* Setup test pattern if enabled */
987 	if (isif_cfg.bayer.config_params.test_pat_gen) {
988 		sync.ccdpg_hdpol = params->hd_pol;
989 		sync.ccdpg_vdpol = params->vd_pol;
990 		dm365_vpss_set_sync_pol(sync);
991 		dm365_vpss_set_pg_frame_size(frame_size);
992 	}
993 	return 0;
994 }
995 
isif_configure(void)996 static int isif_configure(void)
997 {
998 	if (isif_cfg.if_type == VPFE_RAW_BAYER)
999 		return isif_config_raw();
1000 	return isif_config_ycbcr();
1001 }
1002 
isif_close(struct device * device)1003 static int isif_close(struct device *device)
1004 {
1005 	/* copy defaults to module params */
1006 	isif_cfg.bayer.config_params = isif_config_defaults;
1007 	return 0;
1008 }
1009 
1010 static struct ccdc_hw_device isif_hw_dev = {
1011 	.name = "ISIF",
1012 	.owner = THIS_MODULE,
1013 	.hw_ops = {
1014 		.open = isif_open,
1015 		.close = isif_close,
1016 		.enable = isif_enable,
1017 		.enable_out_to_sdram = isif_enable_output_to_sdram,
1018 		.set_hw_if_params = isif_set_hw_if_params,
1019 		.configure = isif_configure,
1020 		.set_buftype = isif_set_buftype,
1021 		.get_buftype = isif_get_buftype,
1022 		.enum_pix = isif_enum_pix,
1023 		.set_pixel_format = isif_set_pixel_format,
1024 		.get_pixel_format = isif_get_pixel_format,
1025 		.set_frame_format = isif_set_frame_format,
1026 		.get_frame_format = isif_get_frame_format,
1027 		.set_image_window = isif_set_image_window,
1028 		.get_image_window = isif_get_image_window,
1029 		.get_line_length = isif_get_line_length,
1030 		.setfbaddr = isif_setfbaddr,
1031 		.getfid = isif_getfid,
1032 	},
1033 };
1034 
isif_probe(struct platform_device * pdev)1035 static int __init isif_probe(struct platform_device *pdev)
1036 {
1037 	void (*setup_pinmux)(void);
1038 	struct resource	*res;
1039 	void *__iomem addr;
1040 	int status = 0, i;
1041 
1042 	/*
1043 	 * first try to register with vpfe. If not correct platform, then we
1044 	 * don't have to iomap
1045 	 */
1046 	status = vpfe_register_ccdc_device(&isif_hw_dev);
1047 	if (status < 0)
1048 		return status;
1049 
1050 	/* Get and enable Master clock */
1051 	isif_cfg.mclk = clk_get(&pdev->dev, "master");
1052 	if (IS_ERR(isif_cfg.mclk)) {
1053 		status = PTR_ERR(isif_cfg.mclk);
1054 		goto fail_mclk;
1055 	}
1056 	if (clk_enable(isif_cfg.mclk)) {
1057 		status = -ENODEV;
1058 		goto fail_mclk;
1059 	}
1060 
1061 	/* Platform data holds setup_pinmux function ptr */
1062 	if (NULL == pdev->dev.platform_data) {
1063 		status = -ENODEV;
1064 		goto fail_mclk;
1065 	}
1066 	setup_pinmux = pdev->dev.platform_data;
1067 	/*
1068 	 * setup Mux configuration for ccdc which may be different for
1069 	 * different SoCs using this CCDC
1070 	 */
1071 	setup_pinmux();
1072 
1073 	i = 0;
1074 	/* Get the ISIF base address, linearization table0 and table1 addr. */
1075 	while (i < 3) {
1076 		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
1077 		if (!res) {
1078 			status = -ENODEV;
1079 			goto fail_nobase_res;
1080 		}
1081 		res = request_mem_region(res->start, resource_size(res),
1082 					 res->name);
1083 		if (!res) {
1084 			status = -EBUSY;
1085 			goto fail_nobase_res;
1086 		}
1087 		addr = ioremap_nocache(res->start, resource_size(res));
1088 		if (!addr) {
1089 			status = -ENOMEM;
1090 			goto fail_base_iomap;
1091 		}
1092 		switch (i) {
1093 		case 0:
1094 			/* ISIF base address */
1095 			isif_cfg.base_addr = addr;
1096 			break;
1097 		case 1:
1098 			/* ISIF linear tbl0 address */
1099 			isif_cfg.linear_tbl0_addr = addr;
1100 			break;
1101 		default:
1102 			/* ISIF linear tbl0 address */
1103 			isif_cfg.linear_tbl1_addr = addr;
1104 			break;
1105 		}
1106 		i++;
1107 	}
1108 	isif_cfg.dev = &pdev->dev;
1109 
1110 	printk(KERN_NOTICE "%s is registered with vpfe.\n",
1111 		isif_hw_dev.name);
1112 	return 0;
1113 fail_base_iomap:
1114 	release_mem_region(res->start, resource_size(res));
1115 	i--;
1116 fail_nobase_res:
1117 	if (isif_cfg.base_addr)
1118 		iounmap(isif_cfg.base_addr);
1119 	if (isif_cfg.linear_tbl0_addr)
1120 		iounmap(isif_cfg.linear_tbl0_addr);
1121 
1122 	while (i >= 0) {
1123 		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
1124 		release_mem_region(res->start, resource_size(res));
1125 		i--;
1126 	}
1127 fail_mclk:
1128 	clk_put(isif_cfg.mclk);
1129 	vpfe_unregister_ccdc_device(&isif_hw_dev);
1130 	return status;
1131 }
1132 
isif_remove(struct platform_device * pdev)1133 static int isif_remove(struct platform_device *pdev)
1134 {
1135 	struct resource	*res;
1136 	int i = 0;
1137 
1138 	iounmap(isif_cfg.base_addr);
1139 	iounmap(isif_cfg.linear_tbl0_addr);
1140 	iounmap(isif_cfg.linear_tbl1_addr);
1141 	while (i < 3) {
1142 		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
1143 		if (res)
1144 			release_mem_region(res->start, resource_size(res));
1145 		i++;
1146 	}
1147 	vpfe_unregister_ccdc_device(&isif_hw_dev);
1148 	return 0;
1149 }
1150 
1151 static struct platform_driver isif_driver = {
1152 	.driver = {
1153 		.name	= "isif",
1154 		.owner = THIS_MODULE,
1155 	},
1156 	.remove = __devexit_p(isif_remove),
1157 	.probe = isif_probe,
1158 };
1159 
1160 module_platform_driver(isif_driver);
1161 
1162 MODULE_LICENSE("GPL");
1163