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 "dm365_ipipeif.h"
23 #include "vpfe_mc_capture.h"
24 
25 static const unsigned int ipipeif_input_fmts[] = {
26 	MEDIA_BUS_FMT_UYVY8_2X8,
27 	MEDIA_BUS_FMT_SGRBG12_1X12,
28 	MEDIA_BUS_FMT_Y8_1X8,
29 	MEDIA_BUS_FMT_UV8_1X8,
30 	MEDIA_BUS_FMT_YDYUYDYV8_1X16,
31 	MEDIA_BUS_FMT_SBGGR8_1X8,
32 };
33 
34 static const unsigned int ipipeif_output_fmts[] = {
35 	MEDIA_BUS_FMT_UYVY8_2X8,
36 	MEDIA_BUS_FMT_SGRBG12_1X12,
37 	MEDIA_BUS_FMT_Y8_1X8,
38 	MEDIA_BUS_FMT_UV8_1X8,
39 	MEDIA_BUS_FMT_YDYUYDYV8_1X16,
40 	MEDIA_BUS_FMT_SBGGR8_1X8,
41 	MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8,
42 	MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8,
43 };
44 
45 static int
ipipeif_get_pack_mode(u32 in_pix_fmt)46 ipipeif_get_pack_mode(u32 in_pix_fmt)
47 {
48 	switch (in_pix_fmt) {
49 	case MEDIA_BUS_FMT_SBGGR8_1X8:
50 	case MEDIA_BUS_FMT_Y8_1X8:
51 	case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8:
52 	case MEDIA_BUS_FMT_UV8_1X8:
53 		return IPIPEIF_5_1_PACK_8_BIT;
54 
55 	case MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8:
56 		return IPIPEIF_5_1_PACK_8_BIT_A_LAW;
57 
58 	case MEDIA_BUS_FMT_SGRBG12_1X12:
59 		return IPIPEIF_5_1_PACK_16_BIT;
60 
61 	case MEDIA_BUS_FMT_SBGGR12_1X12:
62 		return IPIPEIF_5_1_PACK_12_BIT;
63 
64 	default:
65 		return IPIPEIF_5_1_PACK_16_BIT;
66 	}
67 }
68 
ipipeif_read(void * addr,u32 offset)69 static inline u32 ipipeif_read(void *addr, u32 offset)
70 {
71 	return readl(addr + offset);
72 }
73 
ipipeif_write(u32 val,void * addr,u32 offset)74 static inline void ipipeif_write(u32 val, void *addr, u32 offset)
75 {
76 	writel(val, addr + offset);
77 }
78 
ipipeif_config_dpc(void * addr,struct ipipeif_dpc * dpc)79 static void ipipeif_config_dpc(void *addr, struct ipipeif_dpc *dpc)
80 {
81 	u32 val = 0;
82 
83 	if (dpc->en) {
84 		val = (dpc->en & 1) << IPIPEIF_DPC2_EN_SHIFT;
85 		val |= dpc->thr & IPIPEIF_DPC2_THR_MASK;
86 	}
87 	ipipeif_write(val, addr, IPIPEIF_DPC2);
88 }
89 
90 #define IPIPEIF_MODE_CONTINUOUS			0
91 #define IPIPEIF_MODE_ONE_SHOT			1
92 
get_oneshot_mode(enum ipipeif_input_entity input)93 static int get_oneshot_mode(enum ipipeif_input_entity input)
94 {
95 	if (input == IPIPEIF_INPUT_MEMORY)
96 		return IPIPEIF_MODE_ONE_SHOT;
97 	else if (input == IPIPEIF_INPUT_ISIF)
98 		return IPIPEIF_MODE_CONTINUOUS;
99 
100 	return -EINVAL;
101 }
102 
103 static int
ipipeif_get_cfg_src1(struct vpfe_ipipeif_device * ipipeif)104 ipipeif_get_cfg_src1(struct vpfe_ipipeif_device *ipipeif)
105 {
106 	struct v4l2_mbus_framefmt *informat;
107 
108 	informat = &ipipeif->formats[IPIPEIF_PAD_SINK];
109 	if (ipipeif->input == IPIPEIF_INPUT_MEMORY &&
110 	   (informat->code == MEDIA_BUS_FMT_Y8_1X8 ||
111 	    informat->code == MEDIA_BUS_FMT_UV8_1X8))
112 		return IPIPEIF_CCDC;
113 
114 	return IPIPEIF_SRC1_PARALLEL_PORT;
115 }
116 
117 static int
ipipeif_get_data_shift(struct vpfe_ipipeif_device * ipipeif)118 ipipeif_get_data_shift(struct vpfe_ipipeif_device *ipipeif)
119 {
120 	struct v4l2_mbus_framefmt *informat;
121 
122 	informat = &ipipeif->formats[IPIPEIF_PAD_SINK];
123 
124 	switch (informat->code) {
125 	case MEDIA_BUS_FMT_SGRBG12_1X12:
126 		return IPIPEIF_5_1_BITS11_0;
127 
128 	case MEDIA_BUS_FMT_Y8_1X8:
129 	case MEDIA_BUS_FMT_UV8_1X8:
130 		return IPIPEIF_5_1_BITS11_0;
131 
132 	default:
133 		return IPIPEIF_5_1_BITS7_0;
134 	}
135 }
136 
137 static enum ipipeif_input_source
ipipeif_get_source(struct vpfe_ipipeif_device * ipipeif)138 ipipeif_get_source(struct vpfe_ipipeif_device *ipipeif)
139 {
140 	struct v4l2_mbus_framefmt *informat;
141 
142 	informat = &ipipeif->formats[IPIPEIF_PAD_SINK];
143 	if (ipipeif->input == IPIPEIF_INPUT_ISIF)
144 		return IPIPEIF_CCDC;
145 
146 	if (informat->code == MEDIA_BUS_FMT_UYVY8_2X8)
147 		return IPIPEIF_SDRAM_YUV;
148 
149 	return IPIPEIF_SDRAM_RAW;
150 }
151 
vpfe_ipipeif_ss_buffer_isr(struct vpfe_ipipeif_device * ipipeif)152 void vpfe_ipipeif_ss_buffer_isr(struct vpfe_ipipeif_device *ipipeif)
153 {
154 	struct vpfe_video_device *video_in = &ipipeif->video_in;
155 
156 	if (ipipeif->input != IPIPEIF_INPUT_MEMORY)
157 		return;
158 
159 	spin_lock(&video_in->dma_queue_lock);
160 	vpfe_video_process_buffer_complete(video_in);
161 	video_in->state = VPFE_VIDEO_BUFFER_NOT_QUEUED;
162 	vpfe_video_schedule_next_buffer(video_in);
163 	spin_unlock(&video_in->dma_queue_lock);
164 }
165 
vpfe_ipipeif_decimation_enabled(struct vpfe_device * vpfe_dev)166 int vpfe_ipipeif_decimation_enabled(struct vpfe_device *vpfe_dev)
167 {
168 	struct vpfe_ipipeif_device *ipipeif = &vpfe_dev->vpfe_ipipeif;
169 
170 	return ipipeif->config.decimation;
171 }
172 
vpfe_ipipeif_get_rsz(struct vpfe_device * vpfe_dev)173 int vpfe_ipipeif_get_rsz(struct vpfe_device *vpfe_dev)
174 {
175 	struct vpfe_ipipeif_device *ipipeif = &vpfe_dev->vpfe_ipipeif;
176 
177 	return ipipeif->config.rsz;
178 }
179 
180 #define RD_DATA_15_2		0x7
181 
182 /*
183  * ipipeif_hw_setup() - This function sets up IPIPEIF
184  * @sd: pointer to v4l2 subdev structure
185  * return -EINVAL or zero on success
186  */
ipipeif_hw_setup(struct v4l2_subdev * sd)187 static int ipipeif_hw_setup(struct v4l2_subdev *sd)
188 {
189 	struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
190 	struct v4l2_mbus_framefmt *informat, *outformat;
191 	struct ipipeif_params params = ipipeif->config;
192 	enum ipipeif_input_source ipipeif_source;
193 	u32 isif_port_if;
194 	void *ipipeif_base_addr;
195 	unsigned int val;
196 	int data_shift;
197 	int pack_mode;
198 	int source1;
199 	int tmp;
200 
201 	ipipeif_base_addr = ipipeif->ipipeif_base_addr;
202 
203 	/* Enable clock to IPIPEIF and IPIPE */
204 	vpss_enable_clock(VPSS_IPIPEIF_CLOCK, 1);
205 
206 	informat = &ipipeif->formats[IPIPEIF_PAD_SINK];
207 	outformat = &ipipeif->formats[IPIPEIF_PAD_SOURCE];
208 
209 	/* Combine all the fields to make CFG1 register of IPIPEIF */
210 	tmp = val = get_oneshot_mode(ipipeif->input);
211 	if (tmp < 0) {
212 		dev_err(&sd->devnode->dev, "ipipeif: links setup required");
213 		return -EINVAL;
214 	}
215 	val <<= ONESHOT_SHIFT;
216 
217 	ipipeif_source = ipipeif_get_source(ipipeif);
218 	val |= ipipeif_source << INPSRC_SHIFT;
219 
220 	val |= params.clock_select << CLKSEL_SHIFT;
221 	val |= params.avg_filter << AVGFILT_SHIFT;
222 	val |= params.decimation << DECIM_SHIFT;
223 
224 	pack_mode = ipipeif_get_pack_mode(informat->code);
225 	val |= pack_mode << PACK8IN_SHIFT;
226 
227 	source1 = ipipeif_get_cfg_src1(ipipeif);
228 	val |= source1 << INPSRC1_SHIFT;
229 
230 	data_shift = ipipeif_get_data_shift(ipipeif);
231 	if (ipipeif_source != IPIPEIF_SDRAM_YUV)
232 		val |= data_shift << DATASFT_SHIFT;
233 	else
234 		val &= ~(RD_DATA_15_2 << DATASFT_SHIFT);
235 
236 	ipipeif_write(val, ipipeif_base_addr, IPIPEIF_CFG1);
237 
238 	switch (ipipeif_source) {
239 	case IPIPEIF_CCDC:
240 		ipipeif_write(ipipeif->gain, ipipeif_base_addr, IPIPEIF_GAIN);
241 		break;
242 
243 	case IPIPEIF_SDRAM_RAW:
244 	case IPIPEIF_CCDC_DARKFM:
245 		ipipeif_write(ipipeif->gain, ipipeif_base_addr, IPIPEIF_GAIN);
246 		/* fall through */
247 	case IPIPEIF_SDRAM_YUV:
248 		val |= data_shift << DATASFT_SHIFT;
249 		ipipeif_write(params.ppln, ipipeif_base_addr, IPIPEIF_PPLN);
250 		ipipeif_write(params.lpfr, ipipeif_base_addr, IPIPEIF_LPFR);
251 		ipipeif_write(informat->width, ipipeif_base_addr, IPIPEIF_HNUM);
252 		ipipeif_write(informat->height,
253 			      ipipeif_base_addr, IPIPEIF_VNUM);
254 		break;
255 
256 	default:
257 		return -EINVAL;
258 	}
259 
260 	/*check if decimation is enable or not */
261 	if (params.decimation)
262 		ipipeif_write(params.rsz, ipipeif_base_addr, IPIPEIF_RSZ);
263 
264 	/* Setup sync alignment and initial rsz position */
265 	val = params.if_5_1.align_sync & 1;
266 	val <<= IPIPEIF_INIRSZ_ALNSYNC_SHIFT;
267 	val |= params.if_5_1.rsz_start & IPIPEIF_INIRSZ_MASK;
268 	ipipeif_write(val, ipipeif_base_addr, IPIPEIF_INIRSZ);
269 	isif_port_if = informat->code;
270 
271 	if (isif_port_if == MEDIA_BUS_FMT_Y8_1X8)
272 		isif_port_if = MEDIA_BUS_FMT_YUYV8_1X16;
273 	else if (isif_port_if == MEDIA_BUS_FMT_UV8_1X8)
274 		isif_port_if = MEDIA_BUS_FMT_SGRBG12_1X12;
275 
276 	/* Enable DPCM decompression */
277 	switch (ipipeif_source) {
278 	case IPIPEIF_SDRAM_RAW:
279 		val = 0;
280 		if (outformat->code == MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8) {
281 			val = 1;
282 			val |= (IPIPEIF_DPCM_8BIT_10BIT & 1) <<
283 				IPIPEIF_DPCM_BITS_SHIFT;
284 			val |= (ipipeif->dpcm_predictor & 1) <<
285 				IPIPEIF_DPCM_PRED_SHIFT;
286 		}
287 		ipipeif_write(val, ipipeif_base_addr, IPIPEIF_DPCM);
288 
289 		/* set DPC */
290 		ipipeif_config_dpc(ipipeif_base_addr, &params.if_5_1.dpc);
291 
292 		ipipeif_write(params.if_5_1.clip,
293 			      ipipeif_base_addr, IPIPEIF_OCLIP);
294 
295 		/* fall through for SDRAM YUV mode */
296 		/* configure CFG2 */
297 		val = ipipeif_read(ipipeif_base_addr, IPIPEIF_CFG2);
298 		switch (isif_port_if) {
299 		case MEDIA_BUS_FMT_YUYV8_1X16:
300 		case MEDIA_BUS_FMT_UYVY8_2X8:
301 		case MEDIA_BUS_FMT_Y8_1X8:
302 			RESETBIT(val, IPIPEIF_CFG2_YUV8_SHIFT);
303 			SETBIT(val, IPIPEIF_CFG2_YUV16_SHIFT);
304 			ipipeif_write(val, ipipeif_base_addr, IPIPEIF_CFG2);
305 			break;
306 
307 		default:
308 			RESETBIT(val, IPIPEIF_CFG2_YUV8_SHIFT);
309 			RESETBIT(val, IPIPEIF_CFG2_YUV16_SHIFT);
310 			ipipeif_write(val, ipipeif_base_addr, IPIPEIF_CFG2);
311 			break;
312 		}
313 
314 	case IPIPEIF_SDRAM_YUV:
315 		/* Set clock divider */
316 		if (params.clock_select == IPIPEIF_SDRAM_CLK) {
317 			val = ipipeif_read(ipipeif_base_addr, IPIPEIF_CLKDIV);
318 			val |= (params.if_5_1.clk_div.m - 1) <<
319 				IPIPEIF_CLKDIV_M_SHIFT;
320 			val |= (params.if_5_1.clk_div.n - 1);
321 			ipipeif_write(val, ipipeif_base_addr, IPIPEIF_CLKDIV);
322 		}
323 		break;
324 
325 	case IPIPEIF_CCDC:
326 	case IPIPEIF_CCDC_DARKFM:
327 		/* set DPC */
328 		ipipeif_config_dpc(ipipeif_base_addr, &params.if_5_1.dpc);
329 
330 		/* Set DF gain & threshold control */
331 		val = 0;
332 		if (params.if_5_1.df_gain_en) {
333 			val = params.if_5_1.df_gain_thr &
334 				IPIPEIF_DF_GAIN_THR_MASK;
335 			ipipeif_write(val, ipipeif_base_addr, IPIPEIF_DFSGTH);
336 			val = (params.if_5_1.df_gain_en & 1) <<
337 				IPIPEIF_DF_GAIN_EN_SHIFT;
338 			val |= params.if_5_1.df_gain &
339 				IPIPEIF_DF_GAIN_MASK;
340 		}
341 		ipipeif_write(val, ipipeif_base_addr, IPIPEIF_DFSGVL);
342 		/* configure CFG2 */
343 		val = VPFE_PINPOL_POSITIVE << IPIPEIF_CFG2_HDPOL_SHIFT;
344 		val |= VPFE_PINPOL_POSITIVE << IPIPEIF_CFG2_VDPOL_SHIFT;
345 
346 		switch (isif_port_if) {
347 		case MEDIA_BUS_FMT_YUYV8_1X16:
348 		case MEDIA_BUS_FMT_YUYV10_1X20:
349 			RESETBIT(val, IPIPEIF_CFG2_YUV8_SHIFT);
350 			SETBIT(val, IPIPEIF_CFG2_YUV16_SHIFT);
351 			break;
352 
353 		case MEDIA_BUS_FMT_YUYV8_2X8:
354 		case MEDIA_BUS_FMT_UYVY8_2X8:
355 		case MEDIA_BUS_FMT_Y8_1X8:
356 		case MEDIA_BUS_FMT_YUYV10_2X10:
357 			SETBIT(val, IPIPEIF_CFG2_YUV8_SHIFT);
358 			SETBIT(val, IPIPEIF_CFG2_YUV16_SHIFT);
359 			val |= IPIPEIF_CBCR_Y << IPIPEIF_CFG2_YUV8P_SHIFT;
360 			break;
361 
362 		default:
363 			/* Bayer */
364 			ipipeif_write(params.if_5_1.clip, ipipeif_base_addr,
365 				IPIPEIF_OCLIP);
366 		}
367 		ipipeif_write(val, ipipeif_base_addr, IPIPEIF_CFG2);
368 		break;
369 
370 	default:
371 		return -EINVAL;
372 	}
373 
374 	return 0;
375 }
376 
377 static int
ipipeif_set_config(struct v4l2_subdev * sd,struct ipipeif_params * config)378 ipipeif_set_config(struct v4l2_subdev *sd, struct ipipeif_params *config)
379 {
380 	struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
381 	struct device *dev = ipipeif->subdev.v4l2_dev->dev;
382 
383 	if (!config) {
384 		dev_err(dev, "Invalid configuration pointer\n");
385 		return -EINVAL;
386 	}
387 
388 	ipipeif->config.clock_select = config->clock_select;
389 	ipipeif->config.ppln = config->ppln;
390 	ipipeif->config.lpfr = config->lpfr;
391 	ipipeif->config.rsz = config->rsz;
392 	ipipeif->config.decimation = config->decimation;
393 	if (ipipeif->config.decimation &&
394 	   (ipipeif->config.rsz < IPIPEIF_RSZ_MIN ||
395 	    ipipeif->config.rsz > IPIPEIF_RSZ_MAX)) {
396 		dev_err(dev, "rsz range is %d to %d\n",
397 			IPIPEIF_RSZ_MIN, IPIPEIF_RSZ_MAX);
398 		return -EINVAL;
399 	}
400 
401 	ipipeif->config.avg_filter = config->avg_filter;
402 
403 	ipipeif->config.if_5_1.df_gain_thr = config->if_5_1.df_gain_thr;
404 	ipipeif->config.if_5_1.df_gain = config->if_5_1.df_gain;
405 	ipipeif->config.if_5_1.df_gain_en = config->if_5_1.df_gain_en;
406 
407 	ipipeif->config.if_5_1.rsz_start = config->if_5_1.rsz_start;
408 	ipipeif->config.if_5_1.align_sync = config->if_5_1.align_sync;
409 	ipipeif->config.if_5_1.clip = config->if_5_1.clip;
410 
411 	ipipeif->config.if_5_1.dpc.en = config->if_5_1.dpc.en;
412 	ipipeif->config.if_5_1.dpc.thr = config->if_5_1.dpc.thr;
413 
414 	ipipeif->config.if_5_1.clk_div.m = config->if_5_1.clk_div.m;
415 	ipipeif->config.if_5_1.clk_div.n = config->if_5_1.clk_div.n;
416 
417 	return 0;
418 }
419 
420 static int
ipipeif_get_config(struct v4l2_subdev * sd,void __user * arg)421 ipipeif_get_config(struct v4l2_subdev *sd, void __user *arg)
422 {
423 	struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
424 	struct ipipeif_params *config = arg;
425 	struct device *dev = ipipeif->subdev.v4l2_dev->dev;
426 
427 	if (!arg) {
428 		dev_err(dev, "Invalid configuration pointer\n");
429 		return -EINVAL;
430 	}
431 
432 	config->clock_select = ipipeif->config.clock_select;
433 	config->ppln = ipipeif->config.ppln;
434 	config->lpfr = ipipeif->config.lpfr;
435 	config->rsz = ipipeif->config.rsz;
436 	config->decimation = ipipeif->config.decimation;
437 	config->avg_filter = ipipeif->config.avg_filter;
438 
439 	config->if_5_1.df_gain_thr = ipipeif->config.if_5_1.df_gain_thr;
440 	config->if_5_1.df_gain = ipipeif->config.if_5_1.df_gain;
441 	config->if_5_1.df_gain_en = ipipeif->config.if_5_1.df_gain_en;
442 
443 	config->if_5_1.rsz_start = ipipeif->config.if_5_1.rsz_start;
444 	config->if_5_1.align_sync = ipipeif->config.if_5_1.align_sync;
445 	config->if_5_1.clip = ipipeif->config.if_5_1.clip;
446 
447 	config->if_5_1.dpc.en = ipipeif->config.if_5_1.dpc.en;
448 	config->if_5_1.dpc.thr = ipipeif->config.if_5_1.dpc.thr;
449 
450 	config->if_5_1.clk_div.m = ipipeif->config.if_5_1.clk_div.m;
451 	config->if_5_1.clk_div.n = ipipeif->config.if_5_1.clk_div.n;
452 
453 	return 0;
454 }
455 
456 /*
457  * ipipeif_ioctl() - Handle ipipeif module private ioctl's
458  * @sd: pointer to v4l2 subdev structure
459  * @cmd: configuration command
460  * @arg: configuration argument
461  */
ipipeif_ioctl(struct v4l2_subdev * sd,unsigned int cmd,void * arg)462 static long ipipeif_ioctl(struct v4l2_subdev *sd,
463 			  unsigned int cmd, void *arg)
464 {
465 	struct ipipeif_params *config = arg;
466 	int ret = -ENOIOCTLCMD;
467 
468 	switch (cmd) {
469 	case VIDIOC_VPFE_IPIPEIF_S_CONFIG:
470 		ret = ipipeif_set_config(sd, config);
471 		break;
472 
473 	case VIDIOC_VPFE_IPIPEIF_G_CONFIG:
474 		ret = ipipeif_get_config(sd, arg);
475 		break;
476 	}
477 	return ret;
478 }
479 
480 /*
481  * ipipeif_s_ctrl() - Handle set control subdev method
482  * @ctrl: pointer to v4l2 control structure
483  */
ipipeif_s_ctrl(struct v4l2_ctrl * ctrl)484 static int ipipeif_s_ctrl(struct v4l2_ctrl *ctrl)
485 {
486 	struct vpfe_ipipeif_device *ipipeif =
487 		container_of(ctrl->handler, struct vpfe_ipipeif_device, ctrls);
488 
489 	switch (ctrl->id) {
490 	case VPFE_CID_DPCM_PREDICTOR:
491 		ipipeif->dpcm_predictor = ctrl->val;
492 		break;
493 
494 	case V4L2_CID_GAIN:
495 		ipipeif->gain = ctrl->val;
496 		break;
497 
498 	default:
499 		return -EINVAL;
500 	}
501 
502 	return 0;
503 }
504 
505 #define ENABLE_IPIPEIF		0x1
506 
vpfe_ipipeif_enable(struct vpfe_device * vpfe_dev)507 void vpfe_ipipeif_enable(struct vpfe_device *vpfe_dev)
508 {
509 	struct vpfe_ipipeif_device *ipipeif = &vpfe_dev->vpfe_ipipeif;
510 	void *ipipeif_base_addr = ipipeif->ipipeif_base_addr;
511 	unsigned char val;
512 
513 	if (ipipeif->input != IPIPEIF_INPUT_MEMORY)
514 		return;
515 
516 	do {
517 		val = ipipeif_read(ipipeif_base_addr, IPIPEIF_ENABLE);
518 	} while (val & 0x1);
519 
520 	ipipeif_write(ENABLE_IPIPEIF, ipipeif_base_addr, IPIPEIF_ENABLE);
521 }
522 
523 /*
524  * ipipeif_set_stream() - Enable/Disable streaming on ipipeif subdev
525  * @sd: pointer to v4l2 subdev structure
526  * @enable: 1 == Enable, 0 == Disable
527  */
ipipeif_set_stream(struct v4l2_subdev * sd,int enable)528 static int ipipeif_set_stream(struct v4l2_subdev *sd, int enable)
529 {
530 	struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
531 	struct vpfe_device *vpfe_dev = to_vpfe_device(ipipeif);
532 	int ret = 0;
533 
534 	if (!enable)
535 		return ret;
536 
537 	ret = ipipeif_hw_setup(sd);
538 	if (!ret)
539 		vpfe_ipipeif_enable(vpfe_dev);
540 
541 	return ret;
542 }
543 
544 /*
545  * ipipeif_enum_mbus_code() - Handle pixel format enumeration
546  * @sd: pointer to v4l2 subdev structure
547  * @cfg: V4L2 subdev pad config
548  * @code: pointer to v4l2_subdev_mbus_code_enum structure
549  * return -EINVAL or zero on success
550  */
ipipeif_enum_mbus_code(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_mbus_code_enum * code)551 static int ipipeif_enum_mbus_code(struct v4l2_subdev *sd,
552 				  struct v4l2_subdev_pad_config *cfg,
553 			struct v4l2_subdev_mbus_code_enum *code)
554 {
555 	switch (code->pad) {
556 	case IPIPEIF_PAD_SINK:
557 		if (code->index >= ARRAY_SIZE(ipipeif_input_fmts))
558 			return -EINVAL;
559 
560 		code->code = ipipeif_input_fmts[code->index];
561 		break;
562 
563 	case IPIPEIF_PAD_SOURCE:
564 		if (code->index >= ARRAY_SIZE(ipipeif_output_fmts))
565 			return -EINVAL;
566 
567 		code->code = ipipeif_output_fmts[code->index];
568 		break;
569 
570 	default:
571 		return -EINVAL;
572 	}
573 
574 	return 0;
575 }
576 
577 /*
578  * ipipeif_get_format() - Handle get format by pads subdev method
579  * @sd: pointer to v4l2 subdev structure
580  * @cfg: V4L2 subdev pad config
581  * @fmt: pointer to v4l2 subdev format structure
582  */
583 static int
ipipeif_get_format(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_format * fmt)584 ipipeif_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
585 		struct v4l2_subdev_format *fmt)
586 {
587 	struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
588 
589 	if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
590 		fmt->format = ipipeif->formats[fmt->pad];
591 	else
592 		fmt->format = *(v4l2_subdev_get_try_format(sd, cfg, fmt->pad));
593 
594 	return 0;
595 }
596 
597 #define MIN_OUT_WIDTH			32
598 #define MIN_OUT_HEIGHT			32
599 
600 /*
601  * ipipeif_try_format() - Handle try format by pad subdev method
602  * @ipipeif: VPFE ipipeif device.
603  * @cfg: V4L2 subdev pad config
604  * @pad: pad num.
605  * @fmt: pointer to v4l2 format structure.
606  * @which : wanted subdev format
607  */
608 static void
ipipeif_try_format(struct vpfe_ipipeif_device * ipipeif,struct v4l2_subdev_pad_config * cfg,unsigned int pad,struct v4l2_mbus_framefmt * fmt,enum v4l2_subdev_format_whence which)609 ipipeif_try_format(struct vpfe_ipipeif_device *ipipeif,
610 		   struct v4l2_subdev_pad_config *cfg, unsigned int pad,
611 		   struct v4l2_mbus_framefmt *fmt,
612 		   enum v4l2_subdev_format_whence which)
613 {
614 	unsigned int max_out_height;
615 	unsigned int max_out_width;
616 	unsigned int i;
617 
618 	max_out_width = IPIPE_MAX_OUTPUT_WIDTH_A;
619 	max_out_height = IPIPE_MAX_OUTPUT_HEIGHT_A;
620 
621 	if (pad == IPIPEIF_PAD_SINK) {
622 		for (i = 0; i < ARRAY_SIZE(ipipeif_input_fmts); i++)
623 			if (fmt->code == ipipeif_input_fmts[i])
624 				break;
625 
626 		/* If not found, use SBGGR10 as default */
627 		if (i >= ARRAY_SIZE(ipipeif_input_fmts))
628 			fmt->code = MEDIA_BUS_FMT_SGRBG12_1X12;
629 	} else if (pad == IPIPEIF_PAD_SOURCE) {
630 		for (i = 0; i < ARRAY_SIZE(ipipeif_output_fmts); i++)
631 			if (fmt->code == ipipeif_output_fmts[i])
632 				break;
633 
634 		/* If not found, use UYVY as default */
635 		if (i >= ARRAY_SIZE(ipipeif_output_fmts))
636 			fmt->code = MEDIA_BUS_FMT_UYVY8_2X8;
637 	}
638 
639 	fmt->width = clamp_t(u32, fmt->width, MIN_OUT_HEIGHT, max_out_width);
640 	fmt->height = clamp_t(u32, fmt->height, MIN_OUT_WIDTH, max_out_height);
641 }
642 
643 static int
ipipeif_enum_frame_size(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_frame_size_enum * fse)644 ipipeif_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
645 		     struct v4l2_subdev_frame_size_enum *fse)
646 {
647 	struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
648 	struct v4l2_mbus_framefmt format;
649 
650 	if (fse->index != 0)
651 		return -EINVAL;
652 
653 	format.code = fse->code;
654 	format.width = 1;
655 	format.height = 1;
656 	ipipeif_try_format(ipipeif, cfg, fse->pad, &format, fse->which);
657 	fse->min_width = format.width;
658 	fse->min_height = format.height;
659 
660 	if (format.code != fse->code)
661 		return -EINVAL;
662 
663 	format.code = fse->code;
664 	format.width = -1;
665 	format.height = -1;
666 	ipipeif_try_format(ipipeif, cfg, fse->pad, &format, fse->which);
667 	fse->max_width = format.width;
668 	fse->max_height = format.height;
669 
670 	return 0;
671 }
672 
673 /*
674  * __ipipeif_get_format() - helper function for getting ipipeif format
675  * @ipipeif: pointer to ipipeif private structure.
676  * @cfg: V4L2 subdev pad config
677  * @pad: pad number.
678  * @which: wanted subdev format.
679  *
680  */
681 static struct v4l2_mbus_framefmt *
__ipipeif_get_format(struct vpfe_ipipeif_device * ipipeif,struct v4l2_subdev_pad_config * cfg,unsigned int pad,enum v4l2_subdev_format_whence which)682 __ipipeif_get_format(struct vpfe_ipipeif_device *ipipeif,
683 		       struct v4l2_subdev_pad_config *cfg, unsigned int pad,
684 		       enum v4l2_subdev_format_whence which)
685 {
686 	if (which == V4L2_SUBDEV_FORMAT_TRY)
687 		return v4l2_subdev_get_try_format(&ipipeif->subdev, cfg, pad);
688 
689 	return &ipipeif->formats[pad];
690 }
691 
692 /*
693  * ipipeif_set_format() - Handle set format by pads subdev method
694  * @sd: pointer to v4l2 subdev structure
695  * @cfg: V4L2 subdev pad config
696  * @fmt: pointer to v4l2 subdev format structure
697  * return -EINVAL or zero on success
698  */
699 static int
ipipeif_set_format(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_format * fmt)700 ipipeif_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
701 		struct v4l2_subdev_format *fmt)
702 {
703 	struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
704 	struct v4l2_mbus_framefmt *format;
705 
706 	format = __ipipeif_get_format(ipipeif, cfg, fmt->pad, fmt->which);
707 	if (format == NULL)
708 		return -EINVAL;
709 
710 	ipipeif_try_format(ipipeif, cfg, fmt->pad, &fmt->format, fmt->which);
711 	*format = fmt->format;
712 
713 	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
714 		return 0;
715 
716 	if (fmt->pad == IPIPEIF_PAD_SINK &&
717 	    ipipeif->input != IPIPEIF_INPUT_NONE)
718 		ipipeif->formats[fmt->pad] = fmt->format;
719 	else if (fmt->pad == IPIPEIF_PAD_SOURCE &&
720 		 ipipeif->output != IPIPEIF_OUTPUT_NONE)
721 		ipipeif->formats[fmt->pad] = fmt->format;
722 	else
723 		return -EINVAL;
724 
725 	return 0;
726 }
727 
ipipeif_set_default_config(struct vpfe_ipipeif_device * ipipeif)728 static void ipipeif_set_default_config(struct vpfe_ipipeif_device *ipipeif)
729 {
730 #define WIDTH_I			640
731 #define HEIGHT_I		480
732 
733 	const struct ipipeif_params ipipeif_defaults = {
734 		.clock_select = IPIPEIF_SDRAM_CLK,
735 		.ppln = WIDTH_I + 8,
736 		.lpfr = HEIGHT_I + 10,
737 		.rsz = 16,	/* resize ratio 16/rsz */
738 		.decimation = IPIPEIF_DECIMATION_OFF,
739 		.avg_filter = IPIPEIF_AVG_OFF,
740 		.if_5_1 = {
741 			.clk_div = {
742 				.m = 1,	/* clock = sdram clock * (m/n) */
743 				.n = 6
744 			},
745 			.clip = 4095,
746 		},
747 	};
748 	memcpy(&ipipeif->config, &ipipeif_defaults,
749 	       sizeof(struct ipipeif_params));
750 }
751 
752 /*
753  * ipipeif_init_formats() - Initialize formats on all pads
754  * @sd: VPFE ipipeif V4L2 subdevice
755  * @fh: V4L2 subdev file handle
756  *
757  * Initialize all pad formats with default values. Try formats are initialized
758  * on the file handle.
759  */
760 static int
ipipeif_init_formats(struct v4l2_subdev * sd,struct v4l2_subdev_fh * fh)761 ipipeif_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
762 {
763 	struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
764 	struct v4l2_subdev_format format;
765 
766 	memset(&format, 0, sizeof(format));
767 	format.pad = IPIPEIF_PAD_SINK;
768 	format.which = V4L2_SUBDEV_FORMAT_TRY;
769 	format.format.code = MEDIA_BUS_FMT_SGRBG12_1X12;
770 	format.format.width = IPIPE_MAX_OUTPUT_WIDTH_A;
771 	format.format.height = IPIPE_MAX_OUTPUT_HEIGHT_A;
772 	ipipeif_set_format(sd, fh->pad, &format);
773 
774 	memset(&format, 0, sizeof(format));
775 	format.pad = IPIPEIF_PAD_SOURCE;
776 	format.which = V4L2_SUBDEV_FORMAT_TRY;
777 	format.format.code = MEDIA_BUS_FMT_UYVY8_2X8;
778 	format.format.width = IPIPE_MAX_OUTPUT_WIDTH_A;
779 	format.format.height = IPIPE_MAX_OUTPUT_HEIGHT_A;
780 	ipipeif_set_format(sd, fh->pad, &format);
781 
782 	ipipeif_set_default_config(ipipeif);
783 
784 	return 0;
785 }
786 
787 /*
788  * ipipeif_video_in_queue() - ipipeif video in queue
789  * @vpfe_dev: vpfe device pointer
790  * @addr: buffer address
791  */
792 static int
ipipeif_video_in_queue(struct vpfe_device * vpfe_dev,unsigned long addr)793 ipipeif_video_in_queue(struct vpfe_device *vpfe_dev, unsigned long addr)
794 {
795 	struct vpfe_ipipeif_device *ipipeif = &vpfe_dev->vpfe_ipipeif;
796 	void *ipipeif_base_addr = ipipeif->ipipeif_base_addr;
797 	unsigned int adofs;
798 	u32 val;
799 
800 	if (ipipeif->input != IPIPEIF_INPUT_MEMORY)
801 		return -EINVAL;
802 
803 	switch (ipipeif->formats[IPIPEIF_PAD_SINK].code) {
804 	case MEDIA_BUS_FMT_Y8_1X8:
805 	case MEDIA_BUS_FMT_UV8_1X8:
806 	case MEDIA_BUS_FMT_YDYUYDYV8_1X16:
807 		adofs = ipipeif->formats[IPIPEIF_PAD_SINK].width;
808 		break;
809 
810 	default:
811 		adofs = ipipeif->formats[IPIPEIF_PAD_SINK].width << 1;
812 		break;
813 	}
814 
815 	/* adjust the line len to be a multiple of 32 */
816 	adofs += 31;
817 	adofs &= ~0x1f;
818 	val = (adofs >> 5) & IPIPEIF_ADOFS_LSB_MASK;
819 	ipipeif_write(val, ipipeif_base_addr, IPIPEIF_ADOFS);
820 
821 	/* lower sixteen bit */
822 	val = (addr >> IPIPEIF_ADDRL_SHIFT) & IPIPEIF_ADDRL_MASK;
823 	ipipeif_write(val, ipipeif_base_addr, IPIPEIF_ADDRL);
824 
825 	/* upper next seven bit */
826 	val = (addr >> IPIPEIF_ADDRU_SHIFT) & IPIPEIF_ADDRU_MASK;
827 	ipipeif_write(val, ipipeif_base_addr, IPIPEIF_ADDRU);
828 
829 	return 0;
830 }
831 
832 /* subdev core operations */
833 static const struct v4l2_subdev_core_ops ipipeif_v4l2_core_ops = {
834 	.ioctl = ipipeif_ioctl,
835 };
836 
837 static const struct v4l2_ctrl_ops ipipeif_ctrl_ops = {
838 	.s_ctrl = ipipeif_s_ctrl,
839 };
840 
841 static const struct v4l2_ctrl_config vpfe_ipipeif_dpcm_pred = {
842 	.ops = &ipipeif_ctrl_ops,
843 	.id = VPFE_CID_DPCM_PREDICTOR,
844 	.name = "DPCM Predictor",
845 	.type = V4L2_CTRL_TYPE_INTEGER,
846 	.min = 0,
847 	.max = 1,
848 	.step = 1,
849 	.def = 0,
850 };
851 
852 /* subdev file operations */
853 static const struct v4l2_subdev_internal_ops ipipeif_v4l2_internal_ops = {
854 	.open = ipipeif_init_formats,
855 };
856 
857 /* subdev video operations */
858 static const struct v4l2_subdev_video_ops ipipeif_v4l2_video_ops = {
859 	.s_stream = ipipeif_set_stream,
860 };
861 
862 /* subdev pad operations */
863 static const struct v4l2_subdev_pad_ops ipipeif_v4l2_pad_ops = {
864 	.enum_mbus_code = ipipeif_enum_mbus_code,
865 	.enum_frame_size = ipipeif_enum_frame_size,
866 	.get_fmt = ipipeif_get_format,
867 	.set_fmt = ipipeif_set_format,
868 };
869 
870 /* subdev operations */
871 static const struct v4l2_subdev_ops ipipeif_v4l2_ops = {
872 	.core = &ipipeif_v4l2_core_ops,
873 	.video = &ipipeif_v4l2_video_ops,
874 	.pad = &ipipeif_v4l2_pad_ops,
875 };
876 
877 static const struct vpfe_video_operations video_in_ops = {
878 	.queue = ipipeif_video_in_queue,
879 };
880 
881 static int
ipipeif_link_setup(struct media_entity * entity,const struct media_pad * local,const struct media_pad * remote,u32 flags)882 ipipeif_link_setup(struct media_entity *entity, const struct media_pad *local,
883 		const struct media_pad *remote, u32 flags)
884 {
885 	struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
886 	struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
887 	struct vpfe_device *vpfe = to_vpfe_device(ipipeif);
888 
889 	switch (local->index | media_entity_type(remote->entity)) {
890 	case IPIPEIF_PAD_SINK | MEDIA_ENT_T_DEVNODE:
891 		/* Single shot mode */
892 		if (!(flags & MEDIA_LNK_FL_ENABLED)) {
893 			ipipeif->input = IPIPEIF_INPUT_NONE;
894 			break;
895 		}
896 		ipipeif->input = IPIPEIF_INPUT_MEMORY;
897 		break;
898 
899 	case IPIPEIF_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
900 		/* read from isif */
901 		if (!(flags & MEDIA_LNK_FL_ENABLED)) {
902 			ipipeif->input = IPIPEIF_INPUT_NONE;
903 			break;
904 		}
905 		if (ipipeif->input != IPIPEIF_INPUT_NONE)
906 			return -EBUSY;
907 
908 		ipipeif->input = IPIPEIF_INPUT_ISIF;
909 		break;
910 
911 	case IPIPEIF_PAD_SOURCE | MEDIA_ENT_T_V4L2_SUBDEV:
912 		if (!(flags & MEDIA_LNK_FL_ENABLED)) {
913 			ipipeif->output = IPIPEIF_OUTPUT_NONE;
914 			break;
915 		}
916 		if (remote->entity == &vpfe->vpfe_ipipe.subdev.entity)
917 			/* connencted to ipipe */
918 			ipipeif->output = IPIPEIF_OUTPUT_IPIPE;
919 		else if (remote->entity == &vpfe->vpfe_resizer.
920 			crop_resizer.subdev.entity)
921 			/* connected to resizer */
922 			ipipeif->output = IPIPEIF_OUTPUT_RESIZER;
923 		else
924 			return -EINVAL;
925 		break;
926 
927 	default:
928 		return -EINVAL;
929 	}
930 
931 	return 0;
932 }
933 
934 static const struct media_entity_operations ipipeif_media_ops = {
935 	.link_setup = ipipeif_link_setup,
936 };
937 
938 /*
939  * vpfe_ipipeif_unregister_entities() - Unregister entity
940  * @ipipeif - pointer to ipipeif subdevice structure.
941  */
vpfe_ipipeif_unregister_entities(struct vpfe_ipipeif_device * ipipeif)942 void vpfe_ipipeif_unregister_entities(struct vpfe_ipipeif_device *ipipeif)
943 {
944 	/* unregister video device */
945 	vpfe_video_unregister(&ipipeif->video_in);
946 
947 	/* unregister subdev */
948 	v4l2_device_unregister_subdev(&ipipeif->subdev);
949 	/* cleanup entity */
950 	media_entity_cleanup(&ipipeif->subdev.entity);
951 }
952 
953 int
vpfe_ipipeif_register_entities(struct vpfe_ipipeif_device * ipipeif,struct v4l2_device * vdev)954 vpfe_ipipeif_register_entities(struct vpfe_ipipeif_device *ipipeif,
955 			       struct v4l2_device *vdev)
956 {
957 	struct vpfe_device *vpfe_dev = to_vpfe_device(ipipeif);
958 	unsigned int flags;
959 	int ret;
960 
961 	/* Register the subdev */
962 	ret = v4l2_device_register_subdev(vdev, &ipipeif->subdev);
963 	if (ret < 0)
964 		return ret;
965 
966 	ret = vpfe_video_register(&ipipeif->video_in, vdev);
967 	if (ret) {
968 		pr_err("Failed to register ipipeif video-in device\n");
969 		goto fail;
970 	}
971 	ipipeif->video_in.vpfe_dev = vpfe_dev;
972 
973 	flags = 0;
974 	ret = media_entity_create_link(&ipipeif->video_in.video_dev.entity, 0,
975 					&ipipeif->subdev.entity, 0, flags);
976 	if (ret < 0)
977 		goto fail;
978 
979 	return 0;
980 fail:
981 	v4l2_device_unregister_subdev(&ipipeif->subdev);
982 
983 	return ret;
984 }
985 
986 #define IPIPEIF_GAIN_HIGH		0x3ff
987 #define IPIPEIF_DEFAULT_GAIN		0x200
988 
vpfe_ipipeif_init(struct vpfe_ipipeif_device * ipipeif,struct platform_device * pdev)989 int vpfe_ipipeif_init(struct vpfe_ipipeif_device *ipipeif,
990 		      struct platform_device *pdev)
991 {
992 	struct v4l2_subdev *sd = &ipipeif->subdev;
993 	struct media_pad *pads = &ipipeif->pads[0];
994 	struct media_entity *me = &sd->entity;
995 	static resource_size_t  res_len;
996 	struct resource *res;
997 	int ret;
998 
999 	res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
1000 	if (!res)
1001 		return -ENOENT;
1002 
1003 	res_len = resource_size(res);
1004 	res = request_mem_region(res->start, res_len, res->name);
1005 	if (!res)
1006 		return -EBUSY;
1007 
1008 	ipipeif->ipipeif_base_addr = ioremap_nocache(res->start, res_len);
1009 	if (!ipipeif->ipipeif_base_addr) {
1010 		ret =  -EBUSY;
1011 		goto fail;
1012 	}
1013 
1014 	v4l2_subdev_init(sd, &ipipeif_v4l2_ops);
1015 
1016 	sd->internal_ops = &ipipeif_v4l2_internal_ops;
1017 	strlcpy(sd->name, "DAVINCI IPIPEIF", sizeof(sd->name));
1018 	sd->grp_id = 1 << 16;	/* group ID for davinci subdevs */
1019 
1020 	v4l2_set_subdevdata(sd, ipipeif);
1021 
1022 	sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE;
1023 	pads[IPIPEIF_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
1024 	pads[IPIPEIF_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
1025 	ipipeif->input = IPIPEIF_INPUT_NONE;
1026 	ipipeif->output = IPIPEIF_OUTPUT_NONE;
1027 	me->ops = &ipipeif_media_ops;
1028 
1029 	ret = media_entity_init(me, IPIPEIF_NUM_PADS, pads, 0);
1030 	if (ret)
1031 		goto fail;
1032 
1033 	v4l2_ctrl_handler_init(&ipipeif->ctrls, 2);
1034 	v4l2_ctrl_new_std(&ipipeif->ctrls, &ipipeif_ctrl_ops,
1035 			  V4L2_CID_GAIN, 0,
1036 			  IPIPEIF_GAIN_HIGH, 1, IPIPEIF_DEFAULT_GAIN);
1037 	v4l2_ctrl_new_custom(&ipipeif->ctrls, &vpfe_ipipeif_dpcm_pred, NULL);
1038 	v4l2_ctrl_handler_setup(&ipipeif->ctrls);
1039 	sd->ctrl_handler = &ipipeif->ctrls;
1040 
1041 	ipipeif->video_in.ops = &video_in_ops;
1042 	ipipeif->video_in.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
1043 	ret = vpfe_video_init(&ipipeif->video_in, "IPIPEIF");
1044 	if (ret) {
1045 		pr_err("Failed to init IPIPEIF video-in device\n");
1046 		goto fail;
1047 	}
1048 	ipipeif_set_default_config(ipipeif);
1049 	return 0;
1050 fail:
1051 	release_mem_region(res->start, res_len);
1052 	return ret;
1053 }
1054 
1055 void
vpfe_ipipeif_cleanup(struct vpfe_ipipeif_device * ipipeif,struct platform_device * pdev)1056 vpfe_ipipeif_cleanup(struct vpfe_ipipeif_device *ipipeif,
1057 		     struct platform_device *pdev)
1058 {
1059 	struct resource *res;
1060 
1061 	v4l2_ctrl_handler_free(&ipipeif->ctrls);
1062 	iounmap(ipipeif->ipipeif_base_addr);
1063 	res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
1064 	if (res)
1065 		release_mem_region(res->start, resource_size(res));
1066 
1067 }
1068