1 /*
2  * Copyright (C) 2012 Texas Instruments Inc
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation version 2.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16  *
17  * Contributors:
18  *      Manjunath Hadli <manjunath.hadli@ti.com>
19  *      Prabhakar Lad <prabhakar.lad@ti.com>
20  */
21 
22 #include <linux/delay.h>
23 #include "dm365_isif.h"
24 #include "vpfe_mc_capture.h"
25 
26 #define MAX_WIDTH	4096
27 #define MAX_HEIGHT	4096
28 
29 static const unsigned int isif_fmts[] = {
30 	MEDIA_BUS_FMT_YUYV8_2X8,
31 	MEDIA_BUS_FMT_UYVY8_2X8,
32 	MEDIA_BUS_FMT_YUYV8_1X16,
33 	MEDIA_BUS_FMT_YUYV10_1X20,
34 	MEDIA_BUS_FMT_SGRBG12_1X12,
35 	MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8,
36 	MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8,
37 };
38 
39 #define ISIF_COLPTN_R_Ye	0x0
40 #define ISIF_COLPTN_Gr_Cy	0x1
41 #define ISIF_COLPTN_Gb_G	0x2
42 #define ISIF_COLPTN_B_Mg	0x3
43 
44 #define ISIF_CCOLP_CP01_0	0
45 #define ISIF_CCOLP_CP03_2	2
46 #define ISIF_CCOLP_CP05_4	4
47 #define ISIF_CCOLP_CP07_6	6
48 #define ISIF_CCOLP_CP11_0	8
49 #define ISIF_CCOLP_CP13_2	10
50 #define ISIF_CCOLP_CP15_4	12
51 #define ISIF_CCOLP_CP17_6	14
52 
53 static const u32 isif_sgrbg_pattern =
54 	ISIF_COLPTN_Gr_Cy <<  ISIF_CCOLP_CP01_0 |
55 	ISIF_COLPTN_R_Ye  << ISIF_CCOLP_CP03_2 |
56 	ISIF_COLPTN_B_Mg  << ISIF_CCOLP_CP05_4 |
57 	ISIF_COLPTN_Gb_G  << ISIF_CCOLP_CP07_6 |
58 	ISIF_COLPTN_Gr_Cy << ISIF_CCOLP_CP11_0 |
59 	ISIF_COLPTN_R_Ye  << ISIF_CCOLP_CP13_2 |
60 	ISIF_COLPTN_B_Mg  << ISIF_CCOLP_CP15_4 |
61 	ISIF_COLPTN_Gb_G  << ISIF_CCOLP_CP17_6;
62 
63 static const u32 isif_srggb_pattern =
64 	ISIF_COLPTN_R_Ye  << ISIF_CCOLP_CP01_0 |
65 	ISIF_COLPTN_Gr_Cy << ISIF_CCOLP_CP03_2 |
66 	ISIF_COLPTN_Gb_G  << ISIF_CCOLP_CP05_4 |
67 	ISIF_COLPTN_B_Mg  << ISIF_CCOLP_CP07_6 |
68 	ISIF_COLPTN_R_Ye  << ISIF_CCOLP_CP11_0 |
69 	ISIF_COLPTN_Gr_Cy << ISIF_CCOLP_CP13_2 |
70 	ISIF_COLPTN_Gb_G  << ISIF_CCOLP_CP15_4 |
71 	ISIF_COLPTN_B_Mg  << ISIF_CCOLP_CP17_6;
72 
isif_read(void __iomem * base_addr,u32 offset)73 static inline u32 isif_read(void __iomem *base_addr, u32 offset)
74 {
75 	return readl(base_addr + offset);
76 }
77 
isif_write(void __iomem * base_addr,u32 val,u32 offset)78 static inline void isif_write(void __iomem *base_addr, u32 val, u32 offset)
79 {
80 	writel(val, base_addr + offset);
81 }
82 
isif_merge(void __iomem * base_addr,u32 mask,u32 val,u32 offset)83 static inline u32 isif_merge(void __iomem *base_addr, u32 mask, u32 val,
84 			     u32 offset)
85 {
86 	u32 new_val = (isif_read(base_addr, offset) & ~mask) | (val & mask);
87 
88 	isif_write(base_addr, new_val, offset);
89 
90 	return new_val;
91 }
92 
isif_enable_output_to_sdram(struct vpfe_isif_device * isif,int en)93 static void isif_enable_output_to_sdram(struct vpfe_isif_device *isif, int en)
94 {
95 	isif_merge(isif->isif_cfg.base_addr, ISIF_SYNCEN_WEN_MASK,
96 		   en << ISIF_SYNCEN_WEN_SHIFT, SYNCEN);
97 }
98 
99 static inline void
isif_regw_lin_tbl(struct vpfe_isif_device * isif,u32 val,u32 offset,int i)100 isif_regw_lin_tbl(struct vpfe_isif_device *isif, u32 val, u32 offset, int i)
101 {
102 	if (!i)
103 		writel(val, isif->isif_cfg.linear_tbl0_addr + offset);
104 	else
105 		writel(val, isif->isif_cfg.linear_tbl1_addr + offset);
106 }
107 
isif_disable_all_modules(struct vpfe_isif_device * isif)108 static void isif_disable_all_modules(struct vpfe_isif_device *isif)
109 {
110 	/* disable BC */
111 	isif_write(isif->isif_cfg.base_addr, 0, CLAMPCFG);
112 	/* disable vdfc */
113 	isif_write(isif->isif_cfg.base_addr, 0, DFCCTL);
114 	/* disable CSC */
115 	isif_write(isif->isif_cfg.base_addr, 0, CSCCTL);
116 	/* disable linearization */
117 	isif_write(isif->isif_cfg.base_addr, 0, LINCFG0);
118 }
119 
isif_enable(struct vpfe_isif_device * isif,int en)120 static void isif_enable(struct vpfe_isif_device *isif, int en)
121 {
122 	if (!en)
123 		/* Before disable isif, disable all ISIF modules */
124 		isif_disable_all_modules(isif);
125 
126 	/*
127 	 * wait for next VD. Assume lowest scan rate is 12 Hz. So
128 	 * 100 msec delay is good enough
129 	 */
130 	msleep(100);
131 	isif_merge(isif->isif_cfg.base_addr, ISIF_SYNCEN_VDHDEN_MASK,
132 		   en, SYNCEN);
133 }
134 
135 /*
136  * ISIF helper functions
137  */
138 
139 #define DM365_ISIF_MDFS_OFFSET		15
140 #define DM365_ISIF_MDFS_MASK		0x1
141 
142 /* get field id in isif hardware */
vpfe_isif_get_fid(struct vpfe_device * vpfe_dev)143 enum v4l2_field vpfe_isif_get_fid(struct vpfe_device *vpfe_dev)
144 {
145 	struct vpfe_isif_device *isif = &vpfe_dev->vpfe_isif;
146 	u32 field_status;
147 
148 	field_status = isif_read(isif->isif_cfg.base_addr, MODESET);
149 	return (field_status >> DM365_ISIF_MDFS_OFFSET) &
150 		DM365_ISIF_MDFS_MASK;
151 }
152 
153 static int
isif_set_pixel_format(struct vpfe_isif_device * isif,unsigned int pixfmt)154 isif_set_pixel_format(struct vpfe_isif_device *isif, unsigned int pixfmt)
155 {
156 	if (isif->formats[ISIF_PAD_SINK].code == MEDIA_BUS_FMT_SGRBG12_1X12) {
157 		if (pixfmt == V4L2_PIX_FMT_SBGGR16)
158 			isif->isif_cfg.data_pack = ISIF_PACK_16BIT;
159 		else if ((pixfmt == V4L2_PIX_FMT_SGRBG10DPCM8) ||
160 				(pixfmt == V4L2_PIX_FMT_SGRBG10ALAW8))
161 			isif->isif_cfg.data_pack = ISIF_PACK_8BIT;
162 		else
163 			return -EINVAL;
164 
165 		isif->isif_cfg.bayer.pix_fmt = ISIF_PIXFMT_RAW;
166 		isif->isif_cfg.bayer.v4l2_pix_fmt = pixfmt;
167 	} else {
168 		if (pixfmt == V4L2_PIX_FMT_YUYV)
169 			isif->isif_cfg.ycbcr.pix_order = ISIF_PIXORDER_YCBYCR;
170 		else if (pixfmt == V4L2_PIX_FMT_UYVY)
171 			isif->isif_cfg.ycbcr.pix_order = ISIF_PIXORDER_CBYCRY;
172 		else
173 			return -EINVAL;
174 
175 		isif->isif_cfg.data_pack = ISIF_PACK_8BIT;
176 		isif->isif_cfg.ycbcr.v4l2_pix_fmt = pixfmt;
177 	}
178 
179 	return 0;
180 }
181 
182 static int
isif_set_frame_format(struct vpfe_isif_device * isif,enum isif_frmfmt frm_fmt)183 isif_set_frame_format(struct vpfe_isif_device *isif,
184 		      enum isif_frmfmt frm_fmt)
185 {
186 	if (isif->formats[ISIF_PAD_SINK].code == MEDIA_BUS_FMT_SGRBG12_1X12)
187 		isif->isif_cfg.bayer.frm_fmt = frm_fmt;
188 	else
189 		isif->isif_cfg.ycbcr.frm_fmt = frm_fmt;
190 
191 	return 0;
192 }
193 
isif_set_image_window(struct vpfe_isif_device * isif)194 static int isif_set_image_window(struct vpfe_isif_device *isif)
195 {
196 	struct v4l2_rect *win = &isif->crop;
197 
198 	if (isif->formats[ISIF_PAD_SINK].code == MEDIA_BUS_FMT_SGRBG12_1X12) {
199 		isif->isif_cfg.bayer.win.top = win->top;
200 		isif->isif_cfg.bayer.win.left = win->left;
201 		isif->isif_cfg.bayer.win.width = win->width;
202 		isif->isif_cfg.bayer.win.height = win->height;
203 		return 0;
204 	}
205 	isif->isif_cfg.ycbcr.win.top = win->top;
206 	isif->isif_cfg.ycbcr.win.left = win->left;
207 	isif->isif_cfg.ycbcr.win.width = win->width;
208 	isif->isif_cfg.ycbcr.win.height = win->height;
209 
210 	return 0;
211 }
212 
213 static int
isif_set_buftype(struct vpfe_isif_device * isif,enum isif_buftype buf_type)214 isif_set_buftype(struct vpfe_isif_device *isif, enum isif_buftype buf_type)
215 {
216 	if (isif->formats[ISIF_PAD_SINK].code == MEDIA_BUS_FMT_SGRBG12_1X12)
217 		isif->isif_cfg.bayer.buf_type = buf_type;
218 	else
219 		isif->isif_cfg.ycbcr.buf_type = buf_type;
220 
221 	return 0;
222 }
223 
224 /* configure format in isif hardware */
225 static int
isif_config_format(struct vpfe_device * vpfe_dev,unsigned int pad)226 isif_config_format(struct vpfe_device *vpfe_dev, unsigned int pad)
227 {
228 	struct vpfe_isif_device *vpfe_isif = &vpfe_dev->vpfe_isif;
229 	enum isif_frmfmt frm_fmt = ISIF_FRMFMT_INTERLACED;
230 	struct v4l2_pix_format format;
231 	int ret = 0;
232 
233 	v4l2_fill_pix_format(&format, &vpfe_dev->vpfe_isif.formats[pad]);
234 	mbus_to_pix(&vpfe_dev->vpfe_isif.formats[pad], &format);
235 
236 	if (isif_set_pixel_format(vpfe_isif, format.pixelformat) < 0) {
237 		v4l2_err(&vpfe_dev->v4l2_dev,
238 			 "Failed to set pixel format in isif\n");
239 		return -EINVAL;
240 	}
241 
242 	/* call for s_crop will override these values */
243 	vpfe_isif->crop.left = 0;
244 	vpfe_isif->crop.top = 0;
245 	vpfe_isif->crop.width = format.width;
246 	vpfe_isif->crop.height = format.height;
247 
248 	/* configure the image window */
249 	isif_set_image_window(vpfe_isif);
250 
251 	switch (vpfe_dev->vpfe_isif.formats[pad].field) {
252 	case V4L2_FIELD_INTERLACED:
253 		/* do nothing, since it is default */
254 		ret = isif_set_buftype(vpfe_isif, ISIF_BUFTYPE_FLD_INTERLEAVED);
255 		break;
256 
257 	case V4L2_FIELD_NONE:
258 		frm_fmt = ISIF_FRMFMT_PROGRESSIVE;
259 		/* buffer type only applicable for interlaced scan */
260 		break;
261 
262 	case V4L2_FIELD_SEQ_TB:
263 		ret = isif_set_buftype(vpfe_isif, ISIF_BUFTYPE_FLD_SEPARATED);
264 		break;
265 
266 	default:
267 		return -EINVAL;
268 	}
269 
270 	/* set the frame format */
271 	if (!ret)
272 		ret = isif_set_frame_format(vpfe_isif, frm_fmt);
273 
274 	return ret;
275 }
276 
277 /*
278  * isif_try_format() - Try video format on a pad
279  * @isif: VPFE isif device
280  * @cfg: V4L2 subdev pad config
281  * @fmt: pointer to v4l2 subdev format structure
282  */
283 static void
isif_try_format(struct vpfe_isif_device * isif,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_format * fmt)284 isif_try_format(struct vpfe_isif_device *isif,
285 		struct v4l2_subdev_pad_config *cfg,
286 		struct v4l2_subdev_format *fmt)
287 {
288 	unsigned int width = fmt->format.width;
289 	unsigned int height = fmt->format.height;
290 	unsigned int i;
291 
292 	for (i = 0; i < ARRAY_SIZE(isif_fmts); i++) {
293 		if (fmt->format.code == isif_fmts[i])
294 			break;
295 	}
296 
297 	/* If not found, use YUYV8_2x8 as default */
298 	if (i >= ARRAY_SIZE(isif_fmts))
299 		fmt->format.code = MEDIA_BUS_FMT_YUYV8_2X8;
300 
301 	/* Clamp the size. */
302 	fmt->format.width = clamp_t(u32, width, 32, MAX_WIDTH);
303 	fmt->format.height = clamp_t(u32, height, 32, MAX_HEIGHT);
304 
305 	/* The data formatter truncates the number of horizontal output
306 	 * pixels to a multiple of 16. To avoid clipping data, allow
307 	 * callers to request an output size bigger than the input size
308 	 * up to the nearest multiple of 16.
309 	 */
310 	if (fmt->pad == ISIF_PAD_SOURCE)
311 		fmt->format.width &= ~15;
312 }
313 
314 /*
315  * vpfe_isif_buffer_isr() - isif module non-progressive buffer scheduling isr
316  * @isif: Pointer to isif subdevice.
317  */
vpfe_isif_buffer_isr(struct vpfe_isif_device * isif)318 void vpfe_isif_buffer_isr(struct vpfe_isif_device *isif)
319 {
320 	struct vpfe_device *vpfe_dev = to_vpfe_device(isif);
321 	struct vpfe_video_device *video = &isif->video_out;
322 	enum v4l2_field field;
323 	int fid;
324 
325 	if (!video->started)
326 		return;
327 
328 	field = video->fmt.fmt.pix.field;
329 
330 	if (field == V4L2_FIELD_NONE) {
331 		/* handle progressive frame capture */
332 		if (video->cur_frm != video->next_frm)
333 			vpfe_video_process_buffer_complete(video);
334 		return;
335 	}
336 
337 	/* interlaced or TB capture check which field we
338 	 * are in hardware
339 	 */
340 	fid = vpfe_isif_get_fid(vpfe_dev);
341 
342 	/* switch the software maintained field id */
343 	video->field_id ^= 1;
344 	if (fid == video->field_id) {
345 		/* we are in-sync here,continue */
346 		if (fid == 0) {
347 			/*
348 			 * One frame is just being captured. If the
349 			 * next frame is available, release the current
350 			 * frame and move on
351 			 */
352 			if (video->cur_frm != video->next_frm)
353 				vpfe_video_process_buffer_complete(video);
354 			/*
355 			 * based on whether the two fields are stored
356 			 * interleavely or separately in memory,
357 			 * reconfigure the ISIF memory address
358 			 */
359 			if (field == V4L2_FIELD_SEQ_TB)
360 				vpfe_video_schedule_bottom_field(video);
361 			return;
362 		}
363 		/*
364 		 * if one field is just being captured configure
365 		 * the next frame get the next frame from the
366 		 * empty queue if no frame is available hold on
367 		 * to the current buffer
368 		 */
369 		spin_lock(&video->dma_queue_lock);
370 		if (!list_empty(&video->dma_queue) &&
371 		video->cur_frm == video->next_frm)
372 			vpfe_video_schedule_next_buffer(video);
373 		spin_unlock(&video->dma_queue_lock);
374 	} else if (fid == 0) {
375 		/*
376 		 * out of sync. Recover from any hardware out-of-sync.
377 		 * May loose one frame
378 		 */
379 		video->field_id = fid;
380 	}
381 }
382 
383 /*
384  * vpfe_isif_vidint1_isr() - ISIF module progressive buffer scheduling isr
385  * @isif: Pointer to isif subdevice.
386  */
vpfe_isif_vidint1_isr(struct vpfe_isif_device * isif)387 void vpfe_isif_vidint1_isr(struct vpfe_isif_device *isif)
388 {
389 	struct vpfe_video_device *video = &isif->video_out;
390 
391 	if (!video->started)
392 		return;
393 
394 	spin_lock(&video->dma_queue_lock);
395 	if (video->fmt.fmt.pix.field == V4L2_FIELD_NONE &&
396 	    !list_empty(&video->dma_queue) && video->cur_frm == video->next_frm)
397 		vpfe_video_schedule_next_buffer(video);
398 
399 	spin_unlock(&video->dma_queue_lock);
400 }
401 
402 /*
403  * VPFE video operations
404  */
405 
isif_video_queue(struct vpfe_device * vpfe_dev,unsigned long addr)406 static int isif_video_queue(struct vpfe_device *vpfe_dev, unsigned long addr)
407 {
408 	struct vpfe_isif_device *isif = &vpfe_dev->vpfe_isif;
409 
410 	isif_write(isif->isif_cfg.base_addr, (addr >> 21) &
411 		ISIF_CADU_BITS, CADU);
412 	isif_write(isif->isif_cfg.base_addr, (addr >> 5) &
413 		ISIF_CADL_BITS, CADL);
414 
415 	return 0;
416 }
417 
418 static const struct vpfe_video_operations isif_video_ops = {
419 	.queue = isif_video_queue,
420 };
421 
422 /*
423  * V4L2 subdev operations
424  */
425 
426 /* Parameter operations */
isif_get_params(struct v4l2_subdev * sd,void * params)427 static int isif_get_params(struct v4l2_subdev *sd, void *params)
428 {
429 	struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd);
430 
431 	/* only raw module parameters can be set through the IOCTL */
432 	if (isif->formats[ISIF_PAD_SINK].code != MEDIA_BUS_FMT_SGRBG12_1X12)
433 		return -EINVAL;
434 	memcpy(params, &isif->isif_cfg.bayer.config_params,
435 			sizeof(isif->isif_cfg.bayer.config_params));
436 	return 0;
437 }
438 
isif_validate_df_csc_params(struct vpfe_isif_df_csc * df_csc)439 static int isif_validate_df_csc_params(struct vpfe_isif_df_csc *df_csc)
440 {
441 	struct vpfe_isif_color_space_conv *csc;
442 	int err = -EINVAL;
443 	int i;
444 
445 	if (!df_csc->df_or_csc) {
446 		/* csc configuration */
447 		csc = &df_csc->csc;
448 		if (csc->en) {
449 			for (i = 0; i < VPFE_ISIF_CSC_NUM_COEFF; i++)
450 				if (csc->coeff[i].integer >
451 				    ISIF_CSC_COEF_INTEG_MASK ||
452 				    csc->coeff[i].decimal >
453 				    ISIF_CSC_COEF_DECIMAL_MASK) {
454 					pr_err("Invalid CSC coefficients\n");
455 					return err;
456 				}
457 		}
458 	}
459 	if (df_csc->start_pix > ISIF_DF_CSC_SPH_MASK) {
460 		pr_err("Invalid df_csc start pix value\n");
461 		return err;
462 	}
463 
464 	if (df_csc->num_pixels > ISIF_DF_NUMPIX) {
465 		pr_err("Invalid df_csc num pixels value\n");
466 		return err;
467 	}
468 
469 	if (df_csc->start_line > ISIF_DF_CSC_LNH_MASK) {
470 		pr_err("Invalid df_csc start_line value\n");
471 		return err;
472 	}
473 
474 	if (df_csc->num_lines > ISIF_DF_NUMLINES) {
475 		pr_err("Invalid df_csc num_lines value\n");
476 		return err;
477 	}
478 
479 	return 0;
480 }
481 
482 #define DM365_ISIF_MAX_VDFLSFT		4
483 #define DM365_ISIF_MAX_VDFSLV		4095
484 #define DM365_ISIF_MAX_DFCMEM0		0x1fff
485 #define DM365_ISIF_MAX_DFCMEM1		0x1fff
486 
isif_validate_dfc_params(struct vpfe_isif_dfc * dfc)487 static int isif_validate_dfc_params(struct vpfe_isif_dfc *dfc)
488 {
489 	int err = -EINVAL;
490 	int i;
491 
492 	if (!dfc->en)
493 		return 0;
494 
495 	if (dfc->corr_whole_line > 1) {
496 		pr_err("Invalid corr_whole_line value\n");
497 		return err;
498 	}
499 
500 	if (dfc->def_level_shift > DM365_ISIF_MAX_VDFLSFT) {
501 		pr_err("Invalid def_level_shift value\n");
502 		return err;
503 	}
504 
505 	if (dfc->def_sat_level > DM365_ISIF_MAX_VDFSLV) {
506 		pr_err("Invalid def_sat_level value\n");
507 		return err;
508 	}
509 
510 	if (!dfc->num_vdefects ||
511 	    dfc->num_vdefects > VPFE_ISIF_VDFC_TABLE_SIZE) {
512 		pr_err("Invalid num_vdefects value\n");
513 		return err;
514 	}
515 
516 	for (i = 0; i < VPFE_ISIF_VDFC_TABLE_SIZE; i++) {
517 		if (dfc->table[i].pos_vert > DM365_ISIF_MAX_DFCMEM0) {
518 			pr_err("Invalid pos_vert value\n");
519 			return err;
520 		}
521 		if (dfc->table[i].pos_horz > DM365_ISIF_MAX_DFCMEM1) {
522 			pr_err("Invalid pos_horz value\n");
523 			return err;
524 		}
525 	}
526 
527 	return 0;
528 }
529 
530 #define DM365_ISIF_MAX_CLVRV			0xfff
531 #define DM365_ISIF_MAX_CLDC			0x1fff
532 #define DM365_ISIF_MAX_CLHSH			0x1fff
533 #define DM365_ISIF_MAX_CLHSV			0x1fff
534 #define DM365_ISIF_MAX_CLVSH			0x1fff
535 #define DM365_ISIF_MAX_CLVSV			0x1fff
536 #define DM365_ISIF_MAX_HEIGHT_BLACK_REGION	0x1fff
537 
isif_validate_bclamp_params(struct vpfe_isif_black_clamp * bclamp)538 static int isif_validate_bclamp_params(struct vpfe_isif_black_clamp *bclamp)
539 {
540 	int err = -EINVAL;
541 
542 	if (bclamp->dc_offset > DM365_ISIF_MAX_CLDC) {
543 		pr_err("Invalid bclamp dc_offset value\n");
544 		return err;
545 	}
546 	if (!bclamp->en)
547 		return 0;
548 	if (bclamp->horz.clamp_pix_limit > 1) {
549 		pr_err("Invalid bclamp horz clamp_pix_limit value\n");
550 		return err;
551 	}
552 	if (bclamp->horz.win_count_calc < 1 ||
553 			bclamp->horz.win_count_calc > 32) {
554 		pr_err("Invalid bclamp horz win_count_calc value\n");
555 		return err;
556 	}
557 	if (bclamp->horz.win_start_h_calc > DM365_ISIF_MAX_CLHSH) {
558 		pr_err("Invalid bclamp win_start_v_calc value\n");
559 		return err;
560 	}
561 
562 	if (bclamp->horz.win_start_v_calc > DM365_ISIF_MAX_CLHSV) {
563 		pr_err("Invalid bclamp win_start_v_calc value\n");
564 		return err;
565 	}
566 	if (bclamp->vert.reset_clamp_val > DM365_ISIF_MAX_CLVRV) {
567 		pr_err("Invalid bclamp reset_clamp_val value\n");
568 		return err;
569 	}
570 	if (bclamp->vert.ob_v_sz_calc > DM365_ISIF_MAX_HEIGHT_BLACK_REGION) {
571 		pr_err("Invalid bclamp ob_v_sz_calc value\n");
572 		return err;
573 	}
574 	if (bclamp->vert.ob_start_h > DM365_ISIF_MAX_CLVSH) {
575 		pr_err("Invalid bclamp ob_start_h value\n");
576 		return err;
577 	}
578 	if (bclamp->vert.ob_start_v > DM365_ISIF_MAX_CLVSV) {
579 		pr_err("Invalid bclamp ob_start_h value\n");
580 		return err;
581 	}
582 	return 0;
583 }
584 
585 static int
isif_validate_raw_params(struct vpfe_isif_raw_config * params)586 isif_validate_raw_params(struct vpfe_isif_raw_config *params)
587 {
588 	int ret;
589 
590 	ret = isif_validate_df_csc_params(&params->df_csc);
591 	if (ret)
592 		return ret;
593 	ret = isif_validate_dfc_params(&params->dfc);
594 	if (ret)
595 		return ret;
596 	return isif_validate_bclamp_params(&params->bclamp);
597 }
598 
isif_set_params(struct v4l2_subdev * sd,void * params)599 static int isif_set_params(struct v4l2_subdev *sd, void *params)
600 {
601 	struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd);
602 	struct vpfe_isif_raw_config isif_raw_params;
603 	int ret = -EINVAL;
604 
605 	/* only raw module parameters can be set through the IOCTL */
606 	if (isif->formats[ISIF_PAD_SINK].code != MEDIA_BUS_FMT_SGRBG12_1X12)
607 		return ret;
608 
609 	memcpy(&isif_raw_params, params, sizeof(isif_raw_params));
610 	if (!isif_validate_raw_params(&isif_raw_params)) {
611 		memcpy(&isif->isif_cfg.bayer.config_params, &isif_raw_params,
612 			sizeof(isif_raw_params));
613 		ret = 0;
614 	}
615 	return ret;
616 }
617 /*
618  * isif_ioctl() - isif module private ioctl's
619  * @sd: VPFE isif V4L2 subdevice
620  * @cmd: ioctl command
621  * @arg: ioctl argument
622  *
623  * Return 0 on success or a negative error code otherwise.
624  */
isif_ioctl(struct v4l2_subdev * sd,unsigned int cmd,void * arg)625 static long isif_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
626 {
627 	switch (cmd) {
628 	case VIDIOC_VPFE_ISIF_S_RAW_PARAMS:
629 		return isif_set_params(sd, arg);
630 
631 	case VIDIOC_VPFE_ISIF_G_RAW_PARAMS:
632 		return isif_get_params(sd, arg);
633 
634 	default:
635 		return -ENOIOCTLCMD;
636 	}
637 }
638 
isif_config_gain_offset(struct vpfe_isif_device * isif)639 static void isif_config_gain_offset(struct vpfe_isif_device *isif)
640 {
641 	struct vpfe_isif_gain_offsets_adj *gain_off_ptr =
642 		&isif->isif_cfg.bayer.config_params.gain_offset;
643 	void __iomem *base = isif->isif_cfg.base_addr;
644 	u32 val;
645 
646 	val = ((gain_off_ptr->gain_sdram_en & 1) << GAIN_SDRAM_EN_SHIFT) |
647 	      ((gain_off_ptr->gain_ipipe_en & 1) << GAIN_IPIPE_EN_SHIFT) |
648 	      ((gain_off_ptr->gain_h3a_en & 1) << GAIN_H3A_EN_SHIFT) |
649 	      ((gain_off_ptr->offset_sdram_en & 1) << OFST_SDRAM_EN_SHIFT) |
650 	      ((gain_off_ptr->offset_ipipe_en & 1) << OFST_IPIPE_EN_SHIFT) |
651 	      ((gain_off_ptr->offset_h3a_en & 1) << OFST_H3A_EN_SHIFT);
652 	isif_merge(base, GAIN_OFFSET_EN_MASK, val, CGAMMAWD);
653 
654 	isif_write(base, isif->isif_cfg.isif_gain_params.cr_gain, CRGAIN);
655 	isif_write(base, isif->isif_cfg.isif_gain_params.cgr_gain, CGRGAIN);
656 	isif_write(base, isif->isif_cfg.isif_gain_params.cgb_gain, CGBGAIN);
657 	isif_write(base, isif->isif_cfg.isif_gain_params.cb_gain, CBGAIN);
658 	isif_write(base, isif->isif_cfg.isif_gain_params.offset & OFFSET_MASK,
659 		   COFSTA);
660 
661 }
662 
isif_config_bclamp(struct vpfe_isif_device * isif,struct vpfe_isif_black_clamp * bc)663 static void isif_config_bclamp(struct vpfe_isif_device *isif,
664 		   struct vpfe_isif_black_clamp *bc)
665 {
666 	u32 val;
667 
668 	/**
669 	 * DC Offset is always added to image data irrespective of bc enable
670 	 * status
671 	 */
672 	val = bc->dc_offset & ISIF_BC_DCOFFSET_MASK;
673 	isif_write(isif->isif_cfg.base_addr, val, CLDCOFST);
674 
675 	if (!bc->en)
676 		return;
677 
678 	val = (bc->bc_mode_color & ISIF_BC_MODE_COLOR_MASK) <<
679 		ISIF_BC_MODE_COLOR_SHIFT;
680 
681 	/* Enable BC and horizontal clamp calculation paramaters */
682 	val = val | 1 | ((bc->horz.mode & ISIF_HORZ_BC_MODE_MASK) <<
683 	      ISIF_HORZ_BC_MODE_SHIFT);
684 
685 	isif_write(isif->isif_cfg.base_addr, val, CLAMPCFG);
686 
687 	if (bc->horz.mode != VPFE_ISIF_HORZ_BC_DISABLE) {
688 		/*
689 		 * Window count for calculation
690 		 * Base window selection
691 		 * pixel limit
692 		 * Horizontal size of window
693 		 * vertical size of the window
694 		 * Horizontal start position of the window
695 		 * Vertical start position of the window
696 		 */
697 		val = (bc->horz.win_count_calc & ISIF_HORZ_BC_WIN_COUNT_MASK) |
698 		      ((bc->horz.base_win_sel_calc & 1) <<
699 		      ISIF_HORZ_BC_WIN_SEL_SHIFT) |
700 		      ((bc->horz.clamp_pix_limit & 1) <<
701 		      ISIF_HORZ_BC_PIX_LIMIT_SHIFT) |
702 		      ((bc->horz.win_h_sz_calc &
703 		      ISIF_HORZ_BC_WIN_H_SIZE_MASK) <<
704 		      ISIF_HORZ_BC_WIN_H_SIZE_SHIFT) |
705 		      ((bc->horz.win_v_sz_calc &
706 		      ISIF_HORZ_BC_WIN_V_SIZE_MASK) <<
707 		      ISIF_HORZ_BC_WIN_V_SIZE_SHIFT);
708 
709 		isif_write(isif->isif_cfg.base_addr, val, CLHWIN0);
710 
711 		val = bc->horz.win_start_h_calc & ISIF_HORZ_BC_WIN_START_H_MASK;
712 		isif_write(isif->isif_cfg.base_addr, val, CLHWIN1);
713 
714 		val = bc->horz.win_start_v_calc & ISIF_HORZ_BC_WIN_START_V_MASK;
715 		isif_write(isif->isif_cfg.base_addr, val, CLHWIN2);
716 	}
717 
718 	/* vertical clamp calculation paramaters */
719 	/* OB H Valid */
720 	val = bc->vert.ob_h_sz_calc & ISIF_VERT_BC_OB_H_SZ_MASK;
721 
722 	/* Reset clamp value sel for previous line */
723 	val |= (bc->vert.reset_val_sel & ISIF_VERT_BC_RST_VAL_SEL_MASK) <<
724 				ISIF_VERT_BC_RST_VAL_SEL_SHIFT;
725 
726 	/* Line average coefficient */
727 	val |= bc->vert.line_ave_coef << ISIF_VERT_BC_LINE_AVE_COEF_SHIFT;
728 	isif_write(isif->isif_cfg.base_addr, val, CLVWIN0);
729 
730 	/* Configured reset value */
731 	if (bc->vert.reset_val_sel == VPFE_ISIF_VERT_BC_USE_CONFIG_CLAMP_VAL) {
732 		val = bc->vert.reset_clamp_val & ISIF_VERT_BC_RST_VAL_MASK;
733 		isif_write(isif->isif_cfg.base_addr, val, CLVRV);
734 	}
735 
736 	/* Optical Black horizontal start position */
737 	val = bc->vert.ob_start_h & ISIF_VERT_BC_OB_START_HORZ_MASK;
738 	isif_write(isif->isif_cfg.base_addr, val, CLVWIN1);
739 
740 	/* Optical Black vertical start position */
741 	val = bc->vert.ob_start_v & ISIF_VERT_BC_OB_START_VERT_MASK;
742 	isif_write(isif->isif_cfg.base_addr, val, CLVWIN2);
743 
744 	val = bc->vert.ob_v_sz_calc & ISIF_VERT_BC_OB_VERT_SZ_MASK;
745 	isif_write(isif->isif_cfg.base_addr, val, CLVWIN3);
746 
747 	/* Vertical start position for BC subtraction */
748 	val = bc->vert_start_sub & ISIF_BC_VERT_START_SUB_V_MASK;
749 	isif_write(isif->isif_cfg.base_addr, val, CLSV);
750 }
751 
752 /* This function will configure the window size to be capture in ISIF reg */
753 static void
isif_setwin(struct vpfe_isif_device * isif,struct v4l2_rect * image_win,enum isif_frmfmt frm_fmt,int ppc,int mode)754 isif_setwin(struct vpfe_isif_device *isif, struct v4l2_rect *image_win,
755 	    enum isif_frmfmt frm_fmt, int ppc, int mode)
756 {
757 	int horz_nr_pixels;
758 	int vert_nr_lines;
759 	int horz_start;
760 	int vert_start;
761 	int mid_img;
762 
763 	/*
764 	 * ppc - per pixel count. indicates how many pixels per cell
765 	 * output to SDRAM. example, for ycbcr, it is one y and one c, so 2.
766 	 * raw capture this is 1
767 	 */
768 	horz_start = image_win->left << (ppc - 1);
769 	horz_nr_pixels = (image_win->width << (ppc - 1)) - 1;
770 
771 	/* Writing the horizontal info into the registers */
772 	isif_write(isif->isif_cfg.base_addr,
773 		   horz_start & START_PX_HOR_MASK, SPH);
774 	isif_write(isif->isif_cfg.base_addr,
775 		   horz_nr_pixels & NUM_PX_HOR_MASK, LNH);
776 	vert_start = image_win->top;
777 
778 	if (frm_fmt == ISIF_FRMFMT_INTERLACED) {
779 		vert_nr_lines = (image_win->height >> 1) - 1;
780 		vert_start >>= 1;
781 		/* To account for VD since line 0 doesn't have any data */
782 		vert_start += 1;
783 	} else {
784 		/* To account for VD since line 0 doesn't have any data */
785 		vert_start += 1;
786 		vert_nr_lines = image_win->height - 1;
787 		/* configure VDINT0 and VDINT1 */
788 		mid_img = vert_start + (image_win->height / 2);
789 		isif_write(isif->isif_cfg.base_addr, mid_img, VDINT1);
790 	}
791 
792 	if (!mode)
793 		isif_write(isif->isif_cfg.base_addr, 0, VDINT0);
794 	else
795 		isif_write(isif->isif_cfg.base_addr, vert_nr_lines, VDINT0);
796 	isif_write(isif->isif_cfg.base_addr,
797 		   vert_start & START_VER_ONE_MASK, SLV0);
798 	isif_write(isif->isif_cfg.base_addr,
799 		   vert_start & START_VER_TWO_MASK, SLV1);
800 	isif_write(isif->isif_cfg.base_addr,
801 		   vert_nr_lines & NUM_LINES_VER, LNV);
802 }
803 
804 #define DM365_ISIF_DFCMWR_MEMORY_WRITE		1
805 #define DM365_ISIF_DFCMRD_MEMORY_READ		0x2
806 
807 static void
isif_config_dfc(struct vpfe_isif_device * isif,struct vpfe_isif_dfc * vdfc)808 isif_config_dfc(struct vpfe_isif_device *isif, struct vpfe_isif_dfc *vdfc)
809 {
810 #define DFC_WRITE_WAIT_COUNT	1000
811 	u32 count = DFC_WRITE_WAIT_COUNT;
812 	u32 val;
813 	int i;
814 
815 	if (!vdfc->en)
816 		return;
817 
818 	/* Correction mode */
819 	val = (vdfc->corr_mode & ISIF_VDFC_CORR_MOD_MASK) <<
820 	       ISIF_VDFC_CORR_MOD_SHIFT;
821 
822 	/* Correct whole line or partial */
823 	if (vdfc->corr_whole_line)
824 		val |= 1 << ISIF_VDFC_CORR_WHOLE_LN_SHIFT;
825 
826 	/* level shift value */
827 	val |= (vdfc->def_level_shift & ISIF_VDFC_LEVEL_SHFT_MASK) <<
828 		ISIF_VDFC_LEVEL_SHFT_SHIFT;
829 
830 	isif_write(isif->isif_cfg.base_addr, val, DFCCTL);
831 
832 	/* Defect saturation level */
833 	val = vdfc->def_sat_level & ISIF_VDFC_SAT_LEVEL_MASK;
834 	isif_write(isif->isif_cfg.base_addr, val, VDFSATLV);
835 
836 	isif_write(isif->isif_cfg.base_addr, vdfc->table[0].pos_vert &
837 		   ISIF_VDFC_POS_MASK, DFCMEM0);
838 	isif_write(isif->isif_cfg.base_addr, vdfc->table[0].pos_horz &
839 		   ISIF_VDFC_POS_MASK, DFCMEM1);
840 	if (vdfc->corr_mode == VPFE_ISIF_VDFC_NORMAL ||
841 	    vdfc->corr_mode == VPFE_ISIF_VDFC_HORZ_INTERPOL_IF_SAT) {
842 		isif_write(isif->isif_cfg.base_addr,
843 			   vdfc->table[0].level_at_pos, DFCMEM2);
844 		isif_write(isif->isif_cfg.base_addr,
845 			   vdfc->table[0].level_up_pixels, DFCMEM3);
846 		isif_write(isif->isif_cfg.base_addr,
847 			   vdfc->table[0].level_low_pixels, DFCMEM4);
848 	}
849 
850 	val = isif_read(isif->isif_cfg.base_addr, DFCMEMCTL);
851 	/* set DFCMARST and set DFCMWR */
852 	val |= 1 << ISIF_DFCMEMCTL_DFCMARST_SHIFT;
853 	val |= 1;
854 	isif_write(isif->isif_cfg.base_addr, val, DFCMEMCTL);
855 
856 	while (count && (isif_read(isif->isif_cfg.base_addr, DFCMEMCTL) & 0x01))
857 		count--;
858 
859 	val = isif_read(isif->isif_cfg.base_addr, DFCMEMCTL);
860 	if (!count) {
861 		pr_debug("defect table write timeout !!\n");
862 		return;
863 	}
864 
865 	for (i = 1; i < vdfc->num_vdefects; i++) {
866 		isif_write(isif->isif_cfg.base_addr, vdfc->table[i].pos_vert &
867 			ISIF_VDFC_POS_MASK, DFCMEM0);
868 
869 		isif_write(isif->isif_cfg.base_addr, vdfc->table[i].pos_horz &
870 			ISIF_VDFC_POS_MASK, DFCMEM1);
871 
872 		if (vdfc->corr_mode == VPFE_ISIF_VDFC_NORMAL ||
873 		    vdfc->corr_mode == VPFE_ISIF_VDFC_HORZ_INTERPOL_IF_SAT) {
874 			isif_write(isif->isif_cfg.base_addr,
875 				   vdfc->table[i].level_at_pos, DFCMEM2);
876 			isif_write(isif->isif_cfg.base_addr,
877 				   vdfc->table[i].level_up_pixels, DFCMEM3);
878 			isif_write(isif->isif_cfg.base_addr,
879 				   vdfc->table[i].level_low_pixels, DFCMEM4);
880 		}
881 		val = isif_read(isif->isif_cfg.base_addr, DFCMEMCTL);
882 		/* clear DFCMARST and set DFCMWR */
883 		val &= ~(1 << ISIF_DFCMEMCTL_DFCMARST_SHIFT);
884 		val |= 1;
885 		isif_write(isif->isif_cfg.base_addr, val, DFCMEMCTL);
886 
887 		count = DFC_WRITE_WAIT_COUNT;
888 		while (count && (isif_read(isif->isif_cfg.base_addr,
889 			DFCMEMCTL) & 0x01))
890 			count--;
891 
892 		val = isif_read(isif->isif_cfg.base_addr, DFCMEMCTL);
893 		if (!count) {
894 			pr_debug("defect table write timeout !!\n");
895 			return;
896 		}
897 	}
898 	if (vdfc->num_vdefects < VPFE_ISIF_VDFC_TABLE_SIZE) {
899 		/* Extra cycle needed */
900 		isif_write(isif->isif_cfg.base_addr, 0, DFCMEM0);
901 		isif_write(isif->isif_cfg.base_addr,
902 			   DM365_ISIF_MAX_DFCMEM1, DFCMEM1);
903 		isif_write(isif->isif_cfg.base_addr,
904 			   DM365_ISIF_DFCMWR_MEMORY_WRITE, DFCMEMCTL);
905 	}
906 	/* enable VDFC */
907 	isif_merge(isif->isif_cfg.base_addr, (1 << ISIF_VDFC_EN_SHIFT),
908 		   (1 << ISIF_VDFC_EN_SHIFT), DFCCTL);
909 
910 	isif_merge(isif->isif_cfg.base_addr, (1 << ISIF_VDFC_EN_SHIFT),
911 		   (0 << ISIF_VDFC_EN_SHIFT), DFCCTL);
912 
913 	isif_write(isif->isif_cfg.base_addr, 0x6, DFCMEMCTL);
914 	for (i = 0; i < vdfc->num_vdefects; i++) {
915 		count = DFC_WRITE_WAIT_COUNT;
916 		while (count &&
917 			(isif_read(isif->isif_cfg.base_addr, DFCMEMCTL) & 0x2))
918 			count--;
919 		val = isif_read(isif->isif_cfg.base_addr, DFCMEMCTL);
920 		if (!count) {
921 			pr_debug("defect table write timeout !!\n");
922 			return;
923 		}
924 		isif_write(isif->isif_cfg.base_addr,
925 			   DM365_ISIF_DFCMRD_MEMORY_READ, DFCMEMCTL);
926 	}
927 }
928 
929 static void
isif_config_csc(struct vpfe_isif_device * isif,struct vpfe_isif_df_csc * df_csc)930 isif_config_csc(struct vpfe_isif_device *isif, struct vpfe_isif_df_csc *df_csc)
931 {
932 	u32 val1;
933 	u32 val2;
934 	u32 i;
935 
936 	if (!df_csc->csc.en) {
937 		isif_write(isif->isif_cfg.base_addr, 0, CSCCTL);
938 		return;
939 	}
940 	/* initialize all bits to 0 */
941 	val1 = 0;
942 	for (i = 0; i < VPFE_ISIF_CSC_NUM_COEFF; i++) {
943 		if ((i % 2) == 0) {
944 			/* CSCM - LSB */
945 			val1 = ((df_csc->csc.coeff[i].integer &
946 				ISIF_CSC_COEF_INTEG_MASK) <<
947 				ISIF_CSC_COEF_INTEG_SHIFT) |
948 				((df_csc->csc.coeff[i].decimal &
949 				ISIF_CSC_COEF_DECIMAL_MASK));
950 		} else {
951 
952 			/* CSCM - MSB */
953 			val2 = ((df_csc->csc.coeff[i].integer &
954 				ISIF_CSC_COEF_INTEG_MASK) <<
955 				ISIF_CSC_COEF_INTEG_SHIFT) |
956 				((df_csc->csc.coeff[i].decimal &
957 				ISIF_CSC_COEF_DECIMAL_MASK));
958 			val2 <<= ISIF_CSCM_MSB_SHIFT;
959 			val2 |= val1;
960 			isif_write(isif->isif_cfg.base_addr, val2,
961 				   (CSCM0 + ((i-1) << 1)));
962 		}
963 	}
964 	/* program the active area */
965 	isif_write(isif->isif_cfg.base_addr, df_csc->start_pix &
966 		ISIF_DF_CSC_SPH_MASK, FMTSPH);
967 	/*
968 	 * one extra pixel as required for CSC. Actually number of
969 	 * pixel - 1 should be configured in this register. So we
970 	 * need to subtract 1 before writing to FMTSPH, but we will
971 	 * not do this since csc requires one extra pixel
972 	 */
973 	isif_write(isif->isif_cfg.base_addr, df_csc->num_pixels &
974 		ISIF_DF_CSC_SPH_MASK, FMTLNH);
975 	isif_write(isif->isif_cfg.base_addr, df_csc->start_line &
976 		ISIF_DF_CSC_SPH_MASK, FMTSLV);
977 	/*
978 	 * one extra line as required for CSC. See reason documented for
979 	 * num_pixels
980 	 */
981 	isif_write(isif->isif_cfg.base_addr, df_csc->num_lines &
982 		ISIF_DF_CSC_SPH_MASK, FMTLNV);
983 	/* Enable CSC */
984 	isif_write(isif->isif_cfg.base_addr, 1, CSCCTL);
985 }
986 
987 static void
isif_config_linearization(struct vpfe_isif_device * isif,struct vpfe_isif_linearize * linearize)988 isif_config_linearization(struct vpfe_isif_device *isif,
989 			  struct vpfe_isif_linearize *linearize)
990 {
991 	u32 val;
992 	u32 i;
993 
994 	if (!linearize->en) {
995 		isif_write(isif->isif_cfg.base_addr, 0, LINCFG0);
996 		return;
997 	}
998 	/* shift value for correction */
999 	val = (linearize->corr_shft & ISIF_LIN_CORRSFT_MASK) <<
1000 	      ISIF_LIN_CORRSFT_SHIFT;
1001 	/* enable */
1002 	val |= 1;
1003 	isif_write(isif->isif_cfg.base_addr, val, LINCFG0);
1004 	/* Scale factor */
1005 	val = (linearize->scale_fact.integer & 1) <<
1006 	      ISIF_LIN_SCALE_FACT_INTEG_SHIFT;
1007 	val |= linearize->scale_fact.decimal & ISIF_LIN_SCALE_FACT_DECIMAL_MASK;
1008 	isif_write(isif->isif_cfg.base_addr, val, LINCFG1);
1009 
1010 	for (i = 0; i < VPFE_ISIF_LINEAR_TAB_SIZE; i++) {
1011 		val = linearize->table[i] & ISIF_LIN_ENTRY_MASK;
1012 		if (i%2)
1013 			isif_regw_lin_tbl(isif, val, ((i >> 1) << 2), 1);
1014 		else
1015 			isif_regw_lin_tbl(isif, val, ((i >> 1) << 2), 0);
1016 	}
1017 }
1018 
1019 static void
isif_config_culling(struct vpfe_isif_device * isif,struct vpfe_isif_cul * cul)1020 isif_config_culling(struct vpfe_isif_device *isif, struct vpfe_isif_cul *cul)
1021 {
1022 	u32 val;
1023 
1024 	/* Horizontal pattern */
1025 	val = cul->hcpat_even << CULL_PAT_EVEN_LINE_SHIFT;
1026 	val |= cul->hcpat_odd;
1027 	isif_write(isif->isif_cfg.base_addr, val, CULH);
1028 	/* vertical pattern */
1029 	isif_write(isif->isif_cfg.base_addr, cul->vcpat, CULV);
1030 	/* LPF */
1031 	isif_merge(isif->isif_cfg.base_addr, ISIF_LPF_MASK << ISIF_LPF_SHIFT,
1032 		   cul->en_lpf << ISIF_LPF_SHIFT, MODESET);
1033 }
1034 
isif_get_pix_fmt(u32 mbus_code)1035 static int isif_get_pix_fmt(u32 mbus_code)
1036 {
1037 	switch (mbus_code) {
1038 	case MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8:
1039 	case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8:
1040 	case MEDIA_BUS_FMT_SGRBG12_1X12:
1041 		return ISIF_PIXFMT_RAW;
1042 
1043 	case MEDIA_BUS_FMT_YUYV8_2X8:
1044 	case MEDIA_BUS_FMT_UYVY8_2X8:
1045 	case MEDIA_BUS_FMT_YUYV10_2X10:
1046 	case MEDIA_BUS_FMT_Y8_1X8:
1047 		return ISIF_PIXFMT_YCBCR_8BIT;
1048 
1049 	case MEDIA_BUS_FMT_YUYV8_1X16:
1050 	case MEDIA_BUS_FMT_YUYV10_1X20:
1051 		return ISIF_PIXFMT_YCBCR_16BIT;
1052 
1053 	default:
1054 		break;
1055 	}
1056 	return -EINVAL;
1057 }
1058 
1059 #define ISIF_INTERLACE_INVERSE_MODE		0x4b6d
1060 #define ISIF_INTERLACE_NON_INVERSE_MODE		0x0b6d
1061 #define ISIF_PROGRESSIVE_INVERSE_MODE		0x4000
1062 #define ISIF_PROGRESSIVE_NON_INVERSE_MODE	0x0000
1063 
isif_config_raw(struct v4l2_subdev * sd,int mode)1064 static int isif_config_raw(struct v4l2_subdev *sd, int mode)
1065 {
1066 	struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd);
1067 	struct isif_params_raw *params = &isif->isif_cfg.bayer;
1068 	struct vpfe_isif_raw_config *module_params =
1069 				&isif->isif_cfg.bayer.config_params;
1070 	struct v4l2_mbus_framefmt *format;
1071 	int pix_fmt;
1072 	u32 val;
1073 
1074 	format = &isif->formats[ISIF_PAD_SINK];
1075 
1076 	/* In case of user has set BT656IF earlier, it should be reset
1077 	 * when configuring for raw input.
1078 	 */
1079 	isif_write(isif->isif_cfg.base_addr, 0, REC656IF);
1080 	/* Configure CCDCFG register
1081 	 * Set CCD Not to swap input since input is RAW data
1082 	 * Set FID detection function to Latch at V-Sync
1083 	 * Set WENLOG - isif valid area
1084 	 * Set TRGSEL
1085 	 * Set EXTRG
1086 	 * Packed to 8 or 16 bits
1087 	 */
1088 	val = ISIF_YCINSWP_RAW | ISIF_CCDCFG_FIDMD_LATCH_VSYNC |
1089 	      ISIF_CCDCFG_WENLOG_AND | ISIF_CCDCFG_TRGSEL_WEN |
1090 	      ISIF_CCDCFG_EXTRG_DISABLE | (isif->isif_cfg.data_pack &
1091 	      ISIF_DATA_PACK_MASK);
1092 	isif_write(isif->isif_cfg.base_addr, val, CCDCFG);
1093 
1094 	pix_fmt = isif_get_pix_fmt(format->code);
1095 	if (pix_fmt < 0) {
1096 		pr_debug("Invalid pix_fmt(input mode)\n");
1097 		return -EINVAL;
1098 	}
1099 	/*
1100 	 * Configure the vertical sync polarity(MODESET.VDPOL)
1101 	 * Configure the horizontal sync polarity (MODESET.HDPOL)
1102 	 * Configure frame id polarity (MODESET.FLDPOL)
1103 	 * Configure data polarity
1104 	 * Configure External WEN Selection
1105 	 * Configure frame format(progressive or interlace)
1106 	 * Configure pixel format (Input mode)
1107 	 * Configure the data shift
1108 	 */
1109 	val = ISIF_VDHDOUT_INPUT | ((params->vd_pol & ISIF_VD_POL_MASK) <<
1110 	      ISIF_VD_POL_SHIFT) | ((params->hd_pol & ISIF_HD_POL_MASK) <<
1111 	      ISIF_HD_POL_SHIFT) | ((params->fid_pol & ISIF_FID_POL_MASK) <<
1112 	      ISIF_FID_POL_SHIFT) | ((ISIF_DATAPOL_NORMAL &
1113 	      ISIF_DATAPOL_MASK) << ISIF_DATAPOL_SHIFT) | ((ISIF_EXWEN_DISABLE &
1114 	      ISIF_EXWEN_MASK) << ISIF_EXWEN_SHIFT) | ((params->frm_fmt &
1115 	      ISIF_FRM_FMT_MASK) << ISIF_FRM_FMT_SHIFT) | ((pix_fmt &
1116 	      ISIF_INPUT_MASK) << ISIF_INPUT_SHIFT);
1117 
1118 	/* currently only MEDIA_BUS_FMT_SGRBG12_1X12 is
1119 	 * supported. shift appropriately depending on
1120 	 * different MBUS fmt's added
1121 	 */
1122 	if (format->code == MEDIA_BUS_FMT_SGRBG12_1X12)
1123 		val |= ((VPFE_ISIF_NO_SHIFT &
1124 			ISIF_DATASFT_MASK) << ISIF_DATASFT_SHIFT);
1125 
1126 	isif_write(isif->isif_cfg.base_addr, val, MODESET);
1127 	/*
1128 	 * Configure GAMMAWD register
1129 	 * CFA pattern setting
1130 	 */
1131 	val = (params->cfa_pat & ISIF_GAMMAWD_CFA_MASK) <<
1132 		ISIF_GAMMAWD_CFA_SHIFT;
1133 	/* Gamma msb */
1134 	if (params->v4l2_pix_fmt == V4L2_PIX_FMT_SGRBG10ALAW8)
1135 		val = val | ISIF_ALAW_ENABLE;
1136 
1137 	val = val | ((params->data_msb & ISIF_ALAW_GAMA_WD_MASK) <<
1138 			ISIF_ALAW_GAMA_WD_SHIFT);
1139 
1140 	isif_write(isif->isif_cfg.base_addr, val, CGAMMAWD);
1141 	/* Configure DPCM compression settings */
1142 	if (params->v4l2_pix_fmt == V4L2_PIX_FMT_SGRBG10DPCM8) {
1143 		val =  1 << ISIF_DPCM_EN_SHIFT;
1144 		val |= (params->dpcm_predictor &
1145 			ISIF_DPCM_PREDICTOR_MASK) << ISIF_DPCM_PREDICTOR_SHIFT;
1146 	}
1147 	isif_write(isif->isif_cfg.base_addr, val, MISC);
1148 	/* Configure Gain & Offset */
1149 	isif_config_gain_offset(isif);
1150 	/* Configure Color pattern */
1151 	if (format->code == MEDIA_BUS_FMT_SGRBG12_1X12)
1152 		val = isif_sgrbg_pattern;
1153 	else
1154 		/* default set to rggb */
1155 		val = isif_srggb_pattern;
1156 
1157 	isif_write(isif->isif_cfg.base_addr, val, CCOLP);
1158 
1159 	/* Configure HSIZE register  */
1160 	val = (params->horz_flip_en & ISIF_HSIZE_FLIP_MASK) <<
1161 	      ISIF_HSIZE_FLIP_SHIFT;
1162 
1163 	/* calculate line offset in 32 bytes based on pack value */
1164 	if (isif->isif_cfg.data_pack == ISIF_PACK_8BIT)
1165 		val |= ((params->win.width + 31) >> 5) & ISIF_LINEOFST_MASK;
1166 	else if (isif->isif_cfg.data_pack == ISIF_PACK_12BIT)
1167 		val |= ((((params->win.width + (params->win.width >> 2)) +
1168 			31) >> 5) & ISIF_LINEOFST_MASK);
1169 	else
1170 		val |= (((params->win.width * 2) + 31) >> 5) &
1171 			ISIF_LINEOFST_MASK;
1172 	isif_write(isif->isif_cfg.base_addr, val, HSIZE);
1173 	/* Configure SDOFST register  */
1174 	if (params->frm_fmt == ISIF_FRMFMT_INTERLACED) {
1175 		if (params->image_invert_en)
1176 			/* For interlace inverse mode */
1177 			isif_write(isif->isif_cfg.base_addr,
1178 				   ISIF_INTERLACE_INVERSE_MODE, SDOFST);
1179 		else
1180 			/* For interlace non inverse mode */
1181 			isif_write(isif->isif_cfg.base_addr,
1182 				   ISIF_INTERLACE_NON_INVERSE_MODE, SDOFST);
1183 	} else if (params->frm_fmt == ISIF_FRMFMT_PROGRESSIVE) {
1184 		if (params->image_invert_en)
1185 			isif_write(isif->isif_cfg.base_addr,
1186 				   ISIF_PROGRESSIVE_INVERSE_MODE, SDOFST);
1187 		else
1188 			/* For progessive non inverse mode */
1189 			isif_write(isif->isif_cfg.base_addr,
1190 				   ISIF_PROGRESSIVE_NON_INVERSE_MODE, SDOFST);
1191 	}
1192 	/* Configure video window */
1193 	isif_setwin(isif, &params->win, params->frm_fmt, 1, mode);
1194 	/* Configure Black Clamp */
1195 	isif_config_bclamp(isif, &module_params->bclamp);
1196 	/* Configure Vertical Defection Pixel Correction */
1197 	isif_config_dfc(isif, &module_params->dfc);
1198 	if (!module_params->df_csc.df_or_csc)
1199 		/* Configure Color Space Conversion */
1200 		isif_config_csc(isif, &module_params->df_csc);
1201 
1202 	isif_config_linearization(isif, &module_params->linearize);
1203 	/* Configure Culling */
1204 	isif_config_culling(isif, &module_params->culling);
1205 	/* Configure Horizontal and vertical offsets(DFC,LSC,Gain) */
1206 	val = module_params->horz_offset & ISIF_DATA_H_OFFSET_MASK;
1207 	isif_write(isif->isif_cfg.base_addr, val, DATAHOFST);
1208 
1209 	val = module_params->vert_offset & ISIF_DATA_V_OFFSET_MASK;
1210 	isif_write(isif->isif_cfg.base_addr, val, DATAVOFST);
1211 
1212 	return 0;
1213 }
1214 
1215 #define DM365_ISIF_HSIZE_MASK		0xffffffe0
1216 #define DM365_ISIF_SDOFST_2_LINES	0x00000249
1217 
1218 /* This function will configure ISIF for YCbCr parameters. */
isif_config_ycbcr(struct v4l2_subdev * sd,int mode)1219 static int isif_config_ycbcr(struct v4l2_subdev *sd, int mode)
1220 {
1221 	struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd);
1222 	struct isif_ycbcr_config *params = &isif->isif_cfg.ycbcr;
1223 	struct v4l2_mbus_framefmt *format;
1224 	int pix_fmt;
1225 	u32 modeset;
1226 	u32 ccdcfg;
1227 
1228 	format = &isif->formats[ISIF_PAD_SINK];
1229 	/*
1230 	 * first reset the ISIF
1231 	 * all registers have default values after reset
1232 	 * This is important since we assume default values to be set in
1233 	 * a lot of registers that we didn't touch
1234 	 */
1235 	/* start with all bits zero */
1236 	ccdcfg = 0;
1237 	modeset = 0;
1238 	pix_fmt = isif_get_pix_fmt(format->code);
1239 	if (pix_fmt < 0) {
1240 		pr_debug("Invalid pix_fmt(input mode)\n");
1241 		return -EINVAL;
1242 	}
1243 	/* configure pixel format or input mode */
1244 	modeset = modeset | ((pix_fmt & ISIF_INPUT_MASK) <<
1245 		  ISIF_INPUT_SHIFT) | ((params->frm_fmt & ISIF_FRM_FMT_MASK) <<
1246 		  ISIF_FRM_FMT_SHIFT) | (((params->fid_pol &
1247 		  ISIF_FID_POL_MASK) << ISIF_FID_POL_SHIFT)) |
1248 		  (((params->hd_pol & ISIF_HD_POL_MASK) << ISIF_HD_POL_SHIFT)) |
1249 		  (((params->vd_pol & ISIF_VD_POL_MASK) << ISIF_VD_POL_SHIFT));
1250 	/* pack the data to 8-bit CCDCCFG */
1251 	switch (format->code) {
1252 	case MEDIA_BUS_FMT_YUYV8_2X8:
1253 	case MEDIA_BUS_FMT_UYVY8_2X8:
1254 		if (pix_fmt != ISIF_PIXFMT_YCBCR_8BIT) {
1255 			pr_debug("Invalid pix_fmt(input mode)\n");
1256 			return -EINVAL;
1257 		}
1258 		modeset |= ((VPFE_PINPOL_NEGATIVE & ISIF_VD_POL_MASK) <<
1259 				ISIF_VD_POL_SHIFT);
1260 		isif_write(isif->isif_cfg.base_addr, 3, REC656IF);
1261 		ccdcfg = ccdcfg | ISIF_PACK_8BIT | ISIF_YCINSWP_YCBCR;
1262 		break;
1263 
1264 	case MEDIA_BUS_FMT_YUYV10_2X10:
1265 		if (pix_fmt != ISIF_PIXFMT_YCBCR_8BIT) {
1266 			pr_debug("Invalid pix_fmt(input mode)\n");
1267 			return -EINVAL;
1268 		}
1269 		/* setup BT.656, embedded sync  */
1270 		isif_write(isif->isif_cfg.base_addr, 3, REC656IF);
1271 		/* enable 10 bit mode in ccdcfg */
1272 		ccdcfg = ccdcfg | ISIF_PACK_8BIT | ISIF_YCINSWP_YCBCR |
1273 			ISIF_BW656_ENABLE;
1274 		break;
1275 
1276 	case MEDIA_BUS_FMT_YUYV10_1X20:
1277 		if (pix_fmt != ISIF_PIXFMT_YCBCR_16BIT) {
1278 			pr_debug("Invalid pix_fmt(input mode)\n");
1279 			return -EINVAL;
1280 		}
1281 		isif_write(isif->isif_cfg.base_addr, 3, REC656IF);
1282 		break;
1283 
1284 	case MEDIA_BUS_FMT_Y8_1X8:
1285 		ccdcfg |= ISIF_PACK_8BIT;
1286 		ccdcfg |= ISIF_YCINSWP_YCBCR;
1287 		if (pix_fmt != ISIF_PIXFMT_YCBCR_8BIT) {
1288 			pr_debug("Invalid pix_fmt(input mode)\n");
1289 			return -EINVAL;
1290 		}
1291 		break;
1292 
1293 	case MEDIA_BUS_FMT_YUYV8_1X16:
1294 		if (pix_fmt != ISIF_PIXFMT_YCBCR_16BIT) {
1295 			pr_debug("Invalid pix_fmt(input mode)\n");
1296 			return -EINVAL;
1297 		}
1298 		break;
1299 
1300 	default:
1301 		/* should never come here */
1302 		pr_debug("Invalid interface type\n");
1303 		return -EINVAL;
1304 	}
1305 	isif_write(isif->isif_cfg.base_addr, modeset, MODESET);
1306 	/* Set up pix order */
1307 	ccdcfg |= (params->pix_order & ISIF_PIX_ORDER_MASK) <<
1308 		ISIF_PIX_ORDER_SHIFT;
1309 	isif_write(isif->isif_cfg.base_addr, ccdcfg, CCDCFG);
1310 	/* configure video window */
1311 	if (format->code == MEDIA_BUS_FMT_YUYV10_1X20 ||
1312 			format->code == MEDIA_BUS_FMT_YUYV8_1X16)
1313 		isif_setwin(isif, &params->win, params->frm_fmt, 1, mode);
1314 	else
1315 		isif_setwin(isif, &params->win, params->frm_fmt, 2, mode);
1316 
1317 	/*
1318 	 * configure the horizontal line offset
1319 	 * this is done by rounding up width to a multiple of 16 pixels
1320 	 * and multiply by two to account for y:cb:cr 4:2:2 data
1321 	 */
1322 	isif_write(isif->isif_cfg.base_addr,
1323 		   ((((params->win.width * 2) + 31) &
1324 		   DM365_ISIF_HSIZE_MASK) >> 5), HSIZE);
1325 
1326 	/* configure the memory line offset */
1327 	if (params->frm_fmt == ISIF_FRMFMT_INTERLACED &&
1328 	    params->buf_type == ISIF_BUFTYPE_FLD_INTERLEAVED)
1329 		/* two fields are interleaved in memory */
1330 		isif_write(isif->isif_cfg.base_addr,
1331 			   DM365_ISIF_SDOFST_2_LINES, SDOFST);
1332 	return 0;
1333 }
1334 
isif_configure(struct v4l2_subdev * sd,int mode)1335 static int isif_configure(struct v4l2_subdev *sd, int mode)
1336 {
1337 	struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd);
1338 	struct v4l2_mbus_framefmt *format;
1339 
1340 	format = &isif->formats[ISIF_PAD_SINK];
1341 
1342 	switch (format->code) {
1343 	case MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8:
1344 	case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8:
1345 	case MEDIA_BUS_FMT_SGRBG12_1X12:
1346 		return isif_config_raw(sd, mode);
1347 
1348 	case MEDIA_BUS_FMT_YUYV8_2X8:
1349 	case MEDIA_BUS_FMT_UYVY8_2X8:
1350 	case MEDIA_BUS_FMT_YUYV10_2X10:
1351 	case MEDIA_BUS_FMT_Y8_1X8:
1352 	case MEDIA_BUS_FMT_YUYV8_1X16:
1353 	case MEDIA_BUS_FMT_YUYV10_1X20:
1354 		return isif_config_ycbcr(sd, mode);
1355 
1356 	default:
1357 		break;
1358 	}
1359 	return -EINVAL;
1360 }
1361 
1362 /*
1363  * isif_set_stream() - Enable/Disable streaming on the ISIF module
1364  * @sd: VPFE ISIF V4L2 subdevice
1365  * @enable: Enable/disable stream
1366  */
isif_set_stream(struct v4l2_subdev * sd,int enable)1367 static int isif_set_stream(struct v4l2_subdev *sd, int enable)
1368 {
1369 	struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd);
1370 	int ret;
1371 
1372 	if (enable) {
1373 		ret = isif_configure(sd,
1374 			(isif->output == ISIF_OUTPUT_MEMORY) ? 0 : 1);
1375 		if (ret)
1376 			return ret;
1377 		if (isif->output == ISIF_OUTPUT_MEMORY)
1378 			isif_enable_output_to_sdram(isif, 1);
1379 		isif_enable(isif, 1);
1380 	} else {
1381 		isif_enable(isif, 0);
1382 		isif_enable_output_to_sdram(isif, 0);
1383 	}
1384 
1385 	return 0;
1386 }
1387 
1388 /*
1389  * __isif_get_format() - helper function for getting isif format
1390  * @isif: pointer to isif private structure.
1391  * @pad: pad number.
1392  * @cfg: V4L2 subdev pad config
1393  * @which: wanted subdev format.
1394  */
1395 static struct v4l2_mbus_framefmt *
__isif_get_format(struct vpfe_isif_device * isif,struct v4l2_subdev_pad_config * cfg,unsigned int pad,enum v4l2_subdev_format_whence which)1396 __isif_get_format(struct vpfe_isif_device *isif,
1397 		  struct v4l2_subdev_pad_config *cfg, unsigned int pad,
1398 		  enum v4l2_subdev_format_whence which)
1399 {
1400 	if (which == V4L2_SUBDEV_FORMAT_TRY)
1401 		return v4l2_subdev_get_try_format(&isif->subdev, cfg, pad);
1402 
1403 	return &isif->formats[pad];
1404 }
1405 
1406 /*
1407  * isif_set_format() - set format on pad
1408  * @sd    : VPFE ISIF device
1409  * @cfg   : V4L2 subdev pad config
1410  * @fmt   : pointer to v4l2 subdev format structure
1411  *
1412  * Return 0 on success or -EINVAL if format or pad is invalid
1413  */
1414 static int
isif_set_format(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_format * fmt)1415 isif_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
1416 		struct v4l2_subdev_format *fmt)
1417 {
1418 	struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd);
1419 	struct vpfe_device *vpfe_dev = to_vpfe_device(isif);
1420 	struct v4l2_mbus_framefmt *format;
1421 
1422 	format = __isif_get_format(isif, cfg, fmt->pad, fmt->which);
1423 	if (format == NULL)
1424 		return -EINVAL;
1425 
1426 	isif_try_format(isif, cfg, fmt);
1427 	memcpy(format, &fmt->format, sizeof(*format));
1428 
1429 	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
1430 		return 0;
1431 
1432 	if (fmt->pad == ISIF_PAD_SOURCE)
1433 		return isif_config_format(vpfe_dev, fmt->pad);
1434 
1435 	return 0;
1436 }
1437 
1438 /*
1439  * isif_get_format() - Retrieve the video format on a pad
1440  * @sd: VPFE ISIF V4L2 subdevice
1441  * @cfg: V4L2 subdev pad config
1442  * @fmt: pointer to v4l2 subdev format structure
1443  *
1444  * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
1445  * to the format type.
1446  */
1447 static int
isif_get_format(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_format * fmt)1448 isif_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
1449 		struct v4l2_subdev_format *fmt)
1450 {
1451 	struct vpfe_isif_device *vpfe_isif = v4l2_get_subdevdata(sd);
1452 	struct v4l2_mbus_framefmt *format;
1453 
1454 	format = __isif_get_format(vpfe_isif, cfg, fmt->pad, fmt->which);
1455 	if (format == NULL)
1456 		return -EINVAL;
1457 
1458 	memcpy(&fmt->format, format, sizeof(fmt->format));
1459 
1460 	return 0;
1461 }
1462 
1463 /*
1464  * isif_enum_frame_size() - enum frame sizes on pads
1465  * @sd: VPFE isif V4L2 subdevice
1466  * @cfg: V4L2 subdev pad config
1467  * @code: pointer to v4l2_subdev_frame_size_enum structure
1468  */
1469 static int
isif_enum_frame_size(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_frame_size_enum * fse)1470 isif_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
1471 		     struct v4l2_subdev_frame_size_enum *fse)
1472 {
1473 	struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd);
1474 	struct v4l2_subdev_format format;
1475 
1476 	if (fse->index != 0)
1477 		return -EINVAL;
1478 
1479 	format.pad = fse->pad;
1480 	format.format.code = fse->code;
1481 	format.format.width = 1;
1482 	format.format.height = 1;
1483 	format.which = fse->which;
1484 	isif_try_format(isif, cfg, &format);
1485 	fse->min_width = format.format.width;
1486 	fse->min_height = format.format.height;
1487 
1488 	if (format.format.code != fse->code)
1489 		return -EINVAL;
1490 
1491 	format.pad = fse->pad;
1492 	format.format.code = fse->code;
1493 	format.format.width = -1;
1494 	format.format.height = -1;
1495 	format.which = fse->which;
1496 	isif_try_format(isif, cfg, &format);
1497 	fse->max_width = format.format.width;
1498 	fse->max_height = format.format.height;
1499 
1500 	return 0;
1501 }
1502 
1503 /*
1504  * isif_enum_mbus_code() - enum mbus codes for pads
1505  * @sd: VPFE isif V4L2 subdevice
1506  * @cfg: V4L2 subdev pad config
1507  * @code: pointer to v4l2_subdev_mbus_code_enum structure
1508  */
1509 static int
isif_enum_mbus_code(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_mbus_code_enum * code)1510 isif_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
1511 		    struct v4l2_subdev_mbus_code_enum *code)
1512 {
1513 	switch (code->pad) {
1514 	case ISIF_PAD_SINK:
1515 	case ISIF_PAD_SOURCE:
1516 		if (code->index >= ARRAY_SIZE(isif_fmts))
1517 			return -EINVAL;
1518 		code->code = isif_fmts[code->index];
1519 		break;
1520 
1521 	default:
1522 		return -EINVAL;
1523 	}
1524 
1525 	return 0;
1526 }
1527 
1528 /*
1529  * isif_pad_set_selection() - set crop rectangle on pad
1530  * @sd: VPFE isif V4L2 subdevice
1531  * @cfg: V4L2 subdev pad config
1532  * @code: pointer to v4l2_subdev_mbus_code_enum structure
1533  *
1534  * Return 0 on success, -EINVAL if pad is invalid
1535  */
1536 static int
isif_pad_set_selection(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_selection * sel)1537 isif_pad_set_selection(struct v4l2_subdev *sd,
1538 		       struct v4l2_subdev_pad_config *cfg,
1539 		       struct v4l2_subdev_selection *sel)
1540 {
1541 	struct vpfe_isif_device *vpfe_isif = v4l2_get_subdevdata(sd);
1542 	struct v4l2_mbus_framefmt *format;
1543 
1544 	/* check whether it's a valid pad and target */
1545 	if (sel->pad != ISIF_PAD_SINK || sel->target != V4L2_SEL_TGT_CROP)
1546 		return -EINVAL;
1547 
1548 	format = __isif_get_format(vpfe_isif, cfg, sel->pad, sel->which);
1549 	if (format == NULL)
1550 		return -EINVAL;
1551 
1552 	/* check wether crop rect is within limits */
1553 	if (sel->r.top < 0 || sel->r.left < 0 ||
1554 		(sel->r.left + sel->r.width >
1555 		vpfe_isif->formats[ISIF_PAD_SINK].width) ||
1556 		(sel->r.top + sel->r.height >
1557 			vpfe_isif->formats[ISIF_PAD_SINK].height)) {
1558 		sel->r.left = 0;
1559 		sel->r.top = 0;
1560 		sel->r.width = format->width;
1561 		sel->r.height = format->height;
1562 	}
1563 	/* adjust the width to 16 pixel boundary */
1564 	sel->r.width = (sel->r.width + 15) & ~0xf;
1565 	vpfe_isif->crop = sel->r;
1566 	if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
1567 		isif_set_image_window(vpfe_isif);
1568 	} else {
1569 		struct v4l2_rect *rect;
1570 
1571 		rect = v4l2_subdev_get_try_crop(sd, cfg, ISIF_PAD_SINK);
1572 		memcpy(rect, &vpfe_isif->crop, sizeof(*rect));
1573 	}
1574 	return 0;
1575 }
1576 
1577 /*
1578  * isif_pad_get_selection() - get crop rectangle on pad
1579  * @sd: VPFE isif V4L2 subdevice
1580  * @cfg: V4L2 subdev pad config
1581  * @code: pointer to v4l2_subdev_mbus_code_enum structure
1582  *
1583  * Return 0 on success, -EINVAL if pad is invalid
1584  */
1585 static int
isif_pad_get_selection(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_selection * sel)1586 isif_pad_get_selection(struct v4l2_subdev *sd,
1587 		       struct v4l2_subdev_pad_config *cfg,
1588 		       struct v4l2_subdev_selection *sel)
1589 {
1590 	struct vpfe_isif_device *vpfe_isif = v4l2_get_subdevdata(sd);
1591 
1592 	/* check whether it's a valid pad and target */
1593 	if (sel->pad != ISIF_PAD_SINK || sel->target != V4L2_SEL_TGT_CROP)
1594 		return -EINVAL;
1595 
1596 	if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
1597 		struct v4l2_rect *rect;
1598 
1599 		rect = v4l2_subdev_get_try_crop(sd, cfg, ISIF_PAD_SINK);
1600 		memcpy(&sel->r, rect, sizeof(*rect));
1601 	} else {
1602 		sel->r = vpfe_isif->crop;
1603 	}
1604 
1605 	return 0;
1606 }
1607 
1608 /*
1609  * isif_init_formats() - Initialize formats on all pads
1610  * @sd: VPFE isif V4L2 subdevice
1611  * @fh: V4L2 subdev file handle
1612  *
1613  * Initialize all pad formats with default values. Try formats are initialized
1614  * on the file handle.
1615  */
1616 static int
isif_init_formats(struct v4l2_subdev * sd,struct v4l2_subdev_fh * fh)1617 isif_init_formats(struct v4l2_subdev *sd,
1618 		  struct v4l2_subdev_fh *fh)
1619 {
1620 	struct v4l2_subdev_format format;
1621 	struct v4l2_subdev_selection sel;
1622 
1623 	memset(&format, 0, sizeof(format));
1624 	format.pad = ISIF_PAD_SINK;
1625 	format.which = V4L2_SUBDEV_FORMAT_TRY;
1626 	format.format.code = MEDIA_BUS_FMT_SGRBG12_1X12;
1627 	format.format.width = MAX_WIDTH;
1628 	format.format.height = MAX_HEIGHT;
1629 	isif_set_format(sd, fh->pad, &format);
1630 
1631 	memset(&format, 0, sizeof(format));
1632 	format.pad = ISIF_PAD_SOURCE;
1633 	format.which = V4L2_SUBDEV_FORMAT_TRY;
1634 	format.format.code = MEDIA_BUS_FMT_SGRBG12_1X12;
1635 	format.format.width = MAX_WIDTH;
1636 	format.format.height = MAX_HEIGHT;
1637 	isif_set_format(sd, fh->pad, &format);
1638 
1639 	memset(&sel, 0, sizeof(sel));
1640 	sel.pad = ISIF_PAD_SINK;
1641 	sel.which = V4L2_SUBDEV_FORMAT_TRY;
1642 	sel.target = V4L2_SEL_TGT_CROP;
1643 	sel.r.width = MAX_WIDTH;
1644 	sel.r.height = MAX_HEIGHT;
1645 	isif_pad_set_selection(sd, fh->pad, &sel);
1646 
1647 	return 0;
1648 }
1649 
1650 /* subdev core operations */
1651 static const struct v4l2_subdev_core_ops isif_v4l2_core_ops = {
1652 	.ioctl = isif_ioctl,
1653 };
1654 
1655 /* subdev file operations */
1656 static const struct v4l2_subdev_internal_ops isif_v4l2_internal_ops = {
1657 	.open = isif_init_formats,
1658 };
1659 
1660 /* subdev video operations */
1661 static const struct v4l2_subdev_video_ops isif_v4l2_video_ops = {
1662 	.s_stream = isif_set_stream,
1663 };
1664 
1665 /* subdev pad operations */
1666 static const struct v4l2_subdev_pad_ops isif_v4l2_pad_ops = {
1667 	.enum_mbus_code = isif_enum_mbus_code,
1668 	.enum_frame_size = isif_enum_frame_size,
1669 	.get_fmt = isif_get_format,
1670 	.set_fmt = isif_set_format,
1671 	.set_selection = isif_pad_set_selection,
1672 	.get_selection = isif_pad_get_selection,
1673 };
1674 
1675 /* subdev operations */
1676 static const struct v4l2_subdev_ops isif_v4l2_ops = {
1677 	.core = &isif_v4l2_core_ops,
1678 	.video = &isif_v4l2_video_ops,
1679 	.pad = &isif_v4l2_pad_ops,
1680 };
1681 
1682 /*
1683  * Media entity operations
1684  */
1685 
1686 /*
1687  * isif_link_setup() - Setup isif connections
1688  * @entity: isif media entity
1689  * @local: Pad at the local end of the link
1690  * @remote: Pad at the remote end of the link
1691  * @flags: Link flags
1692  *
1693  * return -EINVAL or zero on success
1694  */
1695 static int
isif_link_setup(struct media_entity * entity,const struct media_pad * local,const struct media_pad * remote,u32 flags)1696 isif_link_setup(struct media_entity *entity, const struct media_pad *local,
1697 		const struct media_pad *remote, u32 flags)
1698 {
1699 	struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
1700 	struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd);
1701 	unsigned int index = local->index;
1702 
1703 	/* FIXME: this is actually a hack! */
1704 	if (is_media_entity_v4l2_subdev(remote->entity))
1705 		index |= 2 << 16;
1706 
1707 	switch (index) {
1708 	case ISIF_PAD_SINK | 2 << 16:
1709 		/* read from decoder/sensor */
1710 		if (!(flags & MEDIA_LNK_FL_ENABLED)) {
1711 			isif->input = ISIF_INPUT_NONE;
1712 			break;
1713 		}
1714 		if (isif->input != ISIF_INPUT_NONE)
1715 			return -EBUSY;
1716 		isif->input = ISIF_INPUT_PARALLEL;
1717 		break;
1718 
1719 	case ISIF_PAD_SOURCE:
1720 		/* write to memory */
1721 		if (flags & MEDIA_LNK_FL_ENABLED)
1722 			isif->output = ISIF_OUTPUT_MEMORY;
1723 		else
1724 			isif->output = ISIF_OUTPUT_NONE;
1725 		break;
1726 
1727 	case ISIF_PAD_SOURCE | 2 << 16:
1728 		if (flags & MEDIA_LNK_FL_ENABLED)
1729 			isif->output = ISIF_OUTPUT_IPIPEIF;
1730 		else
1731 			isif->output = ISIF_OUTPUT_NONE;
1732 		break;
1733 
1734 	default:
1735 		return -EINVAL;
1736 	}
1737 
1738 	return 0;
1739 }
1740 static const struct media_entity_operations isif_media_ops = {
1741 	.link_setup = isif_link_setup,
1742 };
1743 
1744 /*
1745  * vpfe_isif_unregister_entities() - isif unregister entity
1746  * @isif - pointer to isif subdevice structure.
1747  */
vpfe_isif_unregister_entities(struct vpfe_isif_device * isif)1748 void vpfe_isif_unregister_entities(struct vpfe_isif_device *isif)
1749 {
1750 	vpfe_video_unregister(&isif->video_out);
1751 	/* unregister subdev */
1752 	v4l2_device_unregister_subdev(&isif->subdev);
1753 	/* cleanup entity */
1754 	media_entity_cleanup(&isif->subdev.entity);
1755 }
1756 
isif_restore_defaults(struct vpfe_isif_device * isif)1757 static void isif_restore_defaults(struct vpfe_isif_device *isif)
1758 {
1759 	enum vpss_ccdc_source_sel source = VPSS_CCDCIN;
1760 	int i;
1761 
1762 	memset(&isif->isif_cfg.bayer.config_params, 0,
1763 	       sizeof(struct vpfe_isif_raw_config));
1764 
1765 	isif->isif_cfg.bayer.config_params.linearize.corr_shft =
1766 					VPFE_ISIF_NO_SHIFT;
1767 	isif->isif_cfg.bayer.config_params.linearize.scale_fact.integer = 1;
1768 	isif->isif_cfg.bayer.config_params.culling.hcpat_odd =
1769 			ISIF_CULLING_HCAPT_ODD;
1770 	isif->isif_cfg.bayer.config_params.culling.hcpat_even =
1771 			ISIF_CULLING_HCAPT_EVEN;
1772 	isif->isif_cfg.bayer.config_params.culling.vcpat = ISIF_CULLING_VCAPT;
1773 	/* Enable clock to ISIF, IPIPEIF and BL */
1774 	vpss_enable_clock(VPSS_CCDC_CLOCK, 1);
1775 	vpss_enable_clock(VPSS_IPIPEIF_CLOCK, 1);
1776 	vpss_enable_clock(VPSS_BL_CLOCK, 1);
1777 
1778 	/* set all registers to default value */
1779 	for (i = 0; i <= 0x1f8; i += 4)
1780 		isif_write(isif->isif_cfg.base_addr, 0, i);
1781 	/* no culling support */
1782 	isif_write(isif->isif_cfg.base_addr, 0xffff, CULH);
1783 	isif_write(isif->isif_cfg.base_addr, 0xff, CULV);
1784 
1785 	/* Set default offset and gain */
1786 	isif_config_gain_offset(isif);
1787 	vpss_select_ccdc_source(source);
1788 }
1789 
1790 /*
1791  * vpfe_isif_register_entities() - isif register entity
1792  * @isif - pointer to isif subdevice structure.
1793  * @vdev: pointer to v4l2 device structure.
1794  */
vpfe_isif_register_entities(struct vpfe_isif_device * isif,struct v4l2_device * vdev)1795 int vpfe_isif_register_entities(struct vpfe_isif_device *isif,
1796 			    struct v4l2_device *vdev)
1797 {
1798 	struct vpfe_device *vpfe_dev = to_vpfe_device(isif);
1799 	unsigned int flags;
1800 	int ret;
1801 
1802 	/* Register the subdev */
1803 	ret = v4l2_device_register_subdev(vdev, &isif->subdev);
1804 	if (ret < 0)
1805 		return ret;
1806 
1807 	isif_restore_defaults(isif);
1808 	ret = vpfe_video_register(&isif->video_out, vdev);
1809 	if (ret) {
1810 		pr_err("Failed to register isif video out device\n");
1811 		goto out_video_register;
1812 	}
1813 	isif->video_out.vpfe_dev = vpfe_dev;
1814 	flags = 0;
1815 	/* connect isif to video node */
1816 	ret = media_create_pad_link(&isif->subdev.entity, 1,
1817 				       &isif->video_out.video_dev.entity,
1818 				       0, flags);
1819 	if (ret < 0)
1820 		goto out_create_link;
1821 	return 0;
1822 out_create_link:
1823 	vpfe_video_unregister(&isif->video_out);
1824 out_video_register:
1825 	v4l2_device_unregister_subdev(&isif->subdev);
1826 	return ret;
1827 }
1828 
1829 /* -------------------------------------------------------------------
1830  * V4L2 subdev control operations
1831  */
1832 
vpfe_isif_s_ctrl(struct v4l2_ctrl * ctrl)1833 static int vpfe_isif_s_ctrl(struct v4l2_ctrl *ctrl)
1834 {
1835 	struct vpfe_isif_device *isif =
1836 	     container_of(ctrl->handler, struct vpfe_isif_device, ctrls);
1837 	struct isif_oper_config *config = &isif->isif_cfg;
1838 
1839 	switch (ctrl->id) {
1840 	case VPFE_CID_DPCM_PREDICTOR:
1841 		config->bayer.dpcm_predictor = ctrl->val;
1842 		break;
1843 
1844 	case VPFE_ISIF_CID_CRGAIN:
1845 		config->isif_gain_params.cr_gain = ctrl->val;
1846 		break;
1847 
1848 	case VPFE_ISIF_CID_CGRGAIN:
1849 		config->isif_gain_params.cgr_gain = ctrl->val;
1850 		break;
1851 
1852 	case VPFE_ISIF_CID_CGBGAIN:
1853 		config->isif_gain_params.cgb_gain = ctrl->val;
1854 		break;
1855 
1856 	case VPFE_ISIF_CID_CBGAIN:
1857 		config->isif_gain_params.cb_gain = ctrl->val;
1858 		break;
1859 
1860 	case VPFE_ISIF_CID_GAIN_OFFSET:
1861 		config->isif_gain_params.offset = ctrl->val;
1862 		break;
1863 
1864 	default:
1865 		return -EINVAL;
1866 	}
1867 	return 0;
1868 }
1869 
1870 static const struct v4l2_ctrl_ops vpfe_isif_ctrl_ops = {
1871 	.s_ctrl = vpfe_isif_s_ctrl,
1872 };
1873 
1874 static const struct v4l2_ctrl_config vpfe_isif_dpcm_pred = {
1875 	.ops = &vpfe_isif_ctrl_ops,
1876 	.id = VPFE_CID_DPCM_PREDICTOR,
1877 	.name = "DPCM Predictor",
1878 	.type = V4L2_CTRL_TYPE_INTEGER,
1879 	.min = 0,
1880 	.max = 1,
1881 	.step = 1,
1882 	.def = 0,
1883 };
1884 
1885 static const struct v4l2_ctrl_config vpfe_isif_crgain = {
1886 	.ops = &vpfe_isif_ctrl_ops,
1887 	.id = VPFE_ISIF_CID_CRGAIN,
1888 	.name = "CRGAIN",
1889 	.type = V4L2_CTRL_TYPE_INTEGER,
1890 	.min = 0,
1891 	.max = (1 << 12) - 1,
1892 	.step = 1,
1893 	.def = 0,
1894 };
1895 
1896 static const struct v4l2_ctrl_config vpfe_isif_cgrgain = {
1897 	.ops = &vpfe_isif_ctrl_ops,
1898 	.id = VPFE_ISIF_CID_CGRGAIN,
1899 	.name = "CGRGAIN",
1900 	.type = V4L2_CTRL_TYPE_INTEGER,
1901 	.min = 0,
1902 	.max = (1 << 12) - 1,
1903 	.step = 1,
1904 	.def = 0,
1905 };
1906 
1907 static const struct v4l2_ctrl_config vpfe_isif_cgbgain = {
1908 	.ops = &vpfe_isif_ctrl_ops,
1909 	.id = VPFE_ISIF_CID_CGBGAIN,
1910 	.name = "CGBGAIN",
1911 	.type = V4L2_CTRL_TYPE_INTEGER,
1912 	.min = 0,
1913 	.max = (1 << 12) - 1,
1914 	.step = 1,
1915 	.def = 0,
1916 };
1917 
1918 static const struct v4l2_ctrl_config vpfe_isif_cbgain = {
1919 	.ops = &vpfe_isif_ctrl_ops,
1920 	.id = VPFE_ISIF_CID_CBGAIN,
1921 	.name = "CBGAIN",
1922 	.type = V4L2_CTRL_TYPE_INTEGER,
1923 	.min = 0,
1924 	.max = (1 << 12) - 1,
1925 	.step = 1,
1926 	.def = 0,
1927 };
1928 
1929 static const struct v4l2_ctrl_config vpfe_isif_gain_offset = {
1930 	.ops = &vpfe_isif_ctrl_ops,
1931 	.id = VPFE_ISIF_CID_GAIN_OFFSET,
1932 	.name = "Gain Offset",
1933 	.type = V4L2_CTRL_TYPE_INTEGER,
1934 	.min = 0,
1935 	.max = (1 << 12) - 1,
1936 	.step = 1,
1937 	.def = 0,
1938 };
1939 
isif_remove(struct vpfe_isif_device * isif,struct platform_device * pdev)1940 static void isif_remove(struct vpfe_isif_device *isif,
1941 			struct platform_device *pdev)
1942 {
1943 	struct resource *res;
1944 	int i = 0;
1945 
1946 	iounmap(isif->isif_cfg.base_addr);
1947 	iounmap(isif->isif_cfg.linear_tbl0_addr);
1948 	iounmap(isif->isif_cfg.linear_tbl1_addr);
1949 
1950 	while (i < 3) {
1951 		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
1952 		if (res)
1953 			release_mem_region(res->start,
1954 					   resource_size(res));
1955 		i++;
1956 	}
1957 }
1958 
isif_config_defaults(struct vpfe_isif_device * isif)1959 static void isif_config_defaults(struct vpfe_isif_device *isif)
1960 {
1961 	isif->isif_cfg.ycbcr.v4l2_pix_fmt = V4L2_PIX_FMT_UYVY;
1962 	isif->isif_cfg.ycbcr.pix_fmt = ISIF_PIXFMT_YCBCR_8BIT;
1963 	isif->isif_cfg.ycbcr.frm_fmt = ISIF_FRMFMT_INTERLACED;
1964 	isif->isif_cfg.ycbcr.fid_pol = VPFE_PINPOL_POSITIVE;
1965 	isif->isif_cfg.ycbcr.vd_pol = VPFE_PINPOL_POSITIVE;
1966 	isif->isif_cfg.ycbcr.hd_pol = VPFE_PINPOL_POSITIVE;
1967 	isif->isif_cfg.ycbcr.pix_order = ISIF_PIXORDER_CBYCRY;
1968 	isif->isif_cfg.ycbcr.buf_type = ISIF_BUFTYPE_FLD_INTERLEAVED;
1969 
1970 	isif->isif_cfg.bayer.v4l2_pix_fmt = V4L2_PIX_FMT_SGRBG10ALAW8;
1971 	isif->isif_cfg.bayer.pix_fmt = ISIF_PIXFMT_RAW;
1972 	isif->isif_cfg.bayer.frm_fmt = ISIF_FRMFMT_PROGRESSIVE;
1973 	isif->isif_cfg.bayer.fid_pol = VPFE_PINPOL_POSITIVE;
1974 	isif->isif_cfg.bayer.vd_pol = VPFE_PINPOL_POSITIVE;
1975 	isif->isif_cfg.bayer.hd_pol = VPFE_PINPOL_POSITIVE;
1976 	isif->isif_cfg.bayer.cfa_pat = ISIF_CFA_PAT_MOSAIC;
1977 	isif->isif_cfg.bayer.data_msb = ISIF_BIT_MSB_11;
1978 	isif->isif_cfg.data_pack = ISIF_PACK_8BIT;
1979 }
1980 /*
1981  * vpfe_isif_init() - Initialize V4L2 subdev and media entity
1982  * @isif: VPFE isif module
1983  * @pdev: Pointer to platform device structure.
1984  * Return 0 on success and a negative error code on failure.
1985  */
vpfe_isif_init(struct vpfe_isif_device * isif,struct platform_device * pdev)1986 int vpfe_isif_init(struct vpfe_isif_device *isif, struct platform_device *pdev)
1987 {
1988 	struct v4l2_subdev *sd = &isif->subdev;
1989 	struct media_pad *pads = &isif->pads[0];
1990 	struct media_entity *me = &sd->entity;
1991 	static resource_size_t res_len;
1992 	struct resource *res;
1993 	void __iomem *addr;
1994 	int status;
1995 	int i = 0;
1996 
1997 	/* Get the ISIF base address, linearization table0 and table1 addr. */
1998 	while (i < 3) {
1999 		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
2000 		if (!res) {
2001 			status = -ENOENT;
2002 			goto fail_nobase_res;
2003 		}
2004 		res_len = resource_size(res);
2005 		res = request_mem_region(res->start, res_len, res->name);
2006 		if (!res) {
2007 			status = -EBUSY;
2008 			goto fail_nobase_res;
2009 		}
2010 		addr = ioremap_nocache(res->start, res_len);
2011 		if (!addr) {
2012 			status = -EBUSY;
2013 			goto fail_base_iomap;
2014 		}
2015 		switch (i) {
2016 		case 0:
2017 			/* ISIF base address */
2018 			isif->isif_cfg.base_addr = addr;
2019 			break;
2020 		case 1:
2021 			/* ISIF linear tbl0 address */
2022 			isif->isif_cfg.linear_tbl0_addr = addr;
2023 			break;
2024 		default:
2025 			/* ISIF linear tbl0 address */
2026 			isif->isif_cfg.linear_tbl1_addr = addr;
2027 			break;
2028 		}
2029 		i++;
2030 	}
2031 	davinci_cfg_reg(DM365_VIN_CAM_WEN);
2032 	davinci_cfg_reg(DM365_VIN_CAM_VD);
2033 	davinci_cfg_reg(DM365_VIN_CAM_HD);
2034 	davinci_cfg_reg(DM365_VIN_YIN4_7_EN);
2035 	davinci_cfg_reg(DM365_VIN_YIN0_3_EN);
2036 
2037 	/* queue ops */
2038 	isif->video_out.ops = &isif_video_ops;
2039 	v4l2_subdev_init(sd, &isif_v4l2_ops);
2040 	sd->internal_ops = &isif_v4l2_internal_ops;
2041 	strlcpy(sd->name, "DAVINCI ISIF", sizeof(sd->name));
2042 	sd->grp_id = 1 << 16;	/* group ID for davinci subdevs */
2043 	v4l2_set_subdevdata(sd, isif);
2044 	sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE;
2045 	pads[ISIF_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
2046 	pads[ISIF_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
2047 
2048 	isif->input = ISIF_INPUT_NONE;
2049 	isif->output = ISIF_OUTPUT_NONE;
2050 	me->ops = &isif_media_ops;
2051 	status = media_entity_pads_init(me, ISIF_PADS_NUM, pads);
2052 	if (status)
2053 		goto isif_fail;
2054 	isif->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
2055 	status = vpfe_video_init(&isif->video_out, "ISIF");
2056 	if (status) {
2057 		pr_err("Failed to init isif-out video device\n");
2058 		goto isif_fail;
2059 	}
2060 	v4l2_ctrl_handler_init(&isif->ctrls, 6);
2061 	v4l2_ctrl_new_custom(&isif->ctrls, &vpfe_isif_crgain, NULL);
2062 	v4l2_ctrl_new_custom(&isif->ctrls, &vpfe_isif_cgrgain, NULL);
2063 	v4l2_ctrl_new_custom(&isif->ctrls, &vpfe_isif_cgbgain, NULL);
2064 	v4l2_ctrl_new_custom(&isif->ctrls, &vpfe_isif_cbgain, NULL);
2065 	v4l2_ctrl_new_custom(&isif->ctrls, &vpfe_isif_gain_offset, NULL);
2066 	v4l2_ctrl_new_custom(&isif->ctrls, &vpfe_isif_dpcm_pred, NULL);
2067 
2068 	v4l2_ctrl_handler_setup(&isif->ctrls);
2069 	sd->ctrl_handler = &isif->ctrls;
2070 	isif_config_defaults(isif);
2071 	return 0;
2072 fail_base_iomap:
2073 	release_mem_region(res->start, res_len);
2074 	i--;
2075 fail_nobase_res:
2076 	if (isif->isif_cfg.base_addr)
2077 		iounmap(isif->isif_cfg.base_addr);
2078 	if (isif->isif_cfg.linear_tbl0_addr)
2079 		iounmap(isif->isif_cfg.linear_tbl0_addr);
2080 
2081 	while (i >= 0) {
2082 		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
2083 		release_mem_region(res->start, res_len);
2084 		i--;
2085 	}
2086 	return status;
2087 isif_fail:
2088 	v4l2_ctrl_handler_free(&isif->ctrls);
2089 	isif_remove(isif, pdev);
2090 	return status;
2091 }
2092 
2093 /*
2094  * vpfe_isif_cleanup - isif module cleanup
2095  * @isif: pointer to isif subdevice
2096  * @dev: pointer to platform device structure
2097  */
2098 void
vpfe_isif_cleanup(struct vpfe_isif_device * isif,struct platform_device * pdev)2099 vpfe_isif_cleanup(struct vpfe_isif_device *isif, struct platform_device *pdev)
2100 {
2101 	isif_remove(isif, pdev);
2102 }
2103