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