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