aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSylwester Nawrocki <s.nawrocki@samsung.com>2010-10-07 09:06:16 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2010-10-21 05:55:47 -0400
commit5f3cc4474cdeab3ee44962fd752baec24e8fecec (patch)
tree5c0255cb2c8f531a2b139f700a210c855dea19aa
parent28f06ff4b75a309d9255567b3a15b6a5bf63747d (diff)
[media] s5p-fimc: Add camera capture support
Add a video device driver per each FIMC entity to support the camera capture input mode. Video capture node is registered only if CCD sensor data is provided through driver's platfrom data and board setup code. Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com> Reviewed-by: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--drivers/media/video/s5p-fimc/Makefile2
-rw-r--r--drivers/media/video/s5p-fimc/fimc-capture.c819
-rw-r--r--drivers/media/video/s5p-fimc/fimc-core.c563
-rw-r--r--drivers/media/video/s5p-fimc/fimc-core.h205
-rw-r--r--drivers/media/video/s5p-fimc/fimc-reg.c173
-rw-r--r--include/media/s3c_fimc.h60
6 files changed, 1630 insertions, 192 deletions
diff --git a/drivers/media/video/s5p-fimc/Makefile b/drivers/media/video/s5p-fimc/Makefile
index 0d9d54132ecc..7ea1b1403b1e 100644
--- a/drivers/media/video/s5p-fimc/Makefile
+++ b/drivers/media/video/s5p-fimc/Makefile
@@ -1,3 +1,3 @@
1 1
2obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC) := s5p-fimc.o 2obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC) := s5p-fimc.o
3s5p-fimc-y := fimc-core.o fimc-reg.o 3s5p-fimc-y := fimc-core.o fimc-reg.o fimc-capture.o
diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c
new file mode 100644
index 000000000000..e8f13d3e2df1
--- /dev/null
+++ b/drivers/media/video/s5p-fimc/fimc-capture.c
@@ -0,0 +1,819 @@
1/*
2 * Samsung S5P SoC series camera interface (camera capture) driver
3 *
4 * Copyright (c) 2010 Samsung Electronics Co., Ltd
5 * Author: Sylwester Nawrocki, <s.nawrocki@samsung.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
12#include <linux/module.h>
13#include <linux/kernel.h>
14#include <linux/version.h>
15#include <linux/types.h>
16#include <linux/errno.h>
17#include <linux/bug.h>
18#include <linux/interrupt.h>
19#include <linux/device.h>
20#include <linux/platform_device.h>
21#include <linux/list.h>
22#include <linux/slab.h>
23#include <linux/clk.h>
24#include <linux/i2c.h>
25
26#include <linux/videodev2.h>
27#include <media/v4l2-device.h>
28#include <media/v4l2-ioctl.h>
29#include <media/v4l2-mem2mem.h>
30#include <media/videobuf-core.h>
31#include <media/videobuf-dma-contig.h>
32
33#include "fimc-core.h"
34
35static struct v4l2_subdev *fimc_subdev_register(struct fimc_dev *fimc,
36 struct s3c_fimc_isp_info *isp_info)
37{
38 struct i2c_adapter *i2c_adap;
39 struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
40 struct v4l2_subdev *sd = NULL;
41
42 i2c_adap = i2c_get_adapter(isp_info->i2c_bus_num);
43 if (!i2c_adap)
44 return ERR_PTR(-ENOMEM);
45
46 sd = v4l2_i2c_new_subdev_board(&vid_cap->v4l2_dev, i2c_adap,
47 MODULE_NAME, isp_info->board_info, NULL);
48 if (!sd) {
49 v4l2_err(&vid_cap->v4l2_dev, "failed to acquire subdev\n");
50 return NULL;
51 }
52
53 v4l2_info(&vid_cap->v4l2_dev, "subdevice %s registered successfuly\n",
54 isp_info->board_info->type);
55
56 return sd;
57}
58
59static void fimc_subdev_unregister(struct fimc_dev *fimc)
60{
61 struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
62 struct i2c_client *client;
63
64 if (vid_cap->input_index < 0)
65 return; /* Subdevice already released or not registered. */
66
67 if (vid_cap->sd) {
68 v4l2_device_unregister_subdev(vid_cap->sd);
69 client = v4l2_get_subdevdata(vid_cap->sd);
70 i2c_unregister_device(client);
71 i2c_put_adapter(client->adapter);
72 vid_cap->sd = NULL;
73 }
74
75 vid_cap->input_index = -1;
76}
77
78/**
79 * fimc_subdev_attach - attach v4l2_subdev to camera host interface
80 *
81 * @fimc: FIMC device information
82 * @index: index to the array of available subdevices,
83 * -1 for full array search or non negative value
84 * to select specific subdevice
85 */
86static int fimc_subdev_attach(struct fimc_dev *fimc, int index)
87{
88 struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
89 struct s3c_platform_fimc *pdata = fimc->pdata;
90 struct s3c_fimc_isp_info *isp_info;
91 struct v4l2_subdev *sd;
92 int i;
93
94 for (i = 0; i < FIMC_MAX_CAMIF_CLIENTS; ++i) {
95 isp_info = pdata->isp_info[i];
96
97 if (!isp_info || (index >= 0 && i != index))
98 continue;
99
100 sd = fimc_subdev_register(fimc, isp_info);
101 if (sd) {
102 vid_cap->sd = sd;
103 vid_cap->input_index = i;
104
105 return 0;
106 }
107 }
108
109 vid_cap->input_index = -1;
110 vid_cap->sd = NULL;
111 v4l2_err(&vid_cap->v4l2_dev, "fimc%d: sensor attach failed\n",
112 fimc->id);
113 return -ENODEV;
114}
115
116static int fimc_isp_subdev_init(struct fimc_dev *fimc, int index)
117{
118 struct s3c_fimc_isp_info *isp_info;
119 int ret;
120
121 ret = fimc_subdev_attach(fimc, index);
122 if (ret)
123 return ret;
124
125 isp_info = fimc->pdata->isp_info[fimc->vid_cap.input_index];
126 ret = fimc_hw_set_camera_polarity(fimc, isp_info);
127 if (!ret) {
128 ret = v4l2_subdev_call(fimc->vid_cap.sd, core,
129 s_power, 1);
130 if (!ret)
131 return ret;
132 }
133
134 fimc_subdev_unregister(fimc);
135 err("ISP initialization failed: %d", ret);
136 return ret;
137}
138
139/*
140 * At least one buffer on the pending_buf_q queue is required.
141 * Locking: The caller holds fimc->slock spinlock.
142 */
143int fimc_vid_cap_buf_queue(struct fimc_dev *fimc,
144 struct fimc_vid_buffer *fimc_vb)
145{
146 struct fimc_vid_cap *cap = &fimc->vid_cap;
147 struct fimc_ctx *ctx = cap->ctx;
148 int ret = 0;
149
150 BUG_ON(!fimc || !fimc_vb);
151
152 ret = fimc_prepare_addr(ctx, fimc_vb, &ctx->d_frame,
153 &fimc_vb->paddr);
154 if (ret)
155 return ret;
156
157 if (test_bit(ST_CAPT_STREAM, &fimc->state)) {
158 fimc_pending_queue_add(cap, fimc_vb);
159 } else {
160 /* Setup the buffer directly for processing. */
161 int buf_id = (cap->reqbufs_count == 1) ? -1 : cap->buf_index;
162 fimc_hw_set_output_addr(fimc, &fimc_vb->paddr, buf_id);
163
164 fimc_vb->index = cap->buf_index;
165 active_queue_add(cap, fimc_vb);
166
167 if (++cap->buf_index >= FIMC_MAX_OUT_BUFS)
168 cap->buf_index = 0;
169 }
170 return ret;
171}
172
173static int fimc_stop_capture(struct fimc_dev *fimc)
174{
175 unsigned long flags;
176 struct fimc_vid_cap *cap;
177 int ret;
178
179 cap = &fimc->vid_cap;
180
181 if (!fimc_capture_active(fimc))
182 return 0;
183
184 spin_lock_irqsave(&fimc->slock, flags);
185 set_bit(ST_CAPT_SHUT, &fimc->state);
186 fimc_deactivate_capture(fimc);
187 spin_unlock_irqrestore(&fimc->slock, flags);
188
189 wait_event_timeout(fimc->irq_queue,
190 test_bit(ST_CAPT_SHUT, &fimc->state),
191 FIMC_SHUTDOWN_TIMEOUT);
192
193 ret = v4l2_subdev_call(cap->sd, video, s_stream, 0);
194 if (ret)
195 v4l2_err(&fimc->vid_cap.v4l2_dev, "s_stream(0) failed\n");
196
197 spin_lock_irqsave(&fimc->slock, flags);
198 fimc->state &= ~(1 << ST_CAPT_RUN | 1 << ST_CAPT_PEND |
199 1 << ST_CAPT_STREAM);
200
201 fimc->vid_cap.active_buf_cnt = 0;
202 spin_unlock_irqrestore(&fimc->slock, flags);
203
204 dbg("state: 0x%lx", fimc->state);
205 return 0;
206}
207
208static int fimc_capture_open(struct file *file)
209{
210 struct fimc_dev *fimc = video_drvdata(file);
211 int ret = 0;
212
213 dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state);
214
215 /* Return if the corresponding video mem2mem node is already opened. */
216 if (fimc_m2m_active(fimc))
217 return -EBUSY;
218
219 if (mutex_lock_interruptible(&fimc->lock))
220 return -ERESTARTSYS;
221
222 if (++fimc->vid_cap.refcnt == 1) {
223 ret = fimc_isp_subdev_init(fimc, -1);
224 if (ret) {
225 fimc->vid_cap.refcnt--;
226 ret = -EIO;
227 }
228 }
229
230 file->private_data = fimc->vid_cap.ctx;
231
232 mutex_unlock(&fimc->lock);
233 return ret;
234}
235
236static int fimc_capture_close(struct file *file)
237{
238 struct fimc_dev *fimc = video_drvdata(file);
239
240 if (mutex_lock_interruptible(&fimc->lock))
241 return -ERESTARTSYS;
242
243 dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state);
244
245 if (--fimc->vid_cap.refcnt == 0) {
246 fimc_stop_capture(fimc);
247
248 videobuf_stop(&fimc->vid_cap.vbq);
249 videobuf_mmap_free(&fimc->vid_cap.vbq);
250
251 v4l2_err(&fimc->vid_cap.v4l2_dev, "releasing ISP\n");
252 v4l2_subdev_call(fimc->vid_cap.sd, core, s_power, 0);
253 fimc_subdev_unregister(fimc);
254 }
255
256 mutex_unlock(&fimc->lock);
257 return 0;
258}
259
260static unsigned int fimc_capture_poll(struct file *file,
261 struct poll_table_struct *wait)
262{
263 struct fimc_ctx *ctx = file->private_data;
264 struct fimc_dev *fimc = ctx->fimc_dev;
265 struct fimc_vid_cap *cap = &fimc->vid_cap;
266 int ret;
267
268 if (mutex_lock_interruptible(&fimc->lock))
269 return POLLERR;
270
271 ret = videobuf_poll_stream(file, &cap->vbq, wait);
272 mutex_unlock(&fimc->lock);
273
274 return ret;
275}
276
277static int fimc_capture_mmap(struct file *file, struct vm_area_struct *vma)
278{
279 struct fimc_ctx *ctx = file->private_data;
280 struct fimc_dev *fimc = ctx->fimc_dev;
281 struct fimc_vid_cap *cap = &fimc->vid_cap;
282 int ret;
283
284 if (mutex_lock_interruptible(&fimc->lock))
285 return -ERESTARTSYS;
286
287 ret = videobuf_mmap_mapper(&cap->vbq, vma);
288 mutex_unlock(&fimc->lock);
289
290 return ret;
291}
292
293/* video device file operations */
294static const struct v4l2_file_operations fimc_capture_fops = {
295 .owner = THIS_MODULE,
296 .open = fimc_capture_open,
297 .release = fimc_capture_close,
298 .poll = fimc_capture_poll,
299 .unlocked_ioctl = video_ioctl2,
300 .mmap = fimc_capture_mmap,
301};
302
303static int fimc_vidioc_querycap_capture(struct file *file, void *priv,
304 struct v4l2_capability *cap)
305{
306 struct fimc_ctx *ctx = file->private_data;
307 struct fimc_dev *fimc = ctx->fimc_dev;
308
309 strncpy(cap->driver, fimc->pdev->name, sizeof(cap->driver) - 1);
310 strncpy(cap->card, fimc->pdev->name, sizeof(cap->card) - 1);
311 cap->bus_info[0] = 0;
312 cap->version = KERNEL_VERSION(1, 0, 0);
313 cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE;
314
315 return 0;
316}
317
318/* Synchronize formats of the camera interface input and attached sensor. */
319static int sync_capture_fmt(struct fimc_ctx *ctx)
320{
321 struct fimc_frame *frame = &ctx->s_frame;
322 struct fimc_dev *fimc = ctx->fimc_dev;
323 struct v4l2_mbus_framefmt *fmt = &fimc->vid_cap.fmt;
324 int ret;
325
326 fmt->width = ctx->d_frame.o_width;
327 fmt->height = ctx->d_frame.o_height;
328
329 ret = v4l2_subdev_call(fimc->vid_cap.sd, video, s_mbus_fmt, fmt);
330 if (ret == -ENOIOCTLCMD) {
331 err("s_mbus_fmt failed");
332 return ret;
333 }
334 dbg("w: %d, h: %d, code= %d", fmt->width, fmt->height, fmt->code);
335
336 frame->fmt = find_mbus_format(fmt, FMT_FLAGS_CAM);
337 if (!frame->fmt) {
338 err("fimc source format not found\n");
339 return -EINVAL;
340 }
341
342 frame->f_width = fmt->width;
343 frame->f_height = fmt->height;
344 frame->width = fmt->width;
345 frame->height = fmt->height;
346 frame->o_width = fmt->width;
347 frame->o_height = fmt->height;
348 frame->offs_h = 0;
349 frame->offs_v = 0;
350
351 return 0;
352}
353
354static int fimc_cap_s_fmt(struct file *file, void *priv,
355 struct v4l2_format *f)
356{
357 struct fimc_ctx *ctx = priv;
358 struct fimc_dev *fimc = ctx->fimc_dev;
359 struct fimc_frame *frame;
360 struct v4l2_pix_format *pix;
361 int ret;
362
363 if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
364 return -EINVAL;
365
366 ret = fimc_vidioc_try_fmt(file, priv, f);
367 if (ret)
368 return ret;
369
370 if (mutex_lock_interruptible(&fimc->lock))
371 return -ERESTARTSYS;
372
373 if (fimc_capture_active(fimc)) {
374 ret = -EBUSY;
375 goto sf_unlock;
376 }
377
378 frame = &ctx->d_frame;
379
380 pix = &f->fmt.pix;
381 frame->fmt = find_format(f, FMT_FLAGS_M2M | FMT_FLAGS_CAM);
382 if (!frame->fmt) {
383 err("fimc target format not found\n");
384 ret = -EINVAL;
385 goto sf_unlock;
386 }
387
388 /* Output DMA frame pixel size and offsets. */
389 frame->f_width = pix->bytesperline * 8 / frame->fmt->depth;
390 frame->f_height = pix->height;
391 frame->width = pix->width;
392 frame->height = pix->height;
393 frame->o_width = pix->width;
394 frame->o_height = pix->height;
395 frame->size = (pix->width * pix->height * frame->fmt->depth) >> 3;
396 frame->offs_h = 0;
397 frame->offs_v = 0;
398
399 ret = sync_capture_fmt(ctx);
400
401 ctx->state |= (FIMC_PARAMS | FIMC_DST_FMT);
402
403sf_unlock:
404 mutex_unlock(&fimc->lock);
405 return ret;
406}
407
408static int fimc_cap_enum_input(struct file *file, void *priv,
409 struct v4l2_input *i)
410{
411 struct fimc_ctx *ctx = priv;
412 struct s3c_platform_fimc *pldata = ctx->fimc_dev->pdata;
413 struct s3c_fimc_isp_info *isp_info;
414
415 if (i->index >= FIMC_MAX_CAMIF_CLIENTS)
416 return -EINVAL;
417
418 isp_info = pldata->isp_info[i->index];
419 if (isp_info == NULL)
420 return -EINVAL;
421
422 i->type = V4L2_INPUT_TYPE_CAMERA;
423 strncpy(i->name, isp_info->board_info->type, 32);
424 return 0;
425}
426
427static int fimc_cap_s_input(struct file *file, void *priv,
428 unsigned int i)
429{
430 struct fimc_ctx *ctx = priv;
431 struct fimc_dev *fimc = ctx->fimc_dev;
432 struct s3c_platform_fimc *pdata = fimc->pdata;
433 int ret;
434
435 if (fimc_capture_active(ctx->fimc_dev))
436 return -EBUSY;
437
438 if (mutex_lock_interruptible(&fimc->lock))
439 return -ERESTARTSYS;
440
441 if (i >= FIMC_MAX_CAMIF_CLIENTS || !pdata->isp_info[i]) {
442 ret = -EINVAL;
443 goto si_unlock;
444 }
445
446 if (fimc->vid_cap.sd) {
447 ret = v4l2_subdev_call(fimc->vid_cap.sd, core, s_power, 0);
448 if (ret)
449 err("s_power failed: %d", ret);
450 }
451
452 /* Release the attached sensor subdevice. */
453 fimc_subdev_unregister(fimc);
454
455 ret = fimc_isp_subdev_init(fimc, i);
456
457si_unlock:
458 mutex_unlock(&fimc->lock);
459 return ret;
460}
461
462static int fimc_cap_g_input(struct file *file, void *priv,
463 unsigned int *i)
464{
465 struct fimc_ctx *ctx = priv;
466 struct fimc_vid_cap *cap = &ctx->fimc_dev->vid_cap;
467
468 *i = cap->input_index;
469 return 0;
470}
471
472static int fimc_cap_streamon(struct file *file, void *priv,
473 enum v4l2_buf_type type)
474{
475 struct s3c_fimc_isp_info *isp_info;
476 struct fimc_ctx *ctx = priv;
477 struct fimc_dev *fimc = ctx->fimc_dev;
478 int ret = -EBUSY;
479
480 if (mutex_lock_interruptible(&fimc->lock))
481 return -ERESTARTSYS;
482
483 if (fimc_capture_active(fimc) || !fimc->vid_cap.sd)
484 goto s_unlock;
485
486 if (!(ctx->state & FIMC_DST_FMT)) {
487 v4l2_err(&fimc->vid_cap.v4l2_dev, "Format is not set\n");
488 ret = -EINVAL;
489 goto s_unlock;
490 }
491
492 ret = v4l2_subdev_call(fimc->vid_cap.sd, video, s_stream, 1);
493 if (ret && ret != -ENOIOCTLCMD)
494 goto s_unlock;
495
496 ret = fimc_prepare_config(ctx, ctx->state);
497 if (ret)
498 goto s_unlock;
499
500 isp_info = fimc->pdata->isp_info[fimc->vid_cap.input_index];
501 fimc_hw_set_camera_type(fimc, isp_info);
502 fimc_hw_set_camera_source(fimc, isp_info);
503 fimc_hw_set_camera_offset(fimc, &ctx->s_frame);
504
505 if (ctx->state & FIMC_PARAMS) {
506 ret = fimc_set_scaler_info(ctx);
507 if (ret) {
508 err("Scaler setup error");
509 goto s_unlock;
510 }
511 fimc_hw_set_input_path(ctx);
512 fimc_hw_set_scaler(ctx);
513 fimc_hw_set_target_format(ctx);
514 fimc_hw_set_rotation(ctx);
515 fimc_hw_set_effect(ctx);
516 }
517
518 fimc_hw_set_output_path(ctx);
519 fimc_hw_set_out_dma(ctx);
520
521 INIT_LIST_HEAD(&fimc->vid_cap.pending_buf_q);
522 INIT_LIST_HEAD(&fimc->vid_cap.active_buf_q);
523 fimc->vid_cap.active_buf_cnt = 0;
524 fimc->vid_cap.frame_count = 0;
525
526 set_bit(ST_CAPT_PEND, &fimc->state);
527 ret = videobuf_streamon(&fimc->vid_cap.vbq);
528
529s_unlock:
530 mutex_unlock(&fimc->lock);
531 return ret;
532}
533
534static int fimc_cap_streamoff(struct file *file, void *priv,
535 enum v4l2_buf_type type)
536{
537 struct fimc_ctx *ctx = priv;
538 struct fimc_dev *fimc = ctx->fimc_dev;
539 struct fimc_vid_cap *cap = &fimc->vid_cap;
540 unsigned long flags;
541 int ret;
542
543 spin_lock_irqsave(&fimc->slock, flags);
544 if (!fimc_capture_running(fimc) && !fimc_capture_pending(fimc)) {
545 spin_unlock_irqrestore(&fimc->slock, flags);
546 dbg("state: 0x%lx", fimc->state);
547 return -EINVAL;
548 }
549 spin_unlock_irqrestore(&fimc->slock, flags);
550
551 if (mutex_lock_interruptible(&fimc->lock))
552 return -ERESTARTSYS;
553
554 fimc_stop_capture(fimc);
555 ret = videobuf_streamoff(&cap->vbq);
556 mutex_unlock(&fimc->lock);
557 return ret;
558}
559
560static int fimc_cap_reqbufs(struct file *file, void *priv,
561 struct v4l2_requestbuffers *reqbufs)
562{
563 struct fimc_ctx *ctx = priv;
564 struct fimc_dev *fimc = ctx->fimc_dev;
565 struct fimc_vid_cap *cap = &fimc->vid_cap;
566 int ret;
567
568 if (fimc_capture_active(ctx->fimc_dev))
569 return -EBUSY;
570
571 if (mutex_lock_interruptible(&fimc->lock))
572 return -ERESTARTSYS;
573
574 ret = videobuf_reqbufs(&cap->vbq, reqbufs);
575 if (!ret)
576 cap->reqbufs_count = reqbufs->count;
577
578 mutex_unlock(&fimc->lock);
579 return ret;
580}
581
582static int fimc_cap_querybuf(struct file *file, void *priv,
583 struct v4l2_buffer *buf)
584{
585 struct fimc_ctx *ctx = priv;
586 struct fimc_vid_cap *cap = &ctx->fimc_dev->vid_cap;
587
588 if (fimc_capture_active(ctx->fimc_dev))
589 return -EBUSY;
590
591 return videobuf_querybuf(&cap->vbq, buf);
592}
593
594static int fimc_cap_qbuf(struct file *file, void *priv,
595 struct v4l2_buffer *buf)
596{
597 struct fimc_ctx *ctx = priv;
598 struct fimc_dev *fimc = ctx->fimc_dev;
599 struct fimc_vid_cap *cap = &fimc->vid_cap;
600 int ret;
601
602 if (mutex_lock_interruptible(&fimc->lock))
603 return -ERESTARTSYS;
604
605 ret = videobuf_qbuf(&cap->vbq, buf);
606
607 mutex_unlock(&fimc->lock);
608 return ret;
609}
610
611static int fimc_cap_dqbuf(struct file *file, void *priv,
612 struct v4l2_buffer *buf)
613{
614 struct fimc_ctx *ctx = priv;
615 int ret;
616
617 if (mutex_lock_interruptible(&ctx->fimc_dev->lock))
618 return -ERESTARTSYS;
619
620 ret = videobuf_dqbuf(&ctx->fimc_dev->vid_cap.vbq, buf,
621 file->f_flags & O_NONBLOCK);
622
623 mutex_unlock(&ctx->fimc_dev->lock);
624 return ret;
625}
626
627static int fimc_cap_s_ctrl(struct file *file, void *priv,
628 struct v4l2_control *ctrl)
629{
630 struct fimc_ctx *ctx = priv;
631 int ret = -EINVAL;
632
633 if (mutex_lock_interruptible(&ctx->fimc_dev->lock))
634 return -ERESTARTSYS;
635
636 /* Allow any controls but 90/270 rotation while streaming */
637 if (!fimc_capture_active(ctx->fimc_dev) ||
638 ctrl->id != V4L2_CID_ROTATE ||
639 (ctrl->value != 90 && ctrl->value != 270)) {
640 ret = check_ctrl_val(ctx, ctrl);
641 if (!ret) {
642 ret = fimc_s_ctrl(ctx, ctrl);
643 if (!ret)
644 ctx->state |= FIMC_PARAMS;
645 }
646 }
647 if (ret == -EINVAL)
648 ret = v4l2_subdev_call(ctx->fimc_dev->vid_cap.sd,
649 core, s_ctrl, ctrl);
650
651 mutex_unlock(&ctx->fimc_dev->lock);
652 return ret;
653}
654
655static int fimc_cap_s_crop(struct file *file, void *fh,
656 struct v4l2_crop *cr)
657{
658 struct fimc_frame *f;
659 struct fimc_ctx *ctx = file->private_data;
660 struct fimc_dev *fimc = ctx->fimc_dev;
661 int ret = -EINVAL;
662
663 if (fimc_capture_active(fimc))
664 return -EBUSY;
665
666 ret = fimc_try_crop(ctx, cr);
667 if (ret)
668 return ret;
669
670 if (mutex_lock_interruptible(&fimc->lock))
671 return -ERESTARTSYS;
672
673 if (!(ctx->state & FIMC_DST_FMT)) {
674 v4l2_err(&fimc->vid_cap.v4l2_dev,
675 "Capture color format not set\n");
676 goto sc_unlock;
677 }
678
679 f = &ctx->s_frame;
680 /* Check for the pixel scaling ratio when cropping input image. */
681 ret = fimc_check_scaler_ratio(&cr->c, &ctx->d_frame);
682 if (ret) {
683 v4l2_err(&fimc->vid_cap.v4l2_dev, "Out of the scaler range");
684 } else {
685 ret = 0;
686 f->offs_h = cr->c.left;
687 f->offs_v = cr->c.top;
688 f->width = cr->c.width;
689 f->height = cr->c.height;
690 }
691
692sc_unlock:
693 mutex_unlock(&fimc->lock);
694 return ret;
695}
696
697
698static const struct v4l2_ioctl_ops fimc_capture_ioctl_ops = {
699 .vidioc_querycap = fimc_vidioc_querycap_capture,
700
701 .vidioc_enum_fmt_vid_cap = fimc_vidioc_enum_fmt,
702 .vidioc_try_fmt_vid_cap = fimc_vidioc_try_fmt,
703 .vidioc_s_fmt_vid_cap = fimc_cap_s_fmt,
704 .vidioc_g_fmt_vid_cap = fimc_vidioc_g_fmt,
705
706 .vidioc_reqbufs = fimc_cap_reqbufs,
707 .vidioc_querybuf = fimc_cap_querybuf,
708
709 .vidioc_qbuf = fimc_cap_qbuf,
710 .vidioc_dqbuf = fimc_cap_dqbuf,
711
712 .vidioc_streamon = fimc_cap_streamon,
713 .vidioc_streamoff = fimc_cap_streamoff,
714
715 .vidioc_queryctrl = fimc_vidioc_queryctrl,
716 .vidioc_g_ctrl = fimc_vidioc_g_ctrl,
717 .vidioc_s_ctrl = fimc_cap_s_ctrl,
718
719 .vidioc_g_crop = fimc_vidioc_g_crop,
720 .vidioc_s_crop = fimc_cap_s_crop,
721 .vidioc_cropcap = fimc_vidioc_cropcap,
722
723 .vidioc_enum_input = fimc_cap_enum_input,
724 .vidioc_s_input = fimc_cap_s_input,
725 .vidioc_g_input = fimc_cap_g_input,
726};
727
728int fimc_register_capture_device(struct fimc_dev *fimc)
729{
730 struct v4l2_device *v4l2_dev = &fimc->vid_cap.v4l2_dev;
731 struct video_device *vfd;
732 struct fimc_vid_cap *vid_cap;
733 struct fimc_ctx *ctx;
734 struct v4l2_format f;
735 int ret;
736
737 ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
738 if (!ctx)
739 return -ENOMEM;
740
741 ctx->fimc_dev = fimc;
742 ctx->in_path = FIMC_CAMERA;
743 ctx->out_path = FIMC_DMA;
744 ctx->state = FIMC_CTX_CAP;
745
746 f.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24;
747 ctx->d_frame.fmt = find_format(&f, FMT_FLAGS_M2M);
748
749 if (!v4l2_dev->name[0])
750 snprintf(v4l2_dev->name, sizeof(v4l2_dev->name),
751 "%s.capture", dev_name(&fimc->pdev->dev));
752
753 ret = v4l2_device_register(NULL, v4l2_dev);
754 if (ret)
755 goto err_info;
756
757 vfd = video_device_alloc();
758 if (!vfd) {
759 v4l2_err(v4l2_dev, "Failed to allocate video device\n");
760 goto err_v4l2_reg;
761 }
762
763 snprintf(vfd->name, sizeof(vfd->name), "%s:cap",
764 dev_name(&fimc->pdev->dev));
765
766 vfd->fops = &fimc_capture_fops;
767 vfd->ioctl_ops = &fimc_capture_ioctl_ops;
768 vfd->minor = -1;
769 vfd->release = video_device_release;
770 video_set_drvdata(vfd, fimc);
771
772 vid_cap = &fimc->vid_cap;
773 vid_cap->vfd = vfd;
774 vid_cap->active_buf_cnt = 0;
775 vid_cap->reqbufs_count = 0;
776 vid_cap->refcnt = 0;
777 /* The default color format for image sensor. */
778 vid_cap->fmt.code = V4L2_MBUS_FMT_YUYV8_2X8;
779
780 INIT_LIST_HEAD(&vid_cap->pending_buf_q);
781 INIT_LIST_HEAD(&vid_cap->active_buf_q);
782 spin_lock_init(&ctx->slock);
783 vid_cap->ctx = ctx;
784
785 videobuf_queue_dma_contig_init(&vid_cap->vbq, &fimc_qops,
786 vid_cap->v4l2_dev.dev, &fimc->irqlock,
787 V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
788 sizeof(struct fimc_vid_buffer), (void *)ctx);
789
790 ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
791 if (ret) {
792 v4l2_err(v4l2_dev, "Failed to register video device\n");
793 goto err_vd_reg;
794 }
795
796 v4l2_info(v4l2_dev,
797 "FIMC capture driver registered as /dev/video%d\n",
798 vfd->num);
799
800 return 0;
801
802err_vd_reg:
803 video_device_release(vfd);
804err_v4l2_reg:
805 v4l2_device_unregister(v4l2_dev);
806err_info:
807 dev_err(&fimc->pdev->dev, "failed to install\n");
808 return ret;
809}
810
811void fimc_unregister_capture_device(struct fimc_dev *fimc)
812{
813 struct fimc_vid_cap *capture = &fimc->vid_cap;
814
815 if (capture->vfd)
816 video_unregister_device(capture->vfd);
817
818 kfree(capture->ctx);
819}
diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c
index 23cc054bd7b1..5168a9a5d821 100644
--- a/drivers/media/video/s5p-fimc/fimc-core.c
+++ b/drivers/media/video/s5p-fimc/fimc-core.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * S5P camera interface (video postprocessor) driver 2 * S5P camera interface (video postprocessor) driver
3 * 3 *
4 * Copyright (c) 2010 Samsung Electronics 4 * Copyright (c) 2010 Samsung Electronics Co., Ltd
5 * 5 *
6 * Sylwester Nawrocki, <s.nawrocki@samsung.com> 6 * Sylwester Nawrocki, <s.nawrocki@samsung.com>
7 * 7 *
@@ -38,85 +38,102 @@ static struct fimc_fmt fimc_formats[] = {
38 .depth = 16, 38 .depth = 16,
39 .color = S5P_FIMC_RGB565, 39 .color = S5P_FIMC_RGB565,
40 .buff_cnt = 1, 40 .buff_cnt = 1,
41 .planes_cnt = 1 41 .planes_cnt = 1,
42 .mbus_code = V4L2_MBUS_FMT_RGB565_2X8_BE,
43 .flags = FMT_FLAGS_M2M,
42 }, { 44 }, {
43 .name = "BGR666", 45 .name = "BGR666",
44 .fourcc = V4L2_PIX_FMT_BGR666, 46 .fourcc = V4L2_PIX_FMT_BGR666,
45 .depth = 32, 47 .depth = 32,
46 .color = S5P_FIMC_RGB666, 48 .color = S5P_FIMC_RGB666,
47 .buff_cnt = 1, 49 .buff_cnt = 1,
48 .planes_cnt = 1 50 .planes_cnt = 1,
51 .flags = FMT_FLAGS_M2M,
49 }, { 52 }, {
50 .name = "XRGB-8-8-8-8, 24 bpp", 53 .name = "XRGB-8-8-8-8, 24 bpp",
51 .fourcc = V4L2_PIX_FMT_RGB24, 54 .fourcc = V4L2_PIX_FMT_RGB24,
52 .depth = 32, 55 .depth = 32,
53 .color = S5P_FIMC_RGB888, 56 .color = S5P_FIMC_RGB888,
54 .buff_cnt = 1, 57 .buff_cnt = 1,
55 .planes_cnt = 1 58 .planes_cnt = 1,
59 .flags = FMT_FLAGS_M2M,
56 }, { 60 }, {
57 .name = "YUV 4:2:2 packed, YCbYCr", 61 .name = "YUV 4:2:2 packed, YCbYCr",
58 .fourcc = V4L2_PIX_FMT_YUYV, 62 .fourcc = V4L2_PIX_FMT_YUYV,
59 .depth = 16, 63 .depth = 16,
60 .color = S5P_FIMC_YCBYCR422, 64 .color = S5P_FIMC_YCBYCR422,
61 .buff_cnt = 1, 65 .buff_cnt = 1,
62 .planes_cnt = 1 66 .planes_cnt = 1,
63 }, { 67 .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8,
68 .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM,
69 }, {
64 .name = "YUV 4:2:2 packed, CbYCrY", 70 .name = "YUV 4:2:2 packed, CbYCrY",
65 .fourcc = V4L2_PIX_FMT_UYVY, 71 .fourcc = V4L2_PIX_FMT_UYVY,
66 .depth = 16, 72 .depth = 16,
67 .color = S5P_FIMC_CBYCRY422, 73 .color = S5P_FIMC_CBYCRY422,
68 .buff_cnt = 1, 74 .buff_cnt = 1,
69 .planes_cnt = 1 75 .planes_cnt = 1,
76 .mbus_code = V4L2_MBUS_FMT_UYVY8_2X8,
77 .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM,
70 }, { 78 }, {
71 .name = "YUV 4:2:2 packed, CrYCbY", 79 .name = "YUV 4:2:2 packed, CrYCbY",
72 .fourcc = V4L2_PIX_FMT_VYUY, 80 .fourcc = V4L2_PIX_FMT_VYUY,
73 .depth = 16, 81 .depth = 16,
74 .color = S5P_FIMC_CRYCBY422, 82 .color = S5P_FIMC_CRYCBY422,
75 .buff_cnt = 1, 83 .buff_cnt = 1,
76 .planes_cnt = 1 84 .planes_cnt = 1,
85 .mbus_code = V4L2_MBUS_FMT_VYUY8_2X8,
86 .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM,
77 }, { 87 }, {
78 .name = "YUV 4:2:2 packed, YCrYCb", 88 .name = "YUV 4:2:2 packed, YCrYCb",
79 .fourcc = V4L2_PIX_FMT_YVYU, 89 .fourcc = V4L2_PIX_FMT_YVYU,
80 .depth = 16, 90 .depth = 16,
81 .color = S5P_FIMC_YCRYCB422, 91 .color = S5P_FIMC_YCRYCB422,
82 .buff_cnt = 1, 92 .buff_cnt = 1,
83 .planes_cnt = 1 93 .planes_cnt = 1,
94 .mbus_code = V4L2_MBUS_FMT_YVYU8_2X8,
95 .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM,
84 }, { 96 }, {
85 .name = "YUV 4:2:2 planar, Y/Cb/Cr", 97 .name = "YUV 4:2:2 planar, Y/Cb/Cr",
86 .fourcc = V4L2_PIX_FMT_YUV422P, 98 .fourcc = V4L2_PIX_FMT_YUV422P,
87 .depth = 12, 99 .depth = 12,
88 .color = S5P_FIMC_YCBCR422, 100 .color = S5P_FIMC_YCBCR422,
89 .buff_cnt = 1, 101 .buff_cnt = 1,
90 .planes_cnt = 3 102 .planes_cnt = 3,
103 .flags = FMT_FLAGS_M2M,
91 }, { 104 }, {
92 .name = "YUV 4:2:2 planar, Y/CbCr", 105 .name = "YUV 4:2:2 planar, Y/CbCr",
93 .fourcc = V4L2_PIX_FMT_NV16, 106 .fourcc = V4L2_PIX_FMT_NV16,
94 .depth = 16, 107 .depth = 16,
95 .color = S5P_FIMC_YCBCR422, 108 .color = S5P_FIMC_YCBCR422,
96 .buff_cnt = 1, 109 .buff_cnt = 1,
97 .planes_cnt = 2 110 .planes_cnt = 2,
111 .flags = FMT_FLAGS_M2M,
98 }, { 112 }, {
99 .name = "YUV 4:2:2 planar, Y/CrCb", 113 .name = "YUV 4:2:2 planar, Y/CrCb",
100 .fourcc = V4L2_PIX_FMT_NV61, 114 .fourcc = V4L2_PIX_FMT_NV61,
101 .depth = 16, 115 .depth = 16,
102 .color = S5P_FIMC_RGB565, 116 .color = S5P_FIMC_RGB565,
103 .buff_cnt = 1, 117 .buff_cnt = 1,
104 .planes_cnt = 2 118 .planes_cnt = 2,
119 .flags = FMT_FLAGS_M2M,
105 }, { 120 }, {
106 .name = "YUV 4:2:0 planar, YCbCr", 121 .name = "YUV 4:2:0 planar, YCbCr",
107 .fourcc = V4L2_PIX_FMT_YUV420, 122 .fourcc = V4L2_PIX_FMT_YUV420,
108 .depth = 12, 123 .depth = 12,
109 .color = S5P_FIMC_YCBCR420, 124 .color = S5P_FIMC_YCBCR420,
110 .buff_cnt = 1, 125 .buff_cnt = 1,
111 .planes_cnt = 3 126 .planes_cnt = 3,
127 .flags = FMT_FLAGS_M2M,
112 }, { 128 }, {
113 .name = "YUV 4:2:0 planar, Y/CbCr", 129 .name = "YUV 4:2:0 planar, Y/CbCr",
114 .fourcc = V4L2_PIX_FMT_NV12, 130 .fourcc = V4L2_PIX_FMT_NV12,
115 .depth = 12, 131 .depth = 12,
116 .color = S5P_FIMC_YCBCR420, 132 .color = S5P_FIMC_YCBCR420,
117 .buff_cnt = 1, 133 .buff_cnt = 1,
118 .planes_cnt = 2 134 .planes_cnt = 2,
119 } 135 .flags = FMT_FLAGS_M2M,
136 },
120}; 137};
121 138
122static struct v4l2_queryctrl fimc_ctrls[] = { 139static struct v4l2_queryctrl fimc_ctrls[] = {
@@ -156,7 +173,7 @@ static struct v4l2_queryctrl *get_ctrl(int id)
156 return NULL; 173 return NULL;
157} 174}
158 175
159static int fimc_check_scaler_ratio(struct v4l2_rect *r, struct fimc_frame *f) 176int fimc_check_scaler_ratio(struct v4l2_rect *r, struct fimc_frame *f)
160{ 177{
161 if (r->width > f->width) { 178 if (r->width > f->width) {
162 if (f->width > (r->width * SCALER_MAX_HRATIO)) 179 if (f->width > (r->width * SCALER_MAX_HRATIO))
@@ -199,7 +216,7 @@ static int fimc_get_scaler_factor(u32 src, u32 tar, u32 *ratio, u32 *shift)
199 return 0; 216 return 0;
200} 217}
201 218
202static int fimc_set_scaler_info(struct fimc_ctx *ctx) 219int fimc_set_scaler_info(struct fimc_ctx *ctx)
203{ 220{
204 struct fimc_scaler *sc = &ctx->scaler; 221 struct fimc_scaler *sc = &ctx->scaler;
205 struct fimc_frame *s_frame = &ctx->s_frame; 222 struct fimc_frame *s_frame = &ctx->s_frame;
@@ -259,6 +276,51 @@ static int fimc_set_scaler_info(struct fimc_ctx *ctx)
259 return 0; 276 return 0;
260} 277}
261 278
279static void fimc_capture_handler(struct fimc_dev *fimc)
280{
281 struct fimc_vid_cap *cap = &fimc->vid_cap;
282 struct fimc_vid_buffer *v_buf = NULL;
283
284 if (!list_empty(&cap->active_buf_q)) {
285 v_buf = active_queue_pop(cap);
286 fimc_buf_finish(fimc, v_buf);
287 }
288
289 if (test_and_clear_bit(ST_CAPT_SHUT, &fimc->state)) {
290 wake_up(&fimc->irq_queue);
291 return;
292 }
293
294 if (!list_empty(&cap->pending_buf_q)) {
295
296 v_buf = pending_queue_pop(cap);
297 fimc_hw_set_output_addr(fimc, &v_buf->paddr, cap->buf_index);
298 v_buf->index = cap->buf_index;
299
300 dbg("hw ptr: %d, sw ptr: %d",
301 fimc_hw_get_frame_index(fimc), cap->buf_index);
302
303 spin_lock(&fimc->irqlock);
304 v_buf->vb.state = VIDEOBUF_ACTIVE;
305 spin_unlock(&fimc->irqlock);
306
307 /* Move the buffer to the capture active queue */
308 active_queue_add(cap, v_buf);
309
310 dbg("next frame: %d, done frame: %d",
311 fimc_hw_get_frame_index(fimc), v_buf->index);
312
313 if (++cap->buf_index >= FIMC_MAX_OUT_BUFS)
314 cap->buf_index = 0;
315
316 } else if (test_and_clear_bit(ST_CAPT_STREAM, &fimc->state) &&
317 cap->active_buf_cnt <= 1) {
318 fimc_deactivate_capture(fimc);
319 }
320
321 dbg("frame: %d, active_buf_cnt= %d",
322 fimc_hw_get_frame_index(fimc), cap->active_buf_cnt);
323}
262 324
263static irqreturn_t fimc_isr(int irq, void *priv) 325static irqreturn_t fimc_isr(int irq, void *priv)
264{ 326{
@@ -285,6 +347,16 @@ static irqreturn_t fimc_isr(int irq, void *priv)
285 spin_unlock(&fimc->irqlock); 347 spin_unlock(&fimc->irqlock);
286 v4l2_m2m_job_finish(fimc->m2m.m2m_dev, ctx->m2m_ctx); 348 v4l2_m2m_job_finish(fimc->m2m.m2m_dev, ctx->m2m_ctx);
287 } 349 }
350 goto isr_unlock;
351
352 }
353
354 if (test_bit(ST_CAPT_RUN, &fimc->state))
355 fimc_capture_handler(fimc);
356
357 if (test_and_clear_bit(ST_CAPT_PEND, &fimc->state)) {
358 set_bit(ST_CAPT_RUN, &fimc->state);
359 wake_up(&fimc->irq_queue);
288 } 360 }
289 361
290isr_unlock: 362isr_unlock:
@@ -424,7 +496,7 @@ static void fimc_prepare_dma_offset(struct fimc_ctx *ctx, struct fimc_frame *f)
424 * 496 *
425 * Return: 0 if dimensions are valid or non zero otherwise. 497 * Return: 0 if dimensions are valid or non zero otherwise.
426 */ 498 */
427static int fimc_prepare_config(struct fimc_ctx *ctx, u32 flags) 499int fimc_prepare_config(struct fimc_ctx *ctx, u32 flags)
428{ 500{
429 struct fimc_frame *s_frame, *d_frame; 501 struct fimc_frame *s_frame, *d_frame;
430 struct fimc_vid_buffer *buf = NULL; 502 struct fimc_vid_buffer *buf = NULL;
@@ -513,9 +585,9 @@ static void fimc_dma_run(void *priv)
513 if (ctx->state & FIMC_PARAMS) 585 if (ctx->state & FIMC_PARAMS)
514 fimc_hw_set_out_dma(ctx); 586 fimc_hw_set_out_dma(ctx);
515 587
516 ctx->state = 0;
517 fimc_activate_capture(ctx); 588 fimc_activate_capture(ctx);
518 589
590 ctx->state &= (FIMC_CTX_M2M | FIMC_CTX_CAP);
519 fimc_hw_activate_input_dma(fimc, true); 591 fimc_hw_activate_input_dma(fimc, true);
520 592
521dma_unlock: 593dma_unlock:
@@ -598,10 +670,31 @@ static void fimc_buf_queue(struct videobuf_queue *vq,
598 struct videobuf_buffer *vb) 670 struct videobuf_buffer *vb)
599{ 671{
600 struct fimc_ctx *ctx = vq->priv_data; 672 struct fimc_ctx *ctx = vq->priv_data;
601 v4l2_m2m_buf_queue(ctx->m2m_ctx, vq, vb); 673 struct fimc_dev *fimc = ctx->fimc_dev;
674 struct fimc_vid_cap *cap = &fimc->vid_cap;
675 unsigned long flags;
676
677 dbg("ctx: %p, ctx->state: 0x%x", ctx, ctx->state);
678
679 if ((ctx->state & FIMC_CTX_M2M) && ctx->m2m_ctx) {
680 v4l2_m2m_buf_queue(ctx->m2m_ctx, vq, vb);
681 } else if (ctx->state & FIMC_CTX_CAP) {
682 spin_lock_irqsave(&fimc->slock, flags);
683 fimc_vid_cap_buf_queue(fimc, (struct fimc_vid_buffer *)vb);
684
685 dbg("fimc->cap.active_buf_cnt: %d",
686 fimc->vid_cap.active_buf_cnt);
687
688 if (cap->active_buf_cnt >= cap->reqbufs_count ||
689 cap->active_buf_cnt >= FIMC_MAX_OUT_BUFS) {
690 if (!test_and_set_bit(ST_CAPT_STREAM, &fimc->state))
691 fimc_activate_capture(ctx);
692 }
693 spin_unlock_irqrestore(&fimc->slock, flags);
694 }
602} 695}
603 696
604static struct videobuf_queue_ops fimc_qops = { 697struct videobuf_queue_ops fimc_qops = {
605 .buf_setup = fimc_buf_setup, 698 .buf_setup = fimc_buf_setup,
606 .buf_prepare = fimc_buf_prepare, 699 .buf_prepare = fimc_buf_prepare,
607 .buf_queue = fimc_buf_queue, 700 .buf_queue = fimc_buf_queue,
@@ -624,7 +717,7 @@ static int fimc_m2m_querycap(struct file *file, void *priv,
624 return 0; 717 return 0;
625} 718}
626 719
627static int fimc_m2m_enum_fmt(struct file *file, void *priv, 720int fimc_vidioc_enum_fmt(struct file *file, void *priv,
628 struct v4l2_fmtdesc *f) 721 struct v4l2_fmtdesc *f)
629{ 722{
630 struct fimc_fmt *fmt; 723 struct fimc_fmt *fmt;
@@ -635,109 +728,139 @@ static int fimc_m2m_enum_fmt(struct file *file, void *priv,
635 fmt = &fimc_formats[f->index]; 728 fmt = &fimc_formats[f->index];
636 strncpy(f->description, fmt->name, sizeof(f->description) - 1); 729 strncpy(f->description, fmt->name, sizeof(f->description) - 1);
637 f->pixelformat = fmt->fourcc; 730 f->pixelformat = fmt->fourcc;
731
638 return 0; 732 return 0;
639} 733}
640 734
641static int fimc_m2m_g_fmt(struct file *file, void *priv, struct v4l2_format *f) 735int fimc_vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
642{ 736{
643 struct fimc_ctx *ctx = priv; 737 struct fimc_ctx *ctx = priv;
738 struct fimc_dev *fimc = ctx->fimc_dev;
644 struct fimc_frame *frame; 739 struct fimc_frame *frame;
645 740
646 frame = ctx_get_frame(ctx, f->type); 741 frame = ctx_get_frame(ctx, f->type);
647 if (IS_ERR(frame)) 742 if (IS_ERR(frame))
648 return PTR_ERR(frame); 743 return PTR_ERR(frame);
649 744
745 if (mutex_lock_interruptible(&fimc->lock))
746 return -ERESTARTSYS;
747
650 f->fmt.pix.width = frame->width; 748 f->fmt.pix.width = frame->width;
651 f->fmt.pix.height = frame->height; 749 f->fmt.pix.height = frame->height;
652 f->fmt.pix.field = V4L2_FIELD_NONE; 750 f->fmt.pix.field = V4L2_FIELD_NONE;
653 f->fmt.pix.pixelformat = frame->fmt->fourcc; 751 f->fmt.pix.pixelformat = frame->fmt->fourcc;
654 752
753 mutex_unlock(&fimc->lock);
655 return 0; 754 return 0;
656} 755}
657 756
658static struct fimc_fmt *find_format(struct v4l2_format *f) 757struct fimc_fmt *find_format(struct v4l2_format *f, unsigned int mask)
659{ 758{
660 struct fimc_fmt *fmt; 759 struct fimc_fmt *fmt;
661 unsigned int i; 760 unsigned int i;
662 761
663 for (i = 0; i < ARRAY_SIZE(fimc_formats); ++i) { 762 for (i = 0; i < ARRAY_SIZE(fimc_formats); ++i) {
664 fmt = &fimc_formats[i]; 763 fmt = &fimc_formats[i];
665 if (fmt->fourcc == f->fmt.pix.pixelformat) 764 if (fmt->fourcc == f->fmt.pix.pixelformat &&
765 (fmt->flags & mask))
666 break; 766 break;
667 } 767 }
668 if (i == ARRAY_SIZE(fimc_formats))
669 return NULL;
670 768
671 return fmt; 769 return (i == ARRAY_SIZE(fimc_formats)) ? NULL : fmt;
672} 770}
673 771
674static int fimc_m2m_try_fmt(struct file *file, void *priv, 772struct fimc_fmt *find_mbus_format(struct v4l2_mbus_framefmt *f,
675 struct v4l2_format *f) 773 unsigned int mask)
676{ 774{
677 struct fimc_fmt *fmt; 775 struct fimc_fmt *fmt;
678 u32 max_width, max_height, mod_x, mod_y; 776 unsigned int i;
777
778 for (i = 0; i < ARRAY_SIZE(fimc_formats); ++i) {
779 fmt = &fimc_formats[i];
780 if (fmt->mbus_code == f->code && (fmt->flags & mask))
781 break;
782 }
783
784 return (i == ARRAY_SIZE(fimc_formats)) ? NULL : fmt;
785}
786
787
788int fimc_vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
789{
679 struct fimc_ctx *ctx = priv; 790 struct fimc_ctx *ctx = priv;
680 struct fimc_dev *fimc = ctx->fimc_dev; 791 struct fimc_dev *fimc = ctx->fimc_dev;
681 struct v4l2_pix_format *pix = &f->fmt.pix;
682 struct samsung_fimc_variant *variant = fimc->variant; 792 struct samsung_fimc_variant *variant = fimc->variant;
793 struct v4l2_pix_format *pix = &f->fmt.pix;
794 struct fimc_fmt *fmt;
795 u32 max_width, mod_x, mod_y, mask;
796 int ret = -EINVAL, is_output = 0;
683 797
684 fmt = find_format(f); 798 if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
685 if (!fmt) { 799 if (ctx->state & FIMC_CTX_CAP)
686 v4l2_err(&fimc->m2m.v4l2_dev, 800 return -EINVAL;
687 "Fourcc format (0x%X) invalid.\n", pix->pixelformat); 801 is_output = 1;
802 } else if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
688 return -EINVAL; 803 return -EINVAL;
689 } 804 }
690 805
806 dbg("w: %d, h: %d, bpl: %d",
807 pix->width, pix->height, pix->bytesperline);
808
809 if (mutex_lock_interruptible(&fimc->lock))
810 return -ERESTARTSYS;
811
812 mask = is_output ? FMT_FLAGS_M2M : FMT_FLAGS_M2M | FMT_FLAGS_CAM;
813 fmt = find_format(f, mask);
814 if (!fmt) {
815 v4l2_err(&fimc->m2m.v4l2_dev, "Fourcc format (0x%X) invalid.\n",
816 pix->pixelformat);
817 goto tf_out;
818 }
819
691 if (pix->field == V4L2_FIELD_ANY) 820 if (pix->field == V4L2_FIELD_ANY)
692 pix->field = V4L2_FIELD_NONE; 821 pix->field = V4L2_FIELD_NONE;
693 else if (V4L2_FIELD_NONE != pix->field) 822 else if (V4L2_FIELD_NONE != pix->field)
694 return -EINVAL; 823 goto tf_out;
695 824
696 if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { 825 if (is_output) {
697 max_width = variant->scaler_dis_w; 826 max_width = variant->scaler_dis_w;
698 max_height = variant->scaler_dis_w; 827 mod_x = ffs(variant->min_inp_pixsize) - 1;
699 mod_x = variant->min_inp_pixsize;
700 mod_y = variant->min_inp_pixsize;
701 } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
702 max_width = variant->out_rot_dis_w;
703 max_height = variant->out_rot_dis_w;
704 mod_x = variant->min_out_pixsize;
705 mod_y = variant->min_out_pixsize;
706 } else { 828 } else {
707 err("Wrong stream type (%d)", f->type); 829 max_width = variant->out_rot_dis_w;
708 return -EINVAL; 830 mod_x = ffs(variant->min_out_pixsize) - 1;
709 } 831 }
710 832
711 dbg("max_w= %d, max_h= %d", max_width, max_height);
712
713 if (pix->height > max_height)
714 pix->height = max_height;
715 if (pix->width > max_width)
716 pix->width = max_width;
717
718 if (tiled_fmt(fmt)) { 833 if (tiled_fmt(fmt)) {
719 mod_x = 64; /* 64x32 tile */ 834 mod_x = 6; /* 64 x 32 pixels tile */
720 mod_y = 32; 835 mod_y = 5;
836 } else {
837 if (fimc->id == 1 && fimc->variant->pix_hoff)
838 mod_y = fimc_fmt_is_rgb(fmt->color) ? 0 : 1;
839 else
840 mod_y = mod_x;
721 } 841 }
722 842
723 dbg("mod_x= 0x%X, mod_y= 0x%X", mod_x, mod_y); 843 dbg("mod_x: %d, mod_y: %d, max_w: %d", mod_x, mod_y, max_width);
724 844
725 pix->width = (pix->width == 0) ? mod_x : ALIGN(pix->width, mod_x); 845 v4l_bound_align_image(&pix->width, 16, max_width, mod_x,
726 pix->height = (pix->height == 0) ? mod_y : ALIGN(pix->height, mod_y); 846 &pix->height, 8, variant->scaler_dis_w, mod_y, 0);
727 847
728 if (pix->bytesperline == 0 || 848 if (pix->bytesperline == 0 ||
729 pix->bytesperline * 8 / fmt->depth > pix->width) 849 (pix->bytesperline * 8 / fmt->depth) > pix->width)
730 pix->bytesperline = (pix->width * fmt->depth) >> 3; 850 pix->bytesperline = (pix->width * fmt->depth) >> 3;
731 851
732 if (pix->sizeimage == 0) 852 if (pix->sizeimage == 0)
733 pix->sizeimage = pix->height * pix->bytesperline; 853 pix->sizeimage = pix->height * pix->bytesperline;
734 854
735 dbg("pix->bytesperline= %d, fmt->depth= %d", 855 dbg("w: %d, h: %d, bpl: %d, depth: %d",
736 pix->bytesperline, fmt->depth); 856 pix->width, pix->height, pix->bytesperline, fmt->depth);
737 857
738 return 0; 858 ret = 0;
739}
740 859
860tf_out:
861 mutex_unlock(&fimc->lock);
862 return ret;
863}
741 864
742static int fimc_m2m_s_fmt(struct file *file, void *priv, struct v4l2_format *f) 865static int fimc_m2m_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
743{ 866{
@@ -750,9 +873,7 @@ static int fimc_m2m_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
750 unsigned long flags; 873 unsigned long flags;
751 int ret = 0; 874 int ret = 0;
752 875
753 BUG_ON(!ctx); 876 ret = fimc_vidioc_try_fmt(file, priv, f);
754
755 ret = fimc_m2m_try_fmt(file, priv, f);
756 if (ret) 877 if (ret)
757 return ret; 878 return ret;
758 879
@@ -785,7 +906,7 @@ static int fimc_m2m_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
785 spin_unlock_irqrestore(&ctx->slock, flags); 906 spin_unlock_irqrestore(&ctx->slock, flags);
786 907
787 pix = &f->fmt.pix; 908 pix = &f->fmt.pix;
788 frame->fmt = find_format(f); 909 frame->fmt = find_format(f, FMT_FLAGS_M2M);
789 if (!frame->fmt) { 910 if (!frame->fmt) {
790 ret = -EINVAL; 911 ret = -EINVAL;
791 goto sf_out; 912 goto sf_out;
@@ -857,21 +978,33 @@ static int fimc_m2m_streamoff(struct file *file, void *priv,
857 return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type); 978 return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
858} 979}
859 980
860int fimc_m2m_queryctrl(struct file *file, void *priv, 981int fimc_vidioc_queryctrl(struct file *file, void *priv,
861 struct v4l2_queryctrl *qc) 982 struct v4l2_queryctrl *qc)
862{ 983{
984 struct fimc_ctx *ctx = priv;
863 struct v4l2_queryctrl *c; 985 struct v4l2_queryctrl *c;
986
864 c = get_ctrl(qc->id); 987 c = get_ctrl(qc->id);
865 if (!c) 988 if (c) {
866 return -EINVAL; 989 *qc = *c;
867 *qc = *c; 990 return 0;
868 return 0; 991 }
992
993 if (ctx->state & FIMC_CTX_CAP)
994 return v4l2_subdev_call(ctx->fimc_dev->vid_cap.sd,
995 core, queryctrl, qc);
996 return -EINVAL;
869} 997}
870 998
871int fimc_m2m_g_ctrl(struct file *file, void *priv, 999int fimc_vidioc_g_ctrl(struct file *file, void *priv,
872 struct v4l2_control *ctrl) 1000 struct v4l2_control *ctrl)
873{ 1001{
874 struct fimc_ctx *ctx = priv; 1002 struct fimc_ctx *ctx = priv;
1003 struct fimc_dev *fimc = ctx->fimc_dev;
1004 int ret = 0;
1005
1006 if (mutex_lock_interruptible(&fimc->lock))
1007 return -ERESTARTSYS;
875 1008
876 switch (ctrl->id) { 1009 switch (ctrl->id) {
877 case V4L2_CID_HFLIP: 1010 case V4L2_CID_HFLIP:
@@ -884,15 +1017,22 @@ int fimc_m2m_g_ctrl(struct file *file, void *priv,
884 ctrl->value = ctx->rotation; 1017 ctrl->value = ctx->rotation;
885 break; 1018 break;
886 default: 1019 default:
887 v4l2_err(&ctx->fimc_dev->m2m.v4l2_dev, "Invalid control\n"); 1020 if (ctx->state & FIMC_CTX_CAP) {
888 return -EINVAL; 1021 ret = v4l2_subdev_call(fimc->vid_cap.sd, core,
1022 g_ctrl, ctrl);
1023 } else {
1024 v4l2_err(&fimc->m2m.v4l2_dev,
1025 "Invalid control\n");
1026 ret = -EINVAL;
1027 }
889 } 1028 }
890 dbg("ctrl->value= %d", ctrl->value); 1029 dbg("ctrl->value= %d", ctrl->value);
891 return 0; 1030
1031 mutex_unlock(&fimc->lock);
1032 return ret;
892} 1033}
893 1034
894static int check_ctrl_val(struct fimc_ctx *ctx, 1035int check_ctrl_val(struct fimc_ctx *ctx, struct v4l2_control *ctrl)
895 struct v4l2_control *ctrl)
896{ 1036{
897 struct v4l2_queryctrl *c; 1037 struct v4l2_queryctrl *c;
898 c = get_ctrl(ctrl->id); 1038 c = get_ctrl(ctrl->id);
@@ -909,22 +1049,23 @@ static int check_ctrl_val(struct fimc_ctx *ctx,
909 return 0; 1049 return 0;
910} 1050}
911 1051
912int fimc_m2m_s_ctrl(struct file *file, void *priv, 1052int fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_control *ctrl)
913 struct v4l2_control *ctrl)
914{ 1053{
915 struct fimc_ctx *ctx = priv;
916 struct samsung_fimc_variant *variant = ctx->fimc_dev->variant; 1054 struct samsung_fimc_variant *variant = ctx->fimc_dev->variant;
1055 struct fimc_dev *fimc = ctx->fimc_dev;
917 unsigned long flags; 1056 unsigned long flags;
918 int ret = 0;
919 1057
920 ret = check_ctrl_val(ctx, ctrl); 1058 if (ctx->rotation != 0 &&
921 if (ret) 1059 (ctrl->id == V4L2_CID_HFLIP || ctrl->id == V4L2_CID_VFLIP)) {
922 return ret; 1060 v4l2_err(&fimc->m2m.v4l2_dev,
1061 "Simultaneous flip and rotation is not supported\n");
1062 return -EINVAL;
1063 }
1064
1065 spin_lock_irqsave(&ctx->slock, flags);
923 1066
924 switch (ctrl->id) { 1067 switch (ctrl->id) {
925 case V4L2_CID_HFLIP: 1068 case V4L2_CID_HFLIP:
926 if (ctx->rotation != 0)
927 return 0;
928 if (ctrl->value) 1069 if (ctrl->value)
929 ctx->flip |= FLIP_X_AXIS; 1070 ctx->flip |= FLIP_X_AXIS;
930 else 1071 else
@@ -932,8 +1073,6 @@ int fimc_m2m_s_ctrl(struct file *file, void *priv,
932 break; 1073 break;
933 1074
934 case V4L2_CID_VFLIP: 1075 case V4L2_CID_VFLIP:
935 if (ctx->rotation != 0)
936 return 0;
937 if (ctrl->value) 1076 if (ctrl->value)
938 ctx->flip |= FLIP_Y_AXIS; 1077 ctx->flip |= FLIP_Y_AXIS;
939 else 1078 else
@@ -941,77 +1080,95 @@ int fimc_m2m_s_ctrl(struct file *file, void *priv,
941 break; 1080 break;
942 1081
943 case V4L2_CID_ROTATE: 1082 case V4L2_CID_ROTATE:
944 if (ctrl->value == 90 || ctrl->value == 270) { 1083 /* Check for the output rotator availability */
945 if (ctx->out_path == FIMC_LCDFIFO && 1084 if ((ctrl->value == 90 || ctrl->value == 270) &&
946 !variant->has_inp_rot) { 1085 (ctx->in_path == FIMC_DMA && !variant->has_out_rot)) {
947 return -EINVAL; 1086 spin_unlock_irqrestore(&ctx->slock, flags);
948 } else if (ctx->in_path == FIMC_DMA && 1087 return -EINVAL;
949 !variant->has_out_rot) { 1088 } else {
950 return -EINVAL; 1089 ctx->rotation = ctrl->value;
951 }
952 } 1090 }
953 ctx->rotation = ctrl->value;
954 if (ctrl->value == 180)
955 ctx->flip = FLIP_XY_AXIS;
956 break; 1091 break;
957 1092
958 default: 1093 default:
959 v4l2_err(&ctx->fimc_dev->m2m.v4l2_dev, "Invalid control\n"); 1094 spin_unlock_irqrestore(&ctx->slock, flags);
1095 v4l2_err(&fimc->m2m.v4l2_dev, "Invalid control\n");
960 return -EINVAL; 1096 return -EINVAL;
961 } 1097 }
962 spin_lock_irqsave(&ctx->slock, flags);
963 ctx->state |= FIMC_PARAMS; 1098 ctx->state |= FIMC_PARAMS;
964 spin_unlock_irqrestore(&ctx->slock, flags); 1099 spin_unlock_irqrestore(&ctx->slock, flags);
1100
965 return 0; 1101 return 0;
966} 1102}
967 1103
1104static int fimc_m2m_s_ctrl(struct file *file, void *priv,
1105 struct v4l2_control *ctrl)
1106{
1107 struct fimc_ctx *ctx = priv;
1108 int ret = 0;
1109
1110 ret = check_ctrl_val(ctx, ctrl);
1111 if (ret)
1112 return ret;
1113
1114 ret = fimc_s_ctrl(ctx, ctrl);
1115 return 0;
1116}
968 1117
969static int fimc_m2m_cropcap(struct file *file, void *fh, 1118int fimc_vidioc_cropcap(struct file *file, void *fh,
970 struct v4l2_cropcap *cr) 1119 struct v4l2_cropcap *cr)
971{ 1120{
972 struct fimc_frame *frame; 1121 struct fimc_frame *frame;
973 struct fimc_ctx *ctx = fh; 1122 struct fimc_ctx *ctx = fh;
1123 struct fimc_dev *fimc = ctx->fimc_dev;
974 1124
975 frame = ctx_get_frame(ctx, cr->type); 1125 frame = ctx_get_frame(ctx, cr->type);
976 if (IS_ERR(frame)) 1126 if (IS_ERR(frame))
977 return PTR_ERR(frame); 1127 return PTR_ERR(frame);
978 1128
979 cr->bounds.left = 0; 1129 if (mutex_lock_interruptible(&fimc->lock))
980 cr->bounds.top = 0; 1130 return -ERESTARTSYS;
981 cr->bounds.width = frame->f_width; 1131
982 cr->bounds.height = frame->f_height; 1132 cr->bounds.left = 0;
983 cr->defrect.left = frame->offs_h; 1133 cr->bounds.top = 0;
984 cr->defrect.top = frame->offs_v; 1134 cr->bounds.width = frame->f_width;
985 cr->defrect.width = frame->o_width; 1135 cr->bounds.height = frame->f_height;
986 cr->defrect.height = frame->o_height; 1136 cr->defrect = cr->bounds;
1137
1138 mutex_unlock(&fimc->lock);
987 return 0; 1139 return 0;
988} 1140}
989 1141
990static int fimc_m2m_g_crop(struct file *file, void *fh, struct v4l2_crop *cr) 1142int fimc_vidioc_g_crop(struct file *file, void *fh, struct v4l2_crop *cr)
991{ 1143{
992 struct fimc_frame *frame; 1144 struct fimc_frame *frame;
993 struct fimc_ctx *ctx = file->private_data; 1145 struct fimc_ctx *ctx = file->private_data;
1146 struct fimc_dev *fimc = ctx->fimc_dev;
994 1147
995 frame = ctx_get_frame(ctx, cr->type); 1148 frame = ctx_get_frame(ctx, cr->type);
996 if (IS_ERR(frame)) 1149 if (IS_ERR(frame))
997 return PTR_ERR(frame); 1150 return PTR_ERR(frame);
998 1151
1152 if (mutex_lock_interruptible(&fimc->lock))
1153 return -ERESTARTSYS;
1154
999 cr->c.left = frame->offs_h; 1155 cr->c.left = frame->offs_h;
1000 cr->c.top = frame->offs_v; 1156 cr->c.top = frame->offs_v;
1001 cr->c.width = frame->width; 1157 cr->c.width = frame->width;
1002 cr->c.height = frame->height; 1158 cr->c.height = frame->height;
1003 1159
1160 mutex_unlock(&fimc->lock);
1004 return 0; 1161 return 0;
1005} 1162}
1006 1163
1007static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr) 1164int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr)
1008{ 1165{
1009 struct fimc_ctx *ctx = file->private_data;
1010 struct fimc_dev *fimc = ctx->fimc_dev; 1166 struct fimc_dev *fimc = ctx->fimc_dev;
1011 unsigned long flags;
1012 struct fimc_frame *f; 1167 struct fimc_frame *f;
1013 u32 min_size; 1168 u32 min_size, halign;
1014 int ret = 0; 1169
1170 f = (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) ?
1171 &ctx->s_frame : &ctx->d_frame;
1015 1172
1016 if (cr->c.top < 0 || cr->c.left < 0) { 1173 if (cr->c.top < 0 || cr->c.left < 0) {
1017 v4l2_err(&fimc->m2m.v4l2_dev, 1174 v4l2_err(&fimc->m2m.v4l2_dev,
@@ -1019,66 +1176,98 @@ static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr)
1019 return -EINVAL; 1176 return -EINVAL;
1020 } 1177 }
1021 1178
1022 if (cr->c.width <= 0 || cr->c.height <= 0) {
1023 v4l2_err(&fimc->m2m.v4l2_dev,
1024 "crop width and height must be greater than 0\n");
1025 return -EINVAL;
1026 }
1027
1028 f = ctx_get_frame(ctx, cr->type); 1179 f = ctx_get_frame(ctx, cr->type);
1029 if (IS_ERR(f)) 1180 if (IS_ERR(f))
1030 return PTR_ERR(f); 1181 return PTR_ERR(f);
1031 1182
1032 /* Adjust to required pixel boundary. */ 1183 min_size = (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
1033 min_size = (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) ? 1184 ? fimc->variant->min_inp_pixsize
1034 fimc->variant->min_inp_pixsize : fimc->variant->min_out_pixsize; 1185 : fimc->variant->min_out_pixsize;
1035 1186
1036 cr->c.width = round_down(cr->c.width, min_size); 1187 if (ctx->state & FIMC_CTX_M2M) {
1037 cr->c.height = round_down(cr->c.height, min_size); 1188 if (fimc->id == 1 && fimc->variant->pix_hoff)
1038 cr->c.left = round_down(cr->c.left + 1, min_size); 1189 halign = fimc_fmt_is_rgb(f->fmt->color) ? 0 : 1;
1039 cr->c.top = round_down(cr->c.top + 1, min_size); 1190 else
1040 1191 halign = ffs(min_size) - 1;
1041 if ((cr->c.left + cr->c.width > f->o_width) 1192 /* there are more strict aligment requirements at camera interface */
1042 || (cr->c.top + cr->c.height > f->o_height)) { 1193 } else {
1043 v4l2_err(&fimc->m2m.v4l2_dev, "Error in S_CROP params\n"); 1194 min_size = 16;
1044 return -EINVAL; 1195 halign = 4;
1045 } 1196 }
1046 1197
1198 v4l_bound_align_image(&cr->c.width, min_size, f->o_width,
1199 ffs(min_size) - 1,
1200 &cr->c.height, min_size, f->o_height,
1201 halign, 64/(ALIGN(f->fmt->depth, 8)));
1202
1203 /* adjust left/top if cropping rectangle is out of bounds */
1204 if (cr->c.left + cr->c.width > f->o_width)
1205 cr->c.left = f->o_width - cr->c.width;
1206 if (cr->c.top + cr->c.height > f->o_height)
1207 cr->c.top = f->o_height - cr->c.height;
1208
1209 cr->c.left = round_down(cr->c.left, min_size);
1210 cr->c.top = round_down(cr->c.top,
1211 ctx->state & FIMC_CTX_M2M ? 8 : 16);
1212
1213 dbg("l:%d, t:%d, w:%d, h:%d, f_w: %d, f_h: %d",
1214 cr->c.left, cr->c.top, cr->c.width, cr->c.height,
1215 f->f_width, f->f_height);
1216
1217 return 0;
1218}
1219
1220
1221static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr)
1222{
1223 struct fimc_ctx *ctx = file->private_data;
1224 struct fimc_dev *fimc = ctx->fimc_dev;
1225 unsigned long flags;
1226 struct fimc_frame *f;
1227 int ret;
1228
1229 ret = fimc_try_crop(ctx, cr);
1230 if (ret)
1231 return ret;
1232
1233 f = (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) ?
1234 &ctx->s_frame : &ctx->d_frame;
1235
1047 spin_lock_irqsave(&ctx->slock, flags); 1236 spin_lock_irqsave(&ctx->slock, flags);
1048 if ((ctx->state & FIMC_SRC_FMT) && (ctx->state & FIMC_DST_FMT)) { 1237 if (~ctx->state & (FIMC_SRC_FMT | FIMC_DST_FMT)) {
1049 /* Check for the pixel scaling ratio when cropping input img. */ 1238 /* Check to see if scaling ratio is within supported range */
1050 if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) 1239 if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
1051 ret = fimc_check_scaler_ratio(&cr->c, &ctx->d_frame); 1240 ret = fimc_check_scaler_ratio(&cr->c, &ctx->d_frame);
1052 else if (cr->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) 1241 else
1053 ret = fimc_check_scaler_ratio(&cr->c, &ctx->s_frame); 1242 ret = fimc_check_scaler_ratio(&cr->c, &ctx->s_frame);
1054
1055 if (ret) { 1243 if (ret) {
1056 spin_unlock_irqrestore(&ctx->slock, flags); 1244 spin_unlock_irqrestore(&ctx->slock, flags);
1057 v4l2_err(&fimc->m2m.v4l2_dev, "Out of scaler range"); 1245 v4l2_err(&fimc->m2m.v4l2_dev, "Out of scaler range");
1058 return -EINVAL; 1246 return -EINVAL;
1059 } 1247 }
1060 } 1248 }
1061 ctx->state |= FIMC_PARAMS; 1249 ctx->state |= FIMC_PARAMS;
1062 spin_unlock_irqrestore(&ctx->slock, flags);
1063 1250
1064 f->offs_h = cr->c.left; 1251 f->offs_h = cr->c.left;
1065 f->offs_v = cr->c.top; 1252 f->offs_v = cr->c.top;
1066 f->width = cr->c.width; 1253 f->width = cr->c.width;
1067 f->height = cr->c.height; 1254 f->height = cr->c.height;
1255
1256 spin_unlock_irqrestore(&ctx->slock, flags);
1068 return 0; 1257 return 0;
1069} 1258}
1070 1259
1071static const struct v4l2_ioctl_ops fimc_m2m_ioctl_ops = { 1260static const struct v4l2_ioctl_ops fimc_m2m_ioctl_ops = {
1072 .vidioc_querycap = fimc_m2m_querycap, 1261 .vidioc_querycap = fimc_m2m_querycap,
1073 1262
1074 .vidioc_enum_fmt_vid_cap = fimc_m2m_enum_fmt, 1263 .vidioc_enum_fmt_vid_cap = fimc_vidioc_enum_fmt,
1075 .vidioc_enum_fmt_vid_out = fimc_m2m_enum_fmt, 1264 .vidioc_enum_fmt_vid_out = fimc_vidioc_enum_fmt,
1076 1265
1077 .vidioc_g_fmt_vid_cap = fimc_m2m_g_fmt, 1266 .vidioc_g_fmt_vid_cap = fimc_vidioc_g_fmt,
1078 .vidioc_g_fmt_vid_out = fimc_m2m_g_fmt, 1267 .vidioc_g_fmt_vid_out = fimc_vidioc_g_fmt,
1079 1268
1080 .vidioc_try_fmt_vid_cap = fimc_m2m_try_fmt, 1269 .vidioc_try_fmt_vid_cap = fimc_vidioc_try_fmt,
1081 .vidioc_try_fmt_vid_out = fimc_m2m_try_fmt, 1270 .vidioc_try_fmt_vid_out = fimc_vidioc_try_fmt,
1082 1271
1083 .vidioc_s_fmt_vid_cap = fimc_m2m_s_fmt, 1272 .vidioc_s_fmt_vid_cap = fimc_m2m_s_fmt,
1084 .vidioc_s_fmt_vid_out = fimc_m2m_s_fmt, 1273 .vidioc_s_fmt_vid_out = fimc_m2m_s_fmt,
@@ -1092,13 +1281,13 @@ static const struct v4l2_ioctl_ops fimc_m2m_ioctl_ops = {
1092 .vidioc_streamon = fimc_m2m_streamon, 1281 .vidioc_streamon = fimc_m2m_streamon,
1093 .vidioc_streamoff = fimc_m2m_streamoff, 1282 .vidioc_streamoff = fimc_m2m_streamoff,
1094 1283
1095 .vidioc_queryctrl = fimc_m2m_queryctrl, 1284 .vidioc_queryctrl = fimc_vidioc_queryctrl,
1096 .vidioc_g_ctrl = fimc_m2m_g_ctrl, 1285 .vidioc_g_ctrl = fimc_vidioc_g_ctrl,
1097 .vidioc_s_ctrl = fimc_m2m_s_ctrl, 1286 .vidioc_s_ctrl = fimc_m2m_s_ctrl,
1098 1287
1099 .vidioc_g_crop = fimc_m2m_g_crop, 1288 .vidioc_g_crop = fimc_vidioc_g_crop,
1100 .vidioc_s_crop = fimc_m2m_s_crop, 1289 .vidioc_s_crop = fimc_m2m_s_crop,
1101 .vidioc_cropcap = fimc_m2m_cropcap 1290 .vidioc_cropcap = fimc_vidioc_cropcap
1102 1291
1103}; 1292};
1104 1293
@@ -1120,11 +1309,23 @@ static int fimc_m2m_open(struct file *file)
1120 struct fimc_ctx *ctx = NULL; 1309 struct fimc_ctx *ctx = NULL;
1121 int err = 0; 1310 int err = 0;
1122 1311
1123 mutex_lock(&fimc->lock); 1312 if (mutex_lock_interruptible(&fimc->lock))
1313 return -ERESTARTSYS;
1314
1315 dbg("pid: %d, state: 0x%lx, refcnt: %d",
1316 task_pid_nr(current), fimc->state, fimc->vid_cap.refcnt);
1317
1318 /*
1319 * Return if the corresponding video capture node
1320 * is already opened.
1321 */
1322 if (fimc->vid_cap.refcnt > 0) {
1323 mutex_unlock(&fimc->lock);
1324 return -EBUSY;
1325 }
1326
1124 fimc->m2m.refcnt++; 1327 fimc->m2m.refcnt++;
1125 set_bit(ST_OUTDMA_RUN, &fimc->state); 1328 set_bit(ST_OUTDMA_RUN, &fimc->state);
1126 mutex_unlock(&fimc->lock);
1127
1128 1329
1129 ctx = kzalloc(sizeof *ctx, GFP_KERNEL); 1330 ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
1130 if (!ctx) 1331 if (!ctx)
@@ -1135,8 +1336,8 @@ static int fimc_m2m_open(struct file *file)
1135 /* Default color format */ 1336 /* Default color format */
1136 ctx->s_frame.fmt = &fimc_formats[0]; 1337 ctx->s_frame.fmt = &fimc_formats[0];
1137 ctx->d_frame.fmt = &fimc_formats[0]; 1338 ctx->d_frame.fmt = &fimc_formats[0];
1138 /* per user process device context initialization */ 1339 /* Setup the device context for mem2mem mode. */
1139 ctx->state = 0; 1340 ctx->state = FIMC_CTX_M2M;
1140 ctx->flags = 0; 1341 ctx->flags = 0;
1141 ctx->in_path = FIMC_DMA; 1342 ctx->in_path = FIMC_DMA;
1142 ctx->out_path = FIMC_DMA; 1343 ctx->out_path = FIMC_DMA;
@@ -1147,6 +1348,8 @@ static int fimc_m2m_open(struct file *file)
1147 err = PTR_ERR(ctx->m2m_ctx); 1348 err = PTR_ERR(ctx->m2m_ctx);
1148 kfree(ctx); 1349 kfree(ctx);
1149 } 1350 }
1351
1352 mutex_unlock(&fimc->lock);
1150 return err; 1353 return err;
1151} 1354}
1152 1355
@@ -1155,11 +1358,16 @@ static int fimc_m2m_release(struct file *file)
1155 struct fimc_ctx *ctx = file->private_data; 1358 struct fimc_ctx *ctx = file->private_data;
1156 struct fimc_dev *fimc = ctx->fimc_dev; 1359 struct fimc_dev *fimc = ctx->fimc_dev;
1157 1360
1361 mutex_lock(&fimc->lock);
1362
1363 dbg("pid: %d, state: 0x%lx, refcnt= %d",
1364 task_pid_nr(current), fimc->state, fimc->m2m.refcnt);
1365
1158 v4l2_m2m_ctx_release(ctx->m2m_ctx); 1366 v4l2_m2m_ctx_release(ctx->m2m_ctx);
1159 kfree(ctx); 1367 kfree(ctx);
1160 mutex_lock(&fimc->lock);
1161 if (--fimc->m2m.refcnt <= 0) 1368 if (--fimc->m2m.refcnt <= 0)
1162 clear_bit(ST_OUTDMA_RUN, &fimc->state); 1369 clear_bit(ST_OUTDMA_RUN, &fimc->state);
1370
1163 mutex_unlock(&fimc->lock); 1371 mutex_unlock(&fimc->lock);
1164 return 0; 1372 return 0;
1165} 1373}
@@ -1168,6 +1376,7 @@ static unsigned int fimc_m2m_poll(struct file *file,
1168 struct poll_table_struct *wait) 1376 struct poll_table_struct *wait)
1169{ 1377{
1170 struct fimc_ctx *ctx = file->private_data; 1378 struct fimc_ctx *ctx = file->private_data;
1379
1171 return v4l2_m2m_poll(file, ctx->m2m_ctx, wait); 1380 return v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
1172} 1381}
1173 1382
@@ -1175,6 +1384,7 @@ static unsigned int fimc_m2m_poll(struct file *file,
1175static int fimc_m2m_mmap(struct file *file, struct vm_area_struct *vma) 1384static int fimc_m2m_mmap(struct file *file, struct vm_area_struct *vma)
1176{ 1385{
1177 struct fimc_ctx *ctx = file->private_data; 1386 struct fimc_ctx *ctx = file->private_data;
1387
1178 return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma); 1388 return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
1179} 1389}
1180 1390
@@ -1322,9 +1532,11 @@ static int fimc_probe(struct platform_device *pdev)
1322 fimc->id = pdev->id; 1532 fimc->id = pdev->id;
1323 fimc->variant = drv_data->variant[fimc->id]; 1533 fimc->variant = drv_data->variant[fimc->id];
1324 fimc->pdev = pdev; 1534 fimc->pdev = pdev;
1535 fimc->pdata = pdev->dev.platform_data;
1325 fimc->state = ST_IDLE; 1536 fimc->state = ST_IDLE;
1326 1537
1327 spin_lock_init(&fimc->irqlock); 1538 spin_lock_init(&fimc->irqlock);
1539 init_waitqueue_head(&fimc->irq_queue);
1328 spin_lock_init(&fimc->slock); 1540 spin_lock_init(&fimc->slock);
1329 1541
1330 mutex_init(&fimc->lock); 1542 mutex_init(&fimc->lock);
@@ -1354,6 +1566,7 @@ static int fimc_probe(struct platform_device *pdev)
1354 ret = fimc_clk_get(fimc); 1566 ret = fimc_clk_get(fimc);
1355 if (ret) 1567 if (ret)
1356 goto err_regs_unmap; 1568 goto err_regs_unmap;
1569 clk_set_rate(fimc->clock[0], drv_data->lclk_frequency);
1357 1570
1358 res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 1571 res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
1359 if (!res) { 1572 if (!res) {
@@ -1375,11 +1588,27 @@ static int fimc_probe(struct platform_device *pdev)
1375 if (ret) 1588 if (ret)
1376 goto err_irq; 1589 goto err_irq;
1377 1590
1591 /* At least one camera sensor is required to register capture node */
1592 if (fimc->pdata) {
1593 int i;
1594 for (i = 0; i < FIMC_MAX_CAMIF_CLIENTS; ++i)
1595 if (fimc->pdata->isp_info[i])
1596 break;
1597
1598 if (i < FIMC_MAX_CAMIF_CLIENTS) {
1599 ret = fimc_register_capture_device(fimc);
1600 if (ret)
1601 goto err_m2m;
1602 }
1603 }
1604
1378 dev_dbg(&pdev->dev, "%s(): fimc-%d registered successfully\n", 1605 dev_dbg(&pdev->dev, "%s(): fimc-%d registered successfully\n",
1379 __func__, fimc->id); 1606 __func__, fimc->id);
1380 1607
1381 return 0; 1608 return 0;
1382 1609
1610err_m2m:
1611 fimc_unregister_m2m_device(fimc);
1383err_irq: 1612err_irq:
1384 free_irq(fimc->irq, fimc); 1613 free_irq(fimc->irq, fimc);
1385err_clk: 1614err_clk:
@@ -1404,6 +1633,8 @@ static int __devexit fimc_remove(struct platform_device *pdev)
1404 fimc_hw_reset(fimc); 1633 fimc_hw_reset(fimc);
1405 1634
1406 fimc_unregister_m2m_device(fimc); 1635 fimc_unregister_m2m_device(fimc);
1636 fimc_unregister_capture_device(fimc);
1637
1407 fimc_clk_release(fimc); 1638 fimc_clk_release(fimc);
1408 iounmap(fimc->regs); 1639 iounmap(fimc->regs);
1409 release_resource(fimc->regs_res); 1640 release_resource(fimc->regs_res);
@@ -1474,7 +1705,8 @@ static struct samsung_fimc_driverdata fimc_drvdata_s5p = {
1474 [1] = &fimc01_variant_s5p, 1705 [1] = &fimc01_variant_s5p,
1475 [2] = &fimc2_variant_s5p, 1706 [2] = &fimc2_variant_s5p,
1476 }, 1707 },
1477 .devs_cnt = 3 1708 .devs_cnt = 3,
1709 .lclk_frequency = 133000000UL,
1478}; 1710};
1479 1711
1480static struct samsung_fimc_driverdata fimc_drvdata_s5pv210 = { 1712static struct samsung_fimc_driverdata fimc_drvdata_s5pv210 = {
@@ -1483,7 +1715,8 @@ static struct samsung_fimc_driverdata fimc_drvdata_s5pv210 = {
1483 [1] = &fimc01_variant_s5pv210, 1715 [1] = &fimc01_variant_s5pv210,
1484 [2] = &fimc2_variant_s5pv210, 1716 [2] = &fimc2_variant_s5pv210,
1485 }, 1717 },
1486 .devs_cnt = 3 1718 .devs_cnt = 3,
1719 .lclk_frequency = 166000000UL,
1487}; 1720};
1488 1721
1489static struct platform_device_id fimc_driver_ids[] = { 1722static struct platform_device_id fimc_driver_ids[] = {
@@ -1524,6 +1757,6 @@ static void __exit fimc_exit(void)
1524module_init(fimc_init); 1757module_init(fimc_init);
1525module_exit(fimc_exit); 1758module_exit(fimc_exit);
1526 1759
1527MODULE_AUTHOR("Sylwester Nawrocki, s.nawrocki@samsung.com"); 1760MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
1528MODULE_DESCRIPTION("S3C/S5P FIMC (video postprocessor) driver"); 1761MODULE_DESCRIPTION("S5P FIMC camera host interface/video postprocessor driver");
1529MODULE_LICENSE("GPL"); 1762MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h
index 5aeb3efbd457..ce0a6b8a7d54 100644
--- a/drivers/media/video/s5p-fimc/fimc-core.h
+++ b/drivers/media/video/s5p-fimc/fimc-core.h
@@ -11,10 +11,14 @@
11#ifndef FIMC_CORE_H_ 11#ifndef FIMC_CORE_H_
12#define FIMC_CORE_H_ 12#define FIMC_CORE_H_
13 13
14/*#define DEBUG*/
15
14#include <linux/types.h> 16#include <linux/types.h>
15#include <media/videobuf-core.h> 17#include <media/videobuf-core.h>
16#include <media/v4l2-device.h> 18#include <media/v4l2-device.h>
17#include <media/v4l2-mem2mem.h> 19#include <media/v4l2-mem2mem.h>
20#include <media/v4l2-mediabus.h>
21#include <media/s3c_fimc.h>
18#include <linux/videodev2.h> 22#include <linux/videodev2.h>
19#include "regs-fimc.h" 23#include "regs-fimc.h"
20 24
@@ -28,6 +32,8 @@
28#define dbg(fmt, args...) 32#define dbg(fmt, args...)
29#endif 33#endif
30 34
35/* Time to wait for next frame VSYNC interrupt while stopping operation. */
36#define FIMC_SHUTDOWN_TIMEOUT ((100*HZ)/1000)
31#define NUM_FIMC_CLOCKS 2 37#define NUM_FIMC_CLOCKS 2
32#define MODULE_NAME "s5p-fimc" 38#define MODULE_NAME "s5p-fimc"
33#define FIMC_MAX_DEVS 3 39#define FIMC_MAX_DEVS 3
@@ -36,19 +42,41 @@
36#define SCALER_MAX_VRATIO 64 42#define SCALER_MAX_VRATIO 64
37#define DMA_MIN_SIZE 8 43#define DMA_MIN_SIZE 8
38 44
39enum { 45/* FIMC device state flags */
46enum fimc_dev_flags {
47 /* for m2m node */
40 ST_IDLE, 48 ST_IDLE,
41 ST_OUTDMA_RUN, 49 ST_OUTDMA_RUN,
42 ST_M2M_PEND, 50 ST_M2M_PEND,
51 /* for capture node */
52 ST_CAPT_PEND,
53 ST_CAPT_RUN,
54 ST_CAPT_STREAM,
55 ST_CAPT_SHUT,
43}; 56};
44 57
45#define fimc_m2m_active(dev) test_bit(ST_OUTDMA_RUN, &(dev)->state) 58#define fimc_m2m_active(dev) test_bit(ST_OUTDMA_RUN, &(dev)->state)
46#define fimc_m2m_pending(dev) test_bit(ST_M2M_PEND, &(dev)->state) 59#define fimc_m2m_pending(dev) test_bit(ST_M2M_PEND, &(dev)->state)
47 60
61#define fimc_capture_running(dev) test_bit(ST_CAPT_RUN, &(dev)->state)
62#define fimc_capture_pending(dev) test_bit(ST_CAPT_PEND, &(dev)->state)
63
64#define fimc_capture_active(dev) \
65 (test_bit(ST_CAPT_RUN, &(dev)->state) || \
66 test_bit(ST_CAPT_PEND, &(dev)->state))
67
68#define fimc_capture_streaming(dev) \
69 test_bit(ST_CAPT_STREAM, &(dev)->state)
70
71#define fimc_buf_finish(dev, vid_buf) do { \
72 spin_lock(&(dev)->irqlock); \
73 (vid_buf)->vb.state = VIDEOBUF_DONE; \
74 spin_unlock(&(dev)->irqlock); \
75 wake_up(&(vid_buf)->vb.done); \
76} while (0)
77
48enum fimc_datapath { 78enum fimc_datapath {
49 FIMC_ITU_CAM_A, 79 FIMC_CAMERA,
50 FIMC_ITU_CAM_B,
51 FIMC_MIPI_CAM,
52 FIMC_DMA, 80 FIMC_DMA,
53 FIMC_LCDFIFO, 81 FIMC_LCDFIFO,
54 FIMC_WRITEBACK 82 FIMC_WRITEBACK
@@ -123,20 +151,25 @@ enum fimc_color_fmt {
123 151
124/** 152/**
125 * struct fimc_fmt - the driver's internal color format data 153 * struct fimc_fmt - the driver's internal color format data
154 * @mbus_code: Media Bus pixel code, -1 if not applicable
126 * @name: format description 155 * @name: format description
127 * @fourcc: the fourcc code for this format 156 * @fourcc: the fourcc code for this format, 0 if not applicable
128 * @color: the corresponding fimc_color_fmt 157 * @color: the corresponding fimc_color_fmt
129 * @depth: number of bits per pixel 158 * @depth: driver's private 'number of bits per pixel'
130 * @buff_cnt: number of physically non-contiguous data planes 159 * @buff_cnt: number of physically non-contiguous data planes
131 * @planes_cnt: number of physically contiguous data planes 160 * @planes_cnt: number of physically contiguous data planes
132 */ 161 */
133struct fimc_fmt { 162struct fimc_fmt {
163 enum v4l2_mbus_pixelcode mbus_code;
134 char *name; 164 char *name;
135 u32 fourcc; 165 u32 fourcc;
136 u32 color; 166 u32 color;
137 u32 depth;
138 u16 buff_cnt; 167 u16 buff_cnt;
139 u16 planes_cnt; 168 u16 planes_cnt;
169 u16 depth;
170 u16 flags;
171#define FMT_FLAGS_CAM (1 << 0)
172#define FMT_FLAGS_M2M (1 << 1)
140}; 173};
141 174
142/** 175/**
@@ -220,10 +253,14 @@ struct fimc_addr {
220 253
221/** 254/**
222 * struct fimc_vid_buffer - the driver's video buffer 255 * struct fimc_vid_buffer - the driver's video buffer
223 * @vb: v4l videobuf buffer 256 * @vb: v4l videobuf buffer
257 * @paddr: precalculated physical address set
258 * @index: buffer index for the output DMA engine
224 */ 259 */
225struct fimc_vid_buffer { 260struct fimc_vid_buffer {
226 struct videobuf_buffer vb; 261 struct videobuf_buffer vb;
262 struct fimc_addr paddr;
263 int index;
227}; 264};
228 265
229/** 266/**
@@ -274,6 +311,40 @@ struct fimc_m2m_device {
274}; 311};
275 312
276/** 313/**
314 * struct fimc_vid_cap - camera capture device information
315 * @ctx: hardware context data
316 * @vfd: video device node for camera capture mode
317 * @v4l2_dev: v4l2_device struct to manage subdevs
318 * @sd: pointer to camera sensor subdevice currently in use
319 * @fmt: Media Bus format configured at selected image sensor
320 * @pending_buf_q: the pending buffer queue head
321 * @active_buf_q: the queue head of buffers scheduled in hardware
322 * @vbq: the capture am video buffer queue
323 * @active_buf_cnt: number of video buffers scheduled in hardware
324 * @buf_index: index for managing the output DMA buffers
325 * @frame_count: the frame counter for statistics
326 * @reqbufs_count: the number of buffers requested in REQBUFS ioctl
327 * @input_index: input (camera sensor) index
328 * @refcnt: driver's private reference counter
329 */
330struct fimc_vid_cap {
331 struct fimc_ctx *ctx;
332 struct video_device *vfd;
333 struct v4l2_device v4l2_dev;
334 struct v4l2_subdev *sd;
335 struct v4l2_mbus_framefmt fmt;
336 struct list_head pending_buf_q;
337 struct list_head active_buf_q;
338 struct videobuf_queue vbq;
339 int active_buf_cnt;
340 int buf_index;
341 unsigned int frame_count;
342 unsigned int reqbufs_count;
343 int input_index;
344 int refcnt;
345};
346
347/**
277 * struct samsung_fimc_variant - camera interface variant information 348 * struct samsung_fimc_variant - camera interface variant information
278 * 349 *
279 * @pix_hoff: indicate whether horizontal offset is in pixels or in bytes 350 * @pix_hoff: indicate whether horizontal offset is in pixels or in bytes
@@ -308,10 +379,12 @@ struct samsung_fimc_variant {
308 * 379 *
309 * @variant: the variant information for this driver. 380 * @variant: the variant information for this driver.
310 * @dev_cnt: number of fimc sub-devices available in SoC 381 * @dev_cnt: number of fimc sub-devices available in SoC
382 * @lclk_frequency: fimc bus clock frequency
311 */ 383 */
312struct samsung_fimc_driverdata { 384struct samsung_fimc_driverdata {
313 struct samsung_fimc_variant *variant[FIMC_MAX_DEVS]; 385 struct samsung_fimc_variant *variant[FIMC_MAX_DEVS];
314 int devs_cnt; 386 unsigned long lclk_frequency;
387 int devs_cnt;
315}; 388};
316 389
317struct fimc_ctx; 390struct fimc_ctx;
@@ -322,19 +395,23 @@ struct fimc_ctx;
322 * @slock: the spinlock protecting this data structure 395 * @slock: the spinlock protecting this data structure
323 * @lock: the mutex protecting this data structure 396 * @lock: the mutex protecting this data structure
324 * @pdev: pointer to the FIMC platform device 397 * @pdev: pointer to the FIMC platform device
398 * @pdata: pointer to the device platform data
325 * @id: FIMC device index (0..2) 399 * @id: FIMC device index (0..2)
326 * @clock[]: the clocks required for FIMC operation 400 * @clock[]: the clocks required for FIMC operation
327 * @regs: the mapped hardware registers 401 * @regs: the mapped hardware registers
328 * @regs_res: the resource claimed for IO registers 402 * @regs_res: the resource claimed for IO registers
329 * @irq: interrupt number of the FIMC subdevice 403 * @irq: interrupt number of the FIMC subdevice
330 * @irqlock: spinlock protecting videobuffer queue 404 * @irqlock: spinlock protecting videobuffer queue
405 * @irq_queue:
331 * @m2m: memory-to-memory V4L2 device information 406 * @m2m: memory-to-memory V4L2 device information
332 * @state: the FIMC device state flags 407 * @vid_cap: camera capture device information
408 * @state: flags used to synchronize m2m and capture mode operation
333 */ 409 */
334struct fimc_dev { 410struct fimc_dev {
335 spinlock_t slock; 411 spinlock_t slock;
336 struct mutex lock; 412 struct mutex lock;
337 struct platform_device *pdev; 413 struct platform_device *pdev;
414 struct s3c_platform_fimc *pdata;
338 struct samsung_fimc_variant *variant; 415 struct samsung_fimc_variant *variant;
339 int id; 416 int id;
340 struct clk *clock[NUM_FIMC_CLOCKS]; 417 struct clk *clock[NUM_FIMC_CLOCKS];
@@ -342,7 +419,9 @@ struct fimc_dev {
342 struct resource *regs_res; 419 struct resource *regs_res;
343 int irq; 420 int irq;
344 spinlock_t irqlock; 421 spinlock_t irqlock;
422 wait_queue_head_t irq_queue;
345 struct fimc_m2m_device m2m; 423 struct fimc_m2m_device m2m;
424 struct fimc_vid_cap vid_cap;
346 unsigned long state; 425 unsigned long state;
347}; 426};
348 427
@@ -387,6 +466,7 @@ struct fimc_ctx {
387 struct v4l2_m2m_ctx *m2m_ctx; 466 struct v4l2_m2m_ctx *m2m_ctx;
388}; 467};
389 468
469extern struct videobuf_queue_ops fimc_qops;
390 470
391static inline int tiled_fmt(struct fimc_fmt *fmt) 471static inline int tiled_fmt(struct fimc_fmt *fmt)
392{ 472{
@@ -433,7 +513,10 @@ static inline struct fimc_frame *ctx_get_frame(struct fimc_ctx *ctx,
433 struct fimc_frame *frame; 513 struct fimc_frame *frame;
434 514
435 if (V4L2_BUF_TYPE_VIDEO_OUTPUT == type) { 515 if (V4L2_BUF_TYPE_VIDEO_OUTPUT == type) {
436 frame = &ctx->s_frame; 516 if (ctx->state & FIMC_CTX_M2M)
517 frame = &ctx->s_frame;
518 else
519 return ERR_PTR(-EINVAL);
437 } else if (V4L2_BUF_TYPE_VIDEO_CAPTURE == type) { 520 } else if (V4L2_BUF_TYPE_VIDEO_CAPTURE == type) {
438 frame = &ctx->d_frame; 521 frame = &ctx->d_frame;
439 } else { 522 } else {
@@ -445,6 +528,13 @@ static inline struct fimc_frame *ctx_get_frame(struct fimc_ctx *ctx,
445 return frame; 528 return frame;
446} 529}
447 530
531static inline u32 fimc_hw_get_frame_index(struct fimc_dev *dev)
532{
533 u32 reg = readl(dev->regs + S5P_CISTATUS);
534 return (reg & S5P_CISTATUS_FRAMECNT_MASK) >>
535 S5P_CISTATUS_FRAMECNT_SHIFT;
536}
537
448/* -----------------------------------------------------*/ 538/* -----------------------------------------------------*/
449/* fimc-reg.c */ 539/* fimc-reg.c */
450void fimc_hw_reset(struct fimc_dev *fimc); 540void fimc_hw_reset(struct fimc_dev *fimc);
@@ -462,6 +552,52 @@ void fimc_hw_set_output_path(struct fimc_ctx *ctx);
462void fimc_hw_set_input_addr(struct fimc_dev *fimc, struct fimc_addr *paddr); 552void fimc_hw_set_input_addr(struct fimc_dev *fimc, struct fimc_addr *paddr);
463void fimc_hw_set_output_addr(struct fimc_dev *fimc, struct fimc_addr *paddr, 553void fimc_hw_set_output_addr(struct fimc_dev *fimc, struct fimc_addr *paddr,
464 int index); 554 int index);
555int fimc_hw_set_camera_source(struct fimc_dev *fimc,
556 struct s3c_fimc_isp_info *cam);
557int fimc_hw_set_camera_offset(struct fimc_dev *fimc, struct fimc_frame *f);
558int fimc_hw_set_camera_polarity(struct fimc_dev *fimc,
559 struct s3c_fimc_isp_info *cam);
560int fimc_hw_set_camera_type(struct fimc_dev *fimc,
561 struct s3c_fimc_isp_info *cam);
562
563/* -----------------------------------------------------*/
564/* fimc-core.c */
565int fimc_vidioc_enum_fmt(struct file *file, void *priv,
566 struct v4l2_fmtdesc *f);
567int fimc_vidioc_g_fmt(struct file *file, void *priv,
568 struct v4l2_format *f);
569int fimc_vidioc_try_fmt(struct file *file, void *priv,
570 struct v4l2_format *f);
571int fimc_vidioc_g_crop(struct file *file, void *fh,
572 struct v4l2_crop *cr);
573int fimc_vidioc_cropcap(struct file *file, void *fh,
574 struct v4l2_cropcap *cr);
575int fimc_vidioc_queryctrl(struct file *file, void *priv,
576 struct v4l2_queryctrl *qc);
577int fimc_vidioc_g_ctrl(struct file *file, void *priv,
578 struct v4l2_control *ctrl);
579
580int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr);
581int check_ctrl_val(struct fimc_ctx *ctx, struct v4l2_control *ctrl);
582int fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_control *ctrl);
583
584struct fimc_fmt *find_format(struct v4l2_format *f, unsigned int mask);
585struct fimc_fmt *find_mbus_format(struct v4l2_mbus_framefmt *f,
586 unsigned int mask);
587
588int fimc_check_scaler_ratio(struct v4l2_rect *r, struct fimc_frame *f);
589int fimc_set_scaler_info(struct fimc_ctx *ctx);
590int fimc_prepare_config(struct fimc_ctx *ctx, u32 flags);
591int fimc_prepare_addr(struct fimc_ctx *ctx, struct fimc_vid_buffer *buf,
592 struct fimc_frame *frame, struct fimc_addr *paddr);
593
594/* -----------------------------------------------------*/
595/* fimc-capture.c */
596int fimc_register_capture_device(struct fimc_dev *fimc);
597void fimc_unregister_capture_device(struct fimc_dev *fimc);
598int fimc_sensor_sd_init(struct fimc_dev *fimc, int index);
599int fimc_vid_cap_buf_queue(struct fimc_dev *fimc,
600 struct fimc_vid_buffer *fimc_vb);
465 601
466/* Locking: the caller holds fimc->slock */ 602/* Locking: the caller holds fimc->slock */
467static inline void fimc_activate_capture(struct fimc_ctx *ctx) 603static inline void fimc_activate_capture(struct fimc_ctx *ctx)
@@ -478,4 +614,51 @@ static inline void fimc_deactivate_capture(struct fimc_dev *fimc)
478 fimc_hw_en_lastirq(fimc, false); 614 fimc_hw_en_lastirq(fimc, false);
479} 615}
480 616
617/*
618 * Add video buffer to the active buffers queue.
619 * The caller holds irqlock spinlock.
620 */
621static inline void active_queue_add(struct fimc_vid_cap *vid_cap,
622 struct fimc_vid_buffer *buf)
623{
624 buf->vb.state = VIDEOBUF_ACTIVE;
625 list_add_tail(&buf->vb.queue, &vid_cap->active_buf_q);
626 vid_cap->active_buf_cnt++;
627}
628
629/*
630 * Pop a video buffer from the capture active buffers queue
631 * Locking: Need to be called with dev->slock held.
632 */
633static inline struct fimc_vid_buffer *
634active_queue_pop(struct fimc_vid_cap *vid_cap)
635{
636 struct fimc_vid_buffer *buf;
637 buf = list_entry(vid_cap->active_buf_q.next,
638 struct fimc_vid_buffer, vb.queue);
639 list_del(&buf->vb.queue);
640 vid_cap->active_buf_cnt--;
641 return buf;
642}
643
644/* Add video buffer to the capture pending buffers queue */
645static inline void fimc_pending_queue_add(struct fimc_vid_cap *vid_cap,
646 struct fimc_vid_buffer *buf)
647{
648 buf->vb.state = VIDEOBUF_QUEUED;
649 list_add_tail(&buf->vb.queue, &vid_cap->pending_buf_q);
650}
651
652/* Add video buffer to the capture pending buffers queue */
653static inline struct fimc_vid_buffer *
654pending_queue_pop(struct fimc_vid_cap *vid_cap)
655{
656 struct fimc_vid_buffer *buf;
657 buf = list_entry(vid_cap->pending_buf_q.next,
658 struct fimc_vid_buffer, vb.queue);
659 list_del(&buf->vb.queue);
660 return buf;
661}
662
663
481#endif /* FIMC_CORE_H_ */ 664#endif /* FIMC_CORE_H_ */
diff --git a/drivers/media/video/s5p-fimc/fimc-reg.c b/drivers/media/video/s5p-fimc/fimc-reg.c
index 95adc8464693..511631a2e5c3 100644
--- a/drivers/media/video/s5p-fimc/fimc-reg.c
+++ b/drivers/media/video/s5p-fimc/fimc-reg.c
@@ -13,6 +13,7 @@
13#include <linux/io.h> 13#include <linux/io.h>
14#include <linux/delay.h> 14#include <linux/delay.h>
15#include <mach/map.h> 15#include <mach/map.h>
16#include <media/s3c_fimc.h>
16 17
17#include "fimc-core.h" 18#include "fimc-core.h"
18 19
@@ -176,6 +177,15 @@ static void fimc_hw_set_out_dma_size(struct fimc_ctx *ctx)
176 cfg = S5P_ORIG_SIZE_HOR(frame->f_width); 177 cfg = S5P_ORIG_SIZE_HOR(frame->f_width);
177 cfg |= S5P_ORIG_SIZE_VER(frame->f_height); 178 cfg |= S5P_ORIG_SIZE_VER(frame->f_height);
178 writel(cfg, dev->regs + S5P_ORGOSIZE); 179 writel(cfg, dev->regs + S5P_ORGOSIZE);
180
181 /* Select color space conversion equation (HD/SD size).*/
182 cfg = readl(dev->regs + S5P_CIGCTRL);
183 if (frame->f_width >= 1280) /* HD */
184 cfg |= S5P_CIGCTRL_CSC_ITU601_709;
185 else /* SD */
186 cfg &= ~S5P_CIGCTRL_CSC_ITU601_709;
187 writel(cfg, dev->regs + S5P_CIGCTRL);
188
179} 189}
180 190
181void fimc_hw_set_out_dma(struct fimc_ctx *ctx) 191void fimc_hw_set_out_dma(struct fimc_ctx *ctx)
@@ -231,19 +241,12 @@ static void fimc_hw_en_autoload(struct fimc_dev *dev, int enable)
231 241
232void fimc_hw_en_lastirq(struct fimc_dev *dev, int enable) 242void fimc_hw_en_lastirq(struct fimc_dev *dev, int enable)
233{ 243{
234 unsigned long flags; 244 u32 cfg = readl(dev->regs + S5P_CIOCTRL);
235 u32 cfg;
236
237 spin_lock_irqsave(&dev->slock, flags);
238
239 cfg = readl(dev->regs + S5P_CIOCTRL);
240 if (enable) 245 if (enable)
241 cfg |= S5P_CIOCTRL_LASTIRQ_ENABLE; 246 cfg |= S5P_CIOCTRL_LASTIRQ_ENABLE;
242 else 247 else
243 cfg &= ~S5P_CIOCTRL_LASTIRQ_ENABLE; 248 cfg &= ~S5P_CIOCTRL_LASTIRQ_ENABLE;
244 writel(cfg, dev->regs + S5P_CIOCTRL); 249 writel(cfg, dev->regs + S5P_CIOCTRL);
245
246 spin_unlock_irqrestore(&dev->slock, flags);
247} 250}
248 251
249static void fimc_hw_set_prescaler(struct fimc_ctx *ctx) 252static void fimc_hw_set_prescaler(struct fimc_ctx *ctx)
@@ -325,14 +328,18 @@ void fimc_hw_set_scaler(struct fimc_ctx *ctx)
325void fimc_hw_en_capture(struct fimc_ctx *ctx) 328void fimc_hw_en_capture(struct fimc_ctx *ctx)
326{ 329{
327 struct fimc_dev *dev = ctx->fimc_dev; 330 struct fimc_dev *dev = ctx->fimc_dev;
328 u32 cfg;
329 331
330 cfg = readl(dev->regs + S5P_CIIMGCPT); 332 u32 cfg = readl(dev->regs + S5P_CIIMGCPT);
331 /* One shot mode for output DMA or freerun for FIFO. */ 333
332 if (ctx->out_path == FIMC_DMA) 334 if (ctx->out_path == FIMC_DMA) {
333 cfg |= S5P_CIIMGCPT_CPT_FREN_ENABLE; 335 /* one shot mode */
334 else 336 cfg |= S5P_CIIMGCPT_CPT_FREN_ENABLE | S5P_CIIMGCPT_IMGCPTEN;
335 cfg &= ~S5P_CIIMGCPT_CPT_FREN_ENABLE; 337 } else {
338 /* Continous frame capture mode (freerun). */
339 cfg &= ~(S5P_CIIMGCPT_CPT_FREN_ENABLE |
340 S5P_CIIMGCPT_CPT_FRMOD_CNT);
341 cfg |= S5P_CIIMGCPT_IMGCPTEN;
342 }
336 343
337 if (ctx->scaler.enabled) 344 if (ctx->scaler.enabled)
338 cfg |= S5P_CIIMGCPT_IMGCPTEN_SC; 345 cfg |= S5P_CIIMGCPT_IMGCPTEN_SC;
@@ -523,3 +530,139 @@ void fimc_hw_set_output_addr(struct fimc_dev *dev,
523 i, paddr->y, paddr->cb, paddr->cr); 530 i, paddr->y, paddr->cb, paddr->cr);
524 } while (index == -1 && ++i < FIMC_MAX_OUT_BUFS); 531 } while (index == -1 && ++i < FIMC_MAX_OUT_BUFS);
525} 532}
533
534int fimc_hw_set_camera_polarity(struct fimc_dev *fimc,
535 struct s3c_fimc_isp_info *cam)
536{
537 u32 cfg = readl(fimc->regs + S5P_CIGCTRL);
538
539 cfg &= ~(S5P_CIGCTRL_INVPOLPCLK | S5P_CIGCTRL_INVPOLVSYNC |
540 S5P_CIGCTRL_INVPOLHREF | S5P_CIGCTRL_INVPOLHSYNC);
541
542 if (cam->flags & FIMC_CLK_INV_PCLK)
543 cfg |= S5P_CIGCTRL_INVPOLPCLK;
544
545 if (cam->flags & FIMC_CLK_INV_VSYNC)
546 cfg |= S5P_CIGCTRL_INVPOLVSYNC;
547
548 if (cam->flags & FIMC_CLK_INV_HREF)
549 cfg |= S5P_CIGCTRL_INVPOLHREF;
550
551 if (cam->flags & FIMC_CLK_INV_HSYNC)
552 cfg |= S5P_CIGCTRL_INVPOLHSYNC;
553
554 writel(cfg, fimc->regs + S5P_CIGCTRL);
555
556 return 0;
557}
558
559int fimc_hw_set_camera_source(struct fimc_dev *fimc,
560 struct s3c_fimc_isp_info *cam)
561{
562 struct fimc_frame *f = &fimc->vid_cap.ctx->s_frame;
563 u32 cfg = 0;
564
565 if (cam->bus_type == FIMC_ITU_601 || cam->bus_type == FIMC_ITU_656) {
566
567 switch (fimc->vid_cap.fmt.code) {
568 case V4L2_MBUS_FMT_YUYV8_2X8:
569 cfg = S5P_CISRCFMT_ORDER422_YCBYCR;
570 break;
571 case V4L2_MBUS_FMT_YVYU8_2X8:
572 cfg = S5P_CISRCFMT_ORDER422_YCRYCB;
573 break;
574 case V4L2_MBUS_FMT_VYUY8_2X8:
575 cfg = S5P_CISRCFMT_ORDER422_CRYCBY;
576 break;
577 case V4L2_MBUS_FMT_UYVY8_2X8:
578 cfg = S5P_CISRCFMT_ORDER422_CBYCRY;
579 break;
580 default:
581 err("camera image format not supported: %d",
582 fimc->vid_cap.fmt.code);
583 return -EINVAL;
584 }
585
586 if (cam->bus_type == FIMC_ITU_601) {
587 if (cam->bus_width == 8) {
588 cfg |= S5P_CISRCFMT_ITU601_8BIT;
589 } else if (cam->bus_width == 16) {
590 cfg |= S5P_CISRCFMT_ITU601_16BIT;
591 } else {
592 err("invalid bus width: %d", cam->bus_width);
593 return -EINVAL;
594 }
595 } /* else defaults to ITU-R BT.656 8-bit */
596 }
597
598 cfg |= S5P_CISRCFMT_HSIZE(f->o_width) | S5P_CISRCFMT_VSIZE(f->o_height);
599 writel(cfg, fimc->regs + S5P_CISRCFMT);
600 return 0;
601}
602
603
604int fimc_hw_set_camera_offset(struct fimc_dev *fimc, struct fimc_frame *f)
605{
606 u32 hoff2, voff2;
607
608 u32 cfg = readl(fimc->regs + S5P_CIWDOFST);
609
610 cfg &= ~(S5P_CIWDOFST_HOROFF_MASK | S5P_CIWDOFST_VEROFF_MASK);
611 cfg |= S5P_CIWDOFST_OFF_EN |
612 S5P_CIWDOFST_HOROFF(f->offs_h) |
613 S5P_CIWDOFST_VEROFF(f->offs_v);
614
615 writel(cfg, fimc->regs + S5P_CIWDOFST);
616
617 /* See CIWDOFSTn register description in the datasheet for details. */
618 hoff2 = f->o_width - f->width - f->offs_h;
619 voff2 = f->o_height - f->height - f->offs_v;
620 cfg = S5P_CIWDOFST2_HOROFF(hoff2) | S5P_CIWDOFST2_VEROFF(voff2);
621
622 writel(cfg, fimc->regs + S5P_CIWDOFST2);
623 return 0;
624}
625
626int fimc_hw_set_camera_type(struct fimc_dev *fimc,
627 struct s3c_fimc_isp_info *cam)
628{
629 u32 cfg, tmp;
630 struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
631
632 cfg = readl(fimc->regs + S5P_CIGCTRL);
633
634 /* Select ITU B interface, disable Writeback path and test pattern. */
635 cfg &= ~(S5P_CIGCTRL_TESTPAT_MASK | S5P_CIGCTRL_SELCAM_ITU_A |
636 S5P_CIGCTRL_SELCAM_MIPI | S5P_CIGCTRL_CAMIF_SELWB |
637 S5P_CIGCTRL_SELCAM_MIPI_A);
638
639 if (cam->bus_type == FIMC_MIPI_CSI2) {
640 cfg |= S5P_CIGCTRL_SELCAM_MIPI;
641
642 if (cam->mux_id == 0)
643 cfg |= S5P_CIGCTRL_SELCAM_MIPI_A;
644
645 /* TODO: add remaining supported formats. */
646 if (vid_cap->fmt.code == V4L2_MBUS_FMT_VYUY8_2X8) {
647 tmp = S5P_CSIIMGFMT_YCBCR422_8BIT;
648 } else {
649 err("camera image format not supported: %d",
650 vid_cap->fmt.code);
651 return -EINVAL;
652 }
653 writel(tmp | (0x1 << 8), fimc->regs + S5P_CSIIMGFMT);
654
655 } else if (cam->bus_type == FIMC_ITU_601 ||
656 cam->bus_type == FIMC_ITU_656) {
657 if (cam->mux_id == 0) /* ITU-A, ITU-B: 0, 1 */
658 cfg |= S5P_CIGCTRL_SELCAM_ITU_A;
659 } else if (cam->bus_type == FIMC_LCD_WB) {
660 cfg |= S5P_CIGCTRL_CAMIF_SELWB;
661 } else {
662 err("invalid camera bus type selected\n");
663 return -EINVAL;
664 }
665 writel(cfg, fimc->regs + S5P_CIGCTRL);
666
667 return 0;
668}
diff --git a/include/media/s3c_fimc.h b/include/media/s3c_fimc.h
new file mode 100644
index 000000000000..ca1b6738e4a4
--- /dev/null
+++ b/include/media/s3c_fimc.h
@@ -0,0 +1,60 @@
1/*
2 * Samsung S5P SoC camera interface driver header
3 *
4 * Copyright (c) 2010 Samsung Electronics Co., Ltd
5 * Author: Sylwester Nawrocki, <s.nawrocki@samsung.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
12#ifndef S3C_FIMC_H_
13#define S3C_FIMC_H_
14
15enum cam_bus_type {
16 FIMC_ITU_601 = 1,
17 FIMC_ITU_656,
18 FIMC_MIPI_CSI2,
19 FIMC_LCD_WB, /* FIFO link from LCD mixer */
20};
21
22#define FIMC_CLK_INV_PCLK (1 << 0)
23#define FIMC_CLK_INV_VSYNC (1 << 1)
24#define FIMC_CLK_INV_HREF (1 << 2)
25#define FIMC_CLK_INV_HSYNC (1 << 3)
26
27struct i2c_board_info;
28
29/**
30 * struct s3c_fimc_isp_info - image sensor information required for host
31 * interace configuration.
32 *
33 * @board_info: pointer to I2C subdevice's board info
34 * @bus_type: determines bus type, MIPI, ITU-R BT.601 etc.
35 * @i2c_bus_num: i2c control bus id the sensor is attached to
36 * @mux_id: FIMC camera interface multiplexer index (separate for MIPI and ITU)
37 * @bus_width: camera data bus width in bits
38 * @flags: flags defining bus signals polarity inversion (High by default)
39 */
40struct s3c_fimc_isp_info {
41 struct i2c_board_info *board_info;
42 enum cam_bus_type bus_type;
43 u16 i2c_bus_num;
44 u16 mux_id;
45 u16 bus_width;
46 u16 flags;
47};
48
49
50#define FIMC_MAX_CAMIF_CLIENTS 2
51
52/**
53 * struct s3c_platform_fimc - camera host interface platform data
54 *
55 * @isp_info: properties of camera sensor required for host interface setup
56 */
57struct s3c_platform_fimc {
58 struct s3c_fimc_isp_info *isp_info[FIMC_MAX_CAMIF_CLIENTS];
59};
60#endif /* S3C_FIMC_H_ */