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