• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * linux-5.4/drivers/media/platform/sunxi-vin/vin-csi/sunxi_csi.c
3  *
4  * Copyright (c) 2007-2017 Allwinnertech Co., Ltd.
5  *
6  * This software is licensed under the terms of the GNU General Public
7  * License version 2, as published by the Free Software Foundation, and
8  * may be copied, distributed, and modified under those terms.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  */
16 
17 #include <linux/platform_device.h>
18 #include <linux/kernel.h>
19 #include <linux/module.h>
20 #include <linux/delay.h>
21 
22 #include <media/v4l2-device.h>
23 #include <media/v4l2-mediabus.h>
24 #include <media/v4l2-subdev.h>
25 #include <media/sunxi_camera_v2.h>
26 
27 #include "parser_reg.h"
28 #include "sunxi_csi.h"
29 #include "../vin-video/vin_core.h"
30 #include "../platform/platform_cfg.h"
31 
32 #define CSI_MODULE_NAME "vin_csi"
33 
34 #define IS_FLAG(x, y) (((x)&(y)) == y)
35 
36 struct csi_dev *glb_parser[VIN_MAX_CSI];
37 
38 static struct csi_format sunxi_csi_formats[] = {
39 	{
40 		.code = MEDIA_BUS_FMT_YUYV8_2X8,
41 		.seq = SEQ_YUYV,
42 		.infmt = FMT_YUV422,
43 		.data_width = 8,
44 	}, {
45 		.code = MEDIA_BUS_FMT_YVYU8_2X8,
46 		.seq = SEQ_YVYU,
47 		.infmt = FMT_YUV422,
48 		.data_width = 8,
49 	}, {
50 		.code = MEDIA_BUS_FMT_UYVY8_2X8,
51 		.seq = SEQ_UYVY,
52 		.infmt = FMT_YUV422,
53 		.data_width = 8,
54 	}, {
55 		.code = MEDIA_BUS_FMT_VYUY8_2X8,
56 		.seq = SEQ_VYUY,
57 		.infmt = FMT_YUV422,
58 		.data_width = 8,
59 	}, {
60 		.code = MEDIA_BUS_FMT_YUYV8_1X16,
61 		.seq = SEQ_YUYV,
62 		.infmt = FMT_YUV422,
63 		.data_width = 16,
64 	}, {
65 		.code = MEDIA_BUS_FMT_YVYU8_1X16,
66 		.seq = SEQ_YVYU,
67 		.infmt = FMT_YUV422,
68 		.data_width = 16,
69 	}, {
70 		.code = MEDIA_BUS_FMT_UYVY8_1X16,
71 		.seq = SEQ_UYVY,
72 		.infmt = FMT_YUV422,
73 		.data_width = 16,
74 	}, {
75 		.code = MEDIA_BUS_FMT_VYUY8_1X16,
76 		.seq = SEQ_VYUY,
77 		.infmt = FMT_YUV422,
78 		.data_width = 16,
79 	}, {
80 		.code = MEDIA_BUS_FMT_UYVY10_2X10,
81 		.seq = SEQ_UYVY,
82 		.infmt = FMT_YUV422,
83 		.data_width = 10,
84 	}, {
85 		.code = MEDIA_BUS_FMT_VYUY10_2X10,
86 		.seq = SEQ_VYUY,
87 		.infmt = FMT_YUV422,
88 		.data_width = 10,
89 	}, {
90 		.code = MEDIA_BUS_FMT_YVYU10_2X10,
91 		.seq = SEQ_YVYU,
92 		.infmt = FMT_YUV422,
93 		.data_width = 10,
94 	}, {
95 		.code = MEDIA_BUS_FMT_YUYV10_2X10,
96 		.seq = SEQ_YUYV,
97 		.infmt = FMT_YUV422,
98 		.data_width = 10,
99 	}, {
100 		.code = MEDIA_BUS_FMT_SBGGR8_1X8,
101 		.infmt = FMT_RAW,
102 		.data_width = 8,
103 	}, {
104 		.code = MEDIA_BUS_FMT_SGBRG8_1X8,
105 		.infmt = FMT_RAW,
106 		.data_width = 8,
107 	}, {
108 		.code = MEDIA_BUS_FMT_SGRBG8_1X8,
109 		.infmt = FMT_RAW,
110 		.data_width = 8,
111 	}, {
112 		.code = MEDIA_BUS_FMT_SRGGB8_1X8,
113 		.infmt = FMT_RAW,
114 		.data_width = 8,
115 	}, {
116 		.code = MEDIA_BUS_FMT_SBGGR10_1X10,
117 		.infmt = FMT_RAW,
118 		.data_width = 10,
119 	}, {
120 		.code = MEDIA_BUS_FMT_SGBRG10_1X10,
121 		.infmt = FMT_RAW,
122 		.data_width = 10,
123 	}, {
124 		.code = MEDIA_BUS_FMT_SGRBG10_1X10,
125 		.infmt = FMT_RAW,
126 		.data_width = 10,
127 	}, {
128 		.code = MEDIA_BUS_FMT_SRGGB10_1X10,
129 		.infmt = FMT_RAW,
130 		.data_width = 10,
131 	}, {
132 		.code = MEDIA_BUS_FMT_SBGGR12_1X12,
133 		.infmt = FMT_RAW,
134 		.data_width = 12,
135 	}, {
136 		.code = MEDIA_BUS_FMT_SGBRG12_1X12,
137 		.infmt = FMT_RAW,
138 		.data_width = 12,
139 	}, {
140 		.code = MEDIA_BUS_FMT_SGRBG12_1X12,
141 		.infmt = FMT_RAW,
142 		.data_width = 12,
143 	}, {
144 		.code = MEDIA_BUS_FMT_SRGGB12_1X12,
145 		.infmt = FMT_RAW,
146 		.data_width = 12,
147 	}
148 };
149 
__csi_pin_config(struct csi_dev * dev,int enable)150 static int __csi_pin_config(struct csi_dev *dev, int enable)
151 {
152 #ifndef FPGA_VER
153 	char pinctrl_names[10] = "";
154 
155 	if (dev->bus_info.bus_if == V4L2_MBUS_CSI2_DPHY ||
156 		dev->bus_info.bus_if == V4L2_MBUS_CSI2_CPHY ||
157 		dev->bus_info.bus_if == V4L2_MBUS_CSI1)
158 		return 0;
159 
160 	if (!IS_ERR_OR_NULL(dev->pctrl))
161 		devm_pinctrl_put(dev->pctrl);
162 
163 	if (enable == 1)
164 		strcpy(pinctrl_names, "default");
165 	else
166 		strcpy(pinctrl_names, "sleep");
167 
168 	dev->pctrl = devm_pinctrl_get_select(&dev->pdev->dev, pinctrl_names);
169 	if (IS_ERR_OR_NULL(dev->pctrl)) {
170 		vin_err("csi%d request pinctrl handle failed!\n", dev->id);
171 		return -EINVAL;
172 	}
173 	usleep_range(100, 120);
174 #endif
175 	return 0;
176 }
177 
__csi_pin_release(struct csi_dev * dev)178 static int __csi_pin_release(struct csi_dev *dev)
179 {
180 #ifndef FPGA_VER
181 	if (!IS_ERR_OR_NULL(dev->pctrl))
182 		devm_pinctrl_put(dev->pctrl);
183 #endif
184 	return 0;
185 }
186 
__csi_set_fmt_hw(struct csi_dev * csi)187 static int __csi_set_fmt_hw(struct csi_dev *csi)
188 {
189 	struct v4l2_mbus_framefmt *mf = &csi->mf;
190 	struct prs_ncsi_bt656_header bt656_header;
191 	struct prs_mcsi_if_cfg mcsi_if;
192 	struct prs_cap_mode mode;
193 	struct mbus_framefmt_res *res = (void *)mf->reserved;
194 	int i;
195 
196 	memset(&bt656_header, 0, sizeof(bt656_header));
197 	memset(&mcsi_if, 0, sizeof(mcsi_if));
198 
199 	csi->ncsi_if.seq = csi->csi_fmt->seq;
200 	mcsi_if.seq = csi->csi_fmt->seq;
201 
202 	switch (csi->csi_fmt->data_width) {
203 	case 8:
204 		csi->ncsi_if.dw = DW_8BIT;
205 		break;
206 	case 10:
207 		csi->ncsi_if.dw = DW_10BIT;
208 		break;
209 	case 12:
210 		csi->ncsi_if.dw = DW_12BIT;
211 		break;
212 	default:
213 		csi->ncsi_if.dw = DW_8BIT;
214 		break;
215 	}
216 
217 	switch (mf->field) {
218 	case V4L2_FIELD_ANY:
219 	case V4L2_FIELD_NONE:
220 		csi->ncsi_if.type = PROGRESSED;
221 		csi->ncsi_if.mode = FRAME_MODE;
222 		mcsi_if.mode = FIELD_MODE;
223 		break;
224 	case V4L2_FIELD_TOP:
225 	case V4L2_FIELD_BOTTOM:
226 		csi->ncsi_if.type = INTERLACE;
227 		csi->ncsi_if.mode = FIELD_MODE;
228 		mcsi_if.mode = FIELD_MODE;
229 		break;
230 	case V4L2_FIELD_INTERLACED:
231 		csi->ncsi_if.type = INTERLACE;
232 		csi->ncsi_if.mode = FRAME_MODE;
233 		mcsi_if.mode = FRAME_MODE;
234 		break;
235 	default:
236 		csi->ncsi_if.type = PROGRESSED;
237 		csi->ncsi_if.mode = FRAME_MODE;
238 		mcsi_if.mode = FIELD_MODE;
239 		break;
240 	}
241 
242 	switch (csi->bus_info.bus_if) {
243 	case V4L2_MBUS_PARALLEL:
244 		if (csi->csi_fmt->data_width == 16)
245 			csi->ncsi_if.intf = PRS_IF_INTLV_16BIT;
246 		else
247 			csi->ncsi_if.intf = PRS_IF_INTLV;
248 		csic_prs_mode(csi->id, PRS_NCSI);
249 		csic_prs_ncsi_if_cfg(csi->id, &csi->ncsi_if);
250 		csic_prs_ncsi_en(csi->id, 1);
251 		break;
252 	case V4L2_MBUS_BT656:
253 		if (csi->csi_fmt->data_width == 16) {
254 			if (csi->bus_info.ch_total_num == 1)
255 				csi->ncsi_if.intf = PRS_IF_BT1120_1CH;
256 			else if (csi->bus_info.ch_total_num == 2)
257 				csi->ncsi_if.intf = PRS_IF_BT1120_2CH;
258 			else if (csi->bus_info.ch_total_num == 4)
259 				csi->ncsi_if.intf = PRS_IF_BT1120_4CH;
260 			if (csi->ncsi_if.ddr_sample == 1)
261 				csic_prs_set_pclk_dly(csi->id, 0xb);
262 			else
263 				csic_prs_set_pclk_dly(csi->id, 0x9);
264 		} else {
265 			if (csi->bus_info.ch_total_num == 1)
266 				csi->ncsi_if.intf = PRS_IF_BT656_1CH;
267 			else if (csi->bus_info.ch_total_num == 2)
268 				csi->ncsi_if.intf = PRS_IF_BT656_2CH;
269 			else if (csi->bus_info.ch_total_num == 4)
270 				csi->ncsi_if.intf = PRS_IF_BT656_4CH;
271 			if (csi->ncsi_if.ddr_sample == 1)
272 				csic_prs_set_pclk_dly(csi->id, 0x9);
273 		}
274 		csic_prs_mode(csi->id, PRS_NCSI);
275 		bt656_header.ch0_id = 0;
276 		bt656_header.ch1_id = 1;
277 		bt656_header.ch2_id = 2;
278 		bt656_header.ch3_id = 3;
279 		csic_prs_ncsi_bt656_header_cfg(csi->id, &bt656_header);
280 		csic_prs_ncsi_if_cfg(csi->id, &csi->ncsi_if);
281 		csic_prs_ncsi_en(csi->id, 1);
282 		break;
283 	case V4L2_MBUS_CSI2_DPHY:
284 		csic_prs_mode(csi->id, PRS_MCSI);
285 		csic_prs_mcsi_if_cfg(csi->id, &mcsi_if);
286 		csic_prs_mcsi_en(csi->id, 1);
287 		break;
288 	default:
289 		csic_prs_mode(csi->id, PRS_MCSI);
290 		csic_prs_mcsi_if_cfg(csi->id, &mcsi_if);
291 		csic_prs_mcsi_en(csi->id, 1);
292 		break;
293 	}
294 
295 	if (csi->capture_mode == V4L2_MODE_IMAGE)
296 		mode.mode = SCAP;
297 	else
298 		mode.mode = VCAP;
299 
300 	if (csi->out_size.hor_len != mf->width ||
301 	    csi->out_size.ver_len != mf->height) {
302 		csi->out_size.hor_len = mf->width;
303 		csi->out_size.ver_len = mf->height;
304 		csi->out_size.hor_start = 0;
305 		csi->out_size.ver_start = 0;
306 	}
307 
308 	if (mf->field == V4L2_FIELD_INTERLACED || mf->field == V4L2_FIELD_TOP ||
309 	    mf->field == V4L2_FIELD_BOTTOM)
310 		csi->out_size.ver_len = csi->out_size.ver_len / 2;
311 
312 	for (i = 0; i < csi->bus_info.ch_total_num; i++) {
313 		csic_prs_input_fmt_cfg(csi->id, i, csi->csi_fmt->infmt);
314 		csic_prs_output_size_cfg(csi->id, i, &csi->out_size);
315 	}
316 
317 	if (res->res_wdr_mode == ISP_SEHDR_MODE)
318 		csic_prs_ch_en(csi->id, 1);
319 
320 	csic_prs_fps_ds(csi->id, &csi->prs_fps_ds);
321 	csic_prs_capture_start(csi->id, csi->bus_info.ch_total_num, &mode);
322 	return 0;
323 }
324 
325 #ifdef SUPPORT_ISP_TDM
__sunxi_csi_tdm_off(struct csi_dev * csi)326 static int __sunxi_csi_tdm_off(struct csi_dev *csi)
327 {
328 	struct vin_md *vind = dev_get_drvdata(csi->subdev.v4l2_dev->dev);
329 	struct vin_core *vinc = NULL;
330 	int i, j;
331 
332 	for (i = 0; i < VIN_MAX_DEV; i++) {
333 		if (vind->vinc[i] == NULL)
334 			continue;
335 		if (!vin_streaming(&vind->vinc[i]->vid_cap))
336 			continue;
337 		vinc = vind->vinc[i];
338 		for (j = 0; j < VIN_MAX_CSI; j++) {
339 			if (vinc->csi_sel == j)
340 				return -1;
341 		}
342 	}
343 	return 0;
344 }
345 #endif
346 
sunxi_csi_subdev_s_stream(struct v4l2_subdev * sd,int enable)347 static int sunxi_csi_subdev_s_stream(struct v4l2_subdev *sd, int enable)
348 {
349 	struct csi_dev *csi = v4l2_get_subdevdata(sd);
350 	__maybe_unused int i;
351 
352 	__csi_pin_config(csi, enable);
353 	csic_prs_pclk_en(csi->id, enable);
354 	if (enable) {
355 		csic_prs_enable(csi->id);
356 		csic_prs_disable(csi->id);
357 		csic_prs_enable(csi->id);
358 		__csi_set_fmt_hw(csi);
359 	} else {
360 #ifndef SUPPORT_ISP_TDM
361 		switch (csi->bus_info.bus_if) {
362 		case V4L2_MBUS_PARALLEL:
363 		case V4L2_MBUS_BT656:
364 			csic_prs_ncsi_en(csi->id, 0);
365 			break;
366 		case V4L2_MBUS_CSI2_DPHY:
367 			csic_prs_mcsi_en(csi->id, 0);
368 			break;
369 		default:
370 			return -1;
371 		}
372 #endif
373 		csic_prs_capture_stop(csi->id);
374 #ifndef SUPPORT_ISP_TDM
375 		csic_prs_disable(csi->id);
376 #else
377 		if (__sunxi_csi_tdm_off(csi) == 0) {
378 			for (i = 0; i < VIN_MAX_CSI; i++)
379 				csic_prs_disable(i);
380 		} else
381 			vin_warn("ISP is used in TDM mode, PARSER%d cannot be closing when other isp is used!\n", csi->id);
382 #endif
383 	}
384 
385 	vin_log(VIN_LOG_FMT, "parser%d %s, %d*%d hoff: %d voff: %d code: %x field: %d\n",
386 		csi->id, enable ? "stream on" : "stream off",
387 		csi->out_size.hor_len, csi->out_size.ver_len,
388 		csi->out_size.hor_start, csi->out_size.ver_start,
389 		csi->mf.code, csi->mf.field);
390 
391 	return 0;
392 }
393 
__csi_try_format(struct v4l2_mbus_framefmt * mf)394 static struct csi_format *__csi_try_format(struct v4l2_mbus_framefmt *mf)
395 {
396 	struct csi_format *csi_fmt = NULL;
397 	int i;
398 
399 	for (i = 0; i < ARRAY_SIZE(sunxi_csi_formats); i++)
400 		if (mf->code == sunxi_csi_formats[i].code)
401 			csi_fmt = &sunxi_csi_formats[i];
402 
403 	if (csi_fmt == NULL)
404 		csi_fmt = &sunxi_csi_formats[0];
405 
406 	mf->code = csi_fmt->code;
407 	v4l_bound_align_image(&mf->width, 1, 0xffff, 1, &mf->height, 1, 0xffff, 1, 0);
408 
409 	return csi_fmt;
410 }
411 
sunxi_csi_subdev_set_fmt(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_format * fmt)412 static int sunxi_csi_subdev_set_fmt(struct v4l2_subdev *sd,
413 				    struct v4l2_subdev_pad_config *cfg,
414 				    struct v4l2_subdev_format *fmt)
415 {
416 	struct csi_dev *csi = v4l2_get_subdevdata(sd);
417 	struct v4l2_mbus_framefmt *mf;
418 	struct csi_format *csi_fmt;
419 
420 	vin_log(VIN_LOG_FMT, "%s %d*%d %x %d\n", __func__,
421 		fmt->format.width, fmt->format.height,
422 		fmt->format.code, fmt->format.field);
423 
424 	mf = &csi->mf;
425 
426 	if (fmt->pad == CSI_PAD_SOURCE) {
427 		if (mf) {
428 			mutex_lock(&csi->subdev_lock);
429 			fmt->format = *mf;
430 			mutex_unlock(&csi->subdev_lock);
431 		}
432 		return 0;
433 	}
434 	csi_fmt = __csi_try_format(&fmt->format);
435 	if (mf) {
436 		mutex_lock(&csi->subdev_lock);
437 		*mf = fmt->format;
438 		if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
439 			csi->csi_fmt = csi_fmt;
440 		mutex_unlock(&csi->subdev_lock);
441 	}
442 
443 	return 0;
444 }
445 
sunxi_csi_subdev_get_fmt(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_format * fmt)446 static int sunxi_csi_subdev_get_fmt(struct v4l2_subdev *sd,
447 				    struct v4l2_subdev_pad_config *cfg,
448 				    struct v4l2_subdev_format *fmt)
449 {
450 	struct csi_dev *csi = v4l2_get_subdevdata(sd);
451 
452 	mutex_lock(&csi->subdev_lock);
453 	fmt->format = csi->mf;
454 	mutex_unlock(&csi->subdev_lock);
455 	return 0;
456 }
457 
sunxi_csi_subdev_set_selection(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_selection * sel)458 static int sunxi_csi_subdev_set_selection(struct v4l2_subdev *sd,
459 			    struct v4l2_subdev_pad_config *cfg,
460 			    struct v4l2_subdev_selection *sel)
461 {
462 	struct csi_dev *csi = v4l2_get_subdevdata(sd);
463 
464 	csi->out_size.hor_len = cfg->try_crop.width;
465 	csi->out_size.ver_len = cfg->try_crop.height;
466 	csi->out_size.hor_start = cfg->try_crop.left;
467 	csi->out_size.ver_start = cfg->try_crop.top;
468 	return 0;
469 }
470 
sunxi_csi_s_mbus_config(struct v4l2_subdev * sd,unsigned int pad,struct v4l2_mbus_config * cfg)471 static int sunxi_csi_s_mbus_config(struct v4l2_subdev *sd, unsigned int pad,
472 				   struct v4l2_mbus_config *cfg)
473 {
474 	struct csi_dev *csi = v4l2_get_subdevdata(sd);
475 
476 	if (cfg->type == V4L2_MBUS_CSI2_DPHY || cfg->type == V4L2_MBUS_SUBLVDS ||
477 	    cfg->type == V4L2_MBUS_HISPI) {
478 		csi->bus_info.bus_if = V4L2_MBUS_CSI2_DPHY;
479 		csi->bus_info.ch_total_num = 0;
480 		if (IS_FLAG(cfg->flags, V4L2_MBUS_CSI2_CHANNEL_0))
481 			csi->bus_info.ch_total_num++;
482 		if (IS_FLAG(cfg->flags, V4L2_MBUS_CSI2_CHANNEL_1))
483 			csi->bus_info.ch_total_num++;
484 		if (IS_FLAG(cfg->flags, V4L2_MBUS_CSI2_CHANNEL_2))
485 			csi->bus_info.ch_total_num++;
486 		if (IS_FLAG(cfg->flags, V4L2_MBUS_CSI2_CHANNEL_3))
487 			csi->bus_info.ch_total_num++;
488 	} else if (cfg->type == V4L2_MBUS_PARALLEL) {
489 		csi->bus_info.bus_if = V4L2_MBUS_PARALLEL;
490 		csi->bus_info.ch_total_num = 1;
491 		if (IS_FLAG(cfg->flags, V4L2_MBUS_MASTER)) {
492 			if (IS_FLAG(cfg->flags, V4L2_MBUS_HSYNC_ACTIVE_HIGH)) {
493 				csi->bus_info.bus_tmg.href_pol = ACTIVE_HIGH;
494 				csi->ncsi_if.href = REF_POSITIVE;
495 			} else {
496 				csi->bus_info.bus_tmg.href_pol = ACTIVE_LOW;
497 				csi->ncsi_if.href = REF_NEGATIVE;
498 			}
499 			if (IS_FLAG(cfg->flags, V4L2_MBUS_VSYNC_ACTIVE_HIGH)) {
500 				csi->bus_info.bus_tmg.vref_pol = ACTIVE_HIGH;
501 				csi->ncsi_if.vref = REF_POSITIVE;
502 			} else {
503 				csi->bus_info.bus_tmg.vref_pol = ACTIVE_LOW;
504 				csi->ncsi_if.vref = REF_NEGATIVE;
505 			}
506 			if (IS_FLAG(cfg->flags, V4L2_MBUS_PCLK_SAMPLE_RISING) &&
507 					IS_FLAG(cfg->flags, V4L2_MBUS_PCLK_SAMPLE_FALLING)) {
508 				csi->ncsi_if.ddr_sample = 1;
509 			} else if (IS_FLAG(cfg->flags, V4L2_MBUS_PCLK_SAMPLE_RISING)) {
510 				csi->bus_info.bus_tmg.pclk_sample = RISING;
511 				csi->ncsi_if.clk = CLK_RISING;
512 				csi->ncsi_if.ddr_sample = 0;
513 			} else {
514 				csi->bus_info.bus_tmg.pclk_sample = FALLING;
515 				csi->ncsi_if.clk = CLK_FALLING;
516 				csi->ncsi_if.ddr_sample = 0;
517 			}
518 			if (IS_FLAG(cfg->flags, V4L2_MBUS_FIELD_EVEN_HIGH)) {
519 				csi->bus_info.bus_tmg.field_even_pol = ACTIVE_HIGH;
520 				csi->ncsi_if.field = FIELD_POS;
521 			} else {
522 				csi->bus_info.bus_tmg.field_even_pol = ACTIVE_LOW;
523 				csi->ncsi_if.field = FIELD_NEG;
524 			}
525 		} else {
526 			vin_err("Do not support V4L2_MBUS_SLAVE!\n");
527 			return -1;
528 		}
529 	} else if (cfg->type == V4L2_MBUS_BT656) {
530 		csi->bus_info.bus_if = V4L2_MBUS_BT656;
531 		csi->bus_info.ch_total_num = 0;
532 		if (IS_FLAG(cfg->flags, CSI_CH_0))
533 			csi->bus_info.ch_total_num++;
534 		if (IS_FLAG(cfg->flags, CSI_CH_1))
535 			csi->bus_info.ch_total_num++;
536 		if (IS_FLAG(cfg->flags, CSI_CH_2))
537 			csi->bus_info.ch_total_num++;
538 		if (IS_FLAG(cfg->flags, CSI_CH_3))
539 			csi->bus_info.ch_total_num++;
540 		if (csi->bus_info.ch_total_num == 4) {
541 			csi->arrange.column = 2;
542 			csi->arrange.row = 2;
543 		} else if (csi->bus_info.ch_total_num == 2) {
544 			csi->arrange.column = 2;
545 			csi->arrange.row = 1;
546 		} else {
547 			csi->bus_info.ch_total_num = 1;
548 			csi->arrange.column = 1;
549 			csi->arrange.row = 1;
550 		}
551 		if (IS_FLAG(cfg->flags, V4L2_MBUS_PCLK_SAMPLE_RISING) &&
552 				IS_FLAG(cfg->flags, V4L2_MBUS_PCLK_SAMPLE_FALLING)) {
553 			csi->ncsi_if.ddr_sample = 1;
554 		} else if (IS_FLAG(cfg->flags, V4L2_MBUS_PCLK_SAMPLE_RISING)) {
555 			csi->bus_info.bus_tmg.pclk_sample = RISING;
556 			csi->ncsi_if.clk = CLK_RISING;
557 			csi->ncsi_if.ddr_sample = 0;
558 		} else {
559 			csi->bus_info.bus_tmg.pclk_sample = FALLING;
560 			csi->ncsi_if.clk = CLK_FALLING;
561 			csi->ncsi_if.ddr_sample = 0;
562 		}
563 	}
564 	vin_log(VIN_LOG_CSI, "csi%d total ch = %d\n", csi->id, csi->bus_info.ch_total_num);
565 
566 	return 0;
567 }
568 
569 static const struct v4l2_subdev_video_ops sunxi_csi_subdev_video_ops = {
570 	.s_stream = sunxi_csi_subdev_s_stream,
571 };
572 
573 static const struct v4l2_subdev_pad_ops sunxi_csi_subdev_pad_ops = {
574 	.set_selection = sunxi_csi_subdev_set_selection,
575 	.get_fmt = sunxi_csi_subdev_get_fmt,
576 	.set_fmt = sunxi_csi_subdev_set_fmt,
577 	.set_mbus_config = sunxi_csi_s_mbus_config,
578 };
579 
580 static struct v4l2_subdev_ops sunxi_csi_subdev_ops = {
581 	.video = &sunxi_csi_subdev_video_ops,
582 	.pad = &sunxi_csi_subdev_pad_ops,
583 };
584 
__csi_init_subdev(struct csi_dev * csi)585 static int __csi_init_subdev(struct csi_dev *csi)
586 {
587 	struct v4l2_subdev *sd = &csi->subdev;
588 	int ret;
589 
590 	mutex_init(&csi->subdev_lock);
591 	csi->arrange.row = 1;
592 	csi->arrange.column = 1;
593 	csi->bus_info.ch_total_num = 1;
594 	v4l2_subdev_init(sd, &sunxi_csi_subdev_ops);
595 	sd->grp_id = VIN_GRP_ID_CSI;
596 	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
597 	snprintf(sd->name, sizeof(sd->name), "sunxi_csi.%u", csi->id);
598 	v4l2_set_subdevdata(sd, csi);
599 
600 	csi->csi_pads[CSI_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
601 	csi->csi_pads[CSI_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
602 	sd->entity.function = MEDIA_ENT_F_IO_V4L;
603 
604 	ret = media_entity_pads_init(&sd->entity, CSI_PAD_NUM, csi->csi_pads);
605 	if (ret < 0)
606 		return ret;
607 
608 	return 0;
609 }
610 
csi_probe(struct platform_device * pdev)611 static int csi_probe(struct platform_device *pdev)
612 {
613 	struct device_node *np = pdev->dev.of_node;
614 	struct csi_dev *csi = NULL;
615 	int ret = 0;
616 
617 	if (np == NULL) {
618 		vin_err("CSI failed to get of node\n");
619 		return -ENODEV;
620 	}
621 	csi = kzalloc(sizeof(struct csi_dev), GFP_KERNEL);
622 	if (!csi) {
623 		ret = -ENOMEM;
624 		goto ekzalloc;
625 	}
626 
627 	of_property_read_u32(np, "device_id", &pdev->id);
628 	if (pdev->id < 0) {
629 		vin_err("CSI failed to get device id\n");
630 		ret = -EINVAL;
631 		goto freedev;
632 	}
633 	csi->id = pdev->id;
634 	csi->pdev = pdev;
635 
636 	/*just for test because the csi1 is virtual node*/
637 	csi->base = of_iomap(np, 0);
638 	if (!csi->base) {
639 		ret = -EIO;
640 		goto freedev;
641 	}
642 
643 	ret = csic_prs_set_base_addr(csi->id, (unsigned long)csi->base);
644 	if (ret < 0)
645 		goto unmap;
646 
647 	mutex_init(&csi->reset_lock);
648 	__csi_init_subdev(csi);
649 
650 	platform_set_drvdata(pdev, csi);
651 	glb_parser[csi->id] = csi;
652 
653 	vin_log(VIN_LOG_CSI, "csi%d probe end!\n", csi->id);
654 
655 	return 0;
656 
657 unmap:
658 	iounmap(csi->base);
659 freedev:
660 	kfree(csi);
661 ekzalloc:
662 	vin_log(VIN_LOG_CSI, "csi probe err!\n");
663 	return ret;
664 }
665 
csi_remove(struct platform_device * pdev)666 static int csi_remove(struct platform_device *pdev)
667 {
668 	struct csi_dev *csi = platform_get_drvdata(pdev);
669 	struct v4l2_subdev *sd = &csi->subdev;
670 
671 	platform_set_drvdata(pdev, NULL);
672 	v4l2_set_subdevdata(sd, NULL);
673 	__csi_pin_release(csi);
674 	mutex_destroy(&csi->subdev_lock);
675 	if (csi->base)
676 		iounmap(csi->base);
677 	mutex_destroy(&csi->reset_lock);
678 	media_entity_cleanup(&csi->subdev.entity);
679 	kfree(csi);
680 	return 0;
681 }
682 
683 static const struct of_device_id sunxi_csi_match[] = {
684 	{.compatible = "allwinner,sunxi-csi",},
685 	{},
686 };
687 
688 static struct platform_driver csi_platform_driver = {
689 	.probe = csi_probe,
690 	.remove = csi_remove,
691 	.driver = {
692 		   .name = CSI_MODULE_NAME,
693 		   .owner = THIS_MODULE,
694 		   .of_match_table = sunxi_csi_match,
695 		   },
696 };
697 
sunxi_csi_subdev_s_parm(struct v4l2_subdev * sd,struct v4l2_streamparm * param)698 int sunxi_csi_subdev_s_parm(struct v4l2_subdev *sd,
699 				   struct v4l2_streamparm *param)
700 {
701 	struct csi_dev *csi = v4l2_get_subdevdata(sd);
702 
703 	csi->capture_mode = param->parm.capture.capturemode;
704 	return 0;
705 }
706 
sunxi_csi_get_subdev(int id)707 struct v4l2_subdev *sunxi_csi_get_subdev(int id)
708 {
709 	if (id < VIN_MAX_CSI && glb_parser[id])
710 		return &glb_parser[id]->subdev;
711 	else
712 		return NULL;
713 }
714 
sunxi_csi_platform_register(void)715 int sunxi_csi_platform_register(void)
716 {
717 	return platform_driver_register(&csi_platform_driver);
718 }
719 
sunxi_csi_platform_unregister(void)720 void sunxi_csi_platform_unregister(void)
721 {
722 	platform_driver_unregister(&csi_platform_driver);
723 	vin_log(VIN_LOG_CSI, "csi_exit end\n");
724 }
725