• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /*
3  * mipi subdev driver module
4  *
5  * Copyright (c) 2017 by Allwinnertech Co., Ltd.  http://www.allwinnertech.com
6  *
7  * Authors:  Zhao Wei <zhaowei@allwinnertech.com>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License version 2 as
11  * published by the Free Software Foundation.
12  */
13 
14 #include <linux/platform_device.h>
15 #include <linux/kernel.h>
16 #include <linux/module.h>
17 #include <linux/delay.h>
18 #include <media/v4l2-device.h>
19 #include <media/v4l2-mediabus.h>
20 #include <media/v4l2-subdev.h>
21 #include "bsp_mipi_csi.h"
22 #include "combo_rx/combo_rx_reg.h"
23 #include "combo_rx/combo_rx_reg_i.h"
24 #include "combo_csi/combo_csi_reg.h"
25 #include "sunxi_mipi.h"
26 #include "../platform/platform_cfg.h"
27 #define MIPI_MODULE_NAME "vin_mipi"
28 
29 #define IS_FLAG(x, y) (((x)&(y)) == y)
30 
31 struct mipi_dev *glb_mipi[VIN_MAX_MIPI];
32 
mipi_set_st_time(int id,unsigned int time)33 static void mipi_set_st_time(int id, unsigned int time)
34 {
35 	struct mipi_dev *mipi;
36 
37 	if (id >= VIN_MAX_MIPI) {
38 		vin_print("mipi id error,set it less than %d\n", VIN_MAX_MIPI);
39 		return;
40 	}
41 
42 	vin_print("Set mipi%d settle time as 0x%x\n", id, time);
43 	mipi = glb_mipi[id];
44 	if (mipi) {
45 		mipi->settle_time = time;
46 		if (mipi->subdev.entity.stream_count > 0) {
47 #if defined CONFIG_ARCH_SUN8IW16P1
48 			cmb_rx_mipi_stl_time(mipi->id, time);
49 #elif defined CONFIG_ARCH_SUN50IW10
50 			cmb_phy0_s2p_dly(mipi->id, time);
51 #else
52 			mipi_dphy_cfg_1data(mipi->id, 0x75, time);
53 #endif
54 		}
55 	}
56 }
57 
mipi_settle_time_show(struct device * dev,struct device_attribute * attr,char * buf)58 static ssize_t mipi_settle_time_show(struct device *dev,
59 			struct device_attribute *attr, char *buf)
60 {
61 	struct mipi_dev *mipi;
62 	int i, cnt = 0;
63 
64 	for (i = 0; i < VIN_MAX_MIPI; i++) {
65 		mipi = glb_mipi[i];
66 		if (mipi)
67 			cnt += sprintf(buf + cnt, "mipi%d settle time = 0x%x\n",
68 										mipi->id, mipi->settle_time);
69 	}
70 	return cnt;
71 }
72 
mipi_settle_time_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)73 static ssize_t mipi_settle_time_store(struct device *dev,
74 		struct device_attribute *attr, const char *buf, size_t count)
75 {
76 	unsigned long val;
77 	int mipi_id;
78 
79 	val = simple_strtoul(buf, NULL, 16);
80 	mipi_id = val >> 8;
81 	mipi_set_st_time(mipi_id, val & 0xff);
82 	return count;
83 }
84 
85 static DEVICE_ATTR(settle_time, S_IRUGO | S_IWUSR | S_IWGRP,
86 		   mipi_settle_time_show, mipi_settle_time_store);
87 
88 static struct combo_format sunxi_mipi_formats[] = {
89 	{
90 		.code = MEDIA_BUS_FMT_SBGGR8_1X8,
91 		.bit_width = RAW8,
92 	}, {
93 		.code = MEDIA_BUS_FMT_SGBRG8_1X8,
94 		.bit_width = RAW8,
95 	}, {
96 		.code = MEDIA_BUS_FMT_SGRBG8_1X8,
97 		.bit_width = RAW8,
98 	}, {
99 		.code = MEDIA_BUS_FMT_SRGGB8_1X8,
100 		.bit_width = RAW8,
101 	}, {
102 		.code = MEDIA_BUS_FMT_SBGGR10_1X10,
103 		.bit_width = RAW10,
104 	}, {
105 		.code = MEDIA_BUS_FMT_SGBRG10_1X10,
106 		.bit_width = RAW10,
107 	}, {
108 		.code = MEDIA_BUS_FMT_SGRBG10_1X10,
109 		.bit_width = RAW10,
110 	}, {
111 		.code = MEDIA_BUS_FMT_SRGGB10_1X10,
112 		.bit_width = RAW10,
113 	}, {
114 		.code = MEDIA_BUS_FMT_SBGGR12_1X12,
115 		.bit_width = RAW12,
116 	}, {
117 		.code = MEDIA_BUS_FMT_SGBRG12_1X12,
118 		.bit_width = RAW12,
119 	}, {
120 		.code = MEDIA_BUS_FMT_SGRBG12_1X12,
121 		.bit_width = RAW12,
122 	}, {
123 		.code = MEDIA_BUS_FMT_SRGGB12_1X12,
124 		.bit_width = RAW12,
125 	}, {
126 		.code = MEDIA_BUS_FMT_UYVY8_2X8,
127 		.bit_width = YUV8,
128 		.yuv_seq = UYVY,
129 	}, {
130 		.code = MEDIA_BUS_FMT_VYUY8_2X8,
131 		.bit_width = YUV8,
132 		.yuv_seq = VYUY,
133 	}, {
134 		.code = MEDIA_BUS_FMT_YUYV8_2X8,
135 		.bit_width = YUV8,
136 		.yuv_seq = YUYV,
137 	}, {
138 		.code = MEDIA_BUS_FMT_YVYU8_2X8,
139 		.bit_width = YUV8,
140 		.yuv_seq = YVYU,
141 	}, {
142 		.code = MEDIA_BUS_FMT_UYVY8_1X16,
143 		.bit_width = YUV8,
144 		.yuv_seq = UYVY,
145 	}, {
146 		.code = MEDIA_BUS_FMT_VYUY8_1X16,
147 		.bit_width = YUV8,
148 		.yuv_seq = VYUY,
149 	}, {
150 		.code = MEDIA_BUS_FMT_YUYV8_1X16,
151 		.bit_width = YUV8,
152 		.yuv_seq = YUYV,
153 	}, {
154 		.code = MEDIA_BUS_FMT_YVYU8_1X16,
155 		.bit_width = YUV8,
156 		.yuv_seq = YVYU,
157 	}, {
158 		.code = MEDIA_BUS_FMT_UYVY10_2X10,
159 		.bit_width = YUV10,
160 		.yuv_seq = UYVY,
161 	}, {
162 		.code = MEDIA_BUS_FMT_VYUY10_2X10,
163 		.bit_width = YUV10,
164 		.yuv_seq = VYUY,
165 	}, {
166 		.code = MEDIA_BUS_FMT_YUYV10_2X10,
167 		.bit_width = YUV10,
168 		.yuv_seq = YUYV,
169 	}, {
170 		.code = MEDIA_BUS_FMT_YVYU10_2X10,
171 		.bit_width = YUV10,
172 		.yuv_seq = YVYU,
173 	}
174 };
175 
get_pkt_fmt(u32 code)176 static enum pkt_fmt get_pkt_fmt(u32 code)
177 {
178 	switch (code) {
179 	case MEDIA_BUS_FMT_RGB565_2X8_BE:
180 		return MIPI_RGB565;
181 	case MEDIA_BUS_FMT_UYVY8_1X16:
182 	case MEDIA_BUS_FMT_VYUY8_1X16:
183 	case MEDIA_BUS_FMT_YUYV8_1X16:
184 	case MEDIA_BUS_FMT_YVYU8_1X16:
185 	case MEDIA_BUS_FMT_UYVY8_2X8:
186 	case MEDIA_BUS_FMT_VYUY8_2X8:
187 	case MEDIA_BUS_FMT_YUYV8_2X8:
188 	case MEDIA_BUS_FMT_YVYU8_2X8:
189 		return MIPI_YUV422;
190 	case MEDIA_BUS_FMT_UYVY10_2X10:
191 	case MEDIA_BUS_FMT_VYUY10_2X10:
192 	case MEDIA_BUS_FMT_YUYV10_2X10:
193 	case MEDIA_BUS_FMT_YVYU10_2X10:
194 		return MIPI_YUV422_10;
195 	case MEDIA_BUS_FMT_SBGGR8_1X8:
196 	case MEDIA_BUS_FMT_SGBRG8_1X8:
197 	case MEDIA_BUS_FMT_SGRBG8_1X8:
198 	case MEDIA_BUS_FMT_SRGGB8_1X8:
199 		return MIPI_RAW8;
200 	case MEDIA_BUS_FMT_SBGGR10_1X10:
201 	case MEDIA_BUS_FMT_SGBRG10_1X10:
202 	case MEDIA_BUS_FMT_SGRBG10_1X10:
203 	case MEDIA_BUS_FMT_SRGGB10_1X10:
204 		return MIPI_RAW10;
205 	case MEDIA_BUS_FMT_SBGGR12_1X12:
206 	case MEDIA_BUS_FMT_SGBRG12_1X12:
207 	case MEDIA_BUS_FMT_SGRBG12_1X12:
208 	case MEDIA_BUS_FMT_SRGGB12_1X12:
209 		return MIPI_RAW12;
210 	default:
211 		return MIPI_RAW8;
212 	}
213 }
214 
data_formats_type(u32 code)215 static unsigned int data_formats_type(u32 code)
216 {
217 	switch (code) {
218 	case MIPI_RAW8:
219 	case MIPI_RAW12:
220 		return RAW;
221 	case MIPI_YUV422:
222 	case MIPI_YUV422_10:
223 		return YUV;
224 	case MIPI_RGB565:
225 		return RGB;
226 	default:
227 		return RAW;
228 	}
229 }
230 
231 #if defined CONFIG_ARCH_SUN8IW16P1
combo_rx_mipi_init(struct v4l2_subdev * sd)232 void combo_rx_mipi_init(struct v4l2_subdev *sd)
233 {
234 	struct mipi_dev *mipi = v4l2_get_subdevdata(sd);
235 	struct mipi_ctr mipi_ctr;
236 	struct mipi_lane_map mipi_map;
237 
238 	memset(&mipi_ctr, 0, sizeof(mipi_ctr));
239 	mipi_ctr.mipi_lane_num = mipi->cmb_cfg.mipi_ln;
240 	mipi_ctr.mipi_msb_lsb_sel = 1;
241 
242 	if (mipi->cmb_mode == MIPI_NORMAL_MODE) {
243 		mipi_ctr.mipi_wdr_mode_sel = 0;
244 	} else if (mipi->cmb_mode == MIPI_VC_WDR_MODE) {
245 		mipi_ctr.mipi_wdr_mode_sel = 0;
246 		mipi_ctr.mipi_open_multi_ch = 1;
247 		mipi_ctr.mipi_ch0_height = mipi->format.height;
248 		mipi_ctr.mipi_ch1_height = mipi->format.height;
249 		mipi_ctr.mipi_ch2_height = mipi->format.height;
250 		mipi_ctr.mipi_ch3_height = mipi->format.height;
251 	} else if (mipi->cmb_mode == MIPI_DOL_WDR_MODE) {
252 		mipi_ctr.mipi_wdr_mode_sel = 2;
253 	}
254 
255 	mipi_map.mipi_lane0 = MIPI_IN_L0_USE_PAD_LANE0;
256 	mipi_map.mipi_lane1 = MIPI_IN_L1_USE_PAD_LANE1;
257 	mipi_map.mipi_lane2 = MIPI_IN_L2_USE_PAD_LANE2;
258 	mipi_map.mipi_lane3 = MIPI_IN_L3_USE_PAD_LANE3;
259 
260 	cmb_rx_mode_sel(mipi->id, D_PHY);
261 	cmb_rx_app_pixel_out(mipi->id, TWO_PIXEL);
262 	cmb_rx_mipi_stl_time(mipi->id, mipi->time_hs);
263 	cmb_rx_mipi_ctr(mipi->id, &mipi_ctr);
264 	cmb_rx_mipi_dphy_mapping(mipi->id, &mipi_map);
265 }
266 
combo_rx_sub_lvds_init(struct v4l2_subdev * sd)267 void combo_rx_sub_lvds_init(struct v4l2_subdev *sd)
268 {
269 	struct mipi_dev *mipi = v4l2_get_subdevdata(sd);
270 	struct lvds_ctr lvds_ctr;
271 
272 	memset(&lvds_ctr, 0, sizeof(lvds_ctr));
273 	lvds_ctr.lvds_bit_width = mipi->cmb_fmt->bit_width;
274 	lvds_ctr.lvds_lane_num = mipi->cmb_cfg.lvds_ln;
275 
276 	if (mipi->cmb_mode == LVDS_NORMAL_MODE) {
277 		lvds_ctr.lvds_line_code_mode = 1;
278 	} else if (mipi->cmb_mode == LVDS_4CODE_WDR_MODE) {
279 		lvds_ctr.lvds_line_code_mode = mipi->wdr_cfg.line_code_mode;
280 
281 		lvds_ctr.lvds_wdr_lbl_sel = 1;
282 		lvds_ctr.lvds_sync_code_line_cnt = mipi->wdr_cfg.line_cnt;
283 
284 		lvds_ctr.lvds_code_mask = mipi->wdr_cfg.code_mask;
285 		lvds_ctr.lvds_wdr_fid_mode_sel = mipi->wdr_cfg.wdr_fid_mode_sel;
286 		lvds_ctr.lvds_wdr_fid_map_en = mipi->wdr_cfg.wdr_fid_map_en;
287 		lvds_ctr.lvds_wdr_fid0_map_sel = mipi->wdr_cfg.wdr_fid0_map_sel;
288 		lvds_ctr.lvds_wdr_fid1_map_sel = mipi->wdr_cfg.wdr_fid1_map_sel;
289 		lvds_ctr.lvds_wdr_fid2_map_sel = mipi->wdr_cfg.wdr_fid2_map_sel;
290 		lvds_ctr.lvds_wdr_fid3_map_sel = mipi->wdr_cfg.wdr_fid3_map_sel;
291 
292 		lvds_ctr.lvds_wdr_en_multi_ch = mipi->wdr_cfg.wdr_en_multi_ch;
293 		lvds_ctr.lvds_wdr_ch0_height = mipi->wdr_cfg.wdr_ch0_height;
294 		lvds_ctr.lvds_wdr_ch1_height = mipi->wdr_cfg.wdr_ch1_height;
295 		lvds_ctr.lvds_wdr_ch2_height = mipi->wdr_cfg.wdr_ch2_height;
296 		lvds_ctr.lvds_wdr_ch3_height = mipi->wdr_cfg.wdr_ch3_height;
297 	} else if (mipi->cmb_mode == LVDS_5CODE_WDR_MODE) {
298 		lvds_ctr.lvds_line_code_mode = mipi->wdr_cfg.line_code_mode;
299 		lvds_ctr.lvds_wdr_lbl_sel = 2;
300 		lvds_ctr.lvds_sync_code_line_cnt = mipi->wdr_cfg.line_cnt;
301 
302 		lvds_ctr.lvds_code_mask = mipi->wdr_cfg.code_mask;
303 	}
304 
305 	cmb_rx_mode_sel(mipi->id, SUB_LVDS);
306 	cmb_rx_app_pixel_out(mipi->id, ONE_PIXEL);
307 	cmb_rx_lvds_ctr(mipi->id, &lvds_ctr);
308 	cmb_rx_lvds_mapping(mipi->id, &mipi->lvds_map);
309 	cmb_rx_lvds_sync_code(mipi->id, &mipi->sync_code);
310 }
311 
combo_rx_hispi_init(struct v4l2_subdev * sd)312 void combo_rx_hispi_init(struct v4l2_subdev *sd)
313 {
314 	struct mipi_dev *mipi = v4l2_get_subdevdata(sd);
315 	struct lvds_ctr lvds_ctr;
316 	struct hispi_ctr hispi_ctr;
317 
318 	memset(&hispi_ctr, 0, sizeof(hispi_ctr));
319 	memset(&lvds_ctr, 0, sizeof(lvds_ctr));
320 	lvds_ctr.lvds_bit_width = mipi->cmb_fmt->bit_width;
321 	lvds_ctr.lvds_lane_num = mipi->cmb_cfg.lvds_ln;
322 
323 	if (mipi->cmb_mode == HISPI_NORMAL_MODE) {
324 		lvds_ctr.lvds_line_code_mode = 0;
325 		lvds_ctr.lvds_pix_lsb = 1;
326 
327 		hispi_ctr.hispi_normal = 1;
328 		hispi_ctr.hispi_trans_mode = PACKETIZED_SP;
329 	} else if (mipi->cmb_mode == HISPI_WDR_MODE) {
330 		lvds_ctr.lvds_line_code_mode = mipi->wdr_cfg.line_code_mode;
331 
332 		lvds_ctr.lvds_wdr_lbl_sel = 1;
333 
334 		lvds_ctr.lvds_pix_lsb = mipi->wdr_cfg.pix_lsb;
335 		lvds_ctr.lvds_sync_code_line_cnt = mipi->wdr_cfg.line_cnt;
336 
337 		lvds_ctr.lvds_wdr_fid_mode_sel = mipi->wdr_cfg.wdr_fid_mode_sel;
338 		lvds_ctr.lvds_wdr_fid_map_en = mipi->wdr_cfg.wdr_fid_map_en;
339 		lvds_ctr.lvds_wdr_fid0_map_sel = mipi->wdr_cfg.wdr_fid0_map_sel;
340 		lvds_ctr.lvds_wdr_fid1_map_sel = mipi->wdr_cfg.wdr_fid1_map_sel;
341 		lvds_ctr.lvds_wdr_fid2_map_sel = mipi->wdr_cfg.wdr_fid2_map_sel;
342 		lvds_ctr.lvds_wdr_fid3_map_sel = mipi->wdr_cfg.wdr_fid3_map_sel;
343 
344 		hispi_ctr.hispi_normal = 1;
345 		hispi_ctr.hispi_trans_mode = PACKETIZED_SP;
346 		hispi_ctr.hispi_wdr_en = 1;
347 		hispi_ctr.hispi_wdr_sof_fild = mipi->wdr_cfg.wdr_sof_fild;
348 		hispi_ctr.hispi_wdr_eof_fild = mipi->wdr_cfg.wdr_eof_fild;
349 		hispi_ctr.hispi_code_mask = mipi->wdr_cfg.code_mask;
350 	}
351 
352 	cmb_rx_mode_sel(mipi->id, SUB_LVDS);
353 	cmb_rx_app_pixel_out(mipi->id, ONE_PIXEL);
354 	cmb_rx_lvds_ctr(mipi->id, &lvds_ctr);
355 	cmb_rx_lvds_mapping(mipi->id, &mipi->lvds_map);
356 	cmb_rx_lvds_sync_code(mipi->id, &mipi->sync_code);
357 
358 	cmb_rx_hispi_ctr(mipi->id, &hispi_ctr);
359 }
360 
combo_rx_init(struct v4l2_subdev * sd)361 void combo_rx_init(struct v4l2_subdev *sd)
362 {
363 	struct mipi_dev *mipi = v4l2_get_subdevdata(sd);
364 
365 	/*comnbo rx phya init*/
366 	cmb_rx_phya_config(mipi->id);
367 
368 	if (mipi->terminal_resistance) {
369 		vin_log(VIN_LOG_MIPI, "open combo terminal resitance!\n");
370 		cmb_rx_te_auto_disable(mipi->id, 1);
371 		cmb_rx_phya_a_d0_en(mipi->id, 1);
372 		cmb_rx_phya_b_d0_en(mipi->id, 1);
373 		cmb_rx_phya_c_d0_en(mipi->id, 1);
374 		cmb_rx_phya_a_d1_en(mipi->id, 1);
375 		cmb_rx_phya_b_d1_en(mipi->id, 1);
376 		cmb_rx_phya_c_d1_en(mipi->id, 1);
377 		cmb_rx_phya_a_d2_en(mipi->id, 1);
378 		cmb_rx_phya_b_d2_en(mipi->id, 1);
379 		cmb_rx_phya_c_d2_en(mipi->id, 1);
380 		cmb_rx_phya_a_d3_en(mipi->id, 1);
381 		cmb_rx_phya_b_d3_en(mipi->id, 1);
382 		cmb_rx_phya_c_d3_en(mipi->id, 1);
383 		cmb_rx_phya_a_ck_en(mipi->id, 1);
384 		cmb_rx_phya_b_ck_en(mipi->id, 1);
385 		cmb_rx_phya_c_ck_en(mipi->id, 1);
386 	}
387 	cmb_rx_phya_signal_dly_en(mipi->id, 1);
388 	cmb_rx_phya_offset(mipi->id, mipi->pyha_offset);
389 
390 	switch (mipi->if_type) {
391 	case V4L2_MBUS_PARALLEL:
392 	case V4L2_MBUS_BT656:
393 		cmb_rx_mode_sel(mipi->id, CMOS);
394 		cmb_rx_app_pixel_out(mipi->id, ONE_PIXEL);
395 		break;
396 	case V4L2_MBUS_CSI2:
397 		cmb_rx_phya_ck_mode(mipi->id, 0);
398 		combo_rx_mipi_init(sd);
399 		break;
400 	case V4L2_MBUS_SUBLVDS:
401 		cmb_rx_phya_ck_mode(mipi->id, 1);
402 		combo_rx_sub_lvds_init(sd);
403 		break;
404 	case V4L2_MBUS_HISPI:
405 		cmb_rx_phya_ck_mode(mipi->id, 0);
406 		combo_rx_hispi_init(sd);
407 		break;
408 	default:
409 		combo_rx_mipi_init(sd);
410 		break;
411 	}
412 
413 	cmb_rx_enable(mipi->id);
414 }
415 #elif defined CONFIG_ARCH_SUN50IW10
combo_csi_mipi_init(struct v4l2_subdev * sd)416 static void combo_csi_mipi_init(struct v4l2_subdev *sd)
417 {
418 	struct mipi_dev *mipi = v4l2_get_subdevdata(sd);
419 	int i;
420 
421 	mipi->cmb_csi_cfg.phy_lane_cfg.phy_laneck_en = CK_1LANE;
422 	mipi->cmb_csi_cfg.phy_lane_cfg.phy_mipi_lpck_en = LPCK_1LANE;
423 	mipi->cmb_csi_cfg.phy_lane_cfg.phy_termck_en = TERMCK_CLOSE;
424 	mipi->cmb_csi_cfg.phy_lane_cfg.phy_termdt_en = TERMDT_CLOSE;
425 	mipi->cmb_csi_cfg.phy_lane_cfg.phy_s2p_en = S2PDT_CLOSE;
426 	mipi->cmb_csi_cfg.phy_lane_cfg.phy_hsck_en = HSCK_CLOSE;
427 	mipi->cmb_csi_cfg.phy_lane_cfg.phy_hsdt_en = HSDT_CLOSE;
428 
429 	cmb_phy_lane_num_en(mipi->id, mipi->cmb_csi_cfg.phy_lane_cfg);
430 	cmb_phy0_work_mode(mipi->id, 0);
431 	cmb_phy0_ofscal_cfg(mipi->id);
432 	cmb_phy_deskew_en(mipi->id, mipi->cmb_csi_cfg.phy_lane_cfg);
433 	cmb_term_ctl(mipi->id, mipi->cmb_csi_cfg.phy_lane_cfg);
434 	cmb_hs_ctl(mipi->id, mipi->cmb_csi_cfg.phy_lane_cfg);
435 	cmb_s2p_ctl(mipi->id, mipi->time_hs, mipi->cmb_csi_cfg.phy_lane_cfg);
436 	cmb_mipirx_ctl(mipi->id, mipi->cmb_csi_cfg.phy_lane_cfg);
437 	cmb_phy0_en(mipi->id, 1);
438 
439 	for (i = 0; i < mipi->cmb_csi_cfg.lane_num; i++)
440 		mipi->cmb_csi_cfg.mipi_lane[i] = cmb_port_set_lane_map(mipi->id, i);
441 	for (i = 0; i < mipi->cmb_csi_cfg.total_rx_ch; i++) {
442 		if (mipi->cmb_csi_cfg.total_rx_ch > 3)
443 			mipi->cmb_csi_cfg.total_rx_ch = 3;
444 		mipi->cmb_csi_cfg.mipi_datatype[i] = get_pkt_fmt(mipi->format.code);
445 		mipi->cmb_csi_cfg.vc[i] = i;
446 	}
447 	cmb_port_lane_num(mipi->id, mipi->cmb_csi_cfg.lane_num);
448 	cmb_port_out_num(mipi->id, TWO_DATA);
449 	cmb_port_out_chnum(mipi->id, 0);
450 	cmb_port_lane_map(mipi->id, mipi->cmb_csi_cfg.mipi_lane);
451 	cmb_port_mipi_cfg(mipi->id, mipi->cmb_fmt->yuv_seq);
452 	cmb_port_set_mipi_datatype(mipi->id, &mipi->cmb_csi_cfg);
453 	cmb_port_mipi_ch_trigger_en(mipi->id, 1);
454 	if (mipi->cmb_mode == MIPI_DOL_WDR_MODE)
455 		cmb_port_set_mipi_wdr(mipi->id, 0, 2);
456 	cmb_port_enable(mipi->id);
457 }
458 
combo_csi_init(struct v4l2_subdev * sd)459 void combo_csi_init(struct v4l2_subdev *sd)
460 {
461 	struct mipi_dev *mipi = v4l2_get_subdevdata(sd);
462 
463 	switch (mipi->if_type) {
464 	case V4L2_MBUS_PARALLEL:
465 	case V4L2_MBUS_BT656:
466 		break;
467 	case V4L2_MBUS_CSI2_DPHY:
468 		combo_csi_mipi_init(sd);
469 		break;
470 	case V4L2_MBUS_CSI2_CPHY:
471 		break;
472 	case V4L2_MBUS_CSI1:
473 		break;
474 	case V4L2_MBUS_CCP2:
475 		break;
476 	case V4L2_MBUS_SUBLVDS:
477 		break;
478 	case V4L2_MBUS_HISPI:
479 		break;
480 	case V4L2_MBUS_UNKNOWN:
481 		break;
482 	default:
483 		break;
484 	}
485 }
486 #endif
487 
sunxi_mipi_subdev_s_stream(struct v4l2_subdev * sd,int enable)488 static int sunxi_mipi_subdev_s_stream(struct v4l2_subdev *sd, int enable)
489 {
490 	struct mipi_dev *mipi = v4l2_get_subdevdata(sd);
491 	struct v4l2_mbus_framefmt *mf = &mipi->format;
492 	struct mbus_framefmt_res *res = (void *)mf->reserved;
493 
494 	int i;
495 
496 	mipi->csi2_cfg.bps = res->res_mipi_bps;
497 	mipi->csi2_cfg.auto_check_bps = 0;
498 	mipi->csi2_cfg.dphy_freq = DPHY_CLK;
499 
500 	for (i = 0; i < mipi->csi2_cfg.total_rx_ch; i++) {
501 		mipi->csi2_fmt.packet_fmt[i] = get_pkt_fmt(mf->code);
502 		mipi->csi2_fmt.field[i] = mf->field;
503 		mipi->csi2_fmt.vc[i] = i;
504 	}
505 
506 	mipi->csi2_fmt.fmt_type = data_formats_type(get_pkt_fmt(mf->code));
507 	mipi->cmb_mode = res->res_combo_mode & 0xf;
508 	mipi->terminal_resistance = res->res_combo_mode & CMB_TERMINAL_RES;
509 	mipi->pyha_offset = (res->res_combo_mode & 0x70) >> 4;
510 	if (mipi->settle_time > 0) {
511 		mipi->time_hs = mipi->settle_time;
512 	} else if (res->res_time_hs)
513 		mipi->time_hs = res->res_time_hs;
514 	else {
515 #if defined CONFIG_ARCH_SUN8IW16P1
516 		mipi->time_hs = 0x30;
517 #else
518 		mipi->time_hs = 0x28;
519 #endif
520 	}
521 
522 	if (enable) {
523 #if defined CONFIG_ARCH_SUN8IW16P1
524 		combo_rx_init(sd);
525 #elif defined CONFIG_ARCH_SUN50IW10
526 		combo_csi_init(sd);
527 #else
528 		bsp_mipi_csi_dphy_init(mipi->id);
529 		mipi_dphy_cfg_1data(mipi->id, 0x75,
530 			mipi->settle_time ? mipi->settle_time : 0xa0);
531 		bsp_mipi_csi_set_para(mipi->id, &mipi->csi2_cfg);
532 		bsp_mipi_csi_set_fmt(mipi->id, mipi->csi2_cfg.total_rx_ch,
533 				     &mipi->csi2_fmt);
534 		if (mipi->cmb_mode == MIPI_DOL_WDR_MODE)
535 			bsp_mipi_csi_set_dol(mipi->id, 0, 2);
536 		/*for dphy clock async*/
537 		bsp_mipi_csi_dphy_disable(mipi->id, mipi->sensor_flags);
538 		bsp_mipi_csi_dphy_enable(mipi->id, mipi->sensor_flags);
539 		bsp_mipi_csi_protocol_enable(mipi->id);
540 #endif
541 	} else {
542 #if defined CONFIG_ARCH_SUN8IW16P1
543 		cmb_rx_disable(mipi->id);
544 #elif defined CONFIG_ARCH_SUN50IW10
545 		cmb_port_disable(mipi->id);
546 		cmb_phy0_en(mipi->id, 0);
547 #else
548 		bsp_mipi_csi_dphy_disable(mipi->id, mipi->sensor_flags);
549 		bsp_mipi_csi_protocol_disable(mipi->id);
550 		bsp_mipi_csi_dphy_exit(mipi->id);
551 #endif
552 	}
553 
554 	vin_log(VIN_LOG_FMT, "%s%d %s, lane_num %d, code: %x field: %d\n",
555 		mipi->if_name, mipi->id, enable ? "stream on" : "stream off",
556 		mipi->cmb_cfg.lane_num, mf->code, mf->field);
557 
558 	return 0;
559 }
560 
sunxi_mipi_subdev_get_fmt(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_format * fmt)561 static int sunxi_mipi_subdev_get_fmt(struct v4l2_subdev *sd,
562 				     struct v4l2_subdev_pad_config *cfg,
563 				     struct v4l2_subdev_format *fmt)
564 {
565 	struct mipi_dev *mipi = v4l2_get_subdevdata(sd);
566 	struct v4l2_mbus_framefmt *mf;
567 
568 	mf = &mipi->format;
569 	if (!mf)
570 		return -EINVAL;
571 
572 	mutex_lock(&mipi->subdev_lock);
573 	fmt->format = *mf;
574 	mutex_unlock(&mipi->subdev_lock);
575 	return 0;
576 }
577 
__mipi_try_format(struct v4l2_mbus_framefmt * mf)578 static struct combo_format *__mipi_try_format(struct v4l2_mbus_framefmt *mf)
579 {
580 	struct combo_format *mipi_fmt = NULL;
581 	int i;
582 
583 	for (i = 0; i < ARRAY_SIZE(sunxi_mipi_formats); i++)
584 		if (mf->code == sunxi_mipi_formats[i].code)
585 			mipi_fmt = &sunxi_mipi_formats[i];
586 
587 	if (mipi_fmt == NULL)
588 		mipi_fmt = &sunxi_mipi_formats[0];
589 
590 	mf->code = mipi_fmt->code;
591 
592 	return mipi_fmt;
593 }
594 
sunxi_mipi_subdev_set_fmt(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_format * fmt)595 static int sunxi_mipi_subdev_set_fmt(struct v4l2_subdev *sd,
596 				     struct v4l2_subdev_pad_config *cfg,
597 				     struct v4l2_subdev_format *fmt)
598 {
599 	struct mipi_dev *mipi = v4l2_get_subdevdata(sd);
600 	struct v4l2_mbus_framefmt *mf;
601 	struct combo_format *mipi_fmt;
602 
603 	vin_log(VIN_LOG_FMT, "%s %d*%d %x %d\n", __func__,
604 		fmt->format.width, fmt->format.height,
605 		fmt->format.code, fmt->format.field);
606 
607 	mf = &mipi->format;
608 
609 	if (fmt->pad == MIPI_PAD_SOURCE) {
610 		if (mf) {
611 			mutex_lock(&mipi->subdev_lock);
612 			fmt->format = *mf;
613 			mutex_unlock(&mipi->subdev_lock);
614 		}
615 		return 0;
616 	}
617 
618 	mipi_fmt = __mipi_try_format(&fmt->format);
619 	if (mf) {
620 		mutex_lock(&mipi->subdev_lock);
621 		*mf = fmt->format;
622 		if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
623 			mipi->cmb_fmt = mipi_fmt;
624 		mutex_unlock(&mipi->subdev_lock);
625 	}
626 
627 	return 0;
628 }
629 
sunxi_mipi_s_mbus_config(struct v4l2_subdev * sd,unsigned int pad,struct v4l2_mbus_config * cfg)630 static int sunxi_mipi_s_mbus_config(struct v4l2_subdev *sd, unsigned int pad,
631 				    struct v4l2_mbus_config *cfg)
632 {
633 	struct mipi_dev *mipi = v4l2_get_subdevdata(sd);
634 
635 	if (cfg->type == V4L2_MBUS_CSI2_DPHY) {
636 		mipi->if_type = V4L2_MBUS_CSI2_DPHY;
637 		memcpy(mipi->if_name, "mipi_dphy", sizeof("mipi_dphy"));
638 		if (IS_FLAG(cfg->flags, V4L2_MBUS_CSI2_4_LANE)) {
639 			mipi->csi2_cfg.lane_num = 4;
640 			mipi->cmb_cfg.lane_num = 4;
641 			mipi->cmb_cfg.mipi_ln = MIPI_4LANE;
642 			mipi->cmb_csi_cfg.phy_lane_cfg.phy_lanedt_en = DT_4LANE;
643 			mipi->cmb_csi_cfg.phy_lane_cfg.phy_mipi_lpdt_en = LPDT_4LANE;
644 			mipi->cmb_csi_cfg.lane_num = 4;
645 		} else if (IS_FLAG(cfg->flags, V4L2_MBUS_CSI2_3_LANE)) {
646 			mipi->csi2_cfg.lane_num = 3;
647 			mipi->cmb_cfg.lane_num = 3;
648 			mipi->cmb_cfg.mipi_ln = MIPI_3LANE;
649 			mipi->cmb_csi_cfg.phy_lane_cfg.phy_lanedt_en = DT_3LANE;
650 			mipi->cmb_csi_cfg.phy_lane_cfg.phy_mipi_lpdt_en = LPDT_3LANE;
651 			mipi->cmb_csi_cfg.lane_num = 3;
652 		} else if (IS_FLAG(cfg->flags, V4L2_MBUS_CSI2_2_LANE)) {
653 			mipi->csi2_cfg.lane_num = 2;
654 			mipi->cmb_cfg.lane_num = 2;
655 			mipi->cmb_cfg.mipi_ln = MIPI_2LANE;
656 			mipi->cmb_csi_cfg.phy_lane_cfg.phy_lanedt_en = DT_2LANE;
657 			mipi->cmb_csi_cfg.phy_lane_cfg.phy_mipi_lpdt_en = LPDT_2LANE;
658 			mipi->cmb_csi_cfg.lane_num = 2;
659 		} else {
660 			mipi->cmb_cfg.lane_num = 1;
661 			mipi->csi2_cfg.lane_num = 1;
662 			mipi->cmb_cfg.mipi_ln = MIPI_1LANE;
663 			mipi->cmb_csi_cfg.phy_lane_cfg.phy_lanedt_en = DT_1LANE;
664 			mipi->cmb_csi_cfg.phy_lane_cfg.phy_mipi_lpdt_en = LPDT_1LANE;
665 			mipi->cmb_csi_cfg.lane_num = 1;
666 		}
667 	}  else if (cfg->type == V4L2_MBUS_HISPI) {
668 			mipi->if_type = V4L2_MBUS_CSI2_CPHY;
669 			memcpy(mipi->if_name, "mipi_cphy", sizeof("mipi_cphy"));
670 
671 	} else if (cfg->type == V4L2_MBUS_SUBLVDS) {
672 		mipi->if_type = V4L2_MBUS_SUBLVDS;
673 		memcpy(mipi->if_name, "sublvds", sizeof("sublvds"));
674 		if (IS_FLAG(cfg->flags, V4L2_MBUS_SUBLVDS_12_LANE)) {
675 			mipi->cmb_cfg.lane_num = 12;
676 			mipi->cmb_cfg.lvds_ln = LVDS_12LANE;
677 		} else if (IS_FLAG(cfg->flags, V4L2_MBUS_SUBLVDS_10_LANE)) {
678 			mipi->cmb_cfg.lane_num = 10;
679 			mipi->cmb_cfg.lvds_ln = LVDS_10LANE;
680 		} else if (IS_FLAG(cfg->flags, V4L2_MBUS_SUBLVDS_8_LANE)) {
681 			mipi->cmb_cfg.lane_num = 8;
682 			mipi->cmb_cfg.lvds_ln = LVDS_8LANE;
683 		} else if (IS_FLAG(cfg->flags, V4L2_MBUS_SUBLVDS_4_LANE)) {
684 			mipi->cmb_cfg.lane_num = 4;
685 			mipi->cmb_cfg.lvds_ln = LVDS_4LANE;
686 		} else if (IS_FLAG(cfg->flags, V4L2_MBUS_SUBLVDS_2_LANE)) {
687 			mipi->cmb_cfg.lane_num = 2;
688 			mipi->cmb_cfg.lvds_ln = LVDS_2LANE;
689 		} else {
690 			mipi->cmb_cfg.lane_num = 8;
691 			mipi->cmb_cfg.lvds_ln = LVDS_8LANE;
692 		}
693 	} else if (cfg->type == V4L2_MBUS_HISPI) {
694 		mipi->if_type = V4L2_MBUS_HISPI;
695 		memcpy(mipi->if_name, "hispi", sizeof("hispi"));
696 		if (IS_FLAG(cfg->flags, V4L2_MBUS_SUBLVDS_12_LANE)) {
697 			mipi->cmb_cfg.lane_num = 12;
698 			mipi->cmb_cfg.lvds_ln = LVDS_12LANE;
699 		} else if (IS_FLAG(cfg->flags, V4L2_MBUS_SUBLVDS_10_LANE)) {
700 			mipi->cmb_cfg.lane_num = 10;
701 			mipi->cmb_cfg.lvds_ln = LVDS_10LANE;
702 		} else if (IS_FLAG(cfg->flags, V4L2_MBUS_SUBLVDS_8_LANE)) {
703 			mipi->cmb_cfg.lane_num = 8;
704 			mipi->cmb_cfg.lvds_ln = LVDS_8LANE;
705 		} else if (IS_FLAG(cfg->flags, V4L2_MBUS_SUBLVDS_4_LANE)) {
706 			mipi->cmb_cfg.lane_num = 4;
707 			mipi->cmb_cfg.lvds_ln = LVDS_4LANE;
708 		} else if (IS_FLAG(cfg->flags, V4L2_MBUS_SUBLVDS_2_LANE)) {
709 			mipi->cmb_cfg.lane_num = 2;
710 			mipi->cmb_cfg.lvds_ln = LVDS_2LANE;
711 		} else {
712 			mipi->cmb_cfg.lane_num = 4;
713 			mipi->cmb_cfg.lvds_ln = LVDS_4LANE;
714 		}
715 	}  else if (cfg->type == V4L2_MBUS_CCP2) {
716 			mipi->if_type = V4L2_MBUS_CCP2;
717 			memcpy(mipi->if_name, "ccp2", sizeof("ccp2"));
718 
719 	} else if (cfg->type == V4L2_MBUS_CSI1) {
720 			mipi->if_type = V4L2_MBUS_CSI1;
721 			memcpy(mipi->if_name, "mipi_csi1", sizeof("mipi_csi1"));
722 
723 	} else if (cfg->type == V4L2_MBUS_PARALLEL) {
724 			mipi->if_type = V4L2_MBUS_PARALLEL;
725 			memcpy(mipi->if_name, "combo_parallel", sizeof("combo_parallel"));
726 
727 	} else {
728 			memcpy(mipi->if_name, "combo_unknown", sizeof("combo_unknown"));
729 			mipi->if_type = V4L2_MBUS_UNKNOWN;
730 	}
731 
732 	mipi->csi2_cfg.total_rx_ch = 0;
733 	mipi->cmb_csi_cfg.total_rx_ch = 0;
734 	if (IS_FLAG(cfg->flags, V4L2_MBUS_CSI2_CHANNEL_0)) {
735 		mipi->csi2_cfg.total_rx_ch++;
736 		mipi->cmb_csi_cfg.total_rx_ch++;
737 	}
738 	if (IS_FLAG(cfg->flags, V4L2_MBUS_CSI2_CHANNEL_1)) {
739 		mipi->csi2_cfg.total_rx_ch++;
740 		mipi->cmb_csi_cfg.total_rx_ch++;
741 	}
742 	if (IS_FLAG(cfg->flags, V4L2_MBUS_CSI2_CHANNEL_2)) {
743 		mipi->csi2_cfg.total_rx_ch++;
744 		mipi->cmb_csi_cfg.total_rx_ch++;
745 	}
746 	if (IS_FLAG(cfg->flags, V4L2_MBUS_CSI2_CHANNEL_3)) {
747 		mipi->csi2_cfg.total_rx_ch++;
748 		mipi->cmb_csi_cfg.total_rx_ch++;
749 	}
750 
751 	return 0;
752 }
753 
754 static const struct v4l2_subdev_video_ops sunxi_mipi_subdev_video_ops = {
755 	.s_stream = sunxi_mipi_subdev_s_stream,
756 };
757 
758 static const struct v4l2_subdev_pad_ops sunxi_mipi_subdev_pad_ops = {
759 	.get_fmt = sunxi_mipi_subdev_get_fmt,
760 	.set_fmt = sunxi_mipi_subdev_set_fmt,
761 	.set_mbus_config = sunxi_mipi_s_mbus_config,
762 };
763 
764 static struct v4l2_subdev_ops sunxi_mipi_subdev_ops = {
765 	.video = &sunxi_mipi_subdev_video_ops,
766 	.pad = &sunxi_mipi_subdev_pad_ops,
767 };
768 
__mipi_init_subdev(struct mipi_dev * mipi)769 static int __mipi_init_subdev(struct mipi_dev *mipi)
770 {
771 	struct v4l2_subdev *sd = &mipi->subdev;
772 	int ret;
773 
774 	mutex_init(&mipi->subdev_lock);
775 	v4l2_subdev_init(sd, &sunxi_mipi_subdev_ops);
776 	sd->grp_id = VIN_GRP_ID_MIPI;
777 	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
778 	snprintf(sd->name, sizeof(sd->name), "sunxi_mipi.%u", mipi->id);
779 	v4l2_set_subdevdata(sd, mipi);
780 
781 	/*sd->entity->ops = &isp_media_ops;*/
782 	mipi->mipi_pads[MIPI_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
783 	mipi->mipi_pads[MIPI_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
784 	sd->entity.function = MEDIA_ENT_F_IO_V4L;
785 
786 	ret = media_entity_pads_init(&sd->entity, MIPI_PAD_NUM, mipi->mipi_pads);
787 	if (ret < 0)
788 		return ret;
789 
790 	return 0;
791 }
792 
mipi_probe(struct platform_device * pdev)793 static int mipi_probe(struct platform_device *pdev)
794 {
795 	struct device_node *np = pdev->dev.of_node;
796 	struct mipi_dev *mipi = NULL;
797 	int ret = 0;
798 
799 	if (np == NULL) {
800 		vin_err("MIPI failed to get of node\n");
801 		return -ENODEV;
802 	}
803 
804 	mipi = kzalloc(sizeof(struct mipi_dev), GFP_KERNEL);
805 	if (!mipi) {
806 		ret = -ENOMEM;
807 		goto ekzalloc;
808 	}
809 
810 	of_property_read_u32(np, "device_id", &pdev->id);
811 	if (pdev->id < 0) {
812 		vin_err("MIPI failed to get device id\n");
813 		ret = -EINVAL;
814 		goto freedev;
815 	}
816 
817 	mipi->base = of_iomap(np, 0);
818 	if (!mipi->base) {
819 		ret = -EIO;
820 		goto freedev;
821 	}
822 	mipi->id = pdev->id;
823 	mipi->pdev = pdev;
824 
825 #if defined CONFIG_ARCH_SUN8IW16P1
826 	cmb_rx_set_base_addr(mipi->id, (unsigned long)mipi->base);
827 #elif defined CONFIG_ARCH_SUN50IW10
828 	cmb_csi_set_phy_base_addr(mipi->id, (unsigned long)mipi->base);
829 	mipi->port_base = of_iomap(np, 1);
830 	if (!mipi->port_base) {
831 		ret = -EIO;
832 		goto freedev;
833 	}
834 	cmb_csi_set_port_base_addr(mipi->id, (unsigned long)mipi->port_base);
835 #else
836 	bsp_mipi_csi_set_base_addr(mipi->id, (unsigned long)mipi->base);
837 	bsp_mipi_dphy_set_base_addr(mipi->id, (unsigned long)mipi->base + 0x1000);
838 #endif
839 
840 	ret = __mipi_init_subdev(mipi);
841 	if (ret < 0) {
842 		vin_err("mipi init error!\n");
843 		goto unmap;
844 	}
845 
846 	platform_set_drvdata(pdev, mipi);
847 	glb_mipi[mipi->id] = mipi;
848 	ret = device_create_file(&pdev->dev, &dev_attr_settle_time);
849 	if (ret) {
850 		vin_err("mipi settle time node register fail\n");
851 		return ret;
852 	}
853 	vin_log(VIN_LOG_MIPI, "mipi%d probe end!\n", mipi->id);
854 	return 0;
855 
856 unmap:
857 	iounmap(mipi->base);
858 freedev:
859 	kfree(mipi);
860 ekzalloc:
861 	vin_err("mipi probe err!\n");
862 	return ret;
863 }
864 
mipi_remove(struct platform_device * pdev)865 static int mipi_remove(struct platform_device *pdev)
866 {
867 	struct mipi_dev *mipi = platform_get_drvdata(pdev);
868 	struct v4l2_subdev *sd = &mipi->subdev;
869 
870 	platform_set_drvdata(pdev, NULL);
871 	v4l2_set_subdevdata(sd, NULL);
872 	if (mipi->base)
873 		iounmap(mipi->base);
874 	media_entity_cleanup(&mipi->subdev.entity);
875 	kfree(mipi);
876 	return 0;
877 }
878 
879 static const struct of_device_id sunxi_mipi_match[] = {
880 	{.compatible = "allwinner,sunxi-mipi",},
881 	{},
882 };
883 
884 static struct platform_driver mipi_platform_driver = {
885 	.probe = mipi_probe,
886 	.remove = mipi_remove,
887 	.driver = {
888 		.name = MIPI_MODULE_NAME,
889 		.owner = THIS_MODULE,
890 		.of_match_table = sunxi_mipi_match,
891 	}
892 };
893 
sunxi_combo_set_sync_code(struct v4l2_subdev * sd,struct combo_sync_code * sync)894 void sunxi_combo_set_sync_code(struct v4l2_subdev *sd,
895 		struct combo_sync_code *sync)
896 {
897 	struct mipi_dev *combo = v4l2_get_subdevdata(sd);
898 
899 	memset(&combo->sync_code, 0, sizeof(combo->sync_code));
900 	combo->sync_code = *sync;
901 }
902 
sunxi_combo_set_lane_map(struct v4l2_subdev * sd,struct combo_lane_map * map)903 void sunxi_combo_set_lane_map(struct v4l2_subdev *sd,
904 		struct combo_lane_map *map)
905 {
906 	struct mipi_dev *combo = v4l2_get_subdevdata(sd);
907 
908 	memset(&combo->lvds_map, 0, sizeof(combo->lvds_map));
909 	combo->lvds_map = *map;
910 }
911 
sunxi_combo_wdr_config(struct v4l2_subdev * sd,struct combo_wdr_cfg * wdr)912 void sunxi_combo_wdr_config(struct v4l2_subdev *sd,
913 		struct combo_wdr_cfg *wdr)
914 {
915 	struct mipi_dev *combo = v4l2_get_subdevdata(sd);
916 
917 	memset(&combo->wdr_cfg, 0, sizeof(combo->wdr_cfg));
918 	combo->wdr_cfg = *wdr;
919 }
920 
sunxi_mipi_get_subdev(int id)921 struct v4l2_subdev *sunxi_mipi_get_subdev(int id)
922 {
923 	if (id < VIN_MAX_MIPI && glb_mipi[id])
924 		return &glb_mipi[id]->subdev;
925 	else
926 		return NULL;
927 }
928 
sunxi_mipi_platform_register(void)929 int sunxi_mipi_platform_register(void)
930 {
931 	return platform_driver_register(&mipi_platform_driver);
932 }
933 
sunxi_mipi_platform_unregister(void)934 void sunxi_mipi_platform_unregister(void)
935 {
936 	platform_driver_unregister(&mipi_platform_driver);
937 	vin_log(VIN_LOG_MIPI, "mipi_exit end\n");
938 }
939