1 /*
2  * soc-camera media bus helper routines
3  *
4  * Copyright (C) 2009, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  */
10 
11 #include <linux/kernel.h>
12 #include <linux/module.h>
13 
14 #include <media/v4l2-device.h>
15 #include <media/v4l2-mediabus.h>
16 #include <media/soc_mediabus.h>
17 
18 static const struct soc_mbus_lookup mbus_fmt[] = {
19 {
20 	.code = V4L2_MBUS_FMT_YUYV8_2X8,
21 	.fmt = {
22 		.fourcc			= V4L2_PIX_FMT_YUYV,
23 		.name			= "YUYV",
24 		.bits_per_sample	= 8,
25 		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
26 		.order			= SOC_MBUS_ORDER_LE,
27 	},
28 }, {
29 	.code = V4L2_MBUS_FMT_YVYU8_2X8,
30 	.fmt = {
31 		.fourcc			= V4L2_PIX_FMT_YVYU,
32 		.name			= "YVYU",
33 		.bits_per_sample	= 8,
34 		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
35 		.order			= SOC_MBUS_ORDER_LE,
36 	},
37 }, {
38 	.code = V4L2_MBUS_FMT_UYVY8_2X8,
39 	.fmt = {
40 		.fourcc			= V4L2_PIX_FMT_UYVY,
41 		.name			= "UYVY",
42 		.bits_per_sample	= 8,
43 		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
44 		.order			= SOC_MBUS_ORDER_LE,
45 	},
46 }, {
47 	.code = V4L2_MBUS_FMT_VYUY8_2X8,
48 	.fmt = {
49 		.fourcc			= V4L2_PIX_FMT_VYUY,
50 		.name			= "VYUY",
51 		.bits_per_sample	= 8,
52 		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
53 		.order			= SOC_MBUS_ORDER_LE,
54 	},
55 }, {
56 	.code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
57 	.fmt = {
58 		.fourcc			= V4L2_PIX_FMT_RGB555,
59 		.name			= "RGB555",
60 		.bits_per_sample	= 8,
61 		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
62 		.order			= SOC_MBUS_ORDER_LE,
63 	},
64 }, {
65 	.code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE,
66 	.fmt = {
67 		.fourcc			= V4L2_PIX_FMT_RGB555X,
68 		.name			= "RGB555X",
69 		.bits_per_sample	= 8,
70 		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
71 		.order			= SOC_MBUS_ORDER_LE,
72 	},
73 }, {
74 	.code = V4L2_MBUS_FMT_RGB565_2X8_LE,
75 	.fmt = {
76 		.fourcc			= V4L2_PIX_FMT_RGB565,
77 		.name			= "RGB565",
78 		.bits_per_sample	= 8,
79 		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
80 		.order			= SOC_MBUS_ORDER_LE,
81 	},
82 }, {
83 	.code = V4L2_MBUS_FMT_RGB565_2X8_BE,
84 	.fmt = {
85 		.fourcc			= V4L2_PIX_FMT_RGB565X,
86 		.name			= "RGB565X",
87 		.bits_per_sample	= 8,
88 		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
89 		.order			= SOC_MBUS_ORDER_LE,
90 	},
91 }, {
92 	.code = V4L2_MBUS_FMT_SBGGR8_1X8,
93 	.fmt = {
94 		.fourcc			= V4L2_PIX_FMT_SBGGR8,
95 		.name			= "Bayer 8 BGGR",
96 		.bits_per_sample	= 8,
97 		.packing		= SOC_MBUS_PACKING_NONE,
98 		.order			= SOC_MBUS_ORDER_LE,
99 	},
100 }, {
101 	.code = V4L2_MBUS_FMT_SBGGR10_1X10,
102 	.fmt = {
103 		.fourcc			= V4L2_PIX_FMT_SBGGR10,
104 		.name			= "Bayer 10 BGGR",
105 		.bits_per_sample	= 10,
106 		.packing		= SOC_MBUS_PACKING_EXTEND16,
107 		.order			= SOC_MBUS_ORDER_LE,
108 	},
109 }, {
110 	.code = V4L2_MBUS_FMT_Y8_1X8,
111 	.fmt = {
112 		.fourcc			= V4L2_PIX_FMT_GREY,
113 		.name			= "Grey",
114 		.bits_per_sample	= 8,
115 		.packing		= SOC_MBUS_PACKING_NONE,
116 		.order			= SOC_MBUS_ORDER_LE,
117 	},
118 }, {
119 	.code = V4L2_MBUS_FMT_Y10_1X10,
120 	.fmt = {
121 		.fourcc			= V4L2_PIX_FMT_Y10,
122 		.name			= "Grey 10bit",
123 		.bits_per_sample	= 10,
124 		.packing		= SOC_MBUS_PACKING_EXTEND16,
125 		.order			= SOC_MBUS_ORDER_LE,
126 	},
127 }, {
128 	.code = V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE,
129 	.fmt = {
130 		.fourcc			= V4L2_PIX_FMT_SBGGR10,
131 		.name			= "Bayer 10 BGGR",
132 		.bits_per_sample	= 8,
133 		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
134 		.order			= SOC_MBUS_ORDER_LE,
135 	},
136 }, {
137 	.code = V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE,
138 	.fmt = {
139 		.fourcc			= V4L2_PIX_FMT_SBGGR10,
140 		.name			= "Bayer 10 BGGR",
141 		.bits_per_sample	= 8,
142 		.packing		= SOC_MBUS_PACKING_2X8_PADLO,
143 		.order			= SOC_MBUS_ORDER_LE,
144 	},
145 }, {
146 	.code = V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE,
147 	.fmt = {
148 		.fourcc			= V4L2_PIX_FMT_SBGGR10,
149 		.name			= "Bayer 10 BGGR",
150 		.bits_per_sample	= 8,
151 		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
152 		.order			= SOC_MBUS_ORDER_BE,
153 	},
154 }, {
155 	.code = V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE,
156 	.fmt = {
157 		.fourcc			= V4L2_PIX_FMT_SBGGR10,
158 		.name			= "Bayer 10 BGGR",
159 		.bits_per_sample	= 8,
160 		.packing		= SOC_MBUS_PACKING_2X8_PADLO,
161 		.order			= SOC_MBUS_ORDER_BE,
162 	},
163 }, {
164 	.code = V4L2_MBUS_FMT_JPEG_1X8,
165 	.fmt = {
166 		.fourcc                 = V4L2_PIX_FMT_JPEG,
167 		.name                   = "JPEG",
168 		.bits_per_sample        = 8,
169 		.packing                = SOC_MBUS_PACKING_VARIABLE,
170 		.order                  = SOC_MBUS_ORDER_LE,
171 	},
172 }, {
173 	.code = V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE,
174 	.fmt = {
175 		.fourcc			= V4L2_PIX_FMT_RGB444,
176 		.name			= "RGB444",
177 		.bits_per_sample	= 8,
178 		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
179 		.order			= SOC_MBUS_ORDER_BE,
180 	},
181 }, {
182 	.code = V4L2_MBUS_FMT_YUYV8_1_5X8,
183 	.fmt = {
184 		.fourcc			= V4L2_PIX_FMT_YUV420,
185 		.name			= "YUYV 4:2:0",
186 		.bits_per_sample	= 8,
187 		.packing		= SOC_MBUS_PACKING_1_5X8,
188 		.order			= SOC_MBUS_ORDER_LE,
189 	},
190 }, {
191 	.code = V4L2_MBUS_FMT_YVYU8_1_5X8,
192 	.fmt = {
193 		.fourcc			= V4L2_PIX_FMT_YVU420,
194 		.name			= "YVYU 4:2:0",
195 		.bits_per_sample	= 8,
196 		.packing		= SOC_MBUS_PACKING_1_5X8,
197 		.order			= SOC_MBUS_ORDER_LE,
198 	},
199 }, {
200 	.code = V4L2_MBUS_FMT_UYVY8_1X16,
201 	.fmt = {
202 		.fourcc			= V4L2_PIX_FMT_UYVY,
203 		.name			= "UYVY 16bit",
204 		.bits_per_sample	= 16,
205 		.packing		= SOC_MBUS_PACKING_EXTEND16,
206 		.order			= SOC_MBUS_ORDER_LE,
207 	},
208 }, {
209 	.code = V4L2_MBUS_FMT_VYUY8_1X16,
210 	.fmt = {
211 		.fourcc			= V4L2_PIX_FMT_VYUY,
212 		.name			= "VYUY 16bit",
213 		.bits_per_sample	= 16,
214 		.packing		= SOC_MBUS_PACKING_EXTEND16,
215 		.order			= SOC_MBUS_ORDER_LE,
216 	},
217 }, {
218 	.code = V4L2_MBUS_FMT_YUYV8_1X16,
219 	.fmt = {
220 		.fourcc			= V4L2_PIX_FMT_YUYV,
221 		.name			= "YUYV 16bit",
222 		.bits_per_sample	= 16,
223 		.packing		= SOC_MBUS_PACKING_EXTEND16,
224 		.order			= SOC_MBUS_ORDER_LE,
225 	},
226 }, {
227 	.code = V4L2_MBUS_FMT_YVYU8_1X16,
228 	.fmt = {
229 		.fourcc			= V4L2_PIX_FMT_YVYU,
230 		.name			= "YVYU 16bit",
231 		.bits_per_sample	= 16,
232 		.packing		= SOC_MBUS_PACKING_EXTEND16,
233 		.order			= SOC_MBUS_ORDER_LE,
234 	},
235 }, {
236 	.code = V4L2_MBUS_FMT_SGRBG8_1X8,
237 	.fmt = {
238 		.fourcc			= V4L2_PIX_FMT_SGRBG8,
239 		.name			= "Bayer 8 GRBG",
240 		.bits_per_sample	= 8,
241 		.packing		= SOC_MBUS_PACKING_NONE,
242 		.order			= SOC_MBUS_ORDER_LE,
243 	},
244 }, {
245 	.code = V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8,
246 	.fmt = {
247 		.fourcc			= V4L2_PIX_FMT_SGRBG10DPCM8,
248 		.name			= "Bayer 10 BGGR DPCM 8",
249 		.bits_per_sample	= 8,
250 		.packing		= SOC_MBUS_PACKING_NONE,
251 		.order			= SOC_MBUS_ORDER_LE,
252 	},
253 }, {
254 	.code = V4L2_MBUS_FMT_SGBRG10_1X10,
255 	.fmt = {
256 		.fourcc			= V4L2_PIX_FMT_SGBRG10,
257 		.name			= "Bayer 10 GBRG",
258 		.bits_per_sample	= 10,
259 		.packing		= SOC_MBUS_PACKING_EXTEND16,
260 		.order			= SOC_MBUS_ORDER_LE,
261 	},
262 }, {
263 	.code = V4L2_MBUS_FMT_SGRBG10_1X10,
264 	.fmt = {
265 		.fourcc			= V4L2_PIX_FMT_SGRBG10,
266 		.name			= "Bayer 10 GRBG",
267 		.bits_per_sample	= 10,
268 		.packing		= SOC_MBUS_PACKING_EXTEND16,
269 		.order			= SOC_MBUS_ORDER_LE,
270 	},
271 }, {
272 	.code = V4L2_MBUS_FMT_SRGGB10_1X10,
273 	.fmt = {
274 		.fourcc			= V4L2_PIX_FMT_SRGGB10,
275 		.name			= "Bayer 10 RGGB",
276 		.bits_per_sample	= 10,
277 		.packing		= SOC_MBUS_PACKING_EXTEND16,
278 		.order			= SOC_MBUS_ORDER_LE,
279 	},
280 }, {
281 	.code = V4L2_MBUS_FMT_SBGGR12_1X12,
282 	.fmt = {
283 		.fourcc			= V4L2_PIX_FMT_SBGGR12,
284 		.name			= "Bayer 12 BGGR",
285 		.bits_per_sample	= 12,
286 		.packing		= SOC_MBUS_PACKING_EXTEND16,
287 		.order			= SOC_MBUS_ORDER_LE,
288 	},
289 }, {
290 	.code = V4L2_MBUS_FMT_SGBRG12_1X12,
291 	.fmt = {
292 		.fourcc			= V4L2_PIX_FMT_SGBRG12,
293 		.name			= "Bayer 12 GBRG",
294 		.bits_per_sample	= 12,
295 		.packing		= SOC_MBUS_PACKING_EXTEND16,
296 		.order			= SOC_MBUS_ORDER_LE,
297 	},
298 }, {
299 	.code = V4L2_MBUS_FMT_SGRBG12_1X12,
300 	.fmt = {
301 		.fourcc			= V4L2_PIX_FMT_SGRBG12,
302 		.name			= "Bayer 12 GRBG",
303 		.bits_per_sample	= 12,
304 		.packing		= SOC_MBUS_PACKING_EXTEND16,
305 		.order			= SOC_MBUS_ORDER_LE,
306 	},
307 }, {
308 	.code = V4L2_MBUS_FMT_SRGGB12_1X12,
309 	.fmt = {
310 		.fourcc			= V4L2_PIX_FMT_SRGGB12,
311 		.name			= "Bayer 12 RGGB",
312 		.bits_per_sample	= 12,
313 		.packing		= SOC_MBUS_PACKING_EXTEND16,
314 		.order			= SOC_MBUS_ORDER_LE,
315 	},
316 },
317 };
318 
soc_mbus_samples_per_pixel(const struct soc_mbus_pixelfmt * mf,unsigned int * numerator,unsigned int * denominator)319 int soc_mbus_samples_per_pixel(const struct soc_mbus_pixelfmt *mf,
320 			unsigned int *numerator, unsigned int *denominator)
321 {
322 	switch (mf->packing) {
323 	case SOC_MBUS_PACKING_NONE:
324 	case SOC_MBUS_PACKING_EXTEND16:
325 		*numerator = 1;
326 		*denominator = 1;
327 		return 0;
328 	case SOC_MBUS_PACKING_2X8_PADHI:
329 	case SOC_MBUS_PACKING_2X8_PADLO:
330 		*numerator = 2;
331 		*denominator = 1;
332 		return 0;
333 	case SOC_MBUS_PACKING_1_5X8:
334 		*numerator = 3;
335 		*denominator = 2;
336 		return 0;
337 	case SOC_MBUS_PACKING_VARIABLE:
338 		*numerator = 0;
339 		*denominator = 1;
340 		return 0;
341 	}
342 	return -EINVAL;
343 }
344 EXPORT_SYMBOL(soc_mbus_samples_per_pixel);
345 
soc_mbus_bytes_per_line(u32 width,const struct soc_mbus_pixelfmt * mf)346 s32 soc_mbus_bytes_per_line(u32 width, const struct soc_mbus_pixelfmt *mf)
347 {
348 	switch (mf->packing) {
349 	case SOC_MBUS_PACKING_NONE:
350 		return width * mf->bits_per_sample / 8;
351 	case SOC_MBUS_PACKING_2X8_PADHI:
352 	case SOC_MBUS_PACKING_2X8_PADLO:
353 	case SOC_MBUS_PACKING_EXTEND16:
354 		return width * 2;
355 	case SOC_MBUS_PACKING_1_5X8:
356 		return width * 3 / 2;
357 	case SOC_MBUS_PACKING_VARIABLE:
358 		return 0;
359 	}
360 	return -EINVAL;
361 }
362 EXPORT_SYMBOL(soc_mbus_bytes_per_line);
363 
soc_mbus_find_fmtdesc(enum v4l2_mbus_pixelcode code,const struct soc_mbus_lookup * lookup,int n)364 const struct soc_mbus_pixelfmt *soc_mbus_find_fmtdesc(
365 	enum v4l2_mbus_pixelcode code,
366 	const struct soc_mbus_lookup *lookup,
367 	int n)
368 {
369 	int i;
370 
371 	for (i = 0; i < n; i++)
372 		if (lookup[i].code == code)
373 			return &lookup[i].fmt;
374 
375 	return NULL;
376 }
377 EXPORT_SYMBOL(soc_mbus_find_fmtdesc);
378 
soc_mbus_get_fmtdesc(enum v4l2_mbus_pixelcode code)379 const struct soc_mbus_pixelfmt *soc_mbus_get_fmtdesc(
380 	enum v4l2_mbus_pixelcode code)
381 {
382 	return soc_mbus_find_fmtdesc(code, mbus_fmt, ARRAY_SIZE(mbus_fmt));
383 }
384 EXPORT_SYMBOL(soc_mbus_get_fmtdesc);
385 
soc_mbus_config_compatible(const struct v4l2_mbus_config * cfg,unsigned int flags)386 unsigned int soc_mbus_config_compatible(const struct v4l2_mbus_config *cfg,
387 					unsigned int flags)
388 {
389 	unsigned long common_flags;
390 	bool hsync = true, vsync = true, pclk, data, mode;
391 	bool mipi_lanes, mipi_clock;
392 
393 	common_flags = cfg->flags & flags;
394 
395 	switch (cfg->type) {
396 	case V4L2_MBUS_PARALLEL:
397 		hsync = common_flags & (V4L2_MBUS_HSYNC_ACTIVE_HIGH |
398 					V4L2_MBUS_HSYNC_ACTIVE_LOW);
399 		vsync = common_flags & (V4L2_MBUS_VSYNC_ACTIVE_HIGH |
400 					V4L2_MBUS_VSYNC_ACTIVE_LOW);
401 	case V4L2_MBUS_BT656:
402 		pclk = common_flags & (V4L2_MBUS_PCLK_SAMPLE_RISING |
403 				       V4L2_MBUS_PCLK_SAMPLE_FALLING);
404 		data = common_flags & (V4L2_MBUS_DATA_ACTIVE_HIGH |
405 				       V4L2_MBUS_DATA_ACTIVE_LOW);
406 		mode = common_flags & (V4L2_MBUS_MASTER | V4L2_MBUS_SLAVE);
407 		return (!hsync || !vsync || !pclk || !data || !mode) ?
408 			0 : common_flags;
409 	case V4L2_MBUS_CSI2:
410 		mipi_lanes = common_flags & V4L2_MBUS_CSI2_LANES;
411 		mipi_clock = common_flags & (V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK |
412 					     V4L2_MBUS_CSI2_CONTINUOUS_CLOCK);
413 		return (!mipi_lanes || !mipi_clock) ? 0 : common_flags;
414 	}
415 	return 0;
416 }
417 EXPORT_SYMBOL(soc_mbus_config_compatible);
418 
soc_mbus_init(void)419 static int __init soc_mbus_init(void)
420 {
421 	return 0;
422 }
423 
soc_mbus_exit(void)424 static void __exit soc_mbus_exit(void)
425 {
426 }
427 
428 module_init(soc_mbus_init);
429 module_exit(soc_mbus_exit);
430 
431 MODULE_DESCRIPTION("soc-camera media bus interface");
432 MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
433 MODULE_LICENSE("GPL v2");
434