blob: 7d68d0b9966aa7774edfa1ccce40100768632bab [file] [log] [blame]
Mauro Carvalho Chehab2c3fb082012-08-14 17:31:16 -03001/* linux/drivers/media/platform/s5p-jpeg/jpeg-core.c
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002 *
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003 * Copyright (c) 2011-2013 Samsung Electronics Co., Ltd.
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03004 * http://www.samsung.com
5 *
6 * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03007 * Author: Jacek Anaszewski <j.anaszewski@samsung.com>
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03008 *
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/clk.h>
15#include <linux/err.h>
16#include <linux/gfp.h>
17#include <linux/interrupt.h>
18#include <linux/io.h>
19#include <linux/kernel.h>
20#include <linux/module.h>
Sylwester Nawrockif7074ab2013-08-18 16:14:27 -030021#include <linux/of.h>
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -030022#include <linux/platform_device.h>
23#include <linux/pm_runtime.h>
24#include <linux/slab.h>
25#include <linux/spinlock.h>
26#include <linux/string.h>
27#include <media/v4l2-mem2mem.h>
28#include <media/v4l2-ioctl.h>
29#include <media/videobuf2-core.h>
30#include <media/videobuf2-dma-contig.h>
31
32#include "jpeg-core.h"
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -030033#include "jpeg-hw-s5p.h"
Jacek Anaszewski80529ae2013-12-18 11:04:44 -030034#include "jpeg-hw-exynos4.h"
35#include "jpeg-regs.h"
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -030036
Jacek Anaszewski80529ae2013-12-18 11:04:44 -030037static struct s5p_jpeg_fmt sjpeg_formats[] = {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -030038 {
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -030039 .name = "JPEG JFIF",
40 .fourcc = V4L2_PIX_FMT_JPEG,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -030041 .flags = SJPEG_FMT_FLAG_ENC_CAPTURE |
42 SJPEG_FMT_FLAG_DEC_OUTPUT |
43 SJPEG_FMT_FLAG_S5P |
44 SJPEG_FMT_FLAG_EXYNOS4,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -030045 },
46 {
47 .name = "YUV 4:2:2 packed, YCbYCr",
48 .fourcc = V4L2_PIX_FMT_YUYV,
49 .depth = 16,
50 .colplanes = 1,
51 .h_align = 4,
52 .v_align = 3,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -030053 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
54 SJPEG_FMT_FLAG_DEC_CAPTURE |
55 SJPEG_FMT_FLAG_S5P |
56 SJPEG_FMT_NON_RGB,
57 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -030058 },
59 {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -030060 .name = "YUV 4:2:2 packed, YCbYCr",
61 .fourcc = V4L2_PIX_FMT_YUYV,
62 .depth = 16,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -030063 .colplanes = 1,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -030064 .h_align = 1,
65 .v_align = 0,
66 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
67 SJPEG_FMT_FLAG_DEC_CAPTURE |
68 SJPEG_FMT_FLAG_EXYNOS4 |
69 SJPEG_FMT_NON_RGB,
70 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
71 },
72 {
73 .name = "YUV 4:2:2 packed, YCrYCb",
74 .fourcc = V4L2_PIX_FMT_YVYU,
75 .depth = 16,
76 .colplanes = 1,
77 .h_align = 1,
78 .v_align = 0,
79 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
80 SJPEG_FMT_FLAG_DEC_CAPTURE |
81 SJPEG_FMT_FLAG_EXYNOS4 |
82 SJPEG_FMT_NON_RGB,
83 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
84 },
85 {
86 .name = "RGB565",
87 .fourcc = V4L2_PIX_FMT_RGB565,
88 .depth = 16,
89 .colplanes = 1,
90 .h_align = 0,
91 .v_align = 0,
92 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
93 SJPEG_FMT_FLAG_DEC_CAPTURE |
94 SJPEG_FMT_FLAG_EXYNOS4 |
95 SJPEG_FMT_RGB,
96 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
97 },
98 {
99 .name = "RGB565",
100 .fourcc = V4L2_PIX_FMT_RGB565,
101 .depth = 16,
102 .colplanes = 1,
103 .h_align = 0,
104 .v_align = 0,
105 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
106 SJPEG_FMT_FLAG_S5P |
107 SJPEG_FMT_RGB,
108 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
109 },
110 {
111 .name = "ARGB8888, 32 bpp",
112 .fourcc = V4L2_PIX_FMT_RGB32,
113 .depth = 32,
114 .colplanes = 1,
115 .h_align = 0,
116 .v_align = 0,
117 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
118 SJPEG_FMT_FLAG_DEC_CAPTURE |
119 SJPEG_FMT_FLAG_EXYNOS4 |
120 SJPEG_FMT_RGB,
121 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
122 },
123 {
124 .name = "YUV 4:4:4 planar, Y/CbCr",
125 .fourcc = V4L2_PIX_FMT_NV24,
126 .depth = 24,
127 .colplanes = 2,
128 .h_align = 0,
129 .v_align = 0,
130 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
131 SJPEG_FMT_FLAG_DEC_CAPTURE |
132 SJPEG_FMT_FLAG_EXYNOS4 |
133 SJPEG_FMT_NON_RGB,
134 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
135 },
136 {
137 .name = "YUV 4:4:4 planar, Y/CrCb",
138 .fourcc = V4L2_PIX_FMT_NV42,
139 .depth = 24,
140 .colplanes = 2,
141 .h_align = 0,
142 .v_align = 0,
143 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
144 SJPEG_FMT_FLAG_DEC_CAPTURE |
145 SJPEG_FMT_FLAG_EXYNOS4 |
146 SJPEG_FMT_NON_RGB,
147 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
148 },
149 {
150 .name = "YUV 4:2:2 planar, Y/CrCb",
151 .fourcc = V4L2_PIX_FMT_NV61,
152 .depth = 16,
153 .colplanes = 2,
154 .h_align = 1,
155 .v_align = 0,
156 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
157 SJPEG_FMT_FLAG_DEC_CAPTURE |
158 SJPEG_FMT_FLAG_EXYNOS4 |
159 SJPEG_FMT_NON_RGB,
160 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
161 },
162 {
163 .name = "YUV 4:2:2 planar, Y/CbCr",
164 .fourcc = V4L2_PIX_FMT_NV16,
165 .depth = 16,
166 .colplanes = 2,
167 .h_align = 1,
168 .v_align = 0,
169 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
170 SJPEG_FMT_FLAG_DEC_CAPTURE |
171 SJPEG_FMT_FLAG_EXYNOS4 |
172 SJPEG_FMT_NON_RGB,
173 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
174 },
175 {
176 .name = "YUV 4:2:0 planar, Y/CbCr",
177 .fourcc = V4L2_PIX_FMT_NV12,
Jacek Anaszewskia62cffe2014-01-16 08:26:33 -0300178 .depth = 12,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300179 .colplanes = 2,
180 .h_align = 1,
181 .v_align = 1,
182 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
183 SJPEG_FMT_FLAG_DEC_CAPTURE |
184 SJPEG_FMT_FLAG_EXYNOS4 |
185 SJPEG_FMT_NON_RGB,
186 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
187 },
188 {
189 .name = "YUV 4:2:0 planar, Y/CbCr",
190 .fourcc = V4L2_PIX_FMT_NV12,
Jacek Anaszewskia62cffe2014-01-16 08:26:33 -0300191 .depth = 12,
192 .colplanes = 2,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300193 .h_align = 4,
Jacek Anaszewskia62cffe2014-01-16 08:26:33 -0300194 .v_align = 4,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300195 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
196 SJPEG_FMT_FLAG_DEC_CAPTURE |
197 SJPEG_FMT_FLAG_S5P |
198 SJPEG_FMT_NON_RGB,
199 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
200 },
201 {
202 .name = "YUV 4:2:0 planar, Y/CrCb",
203 .fourcc = V4L2_PIX_FMT_NV21,
204 .depth = 12,
205 .colplanes = 2,
206 .h_align = 1,
207 .v_align = 1,
208 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
209 SJPEG_FMT_FLAG_DEC_CAPTURE |
210 SJPEG_FMT_FLAG_EXYNOS4 |
211 SJPEG_FMT_NON_RGB,
212 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
213 },
214 {
215 .name = "YUV 4:2:0 contiguous 3-planar, Y/Cb/Cr",
216 .fourcc = V4L2_PIX_FMT_YUV420,
217 .depth = 12,
218 .colplanes = 3,
219 .h_align = 1,
220 .v_align = 1,
221 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
222 SJPEG_FMT_FLAG_DEC_CAPTURE |
223 SJPEG_FMT_FLAG_EXYNOS4 |
224 SJPEG_FMT_NON_RGB,
225 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
226 },
227 {
228 .name = "Gray",
229 .fourcc = V4L2_PIX_FMT_GREY,
230 .depth = 8,
231 .colplanes = 1,
232 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
233 SJPEG_FMT_FLAG_DEC_CAPTURE |
234 SJPEG_FMT_FLAG_EXYNOS4 |
235 SJPEG_FMT_NON_RGB,
236 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300237 },
238};
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300239#define SJPEG_NUM_FORMATS ARRAY_SIZE(sjpeg_formats)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300240
241static const unsigned char qtbl_luminance[4][64] = {
Jacek Anaszewski78e5a3c2013-11-25 06:58:08 -0300242 {/*level 0 - high compression quality */
243 20, 16, 25, 39, 50, 46, 62, 68,
244 16, 18, 23, 38, 38, 53, 65, 68,
245 25, 23, 31, 38, 53, 65, 68, 68,
246 39, 38, 38, 53, 65, 68, 68, 68,
247 50, 38, 53, 65, 68, 68, 68, 68,
248 46, 53, 65, 68, 68, 68, 68, 68,
249 62, 65, 68, 68, 68, 68, 68, 68,
250 68, 68, 68, 68, 68, 68, 68, 68
251 },
252 {/* level 1 */
253 16, 11, 11, 16, 23, 27, 31, 30,
254 11, 12, 12, 15, 20, 23, 23, 30,
255 11, 12, 13, 16, 23, 26, 35, 47,
256 16, 15, 16, 23, 26, 37, 47, 64,
257 23, 20, 23, 26, 39, 51, 64, 64,
258 27, 23, 26, 37, 51, 64, 64, 64,
259 31, 23, 35, 47, 64, 64, 64, 64,
260 30, 30, 47, 64, 64, 64, 64, 64
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300261 },
262 {/* level 2 */
263 12, 8, 8, 12, 17, 21, 24, 23,
264 8, 9, 9, 11, 15, 19, 18, 23,
265 8, 9, 10, 12, 19, 20, 27, 36,
266 12, 11, 12, 21, 20, 28, 36, 53,
267 17, 15, 19, 20, 30, 39, 51, 59,
268 21, 19, 20, 28, 39, 51, 59, 59,
269 24, 18, 27, 36, 51, 59, 59, 59,
270 23, 23, 36, 53, 59, 59, 59, 59
271 },
Jacek Anaszewski78e5a3c2013-11-25 06:58:08 -0300272 {/* level 3 - low compression quality */
273 8, 6, 6, 8, 12, 14, 16, 17,
274 6, 6, 6, 8, 10, 13, 12, 15,
275 6, 6, 7, 8, 13, 14, 18, 24,
276 8, 8, 8, 14, 13, 19, 24, 35,
277 12, 10, 13, 13, 20, 26, 34, 39,
278 14, 13, 14, 19, 26, 34, 39, 39,
279 16, 12, 18, 24, 34, 39, 39, 39,
280 17, 15, 24, 35, 39, 39, 39, 39
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300281 }
282};
283
284static const unsigned char qtbl_chrominance[4][64] = {
Jacek Anaszewski78e5a3c2013-11-25 06:58:08 -0300285 {/*level 0 - high compression quality */
286 21, 25, 32, 38, 54, 68, 68, 68,
287 25, 28, 24, 38, 54, 68, 68, 68,
288 32, 24, 32, 43, 66, 68, 68, 68,
289 38, 38, 43, 53, 68, 68, 68, 68,
290 54, 54, 66, 68, 68, 68, 68, 68,
291 68, 68, 68, 68, 68, 68, 68, 68,
292 68, 68, 68, 68, 68, 68, 68, 68,
293 68, 68, 68, 68, 68, 68, 68, 68
294 },
295 {/* level 1 */
296 17, 15, 17, 21, 20, 26, 38, 48,
297 15, 19, 18, 17, 20, 26, 35, 43,
298 17, 18, 20, 22, 26, 30, 46, 53,
299 21, 17, 22, 28, 30, 39, 53, 64,
300 20, 20, 26, 30, 39, 48, 64, 64,
301 26, 26, 30, 39, 48, 63, 64, 64,
302 38, 35, 46, 53, 64, 64, 64, 64,
303 48, 43, 53, 64, 64, 64, 64, 64
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300304 },
305 {/* level 2 */
306 13, 11, 13, 16, 20, 20, 29, 37,
307 11, 14, 14, 14, 16, 20, 26, 32,
308 13, 14, 15, 17, 20, 23, 35, 40,
309 16, 14, 17, 21, 23, 30, 40, 50,
310 20, 16, 20, 23, 30, 37, 50, 59,
311 20, 20, 23, 30, 37, 48, 59, 59,
312 29, 26, 35, 40, 50, 59, 59, 59,
313 37, 32, 40, 50, 59, 59, 59, 59
314 },
Jacek Anaszewski78e5a3c2013-11-25 06:58:08 -0300315 {/* level 3 - low compression quality */
316 9, 8, 9, 11, 14, 17, 19, 24,
317 8, 10, 9, 11, 14, 13, 17, 22,
318 9, 9, 13, 14, 13, 15, 23, 26,
319 11, 11, 14, 14, 15, 20, 26, 33,
320 14, 14, 13, 15, 20, 24, 33, 39,
321 17, 13, 15, 20, 24, 32, 39, 39,
322 19, 17, 23, 26, 33, 39, 39, 39,
323 24, 22, 26, 33, 39, 39, 39, 39
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300324 }
325};
326
327static const unsigned char hdctbl0[16] = {
328 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0
329};
330
331static const unsigned char hdctblg0[12] = {
332 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb
333};
334static const unsigned char hactbl0[16] = {
335 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d
336};
337static const unsigned char hactblg0[162] = {
338 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
339 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
340 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
341 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
342 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
343 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
344 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
345 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
346 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
347 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
348 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
349 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
350 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
351 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
352 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
353 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
354 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
355 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
356 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
357 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
358 0xf9, 0xfa
359};
360
Jacek Anaszewski337777a2013-11-22 06:13:34 -0300361/*
362 * Fourcc downgrade schema lookup tables for 422 and 420
363 * chroma subsampling - fourcc on each position maps on the
364 * fourcc from the table fourcc_to_dwngrd_schema_id which allows
365 * to get the most suitable fourcc counterpart for the given
366 * downgraded subsampling property.
367 */
368static const u32 subs422_fourcc_dwngrd_schema[] = {
369 V4L2_PIX_FMT_NV16,
370 V4L2_PIX_FMT_NV61,
371};
372
373static const u32 subs420_fourcc_dwngrd_schema[] = {
374 V4L2_PIX_FMT_NV12,
375 V4L2_PIX_FMT_NV21,
376 V4L2_PIX_FMT_NV12,
377 V4L2_PIX_FMT_NV21,
378 V4L2_PIX_FMT_NV12,
379 V4L2_PIX_FMT_NV21,
380 V4L2_PIX_FMT_GREY,
381 V4L2_PIX_FMT_GREY,
382 V4L2_PIX_FMT_GREY,
383 V4L2_PIX_FMT_GREY,
384};
385
386/*
387 * Lookup table for translation of a fourcc to the position
388 * of its downgraded counterpart in the *fourcc_dwngrd_schema
389 * tables.
390 */
391static const u32 fourcc_to_dwngrd_schema_id[] = {
392 V4L2_PIX_FMT_NV24,
393 V4L2_PIX_FMT_NV42,
394 V4L2_PIX_FMT_NV16,
395 V4L2_PIX_FMT_NV61,
396 V4L2_PIX_FMT_YUYV,
397 V4L2_PIX_FMT_YVYU,
398 V4L2_PIX_FMT_NV12,
399 V4L2_PIX_FMT_NV21,
400 V4L2_PIX_FMT_YUV420,
401 V4L2_PIX_FMT_GREY,
402};
403
404static int s5p_jpeg_get_dwngrd_sch_id_by_fourcc(u32 fourcc)
405{
406 int i;
407 for (i = 0; i < ARRAY_SIZE(fourcc_to_dwngrd_schema_id); ++i) {
408 if (fourcc_to_dwngrd_schema_id[i] == fourcc)
409 return i;
410 }
411
412 return -EINVAL;
413}
414
415static int s5p_jpeg_adjust_fourcc_to_subsampling(
416 enum v4l2_jpeg_chroma_subsampling subs,
417 u32 in_fourcc,
418 u32 *out_fourcc,
419 struct s5p_jpeg_ctx *ctx)
420{
421 int dwngrd_sch_id;
422
423 if (ctx->subsampling != V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY) {
424 dwngrd_sch_id =
425 s5p_jpeg_get_dwngrd_sch_id_by_fourcc(in_fourcc);
426 if (dwngrd_sch_id < 0)
427 return -EINVAL;
428 }
429
430 switch (ctx->subsampling) {
431 case V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY:
432 *out_fourcc = V4L2_PIX_FMT_GREY;
433 break;
434 case V4L2_JPEG_CHROMA_SUBSAMPLING_420:
435 if (dwngrd_sch_id >
436 ARRAY_SIZE(subs420_fourcc_dwngrd_schema) - 1)
437 return -EINVAL;
438 *out_fourcc = subs420_fourcc_dwngrd_schema[dwngrd_sch_id];
439 break;
440 case V4L2_JPEG_CHROMA_SUBSAMPLING_422:
441 if (dwngrd_sch_id >
442 ARRAY_SIZE(subs422_fourcc_dwngrd_schema) - 1)
443 return -EINVAL;
444 *out_fourcc = subs422_fourcc_dwngrd_schema[dwngrd_sch_id];
445 break;
446 default:
447 *out_fourcc = V4L2_PIX_FMT_GREY;
448 break;
449 }
450
451 return 0;
452}
453
Jacek Anaszewski303b0a92013-12-18 11:14:00 -0300454static int exynos4x12_decoded_subsampling[] = {
455 V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY,
456 V4L2_JPEG_CHROMA_SUBSAMPLING_444,
457 V4L2_JPEG_CHROMA_SUBSAMPLING_422,
458 V4L2_JPEG_CHROMA_SUBSAMPLING_420,
459};
460
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -0300461static inline struct s5p_jpeg_ctx *ctrl_to_ctx(struct v4l2_ctrl *c)
462{
463 return container_of(c->handler, struct s5p_jpeg_ctx, ctrl_handler);
464}
465
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300466static inline struct s5p_jpeg_ctx *fh_to_ctx(struct v4l2_fh *fh)
467{
468 return container_of(fh, struct s5p_jpeg_ctx, fh);
469}
470
Jacek Anaszewski303b0a92013-12-18 11:14:00 -0300471static int s5p_jpeg_to_user_subsampling(struct s5p_jpeg_ctx *ctx)
472{
473 WARN_ON(ctx->subsampling > 3);
474
475 if (ctx->jpeg->variant->version == SJPEG_S5P) {
476 if (ctx->subsampling > 2)
477 return V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY;
478 return ctx->subsampling;
479 } else {
480 if (ctx->subsampling > 2)
481 return V4L2_JPEG_CHROMA_SUBSAMPLING_420;
482 return exynos4x12_decoded_subsampling[ctx->subsampling];
483 }
484}
485
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300486static inline void s5p_jpeg_set_qtbl(void __iomem *regs,
487 const unsigned char *qtbl,
488 unsigned long tab, int len)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300489{
490 int i;
491
492 for (i = 0; i < len; i++)
493 writel((unsigned int)qtbl[i], regs + tab + (i * 0x04));
494}
495
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300496static inline void s5p_jpeg_set_qtbl_lum(void __iomem *regs, int quality)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300497{
498 /* this driver fills quantisation table 0 with data for luma */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300499 s5p_jpeg_set_qtbl(regs, qtbl_luminance[quality],
500 S5P_JPG_QTBL_CONTENT(0),
501 ARRAY_SIZE(qtbl_luminance[quality]));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300502}
503
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300504static inline void s5p_jpeg_set_qtbl_chr(void __iomem *regs, int quality)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300505{
506 /* this driver fills quantisation table 1 with data for chroma */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300507 s5p_jpeg_set_qtbl(regs, qtbl_chrominance[quality],
508 S5P_JPG_QTBL_CONTENT(1),
509 ARRAY_SIZE(qtbl_chrominance[quality]));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300510}
511
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300512static inline void s5p_jpeg_set_htbl(void __iomem *regs,
513 const unsigned char *htbl,
514 unsigned long tab, int len)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300515{
516 int i;
517
518 for (i = 0; i < len; i++)
519 writel((unsigned int)htbl[i], regs + tab + (i * 0x04));
520}
521
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300522static inline void s5p_jpeg_set_hdctbl(void __iomem *regs)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300523{
524 /* this driver fills table 0 for this component */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300525 s5p_jpeg_set_htbl(regs, hdctbl0, S5P_JPG_HDCTBL(0),
526 ARRAY_SIZE(hdctbl0));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300527}
528
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300529static inline void s5p_jpeg_set_hdctblg(void __iomem *regs)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300530{
531 /* this driver fills table 0 for this component */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300532 s5p_jpeg_set_htbl(regs, hdctblg0, S5P_JPG_HDCTBLG(0),
533 ARRAY_SIZE(hdctblg0));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300534}
535
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300536static inline void s5p_jpeg_set_hactbl(void __iomem *regs)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300537{
538 /* this driver fills table 0 for this component */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300539 s5p_jpeg_set_htbl(regs, hactbl0, S5P_JPG_HACTBL(0),
540 ARRAY_SIZE(hactbl0));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300541}
542
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300543static inline void s5p_jpeg_set_hactblg(void __iomem *regs)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300544{
545 /* this driver fills table 0 for this component */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300546 s5p_jpeg_set_htbl(regs, hactblg0, S5P_JPG_HACTBLG(0),
547 ARRAY_SIZE(hactblg0));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300548}
549
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300550static inline void exynos4_jpeg_set_tbl(void __iomem *regs,
551 const unsigned char *tbl,
552 unsigned long tab, int len)
553{
554 int i;
555 unsigned int dword;
556
557 for (i = 0; i < len; i += 4) {
558 dword = tbl[i] |
559 (tbl[i + 1] << 8) |
560 (tbl[i + 2] << 16) |
561 (tbl[i + 3] << 24);
562 writel(dword, regs + tab + i);
563 }
564}
565
566static inline void exynos4_jpeg_set_qtbl_lum(void __iomem *regs, int quality)
567{
568 /* this driver fills quantisation table 0 with data for luma */
569 exynos4_jpeg_set_tbl(regs, qtbl_luminance[quality],
570 EXYNOS4_QTBL_CONTENT(0),
571 ARRAY_SIZE(qtbl_luminance[quality]));
572}
573
574static inline void exynos4_jpeg_set_qtbl_chr(void __iomem *regs, int quality)
575{
576 /* this driver fills quantisation table 1 with data for chroma */
577 exynos4_jpeg_set_tbl(regs, qtbl_chrominance[quality],
578 EXYNOS4_QTBL_CONTENT(1),
579 ARRAY_SIZE(qtbl_chrominance[quality]));
580}
581
582void exynos4_jpeg_set_huff_tbl(void __iomem *base)
583{
584 exynos4_jpeg_set_tbl(base, hdctbl0, EXYNOS4_HUFF_TBL_HDCLL,
585 ARRAY_SIZE(hdctbl0));
586 exynos4_jpeg_set_tbl(base, hdctbl0, EXYNOS4_HUFF_TBL_HDCCL,
587 ARRAY_SIZE(hdctbl0));
588 exynos4_jpeg_set_tbl(base, hdctblg0, EXYNOS4_HUFF_TBL_HDCLV,
589 ARRAY_SIZE(hdctblg0));
590 exynos4_jpeg_set_tbl(base, hdctblg0, EXYNOS4_HUFF_TBL_HDCCV,
591 ARRAY_SIZE(hdctblg0));
592 exynos4_jpeg_set_tbl(base, hactbl0, EXYNOS4_HUFF_TBL_HACLL,
593 ARRAY_SIZE(hactbl0));
594 exynos4_jpeg_set_tbl(base, hactbl0, EXYNOS4_HUFF_TBL_HACCL,
595 ARRAY_SIZE(hactbl0));
596 exynos4_jpeg_set_tbl(base, hactblg0, EXYNOS4_HUFF_TBL_HACLV,
597 ARRAY_SIZE(hactblg0));
598 exynos4_jpeg_set_tbl(base, hactblg0, EXYNOS4_HUFF_TBL_HACCV,
599 ARRAY_SIZE(hactblg0));
600}
601
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300602/*
603 * ============================================================================
604 * Device file operations
605 * ============================================================================
606 */
607
608static int queue_init(void *priv, struct vb2_queue *src_vq,
609 struct vb2_queue *dst_vq);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300610static struct s5p_jpeg_fmt *s5p_jpeg_find_format(struct s5p_jpeg_ctx *ctx,
611 __u32 pixelformat, unsigned int fmt_type);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -0300612static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300613
614static int s5p_jpeg_open(struct file *file)
615{
616 struct s5p_jpeg *jpeg = video_drvdata(file);
617 struct video_device *vfd = video_devdata(file);
618 struct s5p_jpeg_ctx *ctx;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300619 struct s5p_jpeg_fmt *out_fmt, *cap_fmt;
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300620 int ret = 0;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300621
Sachin Kamatb5146c92012-08-16 08:52:58 -0300622 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300623 if (!ctx)
624 return -ENOMEM;
625
Hans Verkuilb0d5cd62012-06-24 06:54:18 -0300626 if (mutex_lock_interruptible(&jpeg->lock)) {
627 ret = -ERESTARTSYS;
628 goto free;
629 }
630
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300631 v4l2_fh_init(&ctx->fh, vfd);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -0300632 /* Use separate control handler per file handle */
633 ctx->fh.ctrl_handler = &ctx->ctrl_handler;
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300634 file->private_data = &ctx->fh;
635 v4l2_fh_add(&ctx->fh);
636
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300637 ctx->jpeg = jpeg;
638 if (vfd == jpeg->vfd_encoder) {
639 ctx->mode = S5P_JPEG_ENCODE;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300640 out_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_RGB565,
641 FMT_TYPE_OUTPUT);
642 cap_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_JPEG,
643 FMT_TYPE_CAPTURE);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300644 } else {
645 ctx->mode = S5P_JPEG_DECODE;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300646 out_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_JPEG,
647 FMT_TYPE_OUTPUT);
648 cap_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_YUYV,
649 FMT_TYPE_CAPTURE);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300650 }
651
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -0300652 ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(jpeg->m2m_dev, ctx, queue_init);
653 if (IS_ERR(ctx->fh.m2m_ctx)) {
654 ret = PTR_ERR(ctx->fh.m2m_ctx);
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300655 goto error;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300656 }
657
658 ctx->out_q.fmt = out_fmt;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300659 ctx->cap_q.fmt = cap_fmt;
660
661 ret = s5p_jpeg_controls_create(ctx);
662 if (ret < 0)
663 goto error;
664
Hans Verkuilb0d5cd62012-06-24 06:54:18 -0300665 mutex_unlock(&jpeg->lock);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300666 return 0;
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300667
668error:
669 v4l2_fh_del(&ctx->fh);
670 v4l2_fh_exit(&ctx->fh);
Hans Verkuilb0d5cd62012-06-24 06:54:18 -0300671 mutex_unlock(&jpeg->lock);
672free:
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300673 kfree(ctx);
674 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300675}
676
677static int s5p_jpeg_release(struct file *file)
678{
Hans Verkuilb0d5cd62012-06-24 06:54:18 -0300679 struct s5p_jpeg *jpeg = video_drvdata(file);
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300680 struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300681
Hans Verkuilb0d5cd62012-06-24 06:54:18 -0300682 mutex_lock(&jpeg->lock);
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -0300683 v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -0300684 v4l2_ctrl_handler_free(&ctx->ctrl_handler);
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300685 v4l2_fh_del(&ctx->fh);
686 v4l2_fh_exit(&ctx->fh);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300687 kfree(ctx);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300688 mutex_unlock(&jpeg->lock);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300689
690 return 0;
691}
692
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300693static const struct v4l2_file_operations s5p_jpeg_fops = {
694 .owner = THIS_MODULE,
695 .open = s5p_jpeg_open,
696 .release = s5p_jpeg_release,
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -0300697 .poll = v4l2_m2m_fop_poll,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300698 .unlocked_ioctl = video_ioctl2,
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -0300699 .mmap = v4l2_m2m_fop_mmap,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300700};
701
702/*
703 * ============================================================================
704 * video ioctl operations
705 * ============================================================================
706 */
707
708static int get_byte(struct s5p_jpeg_buffer *buf)
709{
710 if (buf->curr >= buf->size)
711 return -1;
712
713 return ((unsigned char *)buf->data)[buf->curr++];
714}
715
716static int get_word_be(struct s5p_jpeg_buffer *buf, unsigned int *word)
717{
718 unsigned int temp;
719 int byte;
720
721 byte = get_byte(buf);
722 if (byte == -1)
723 return -1;
724 temp = byte << 8;
725 byte = get_byte(buf);
726 if (byte == -1)
727 return -1;
728 *word = (unsigned int)byte | temp;
729 return 0;
730}
731
732static void skip(struct s5p_jpeg_buffer *buf, long len)
733{
734 if (len <= 0)
735 return;
736
737 while (len--)
738 get_byte(buf);
739}
740
741static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result,
Jacek Anaszewskif8433962013-11-21 13:33:09 -0300742 unsigned long buffer, unsigned long size,
743 struct s5p_jpeg_ctx *ctx)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300744{
745 int c, components, notfound;
Jacek Anaszewskif8433962013-11-21 13:33:09 -0300746 unsigned int height, width, word, subsampling = 0;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300747 long length;
748 struct s5p_jpeg_buffer jpeg_buffer;
749
750 jpeg_buffer.size = size;
751 jpeg_buffer.data = buffer;
752 jpeg_buffer.curr = 0;
753
754 notfound = 1;
755 while (notfound) {
756 c = get_byte(&jpeg_buffer);
757 if (c == -1)
758 break;
759 if (c != 0xff)
760 continue;
761 do
762 c = get_byte(&jpeg_buffer);
763 while (c == 0xff);
764 if (c == -1)
765 break;
766 if (c == 0)
767 continue;
768 length = 0;
769 switch (c) {
770 /* SOF0: baseline JPEG */
771 case SOF0:
772 if (get_word_be(&jpeg_buffer, &word))
773 break;
774 if (get_byte(&jpeg_buffer) == -1)
775 break;
776 if (get_word_be(&jpeg_buffer, &height))
777 break;
778 if (get_word_be(&jpeg_buffer, &width))
779 break;
780 components = get_byte(&jpeg_buffer);
781 if (components == -1)
782 break;
783 notfound = 0;
784
Jacek Anaszewskif8433962013-11-21 13:33:09 -0300785 if (components == 1) {
786 subsampling = 0x33;
787 } else {
788 skip(&jpeg_buffer, 1);
789 subsampling = get_byte(&jpeg_buffer);
790 skip(&jpeg_buffer, 1);
791 }
792
793 skip(&jpeg_buffer, components * 2);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300794 break;
795
796 /* skip payload-less markers */
797 case RST ... RST + 7:
798 case SOI:
799 case EOI:
800 case TEM:
801 break;
802
803 /* skip uninteresting payload markers */
804 default:
805 if (get_word_be(&jpeg_buffer, &word))
806 break;
807 length = (long)word - 2;
808 skip(&jpeg_buffer, length);
809 break;
810 }
811 }
812 result->w = width;
813 result->h = height;
814 result->size = components;
Jacek Anaszewskif8433962013-11-21 13:33:09 -0300815
816 switch (subsampling) {
817 case 0x11:
818 ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444;
819 break;
820 case 0x21:
821 ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422;
822 break;
823 case 0x22:
824 ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420;
825 break;
826 case 0x33:
827 ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY;
828 break;
829 default:
830 return false;
831 }
832
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300833 return !notfound;
834}
835
836static int s5p_jpeg_querycap(struct file *file, void *priv,
837 struct v4l2_capability *cap)
838{
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300839 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300840
841 if (ctx->mode == S5P_JPEG_ENCODE) {
842 strlcpy(cap->driver, S5P_JPEG_M2M_NAME " encoder",
843 sizeof(cap->driver));
844 strlcpy(cap->card, S5P_JPEG_M2M_NAME " encoder",
845 sizeof(cap->card));
846 } else {
847 strlcpy(cap->driver, S5P_JPEG_M2M_NAME " decoder",
848 sizeof(cap->driver));
849 strlcpy(cap->card, S5P_JPEG_M2M_NAME " decoder",
850 sizeof(cap->card));
851 }
852 cap->bus_info[0] = 0;
Sylwester Nawrockif0476a82012-07-26 09:30:00 -0300853 /*
854 * This is only a mem-to-mem video device. The capture and output
855 * device capability flags are left only for backward compatibility
856 * and are scheduled for removal.
857 */
858 cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M |
859 V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300860 return 0;
861}
862
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300863static int enum_fmt(struct s5p_jpeg_fmt *sjpeg_formats, int n,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300864 struct v4l2_fmtdesc *f, u32 type)
865{
866 int i, num = 0;
867
868 for (i = 0; i < n; ++i) {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300869 if (sjpeg_formats[i].flags & type) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300870 /* index-th format of type type found ? */
871 if (num == f->index)
872 break;
873 /* Correct type but haven't reached our index yet,
874 * just increment per-type index */
875 ++num;
876 }
877 }
878
879 /* Format not found */
880 if (i >= n)
881 return -EINVAL;
882
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300883 strlcpy(f->description, sjpeg_formats[i].name, sizeof(f->description));
884 f->pixelformat = sjpeg_formats[i].fourcc;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300885
886 return 0;
887}
888
889static int s5p_jpeg_enum_fmt_vid_cap(struct file *file, void *priv,
890 struct v4l2_fmtdesc *f)
891{
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300892 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300893
894 if (ctx->mode == S5P_JPEG_ENCODE)
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300895 return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
896 SJPEG_FMT_FLAG_ENC_CAPTURE);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300897
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300898 return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
899 SJPEG_FMT_FLAG_DEC_CAPTURE);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300900}
901
902static int s5p_jpeg_enum_fmt_vid_out(struct file *file, void *priv,
903 struct v4l2_fmtdesc *f)
904{
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300905 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300906
907 if (ctx->mode == S5P_JPEG_ENCODE)
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300908 return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
909 SJPEG_FMT_FLAG_ENC_OUTPUT);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300910
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300911 return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
912 SJPEG_FMT_FLAG_DEC_OUTPUT);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300913}
914
915static struct s5p_jpeg_q_data *get_q_data(struct s5p_jpeg_ctx *ctx,
916 enum v4l2_buf_type type)
917{
918 if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
919 return &ctx->out_q;
920 if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
921 return &ctx->cap_q;
922
923 return NULL;
924}
925
926static int s5p_jpeg_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
927{
928 struct vb2_queue *vq;
929 struct s5p_jpeg_q_data *q_data = NULL;
930 struct v4l2_pix_format *pix = &f->fmt.pix;
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300931 struct s5p_jpeg_ctx *ct = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300932
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -0300933 vq = v4l2_m2m_get_vq(ct->fh.m2m_ctx, f->type);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300934 if (!vq)
935 return -EINVAL;
936
937 if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
938 ct->mode == S5P_JPEG_DECODE && !ct->hdr_parsed)
939 return -EINVAL;
940 q_data = get_q_data(ct, f->type);
941 BUG_ON(q_data == NULL);
942
943 pix->width = q_data->w;
944 pix->height = q_data->h;
945 pix->field = V4L2_FIELD_NONE;
946 pix->pixelformat = q_data->fmt->fourcc;
947 pix->bytesperline = 0;
948 if (q_data->fmt->fourcc != V4L2_PIX_FMT_JPEG) {
949 u32 bpl = q_data->w;
950 if (q_data->fmt->colplanes == 1)
951 bpl = (bpl * q_data->fmt->depth) >> 3;
952 pix->bytesperline = bpl;
953 }
954 pix->sizeimage = q_data->size;
955
956 return 0;
957}
958
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300959static struct s5p_jpeg_fmt *s5p_jpeg_find_format(struct s5p_jpeg_ctx *ctx,
960 u32 pixelformat, unsigned int fmt_type)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300961{
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300962 unsigned int k, fmt_flag, ver_flag;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300963
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300964 if (ctx->mode == S5P_JPEG_ENCODE)
965 fmt_flag = (fmt_type == FMT_TYPE_OUTPUT) ?
966 SJPEG_FMT_FLAG_ENC_OUTPUT :
967 SJPEG_FMT_FLAG_ENC_CAPTURE;
968 else
969 fmt_flag = (fmt_type == FMT_TYPE_OUTPUT) ?
970 SJPEG_FMT_FLAG_DEC_OUTPUT :
971 SJPEG_FMT_FLAG_DEC_CAPTURE;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300972
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300973 if (ctx->jpeg->variant->version == SJPEG_S5P)
974 ver_flag = SJPEG_FMT_FLAG_S5P;
975 else
976 ver_flag = SJPEG_FMT_FLAG_EXYNOS4;
977
978 for (k = 0; k < ARRAY_SIZE(sjpeg_formats); k++) {
979 struct s5p_jpeg_fmt *fmt = &sjpeg_formats[k];
980 if (fmt->fourcc == pixelformat &&
981 fmt->flags & fmt_flag &&
982 fmt->flags & ver_flag) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300983 return fmt;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300984 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300985 }
986
987 return NULL;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300988}
989
990static void jpeg_bound_align_image(u32 *w, unsigned int wmin, unsigned int wmax,
991 unsigned int walign,
992 u32 *h, unsigned int hmin, unsigned int hmax,
993 unsigned int halign)
994{
995 int width, height, w_step, h_step;
996
997 width = *w;
998 height = *h;
999
1000 w_step = 1 << walign;
1001 h_step = 1 << halign;
1002 v4l_bound_align_image(w, wmin, wmax, walign, h, hmin, hmax, halign, 0);
1003
1004 if (*w < width && (*w + w_step) < wmax)
1005 *w += w_step;
1006 if (*h < height && (*h + h_step) < hmax)
1007 *h += h_step;
1008
1009}
1010
1011static int vidioc_try_fmt(struct v4l2_format *f, struct s5p_jpeg_fmt *fmt,
1012 struct s5p_jpeg_ctx *ctx, int q_type)
1013{
1014 struct v4l2_pix_format *pix = &f->fmt.pix;
1015
1016 if (pix->field == V4L2_FIELD_ANY)
1017 pix->field = V4L2_FIELD_NONE;
1018 else if (pix->field != V4L2_FIELD_NONE)
1019 return -EINVAL;
1020
1021 /* V4L2 specification suggests the driver corrects the format struct
1022 * if any of the dimensions is unsupported */
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001023 if (q_type == FMT_TYPE_OUTPUT)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001024 jpeg_bound_align_image(&pix->width, S5P_JPEG_MIN_WIDTH,
1025 S5P_JPEG_MAX_WIDTH, 0,
1026 &pix->height, S5P_JPEG_MIN_HEIGHT,
1027 S5P_JPEG_MAX_HEIGHT, 0);
1028 else
1029 jpeg_bound_align_image(&pix->width, S5P_JPEG_MIN_WIDTH,
1030 S5P_JPEG_MAX_WIDTH, fmt->h_align,
1031 &pix->height, S5P_JPEG_MIN_HEIGHT,
1032 S5P_JPEG_MAX_HEIGHT, fmt->v_align);
1033
1034 if (fmt->fourcc == V4L2_PIX_FMT_JPEG) {
1035 if (pix->sizeimage <= 0)
1036 pix->sizeimage = PAGE_SIZE;
1037 pix->bytesperline = 0;
1038 } else {
1039 u32 bpl = pix->bytesperline;
1040
1041 if (fmt->colplanes > 1 && bpl < pix->width)
1042 bpl = pix->width; /* planar */
1043
1044 if (fmt->colplanes == 1 && /* packed */
Jacek Anaszewskicc690902013-11-25 06:58:10 -03001045 (bpl << 3) / fmt->depth < pix->width)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001046 bpl = (pix->width * fmt->depth) >> 3;
1047
1048 pix->bytesperline = bpl;
1049 pix->sizeimage = (pix->width * pix->height * fmt->depth) >> 3;
1050 }
1051
1052 return 0;
1053}
1054
1055static int s5p_jpeg_try_fmt_vid_cap(struct file *file, void *priv,
1056 struct v4l2_format *f)
1057{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001058 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Jacek Anaszewski337777a2013-11-22 06:13:34 -03001059 struct v4l2_pix_format *pix = &f->fmt.pix;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001060 struct s5p_jpeg_fmt *fmt;
Jacek Anaszewski337777a2013-11-22 06:13:34 -03001061 int ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001062
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001063 fmt = s5p_jpeg_find_format(ctx, f->fmt.pix.pixelformat,
1064 FMT_TYPE_CAPTURE);
1065 if (!fmt) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001066 v4l2_err(&ctx->jpeg->v4l2_dev,
1067 "Fourcc format (0x%08x) invalid.\n",
1068 f->fmt.pix.pixelformat);
1069 return -EINVAL;
1070 }
1071
Jacek Anaszewski337777a2013-11-22 06:13:34 -03001072 /*
1073 * The exynos4x12 device requires resulting YUV image
1074 * subsampling not to be lower than the input jpeg subsampling.
1075 * If this requirement is not met then downgrade the requested
1076 * capture format to the one with subsampling equal to the input jpeg.
1077 */
1078 if ((ctx->jpeg->variant->version != SJPEG_S5P) &&
1079 (ctx->mode == S5P_JPEG_DECODE) &&
1080 (fmt->flags & SJPEG_FMT_NON_RGB) &&
1081 (fmt->subsampling < ctx->subsampling)) {
1082 ret = s5p_jpeg_adjust_fourcc_to_subsampling(ctx->subsampling,
1083 fmt->fourcc,
1084 &pix->pixelformat,
1085 ctx);
1086 if (ret < 0)
1087 pix->pixelformat = V4L2_PIX_FMT_GREY;
1088
1089 fmt = s5p_jpeg_find_format(ctx, pix->pixelformat,
1090 FMT_TYPE_CAPTURE);
1091 }
1092
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001093 return vidioc_try_fmt(f, fmt, ctx, FMT_TYPE_CAPTURE);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001094}
1095
1096static int s5p_jpeg_try_fmt_vid_out(struct file *file, void *priv,
1097 struct v4l2_format *f)
1098{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001099 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001100 struct s5p_jpeg_fmt *fmt;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001101
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001102 fmt = s5p_jpeg_find_format(ctx, f->fmt.pix.pixelformat,
1103 FMT_TYPE_OUTPUT);
1104 if (!fmt) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001105 v4l2_err(&ctx->jpeg->v4l2_dev,
1106 "Fourcc format (0x%08x) invalid.\n",
1107 f->fmt.pix.pixelformat);
1108 return -EINVAL;
1109 }
1110
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001111 return vidioc_try_fmt(f, fmt, ctx, FMT_TYPE_OUTPUT);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001112}
1113
1114static int s5p_jpeg_s_fmt(struct s5p_jpeg_ctx *ct, struct v4l2_format *f)
1115{
1116 struct vb2_queue *vq;
1117 struct s5p_jpeg_q_data *q_data = NULL;
1118 struct v4l2_pix_format *pix = &f->fmt.pix;
Jacek Anaszewski4a30d302013-11-21 13:33:52 -03001119 struct v4l2_ctrl *ctrl_subs;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001120 unsigned int f_type;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001121
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001122 vq = v4l2_m2m_get_vq(ct->fh.m2m_ctx, f->type);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001123 if (!vq)
1124 return -EINVAL;
1125
1126 q_data = get_q_data(ct, f->type);
1127 BUG_ON(q_data == NULL);
1128
1129 if (vb2_is_busy(vq)) {
1130 v4l2_err(&ct->jpeg->v4l2_dev, "%s queue busy\n", __func__);
1131 return -EBUSY;
1132 }
1133
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001134 f_type = V4L2_TYPE_IS_OUTPUT(f->type) ?
1135 FMT_TYPE_OUTPUT : FMT_TYPE_CAPTURE;
1136
1137 q_data->fmt = s5p_jpeg_find_format(ct, pix->pixelformat, f_type);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001138 q_data->w = pix->width;
1139 q_data->h = pix->height;
1140 if (q_data->fmt->fourcc != V4L2_PIX_FMT_JPEG)
1141 q_data->size = q_data->w * q_data->h * q_data->fmt->depth >> 3;
1142 else
1143 q_data->size = pix->sizeimage;
1144
Jacek Anaszewski4a30d302013-11-21 13:33:52 -03001145 if (f_type == FMT_TYPE_OUTPUT) {
1146 ctrl_subs = v4l2_ctrl_find(&ct->ctrl_handler,
1147 V4L2_CID_JPEG_CHROMA_SUBSAMPLING);
1148 if (ctrl_subs)
1149 v4l2_ctrl_s_ctrl(ctrl_subs, q_data->fmt->subsampling);
1150 }
1151
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001152 return 0;
1153}
1154
1155static int s5p_jpeg_s_fmt_vid_cap(struct file *file, void *priv,
1156 struct v4l2_format *f)
1157{
1158 int ret;
1159
1160 ret = s5p_jpeg_try_fmt_vid_cap(file, priv, f);
1161 if (ret)
1162 return ret;
1163
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001164 return s5p_jpeg_s_fmt(fh_to_ctx(priv), f);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001165}
1166
1167static int s5p_jpeg_s_fmt_vid_out(struct file *file, void *priv,
1168 struct v4l2_format *f)
1169{
1170 int ret;
1171
1172 ret = s5p_jpeg_try_fmt_vid_out(file, priv, f);
1173 if (ret)
1174 return ret;
1175
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001176 return s5p_jpeg_s_fmt(fh_to_ctx(priv), f);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001177}
1178
Sachin Kamat9f3bd322012-05-10 03:38:40 -03001179static int s5p_jpeg_g_selection(struct file *file, void *priv,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001180 struct v4l2_selection *s)
1181{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001182 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001183
1184 if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001185 s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
1186 ctx->jpeg->variant->version != SJPEG_S5P)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001187 return -EINVAL;
1188
1189 /* For JPEG blob active == default == bounds */
1190 switch (s->target) {
Sylwester Nawrockic1334822012-05-20 11:17:12 -03001191 case V4L2_SEL_TGT_CROP:
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001192 case V4L2_SEL_TGT_CROP_BOUNDS:
1193 case V4L2_SEL_TGT_CROP_DEFAULT:
Sylwester Nawrockic1334822012-05-20 11:17:12 -03001194 case V4L2_SEL_TGT_COMPOSE:
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001195 case V4L2_SEL_TGT_COMPOSE_DEFAULT:
1196 s->r.width = ctx->out_q.w;
1197 s->r.height = ctx->out_q.h;
1198 break;
1199 case V4L2_SEL_TGT_COMPOSE_BOUNDS:
1200 case V4L2_SEL_TGT_COMPOSE_PADDED:
1201 s->r.width = ctx->cap_q.w;
1202 s->r.height = ctx->cap_q.h;
1203 break;
1204 default:
1205 return -EINVAL;
1206 }
1207 s->r.left = 0;
1208 s->r.top = 0;
1209 return 0;
1210}
1211
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001212/*
1213 * V4L2 controls
1214 */
1215
1216static int s5p_jpeg_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001217{
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001218 struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
1219 struct s5p_jpeg *jpeg = ctx->jpeg;
1220 unsigned long flags;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001221
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001222 switch (ctrl->id) {
1223 case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
1224 spin_lock_irqsave(&jpeg->slock, flags);
Jacek Anaszewski303b0a92013-12-18 11:14:00 -03001225 ctrl->val = s5p_jpeg_to_user_subsampling(ctx);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001226 spin_unlock_irqrestore(&jpeg->slock, flags);
1227 break;
1228 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001229
1230 return 0;
1231}
1232
Jacek Anaszewski11fbea32013-11-21 13:34:01 -03001233static int s5p_jpeg_try_ctrl(struct v4l2_ctrl *ctrl)
1234{
1235 struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
1236 unsigned long flags;
1237 int ret = 0;
1238
1239 spin_lock_irqsave(&ctx->jpeg->slock, flags);
1240
1241 if (ctrl->id == V4L2_CID_JPEG_CHROMA_SUBSAMPLING) {
1242 if (ctx->jpeg->variant->version == SJPEG_S5P)
1243 goto error_free;
1244 /*
1245 * The exynos4x12 device requires input raw image fourcc
1246 * to be V4L2_PIX_FMT_GREY if gray jpeg format
1247 * is to be set.
1248 */
1249 if (ctx->out_q.fmt->fourcc != V4L2_PIX_FMT_GREY &&
1250 ctrl->val == V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY) {
1251 ret = -EINVAL;
1252 goto error_free;
1253 }
1254 /*
1255 * The exynos4x12 device requires resulting jpeg subsampling
1256 * not to be lower than the input raw image subsampling.
1257 */
1258 if (ctx->out_q.fmt->subsampling > ctrl->val)
1259 ctrl->val = ctx->out_q.fmt->subsampling;
1260 }
1261
1262error_free:
1263 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
1264 return ret;
1265}
1266
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001267static int s5p_jpeg_s_ctrl(struct v4l2_ctrl *ctrl)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001268{
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001269 struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
1270 unsigned long flags;
1271
1272 spin_lock_irqsave(&ctx->jpeg->slock, flags);
1273
1274 switch (ctrl->id) {
1275 case V4L2_CID_JPEG_COMPRESSION_QUALITY:
Jacek Anaszewski78e5a3c2013-11-25 06:58:08 -03001276 ctx->compr_quality = ctrl->val;
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001277 break;
1278 case V4L2_CID_JPEG_RESTART_INTERVAL:
1279 ctx->restart_interval = ctrl->val;
1280 break;
1281 case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
1282 ctx->subsampling = ctrl->val;
1283 break;
1284 }
1285
1286 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
1287 return 0;
1288}
1289
1290static const struct v4l2_ctrl_ops s5p_jpeg_ctrl_ops = {
1291 .g_volatile_ctrl = s5p_jpeg_g_volatile_ctrl,
Jacek Anaszewski11fbea32013-11-21 13:34:01 -03001292 .try_ctrl = s5p_jpeg_try_ctrl,
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001293 .s_ctrl = s5p_jpeg_s_ctrl,
1294};
1295
1296static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx)
1297{
1298 unsigned int mask = ~0x27; /* 444, 422, 420, GRAY */
1299 struct v4l2_ctrl *ctrl;
Jacek Anaszewski088f8302013-11-25 06:58:15 -03001300 int ret;
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001301
1302 v4l2_ctrl_handler_init(&ctx->ctrl_handler, 3);
1303
1304 if (ctx->mode == S5P_JPEG_ENCODE) {
1305 v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
1306 V4L2_CID_JPEG_COMPRESSION_QUALITY,
Jacek Anaszewski78e5a3c2013-11-25 06:58:08 -03001307 0, 3, 1, S5P_JPEG_COMPR_QUAL_WORST);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001308
1309 v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
1310 V4L2_CID_JPEG_RESTART_INTERVAL,
1311 0, 3, 0xffff, 0);
Jacek Anaszewskifdf9e2b2013-11-21 13:33:41 -03001312 if (ctx->jpeg->variant->version == SJPEG_S5P)
1313 mask = ~0x06; /* 422, 420 */
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001314 }
1315
1316 ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
1317 V4L2_CID_JPEG_CHROMA_SUBSAMPLING,
1318 V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY, mask,
1319 V4L2_JPEG_CHROMA_SUBSAMPLING_422);
1320
Jacek Anaszewski088f8302013-11-25 06:58:15 -03001321 if (ctx->ctrl_handler.error) {
1322 ret = ctx->ctrl_handler.error;
1323 goto error_free;
1324 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001325
1326 if (ctx->mode == S5P_JPEG_DECODE)
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001327 ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE |
1328 V4L2_CTRL_FLAG_READ_ONLY;
Jacek Anaszewski088f8302013-11-25 06:58:15 -03001329
1330 ret = v4l2_ctrl_handler_setup(&ctx->ctrl_handler);
1331 if (ret < 0)
1332 goto error_free;
1333
1334 return ret;
1335
1336error_free:
1337 v4l2_ctrl_handler_free(&ctx->ctrl_handler);
1338 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001339}
1340
1341static const struct v4l2_ioctl_ops s5p_jpeg_ioctl_ops = {
1342 .vidioc_querycap = s5p_jpeg_querycap,
1343
1344 .vidioc_enum_fmt_vid_cap = s5p_jpeg_enum_fmt_vid_cap,
1345 .vidioc_enum_fmt_vid_out = s5p_jpeg_enum_fmt_vid_out,
1346
1347 .vidioc_g_fmt_vid_cap = s5p_jpeg_g_fmt,
1348 .vidioc_g_fmt_vid_out = s5p_jpeg_g_fmt,
1349
1350 .vidioc_try_fmt_vid_cap = s5p_jpeg_try_fmt_vid_cap,
1351 .vidioc_try_fmt_vid_out = s5p_jpeg_try_fmt_vid_out,
1352
1353 .vidioc_s_fmt_vid_cap = s5p_jpeg_s_fmt_vid_cap,
1354 .vidioc_s_fmt_vid_out = s5p_jpeg_s_fmt_vid_out,
1355
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001356 .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
1357 .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
1358 .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
1359 .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001360
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001361 .vidioc_streamon = v4l2_m2m_ioctl_streamon,
1362 .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001363
1364 .vidioc_g_selection = s5p_jpeg_g_selection,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001365};
1366
1367/*
1368 * ============================================================================
1369 * mem2mem callbacks
1370 * ============================================================================
1371 */
1372
1373static void s5p_jpeg_device_run(void *priv)
1374{
1375 struct s5p_jpeg_ctx *ctx = priv;
1376 struct s5p_jpeg *jpeg = ctx->jpeg;
1377 struct vb2_buffer *src_buf, *dst_buf;
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03001378 unsigned long src_addr, dst_addr, flags;
1379
1380 spin_lock_irqsave(&ctx->jpeg->slock, flags);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001381
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001382 src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
1383 dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001384 src_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0);
1385 dst_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
1386
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001387 s5p_jpeg_reset(jpeg->regs);
1388 s5p_jpeg_poweron(jpeg->regs);
1389 s5p_jpeg_proc_mode(jpeg->regs, ctx->mode);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001390 if (ctx->mode == S5P_JPEG_ENCODE) {
1391 if (ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB565)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001392 s5p_jpeg_input_raw_mode(jpeg->regs,
1393 S5P_JPEG_RAW_IN_565);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001394 else
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001395 s5p_jpeg_input_raw_mode(jpeg->regs,
1396 S5P_JPEG_RAW_IN_422);
1397 s5p_jpeg_subsampling_mode(jpeg->regs, ctx->subsampling);
1398 s5p_jpeg_dri(jpeg->regs, ctx->restart_interval);
1399 s5p_jpeg_x(jpeg->regs, ctx->out_q.w);
1400 s5p_jpeg_y(jpeg->regs, ctx->out_q.h);
1401 s5p_jpeg_imgadr(jpeg->regs, src_addr);
1402 s5p_jpeg_jpgadr(jpeg->regs, dst_addr);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001403
1404 /* ultimately comes from sizeimage from userspace */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001405 s5p_jpeg_enc_stream_int(jpeg->regs, ctx->cap_q.size);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001406
1407 /* JPEG RGB to YCbCr conversion matrix */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001408 s5p_jpeg_coef(jpeg->regs, 1, 1, S5P_JPEG_COEF11);
1409 s5p_jpeg_coef(jpeg->regs, 1, 2, S5P_JPEG_COEF12);
1410 s5p_jpeg_coef(jpeg->regs, 1, 3, S5P_JPEG_COEF13);
1411 s5p_jpeg_coef(jpeg->regs, 2, 1, S5P_JPEG_COEF21);
1412 s5p_jpeg_coef(jpeg->regs, 2, 2, S5P_JPEG_COEF22);
1413 s5p_jpeg_coef(jpeg->regs, 2, 3, S5P_JPEG_COEF23);
1414 s5p_jpeg_coef(jpeg->regs, 3, 1, S5P_JPEG_COEF31);
1415 s5p_jpeg_coef(jpeg->regs, 3, 2, S5P_JPEG_COEF32);
1416 s5p_jpeg_coef(jpeg->regs, 3, 3, S5P_JPEG_COEF33);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001417
1418 /*
1419 * JPEG IP allows storing 4 quantization tables
1420 * We fill table 0 for luma and table 1 for chroma
1421 */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -03001422 s5p_jpeg_set_qtbl_lum(jpeg->regs, ctx->compr_quality);
1423 s5p_jpeg_set_qtbl_chr(jpeg->regs, ctx->compr_quality);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001424 /* use table 0 for Y */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001425 s5p_jpeg_qtbl(jpeg->regs, 1, 0);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001426 /* use table 1 for Cb and Cr*/
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001427 s5p_jpeg_qtbl(jpeg->regs, 2, 1);
1428 s5p_jpeg_qtbl(jpeg->regs, 3, 1);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001429
1430 /* Y, Cb, Cr use Huffman table 0 */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001431 s5p_jpeg_htbl_ac(jpeg->regs, 1);
1432 s5p_jpeg_htbl_dc(jpeg->regs, 1);
1433 s5p_jpeg_htbl_ac(jpeg->regs, 2);
1434 s5p_jpeg_htbl_dc(jpeg->regs, 2);
1435 s5p_jpeg_htbl_ac(jpeg->regs, 3);
1436 s5p_jpeg_htbl_dc(jpeg->regs, 3);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03001437 } else { /* S5P_JPEG_DECODE */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001438 s5p_jpeg_rst_int_enable(jpeg->regs, true);
1439 s5p_jpeg_data_num_int_enable(jpeg->regs, true);
1440 s5p_jpeg_final_mcu_num_int_enable(jpeg->regs, true);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03001441 if (ctx->cap_q.fmt->fourcc == V4L2_PIX_FMT_YUYV)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001442 s5p_jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_422);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03001443 else
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001444 s5p_jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_420);
1445 s5p_jpeg_jpgadr(jpeg->regs, src_addr);
1446 s5p_jpeg_imgadr(jpeg->regs, dst_addr);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001447 }
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001448
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001449 s5p_jpeg_start(jpeg->regs);
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03001450
1451 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001452}
1453
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001454static void exynos4_jpeg_set_img_addr(struct s5p_jpeg_ctx *ctx)
1455{
1456 struct s5p_jpeg *jpeg = ctx->jpeg;
1457 struct s5p_jpeg_fmt *fmt;
1458 struct vb2_buffer *vb;
1459 struct s5p_jpeg_addr jpeg_addr;
1460 u32 pix_size, padding_bytes = 0;
1461
1462 pix_size = ctx->cap_q.w * ctx->cap_q.h;
1463
1464 if (ctx->mode == S5P_JPEG_ENCODE) {
1465 vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
1466 fmt = ctx->out_q.fmt;
1467 if (ctx->out_q.w % 2 && fmt->h_align > 0)
1468 padding_bytes = ctx->out_q.h;
1469 } else {
1470 fmt = ctx->cap_q.fmt;
1471 vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
1472 }
1473
1474 jpeg_addr.y = vb2_dma_contig_plane_dma_addr(vb, 0);
1475
1476 if (fmt->colplanes == 2) {
1477 jpeg_addr.cb = jpeg_addr.y + pix_size - padding_bytes;
1478 } else if (fmt->colplanes == 3) {
1479 jpeg_addr.cb = jpeg_addr.y + pix_size;
1480 if (fmt->fourcc == V4L2_PIX_FMT_YUV420)
1481 jpeg_addr.cr = jpeg_addr.cb + pix_size / 4;
1482 else
1483 jpeg_addr.cr = jpeg_addr.cb + pix_size / 2;
1484 }
1485
1486 exynos4_jpeg_set_frame_buf_address(jpeg->regs, &jpeg_addr);
1487}
1488
1489static void exynos4_jpeg_set_jpeg_addr(struct s5p_jpeg_ctx *ctx)
1490{
1491 struct s5p_jpeg *jpeg = ctx->jpeg;
1492 struct vb2_buffer *vb;
1493 unsigned int jpeg_addr = 0;
1494
1495 if (ctx->mode == S5P_JPEG_ENCODE)
1496 vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
1497 else
1498 vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
1499
1500 jpeg_addr = vb2_dma_contig_plane_dma_addr(vb, 0);
1501 exynos4_jpeg_set_stream_buf_address(jpeg->regs, jpeg_addr);
1502}
1503
1504static void exynos4_jpeg_device_run(void *priv)
1505{
1506 struct s5p_jpeg_ctx *ctx = priv;
1507 struct s5p_jpeg *jpeg = ctx->jpeg;
1508 unsigned int bitstream_size;
1509 unsigned long flags;
1510
1511 spin_lock_irqsave(&ctx->jpeg->slock, flags);
1512
1513 if (ctx->mode == S5P_JPEG_ENCODE) {
1514 exynos4_jpeg_sw_reset(jpeg->regs);
1515 exynos4_jpeg_set_interrupt(jpeg->regs);
1516 exynos4_jpeg_set_huf_table_enable(jpeg->regs, 1);
1517
1518 exynos4_jpeg_set_huff_tbl(jpeg->regs);
1519
1520 /*
1521 * JPEG IP allows storing 4 quantization tables
1522 * We fill table 0 for luma and table 1 for chroma
1523 */
1524 exynos4_jpeg_set_qtbl_lum(jpeg->regs, ctx->compr_quality);
1525 exynos4_jpeg_set_qtbl_chr(jpeg->regs, ctx->compr_quality);
1526
1527 exynos4_jpeg_set_encode_tbl_select(jpeg->regs,
1528 ctx->compr_quality);
1529 exynos4_jpeg_set_stream_size(jpeg->regs, ctx->cap_q.w,
1530 ctx->cap_q.h);
1531
1532 exynos4_jpeg_set_enc_out_fmt(jpeg->regs, ctx->subsampling);
1533 exynos4_jpeg_set_img_fmt(jpeg->regs, ctx->out_q.fmt->fourcc);
1534 exynos4_jpeg_set_img_addr(ctx);
1535 exynos4_jpeg_set_jpeg_addr(ctx);
1536 exynos4_jpeg_set_encode_hoff_cnt(jpeg->regs,
1537 ctx->out_q.fmt->fourcc);
1538 } else {
1539 exynos4_jpeg_sw_reset(jpeg->regs);
1540 exynos4_jpeg_set_interrupt(jpeg->regs);
1541 exynos4_jpeg_set_img_addr(ctx);
1542 exynos4_jpeg_set_jpeg_addr(ctx);
1543 exynos4_jpeg_set_img_fmt(jpeg->regs, ctx->cap_q.fmt->fourcc);
1544
1545 bitstream_size = DIV_ROUND_UP(ctx->out_q.size, 32);
1546
1547 exynos4_jpeg_set_dec_bitstream_size(jpeg->regs, bitstream_size);
1548 }
1549
1550 exynos4_jpeg_set_enc_dec_mode(jpeg->regs, ctx->mode);
1551
1552 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
1553}
1554
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001555static int s5p_jpeg_job_ready(void *priv)
1556{
1557 struct s5p_jpeg_ctx *ctx = priv;
1558
1559 if (ctx->mode == S5P_JPEG_DECODE)
1560 return ctx->hdr_parsed;
1561 return 1;
1562}
1563
1564static void s5p_jpeg_job_abort(void *priv)
1565{
1566}
1567
1568static struct v4l2_m2m_ops s5p_jpeg_m2m_ops = {
1569 .device_run = s5p_jpeg_device_run,
1570 .job_ready = s5p_jpeg_job_ready,
1571 .job_abort = s5p_jpeg_job_abort,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001572}
1573;
1574static struct v4l2_m2m_ops exynos_jpeg_m2m_ops = {
1575 .device_run = exynos4_jpeg_device_run,
1576 .job_ready = s5p_jpeg_job_ready,
1577 .job_abort = s5p_jpeg_job_abort,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001578};
1579
1580/*
1581 * ============================================================================
1582 * Queue operations
1583 * ============================================================================
1584 */
1585
Marek Szyprowski719c1742012-01-13 05:12:38 -03001586static int s5p_jpeg_queue_setup(struct vb2_queue *vq,
1587 const struct v4l2_format *fmt,
1588 unsigned int *nbuffers, unsigned int *nplanes,
1589 unsigned int sizes[], void *alloc_ctxs[])
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001590{
1591 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vq);
1592 struct s5p_jpeg_q_data *q_data = NULL;
1593 unsigned int size, count = *nbuffers;
1594
1595 q_data = get_q_data(ctx, vq->type);
1596 BUG_ON(q_data == NULL);
1597
1598 size = q_data->size;
1599
1600 /*
1601 * header is parsed during decoding and parsed information stored
1602 * in the context so we do not allow another buffer to overwrite it
1603 */
1604 if (ctx->mode == S5P_JPEG_DECODE)
1605 count = 1;
1606
1607 *nbuffers = count;
1608 *nplanes = 1;
1609 sizes[0] = size;
1610 alloc_ctxs[0] = ctx->jpeg->alloc_ctx;
1611
1612 return 0;
1613}
1614
1615static int s5p_jpeg_buf_prepare(struct vb2_buffer *vb)
1616{
1617 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
1618 struct s5p_jpeg_q_data *q_data = NULL;
1619
1620 q_data = get_q_data(ctx, vb->vb2_queue->type);
1621 BUG_ON(q_data == NULL);
1622
1623 if (vb2_plane_size(vb, 0) < q_data->size) {
1624 pr_err("%s data will not fit into plane (%lu < %lu)\n",
1625 __func__, vb2_plane_size(vb, 0),
1626 (long)q_data->size);
1627 return -EINVAL;
1628 }
1629
1630 vb2_set_plane_payload(vb, 0, q_data->size);
1631
1632 return 0;
1633}
1634
1635static void s5p_jpeg_buf_queue(struct vb2_buffer *vb)
1636{
1637 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
1638
1639 if (ctx->mode == S5P_JPEG_DECODE &&
1640 vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
1641 struct s5p_jpeg_q_data tmp, *q_data;
1642 ctx->hdr_parsed = s5p_jpeg_parse_hdr(&tmp,
1643 (unsigned long)vb2_plane_vaddr(vb, 0),
1644 min((unsigned long)ctx->out_q.size,
Jacek Anaszewskif8433962013-11-21 13:33:09 -03001645 vb2_get_plane_payload(vb, 0)), ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001646 if (!ctx->hdr_parsed) {
1647 vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
1648 return;
1649 }
1650
1651 q_data = &ctx->out_q;
1652 q_data->w = tmp.w;
1653 q_data->h = tmp.h;
1654
1655 q_data = &ctx->cap_q;
1656 q_data->w = tmp.w;
1657 q_data->h = tmp.h;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001658 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001659
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001660 v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001661}
1662
1663static int s5p_jpeg_start_streaming(struct vb2_queue *q, unsigned int count)
1664{
1665 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(q);
1666 int ret;
1667
1668 ret = pm_runtime_get_sync(ctx->jpeg->dev);
1669
1670 return ret > 0 ? 0 : ret;
1671}
1672
1673static int s5p_jpeg_stop_streaming(struct vb2_queue *q)
1674{
1675 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(q);
1676
1677 pm_runtime_put(ctx->jpeg->dev);
1678
1679 return 0;
1680}
1681
1682static struct vb2_ops s5p_jpeg_qops = {
1683 .queue_setup = s5p_jpeg_queue_setup,
1684 .buf_prepare = s5p_jpeg_buf_prepare,
1685 .buf_queue = s5p_jpeg_buf_queue,
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001686 .wait_prepare = vb2_ops_wait_prepare,
1687 .wait_finish = vb2_ops_wait_finish,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001688 .start_streaming = s5p_jpeg_start_streaming,
1689 .stop_streaming = s5p_jpeg_stop_streaming,
1690};
1691
1692static int queue_init(void *priv, struct vb2_queue *src_vq,
1693 struct vb2_queue *dst_vq)
1694{
1695 struct s5p_jpeg_ctx *ctx = priv;
1696 int ret;
1697
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001698 src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
1699 src_vq->io_modes = VB2_MMAP | VB2_USERPTR;
1700 src_vq->drv_priv = ctx;
1701 src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
1702 src_vq->ops = &s5p_jpeg_qops;
1703 src_vq->mem_ops = &vb2_dma_contig_memops;
Kamil Debskiaca326a2013-04-24 10:08:02 -03001704 src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001705 src_vq->lock = &ctx->jpeg->lock;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001706
1707 ret = vb2_queue_init(src_vq);
1708 if (ret)
1709 return ret;
1710
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001711 dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1712 dst_vq->io_modes = VB2_MMAP | VB2_USERPTR;
1713 dst_vq->drv_priv = ctx;
1714 dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
1715 dst_vq->ops = &s5p_jpeg_qops;
1716 dst_vq->mem_ops = &vb2_dma_contig_memops;
Kamil Debskiaca326a2013-04-24 10:08:02 -03001717 dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001718 dst_vq->lock = &ctx->jpeg->lock;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001719
1720 return vb2_queue_init(dst_vq);
1721}
1722
1723/*
1724 * ============================================================================
1725 * ISR
1726 * ============================================================================
1727 */
1728
1729static irqreturn_t s5p_jpeg_irq(int irq, void *dev_id)
1730{
1731 struct s5p_jpeg *jpeg = dev_id;
1732 struct s5p_jpeg_ctx *curr_ctx;
1733 struct vb2_buffer *src_buf, *dst_buf;
1734 unsigned long payload_size = 0;
1735 enum vb2_buffer_state state = VB2_BUF_STATE_DONE;
1736 bool enc_jpeg_too_large = false;
1737 bool timer_elapsed = false;
1738 bool op_completed = false;
1739
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001740 spin_lock(&jpeg->slock);
1741
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001742 curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
1743
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001744 src_buf = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
1745 dst_buf = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001746
1747 if (curr_ctx->mode == S5P_JPEG_ENCODE)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001748 enc_jpeg_too_large = s5p_jpeg_enc_stream_stat(jpeg->regs);
1749 timer_elapsed = s5p_jpeg_timer_stat(jpeg->regs);
1750 op_completed = s5p_jpeg_result_stat_ok(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001751 if (curr_ctx->mode == S5P_JPEG_DECODE)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001752 op_completed = op_completed &&
1753 s5p_jpeg_stream_stat_ok(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001754
1755 if (enc_jpeg_too_large) {
1756 state = VB2_BUF_STATE_ERROR;
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001757 s5p_jpeg_clear_enc_stream_stat(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001758 } else if (timer_elapsed) {
1759 state = VB2_BUF_STATE_ERROR;
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001760 s5p_jpeg_clear_timer_stat(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001761 } else if (!op_completed) {
1762 state = VB2_BUF_STATE_ERROR;
1763 } else {
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001764 payload_size = s5p_jpeg_compressed_size(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001765 }
1766
Kamil Debskiaca326a2013-04-24 10:08:02 -03001767 dst_buf->v4l2_buf.timecode = src_buf->v4l2_buf.timecode;
1768 dst_buf->v4l2_buf.timestamp = src_buf->v4l2_buf.timestamp;
1769
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001770 v4l2_m2m_buf_done(src_buf, state);
1771 if (curr_ctx->mode == S5P_JPEG_ENCODE)
1772 vb2_set_plane_payload(dst_buf, 0, payload_size);
1773 v4l2_m2m_buf_done(dst_buf, state);
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001774 v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->fh.m2m_ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001775
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001776 curr_ctx->subsampling = s5p_jpeg_get_subsampling_mode(jpeg->regs);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001777 spin_unlock(&jpeg->slock);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03001778
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001779 s5p_jpeg_clear_int(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001780
1781 return IRQ_HANDLED;
1782}
1783
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001784static irqreturn_t exynos4_jpeg_irq(int irq, void *priv)
1785{
1786 unsigned int int_status;
1787 struct vb2_buffer *src_vb, *dst_vb;
1788 struct s5p_jpeg *jpeg = priv;
1789 struct s5p_jpeg_ctx *curr_ctx;
1790 unsigned long payload_size = 0;
1791
1792 spin_lock(&jpeg->slock);
1793
1794 curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
1795
1796 src_vb = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
1797 dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
1798
1799 int_status = exynos4_jpeg_get_int_status(jpeg->regs);
1800
1801 if (int_status) {
1802 switch (int_status & 0x1f) {
1803 case 0x1:
1804 jpeg->irq_ret = ERR_PROT;
1805 break;
1806 case 0x2:
1807 jpeg->irq_ret = OK_ENC_OR_DEC;
1808 break;
1809 case 0x4:
1810 jpeg->irq_ret = ERR_DEC_INVALID_FORMAT;
1811 break;
1812 case 0x8:
1813 jpeg->irq_ret = ERR_MULTI_SCAN;
1814 break;
1815 case 0x10:
1816 jpeg->irq_ret = ERR_FRAME;
1817 break;
1818 default:
1819 jpeg->irq_ret = ERR_UNKNOWN;
1820 break;
1821 }
1822 } else {
1823 jpeg->irq_ret = ERR_UNKNOWN;
1824 }
1825
1826 if (jpeg->irq_ret == OK_ENC_OR_DEC) {
1827 if (curr_ctx->mode == S5P_JPEG_ENCODE) {
1828 payload_size = exynos4_jpeg_get_stream_size(jpeg->regs);
1829 vb2_set_plane_payload(dst_vb, 0, payload_size);
1830 }
1831 v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
1832 v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
1833 } else {
1834 v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_ERROR);
1835 v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_ERROR);
1836 }
1837
1838 v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->fh.m2m_ctx);
1839 curr_ctx->subsampling = exynos4_jpeg_get_frame_fmt(jpeg->regs);
1840
1841 spin_unlock(&jpeg->slock);
1842 return IRQ_HANDLED;
1843}
1844
1845static void *jpeg_get_drv_data(struct platform_device *pdev);
1846
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001847/*
1848 * ============================================================================
1849 * Driver basic infrastructure
1850 * ============================================================================
1851 */
1852
1853static int s5p_jpeg_probe(struct platform_device *pdev)
1854{
1855 struct s5p_jpeg *jpeg;
1856 struct resource *res;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001857 struct v4l2_m2m_ops *samsung_jpeg_m2m_ops;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001858 int ret;
1859
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001860 if (!pdev->dev.of_node)
1861 return -ENODEV;
1862
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001863 /* JPEG IP abstraction struct */
Sachin Kamat5b58b952012-05-14 06:33:34 -03001864 jpeg = devm_kzalloc(&pdev->dev, sizeof(struct s5p_jpeg), GFP_KERNEL);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001865 if (!jpeg)
1866 return -ENOMEM;
1867
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001868 jpeg->variant = jpeg_get_drv_data(pdev);
1869
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001870 mutex_init(&jpeg->lock);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001871 spin_lock_init(&jpeg->slock);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001872 jpeg->dev = &pdev->dev;
1873
1874 /* memory-mapped registers */
1875 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001876
Thierry Redingf23999e2013-01-21 06:09:07 -03001877 jpeg->regs = devm_ioremap_resource(&pdev->dev, res);
1878 if (IS_ERR(jpeg->regs))
1879 return PTR_ERR(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001880
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001881 /* interrupt service routine registration */
1882 jpeg->irq = ret = platform_get_irq(pdev, 0);
1883 if (ret < 0) {
1884 dev_err(&pdev->dev, "cannot find IRQ\n");
Sachin Kamat5b58b952012-05-14 06:33:34 -03001885 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001886 }
1887
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001888 ret = devm_request_irq(&pdev->dev, jpeg->irq, jpeg->variant->jpeg_irq,
1889 0, dev_name(&pdev->dev), jpeg);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001890 if (ret) {
1891 dev_err(&pdev->dev, "cannot claim IRQ %d\n", jpeg->irq);
Sachin Kamat5b58b952012-05-14 06:33:34 -03001892 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001893 }
1894
1895 /* clocks */
1896 jpeg->clk = clk_get(&pdev->dev, "jpeg");
1897 if (IS_ERR(jpeg->clk)) {
1898 dev_err(&pdev->dev, "cannot get clock\n");
1899 ret = PTR_ERR(jpeg->clk);
Sachin Kamat5b58b952012-05-14 06:33:34 -03001900 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001901 }
1902 dev_dbg(&pdev->dev, "clock source %p\n", jpeg->clk);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001903
1904 /* v4l2 device */
1905 ret = v4l2_device_register(&pdev->dev, &jpeg->v4l2_dev);
1906 if (ret) {
1907 dev_err(&pdev->dev, "Failed to register v4l2 device\n");
1908 goto clk_get_rollback;
1909 }
1910
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001911 if (jpeg->variant->version == SJPEG_S5P)
1912 samsung_jpeg_m2m_ops = &s5p_jpeg_m2m_ops;
1913 else
1914 samsung_jpeg_m2m_ops = &exynos_jpeg_m2m_ops;
1915
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001916 /* mem2mem device */
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001917 jpeg->m2m_dev = v4l2_m2m_init(samsung_jpeg_m2m_ops);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001918 if (IS_ERR(jpeg->m2m_dev)) {
1919 v4l2_err(&jpeg->v4l2_dev, "Failed to init mem2mem device\n");
1920 ret = PTR_ERR(jpeg->m2m_dev);
1921 goto device_register_rollback;
1922 }
1923
1924 jpeg->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
1925 if (IS_ERR(jpeg->alloc_ctx)) {
1926 v4l2_err(&jpeg->v4l2_dev, "Failed to init memory allocator\n");
1927 ret = PTR_ERR(jpeg->alloc_ctx);
1928 goto m2m_init_rollback;
1929 }
1930
1931 /* JPEG encoder /dev/videoX node */
1932 jpeg->vfd_encoder = video_device_alloc();
1933 if (!jpeg->vfd_encoder) {
1934 v4l2_err(&jpeg->v4l2_dev, "Failed to allocate video device\n");
1935 ret = -ENOMEM;
1936 goto vb2_allocator_rollback;
1937 }
Seung-Woo Kimbaaf0462013-10-10 04:45:56 -03001938 snprintf(jpeg->vfd_encoder->name, sizeof(jpeg->vfd_encoder->name),
1939 "%s-enc", S5P_JPEG_M2M_NAME);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001940 jpeg->vfd_encoder->fops = &s5p_jpeg_fops;
1941 jpeg->vfd_encoder->ioctl_ops = &s5p_jpeg_ioctl_ops;
1942 jpeg->vfd_encoder->minor = -1;
1943 jpeg->vfd_encoder->release = video_device_release;
1944 jpeg->vfd_encoder->lock = &jpeg->lock;
1945 jpeg->vfd_encoder->v4l2_dev = &jpeg->v4l2_dev;
Hans Verkuil954f3402012-09-05 06:05:50 -03001946 jpeg->vfd_encoder->vfl_dir = VFL_DIR_M2M;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001947
1948 ret = video_register_device(jpeg->vfd_encoder, VFL_TYPE_GRABBER, -1);
1949 if (ret) {
1950 v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n");
1951 goto enc_vdev_alloc_rollback;
1952 }
1953
1954 video_set_drvdata(jpeg->vfd_encoder, jpeg);
1955 v4l2_info(&jpeg->v4l2_dev,
1956 "encoder device registered as /dev/video%d\n",
1957 jpeg->vfd_encoder->num);
1958
1959 /* JPEG decoder /dev/videoX node */
1960 jpeg->vfd_decoder = video_device_alloc();
1961 if (!jpeg->vfd_decoder) {
1962 v4l2_err(&jpeg->v4l2_dev, "Failed to allocate video device\n");
1963 ret = -ENOMEM;
1964 goto enc_vdev_register_rollback;
1965 }
Seung-Woo Kimbaaf0462013-10-10 04:45:56 -03001966 snprintf(jpeg->vfd_decoder->name, sizeof(jpeg->vfd_decoder->name),
1967 "%s-dec", S5P_JPEG_M2M_NAME);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001968 jpeg->vfd_decoder->fops = &s5p_jpeg_fops;
1969 jpeg->vfd_decoder->ioctl_ops = &s5p_jpeg_ioctl_ops;
1970 jpeg->vfd_decoder->minor = -1;
1971 jpeg->vfd_decoder->release = video_device_release;
1972 jpeg->vfd_decoder->lock = &jpeg->lock;
1973 jpeg->vfd_decoder->v4l2_dev = &jpeg->v4l2_dev;
Jacek Anaszewski7f7d8fe2013-09-11 06:17:45 -03001974 jpeg->vfd_decoder->vfl_dir = VFL_DIR_M2M;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001975
1976 ret = video_register_device(jpeg->vfd_decoder, VFL_TYPE_GRABBER, -1);
1977 if (ret) {
1978 v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n");
1979 goto dec_vdev_alloc_rollback;
1980 }
1981
1982 video_set_drvdata(jpeg->vfd_decoder, jpeg);
1983 v4l2_info(&jpeg->v4l2_dev,
1984 "decoder device registered as /dev/video%d\n",
1985 jpeg->vfd_decoder->num);
1986
1987 /* final statements & power management */
1988 platform_set_drvdata(pdev, jpeg);
1989
1990 pm_runtime_enable(&pdev->dev);
1991
1992 v4l2_info(&jpeg->v4l2_dev, "Samsung S5P JPEG codec\n");
1993
1994 return 0;
1995
1996dec_vdev_alloc_rollback:
1997 video_device_release(jpeg->vfd_decoder);
1998
1999enc_vdev_register_rollback:
2000 video_unregister_device(jpeg->vfd_encoder);
2001
2002enc_vdev_alloc_rollback:
2003 video_device_release(jpeg->vfd_encoder);
2004
2005vb2_allocator_rollback:
2006 vb2_dma_contig_cleanup_ctx(jpeg->alloc_ctx);
2007
2008m2m_init_rollback:
2009 v4l2_m2m_release(jpeg->m2m_dev);
2010
2011device_register_rollback:
2012 v4l2_device_unregister(&jpeg->v4l2_dev);
2013
2014clk_get_rollback:
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002015 clk_put(jpeg->clk);
2016
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002017 return ret;
2018}
2019
2020static int s5p_jpeg_remove(struct platform_device *pdev)
2021{
2022 struct s5p_jpeg *jpeg = platform_get_drvdata(pdev);
2023
2024 pm_runtime_disable(jpeg->dev);
2025
2026 video_unregister_device(jpeg->vfd_decoder);
2027 video_device_release(jpeg->vfd_decoder);
2028 video_unregister_device(jpeg->vfd_encoder);
2029 video_device_release(jpeg->vfd_encoder);
2030 vb2_dma_contig_cleanup_ctx(jpeg->alloc_ctx);
2031 v4l2_m2m_release(jpeg->m2m_dev);
2032 v4l2_device_unregister(&jpeg->v4l2_dev);
2033
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002034 if (!pm_runtime_status_suspended(&pdev->dev))
2035 clk_disable_unprepare(jpeg->clk);
2036
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002037 clk_put(jpeg->clk);
2038
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002039 return 0;
2040}
2041
2042static int s5p_jpeg_runtime_suspend(struct device *dev)
2043{
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002044 struct s5p_jpeg *jpeg = dev_get_drvdata(dev);
2045
2046 clk_disable_unprepare(jpeg->clk);
2047
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002048 return 0;
2049}
2050
2051static int s5p_jpeg_runtime_resume(struct device *dev)
2052{
2053 struct s5p_jpeg *jpeg = dev_get_drvdata(dev);
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03002054 unsigned long flags;
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002055 int ret;
2056
2057 ret = clk_prepare_enable(jpeg->clk);
2058 if (ret < 0)
2059 return ret;
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -03002060
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03002061 spin_lock_irqsave(&jpeg->slock, flags);
2062
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002063 /*
2064 * JPEG IP allows storing two Huffman tables for each component
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002065 * We fill table 0 for each component and do this here only
2066 * for S5PC210 device as Exynos4x12 requires programming its
2067 * Huffman tables each time the encoding process is initialized.
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002068 */
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002069 if (jpeg->variant->version == SJPEG_S5P) {
2070 s5p_jpeg_set_hdctbl(jpeg->regs);
2071 s5p_jpeg_set_hdctblg(jpeg->regs);
2072 s5p_jpeg_set_hactbl(jpeg->regs);
2073 s5p_jpeg_set_hactblg(jpeg->regs);
2074 }
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -03002075
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03002076 spin_unlock_irqrestore(&jpeg->slock, flags);
2077
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002078 return 0;
2079}
2080
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002081static int s5p_jpeg_suspend(struct device *dev)
2082{
2083 if (pm_runtime_suspended(dev))
2084 return 0;
2085
2086 return s5p_jpeg_runtime_suspend(dev);
2087}
2088
2089static int s5p_jpeg_resume(struct device *dev)
2090{
2091 if (pm_runtime_suspended(dev))
2092 return 0;
2093
2094 return s5p_jpeg_runtime_resume(dev);
2095}
2096
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002097static const struct dev_pm_ops s5p_jpeg_pm_ops = {
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002098 SET_SYSTEM_SLEEP_PM_OPS(s5p_jpeg_suspend, s5p_jpeg_resume)
2099 SET_RUNTIME_PM_OPS(s5p_jpeg_runtime_suspend, s5p_jpeg_runtime_resume, NULL)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002100};
2101
Sylwester Nawrockif7074ab2013-08-18 16:14:27 -03002102#ifdef CONFIG_OF
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002103static struct s5p_jpeg_variant s5p_jpeg_drvdata = {
2104 .version = SJPEG_S5P,
2105 .jpeg_irq = s5p_jpeg_irq,
Sylwester Nawrockif7074ab2013-08-18 16:14:27 -03002106};
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002107
2108static struct s5p_jpeg_variant exynos4_jpeg_drvdata = {
2109 .version = SJPEG_EXYNOS4,
2110 .jpeg_irq = exynos4_jpeg_irq,
2111};
2112
2113static const struct of_device_id samsung_jpeg_match[] = {
2114 {
2115 .compatible = "samsung,s5pv210-jpeg",
2116 .data = &s5p_jpeg_drvdata,
2117 }, {
2118 .compatible = "samsung,exynos4210-jpeg",
2119 .data = &s5p_jpeg_drvdata,
2120 }, {
2121 .compatible = "samsung,exynos4212-jpeg",
2122 .data = &exynos4_jpeg_drvdata,
2123 },
2124 {},
2125};
2126
2127MODULE_DEVICE_TABLE(of, samsung_jpeg_match);
2128
2129static void *jpeg_get_drv_data(struct platform_device *pdev)
2130{
2131 struct s5p_jpeg_variant *driver_data = NULL;
2132 const struct of_device_id *match;
2133
2134 match = of_match_node(of_match_ptr(samsung_jpeg_match),
2135 pdev->dev.of_node);
2136 if (match)
2137 driver_data = (struct s5p_jpeg_variant *)match->data;
2138
2139 return driver_data;
2140}
Sylwester Nawrockif7074ab2013-08-18 16:14:27 -03002141#endif
2142
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002143static struct platform_driver s5p_jpeg_driver = {
2144 .probe = s5p_jpeg_probe,
2145 .remove = s5p_jpeg_remove,
2146 .driver = {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002147 .of_match_table = of_match_ptr(samsung_jpeg_match),
2148 .owner = THIS_MODULE,
2149 .name = S5P_JPEG_M2M_NAME,
2150 .pm = &s5p_jpeg_pm_ops,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002151 },
2152};
2153
Sachin Kamat87e94292012-07-03 05:54:33 -03002154module_platform_driver(s5p_jpeg_driver);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002155
2156MODULE_AUTHOR("Andrzej Pietrasiewicz <andrzej.p@samsung.com>");
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002157MODULE_AUTHOR("Jacek Anaszewski <j.anaszewski@samsung.com>");
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002158MODULE_DESCRIPTION("Samsung JPEG codec driver");
2159MODULE_LICENSE("GPL");