aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/media/platform/Kconfig12
-rw-r--r--drivers/media/platform/Makefile1
-rw-r--r--drivers/media/platform/s3c-camif/Makefile5
-rw-r--r--drivers/media/platform/s3c-camif/camif-capture.c1672
-rw-r--r--drivers/media/platform/s3c-camif/camif-core.c662
-rw-r--r--drivers/media/platform/s3c-camif/camif-core.h393
-rw-r--r--drivers/media/platform/s3c-camif/camif-regs.c606
-rw-r--r--drivers/media/platform/s3c-camif/camif-regs.h269
-rw-r--r--include/media/s3c_camif.h45
9 files changed, 3665 insertions, 0 deletions
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index 181c7686e412..3dcfea612c42 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -109,6 +109,18 @@ config VIDEO_OMAP3_DEBUG
109 ---help--- 109 ---help---
110 Enable debug messages on OMAP 3 camera controller driver. 110 Enable debug messages on OMAP 3 camera controller driver.
111 111
112config VIDEO_S3C_CAMIF
113 tristate "Samsung S3C24XX/S3C64XX SoC Camera Interface driver"
114 depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API
115 depends on (PLAT_S3C64XX || PLAT_S3C24XX) && PM_RUNTIME
116 select VIDEOBUF2_DMA_CONTIG
117 ---help---
118 This is a v4l2 driver for s3c24xx and s3c64xx SoC series camera
119 host interface (CAMIF).
120
121 To compile this driver as a module, choose M here: the module
122 will be called s3c-camif.
123
112source "drivers/media/platform/soc_camera/Kconfig" 124source "drivers/media/platform/soc_camera/Kconfig"
113source "drivers/media/platform/s5p-fimc/Kconfig" 125source "drivers/media/platform/s5p-fimc/Kconfig"
114source "drivers/media/platform/s5p-tv/Kconfig" 126source "drivers/media/platform/s5p-tv/Kconfig"
diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
index baaa55026c8e..4817d2802171 100644
--- a/drivers/media/platform/Makefile
+++ b/drivers/media/platform/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_VIDEO_CODA) += coda.o
27 27
28obj-$(CONFIG_VIDEO_MEM2MEM_DEINTERLACE) += m2m-deinterlace.o 28obj-$(CONFIG_VIDEO_MEM2MEM_DEINTERLACE) += m2m-deinterlace.o
29 29
30obj-$(CONFIG_VIDEO_S3C_CAMIF) += s3c-camif/
30obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC) += s5p-fimc/ 31obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC) += s5p-fimc/
31obj-$(CONFIG_VIDEO_SAMSUNG_S5P_JPEG) += s5p-jpeg/ 32obj-$(CONFIG_VIDEO_SAMSUNG_S5P_JPEG) += s5p-jpeg/
32obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MFC) += s5p-mfc/ 33obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MFC) += s5p-mfc/
diff --git a/drivers/media/platform/s3c-camif/Makefile b/drivers/media/platform/s3c-camif/Makefile
new file mode 100644
index 000000000000..50bf8c59b99c
--- /dev/null
+++ b/drivers/media/platform/s3c-camif/Makefile
@@ -0,0 +1,5 @@
1# Makefile for s3c244x/s3c64xx CAMIF driver
2
3s3c-camif-objs := camif-core.o camif-capture.o camif-regs.o
4
5obj-$(CONFIG_VIDEO_S3C_CAMIF) += s3c-camif.o
diff --git a/drivers/media/platform/s3c-camif/camif-capture.c b/drivers/media/platform/s3c-camif/camif-capture.c
new file mode 100644
index 000000000000..a55793c3d811
--- /dev/null
+++ b/drivers/media/platform/s3c-camif/camif-capture.c
@@ -0,0 +1,1672 @@
1/*
2 * s3c24xx/s3c64xx SoC series Camera Interface (CAMIF) driver
3 *
4 * Copyright (C) 2012 Sylwester Nawrocki <sylvester.nawrocki@gmail.com>
5 * Copyright (C) 2012 Tomasz Figa <tomasz.figa@gmail.com>
6 *
7 * Based on drivers/media/platform/s5p-fimc,
8 * Copyright (C) 2010 - 2012 Samsung Electronics Co., Ltd.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13*/
14#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__
15
16#include <linux/bug.h>
17#include <linux/clk.h>
18#include <linux/device.h>
19#include <linux/errno.h>
20#include <linux/i2c.h>
21#include <linux/interrupt.h>
22#include <linux/io.h>
23#include <linux/kernel.h>
24#include <linux/list.h>
25#include <linux/module.h>
26#include <linux/platform_device.h>
27#include <linux/pm_runtime.h>
28#include <linux/ratelimit.h>
29#include <linux/slab.h>
30#include <linux/types.h>
31#include <linux/videodev2.h>
32
33#include <media/media-device.h>
34#include <media/v4l2-ctrls.h>
35#include <media/v4l2-event.h>
36#include <media/v4l2-ioctl.h>
37#include <media/videobuf2-core.h>
38#include <media/videobuf2-dma-contig.h>
39
40#include "camif-core.h"
41#include "camif-regs.h"
42
43static int debug;
44module_param(debug, int, 0644);
45
46/* Locking: called with vp->camif->slock spinlock held */
47static void camif_cfg_video_path(struct camif_vp *vp)
48{
49 WARN_ON(s3c_camif_get_scaler_config(vp, &vp->scaler));
50 camif_hw_set_scaler(vp);
51 camif_hw_set_flip(vp);
52 camif_hw_set_target_format(vp);
53 camif_hw_set_output_dma(vp);
54}
55
56static void camif_prepare_dma_offset(struct camif_vp *vp)
57{
58 struct camif_frame *f = &vp->out_frame;
59
60 f->dma_offset.initial = f->rect.top * f->f_width + f->rect.left;
61 f->dma_offset.line = f->f_width - (f->rect.left + f->rect.width);
62
63 pr_debug("dma_offset: initial: %d, line: %d\n",
64 f->dma_offset.initial, f->dma_offset.line);
65}
66
67/* Locking: called with camif->slock spinlock held */
68static int s3c_camif_hw_init(struct camif_dev *camif, struct camif_vp *vp)
69{
70 const struct s3c_camif_variant *variant = camif->variant;
71
72 if (camif->sensor.sd == NULL || vp->out_fmt == NULL)
73 return -EINVAL;
74
75 if (variant->ip_revision == S3C244X_CAMIF_IP_REV)
76 camif_hw_clear_fifo_overflow(vp);
77 camif_hw_set_camera_bus(camif);
78 camif_hw_set_source_format(camif);
79 camif_hw_set_camera_crop(camif);
80 camif_hw_set_test_pattern(camif, camif->test_pattern);
81 if (variant->has_img_effect)
82 camif_hw_set_effect(camif, camif->colorfx,
83 camif->colorfx_cb, camif->colorfx_cr);
84 if (variant->ip_revision == S3C6410_CAMIF_IP_REV)
85 camif_hw_set_input_path(vp);
86 camif_cfg_video_path(vp);
87 vp->state &= ~ST_VP_CONFIG;
88
89 return 0;
90}
91
92/*
93 * Initialize the video path, only up from the scaler stage. The camera
94 * input interface set up is skipped. This is useful to enable one of the
95 * video paths when the other is already running.
96 * Locking: called with camif->slock spinlock held.
97 */
98static int s3c_camif_hw_vp_init(struct camif_dev *camif, struct camif_vp *vp)
99{
100 unsigned int ip_rev = camif->variant->ip_revision;
101
102 if (vp->out_fmt == NULL)
103 return -EINVAL;
104
105 camif_prepare_dma_offset(vp);
106 if (ip_rev == S3C244X_CAMIF_IP_REV)
107 camif_hw_clear_fifo_overflow(vp);
108 camif_cfg_video_path(vp);
109 vp->state &= ~ST_VP_CONFIG;
110 return 0;
111}
112
113static int sensor_set_power(struct camif_dev *camif, int on)
114{
115 struct cam_sensor *sensor = &camif->sensor;
116 int err = 0;
117
118 if (!on == camif->sensor.power_count)
119 err = v4l2_subdev_call(sensor->sd, core, s_power, on);
120 if (!err)
121 sensor->power_count += on ? 1 : -1;
122
123 pr_debug("on: %d, power_count: %d, err: %d\n",
124 on, sensor->power_count, err);
125
126 return err;
127}
128
129static int sensor_set_streaming(struct camif_dev *camif, int on)
130{
131 struct cam_sensor *sensor = &camif->sensor;
132 int err = 0;
133
134 if (!on == camif->sensor.stream_count)
135 err = v4l2_subdev_call(sensor->sd, video, s_stream, on);
136 if (!err)
137 sensor->stream_count += on ? 1 : -1;
138
139 pr_debug("on: %d, stream_count: %d, err: %d\n",
140 on, sensor->stream_count, err);
141
142 return err;
143}
144
145/*
146 * Reinitialize the driver so it is ready to start streaming again.
147 * Return any buffers to vb2, perform CAMIF software reset and
148 * turn off streaming at the data pipeline (sensor) if required.
149 */
150static int camif_reinitialize(struct camif_vp *vp)
151{
152 struct camif_dev *camif = vp->camif;
153 struct camif_buffer *buf;
154 unsigned long flags;
155 bool streaming;
156
157 spin_lock_irqsave(&camif->slock, flags);
158 streaming = vp->state & ST_VP_SENSOR_STREAMING;
159
160 vp->state &= ~(ST_VP_PENDING | ST_VP_RUNNING | ST_VP_OFF |
161 ST_VP_ABORTING | ST_VP_STREAMING |
162 ST_VP_SENSOR_STREAMING | ST_VP_LASTIRQ);
163
164 /* Release unused buffers */
165 while (!list_empty(&vp->pending_buf_q)) {
166 buf = camif_pending_queue_pop(vp);
167 vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
168 }
169
170 while (!list_empty(&vp->active_buf_q)) {
171 buf = camif_active_queue_pop(vp);
172 vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
173 }
174
175 spin_unlock_irqrestore(&camif->slock, flags);
176
177 if (!streaming)
178 return 0;
179
180 return sensor_set_streaming(camif, 0);
181}
182
183static bool s3c_vp_active(struct camif_vp *vp)
184{
185 struct camif_dev *camif = vp->camif;
186 unsigned long flags;
187 bool ret;
188
189 spin_lock_irqsave(&camif->slock, flags);
190 ret = (vp->state & ST_VP_RUNNING) || (vp->state & ST_VP_PENDING);
191 spin_unlock_irqrestore(&camif->slock, flags);
192
193 return ret;
194}
195
196static bool camif_is_streaming(struct camif_dev *camif)
197{
198 unsigned long flags;
199 bool status;
200
201 spin_lock_irqsave(&camif->slock, flags);
202 status = camif->stream_count > 0;
203 spin_unlock_irqrestore(&camif->slock, flags);
204
205 return status;
206}
207
208static int camif_stop_capture(struct camif_vp *vp)
209{
210 struct camif_dev *camif = vp->camif;
211 unsigned long flags;
212 int ret;
213
214 if (!s3c_vp_active(vp))
215 return 0;
216
217 spin_lock_irqsave(&camif->slock, flags);
218 vp->state &= ~(ST_VP_OFF | ST_VP_LASTIRQ);
219 vp->state |= ST_VP_ABORTING;
220 spin_unlock_irqrestore(&camif->slock, flags);
221
222 ret = wait_event_timeout(vp->irq_queue,
223 !(vp->state & ST_VP_ABORTING),
224 msecs_to_jiffies(CAMIF_STOP_TIMEOUT));
225
226 spin_lock_irqsave(&camif->slock, flags);
227
228 if (ret == 0 && !(vp->state & ST_VP_OFF)) {
229 /* Timed out, forcibly stop capture */
230 vp->state &= ~(ST_VP_OFF | ST_VP_ABORTING |
231 ST_VP_LASTIRQ);
232
233 camif_hw_disable_capture(vp);
234 camif_hw_enable_scaler(vp, false);
235 }
236
237 spin_unlock_irqrestore(&camif->slock, flags);
238
239 return camif_reinitialize(vp);
240}
241
242static int camif_prepare_addr(struct camif_vp *vp, struct vb2_buffer *vb,
243 struct camif_addr *paddr)
244{
245 struct camif_frame *frame = &vp->out_frame;
246 u32 pix_size;
247
248 if (vb == NULL || frame == NULL)
249 return -EINVAL;
250
251 pix_size = frame->rect.width * frame->rect.height;
252
253 pr_debug("colplanes: %d, pix_size: %u\n",
254 vp->out_fmt->colplanes, pix_size);
255
256 paddr->y = vb2_dma_contig_plane_dma_addr(vb, 0);
257
258 switch (vp->out_fmt->colplanes) {
259 case 1:
260 paddr->cb = 0;
261 paddr->cr = 0;
262 break;
263 case 2:
264 /* decompose Y into Y/Cb */
265 paddr->cb = (u32)(paddr->y + pix_size);
266 paddr->cr = 0;
267 break;
268 case 3:
269 paddr->cb = (u32)(paddr->y + pix_size);
270 /* decompose Y into Y/Cb/Cr */
271 if (vp->out_fmt->color == IMG_FMT_YCBCR422P)
272 paddr->cr = (u32)(paddr->cb + (pix_size >> 1));
273 else /* 420 */
274 paddr->cr = (u32)(paddr->cb + (pix_size >> 2));
275
276 if (vp->out_fmt->color == IMG_FMT_YCRCB420)
277 swap(paddr->cb, paddr->cr);
278 break;
279 default:
280 return -EINVAL;
281 }
282
283 pr_debug("DMA address: y: %#x cb: %#x cr: %#x\n",
284 paddr->y, paddr->cb, paddr->cr);
285
286 return 0;
287}
288
289irqreturn_t s3c_camif_irq_handler(int irq, void *priv)
290{
291 struct camif_vp *vp = priv;
292 struct camif_dev *camif = vp->camif;
293 unsigned int ip_rev = camif->variant->ip_revision;
294 unsigned int status;
295
296 spin_lock(&camif->slock);
297
298 if (ip_rev == S3C6410_CAMIF_IP_REV)
299 camif_hw_clear_pending_irq(vp);
300
301 status = camif_hw_get_status(vp);
302
303 if (ip_rev == S3C244X_CAMIF_IP_REV && (status & CISTATUS_OVF_MASK)) {
304 camif_hw_clear_fifo_overflow(vp);
305 goto unlock;
306 }
307
308 if (vp->state & ST_VP_ABORTING) {
309 if (vp->state & ST_VP_OFF) {
310 /* Last IRQ */
311 vp->state &= ~(ST_VP_OFF | ST_VP_ABORTING |
312 ST_VP_LASTIRQ);
313 wake_up(&vp->irq_queue);
314 goto unlock;
315 } else if (vp->state & ST_VP_LASTIRQ) {
316 camif_hw_disable_capture(vp);
317 camif_hw_enable_scaler(vp, false);
318 camif_hw_set_lastirq(vp, false);
319 vp->state |= ST_VP_OFF;
320 } else {
321 /* Disable capture, enable last IRQ */
322 camif_hw_set_lastirq(vp, true);
323 vp->state |= ST_VP_LASTIRQ;
324 }
325 }
326
327 if (!list_empty(&vp->pending_buf_q) && (vp->state & ST_VP_RUNNING) &&
328 !list_empty(&vp->active_buf_q)) {
329 unsigned int index;
330 struct camif_buffer *vbuf;
331 struct timeval *tv;
332 struct timespec ts;
333 /*
334 * Get previous DMA write buffer index:
335 * 0 => DMA buffer 0, 2;
336 * 1 => DMA buffer 1, 3.
337 */
338 index = (CISTATUS_FRAMECNT(status) + 2) & 1;
339
340 ktime_get_ts(&ts);
341 vbuf = camif_active_queue_peek(vp, index);
342
343 if (!WARN_ON(vbuf == NULL)) {
344 /* Dequeue a filled buffer */
345 tv = &vbuf->vb.v4l2_buf.timestamp;
346 tv->tv_sec = ts.tv_sec;
347 tv->tv_usec = ts.tv_nsec / NSEC_PER_USEC;
348 vbuf->vb.v4l2_buf.sequence = vp->frame_sequence++;
349 vb2_buffer_done(&vbuf->vb, VB2_BUF_STATE_DONE);
350
351 /* Set up an empty buffer at the DMA engine */
352 vbuf = camif_pending_queue_pop(vp);
353 vbuf->index = index;
354 camif_hw_set_output_addr(vp, &vbuf->paddr, index);
355 camif_hw_set_output_addr(vp, &vbuf->paddr, index + 2);
356
357 /* Scheduled in H/W, add to the queue */
358 camif_active_queue_add(vp, vbuf);
359 }
360 } else if (!(vp->state & ST_VP_ABORTING) &&
361 (vp->state & ST_VP_PENDING)) {
362 vp->state |= ST_VP_RUNNING;
363 }
364
365 if (vp->state & ST_VP_CONFIG) {
366 camif_prepare_dma_offset(vp);
367 camif_hw_set_camera_crop(camif);
368 camif_hw_set_scaler(vp);
369 camif_hw_set_flip(vp);
370 camif_hw_set_test_pattern(camif, camif->test_pattern);
371 if (camif->variant->has_img_effect)
372 camif_hw_set_effect(camif, camif->colorfx,
373 camif->colorfx_cb, camif->colorfx_cr);
374 vp->state &= ~ST_VP_CONFIG;
375 }
376unlock:
377 spin_unlock(&camif->slock);
378 return IRQ_HANDLED;
379}
380
381static int start_streaming(struct vb2_queue *vq, unsigned int count)
382{
383 struct camif_vp *vp = vb2_get_drv_priv(vq);
384 struct camif_dev *camif = vp->camif;
385 unsigned long flags;
386 int ret;
387
388 /*
389 * We assume the codec capture path is always activated
390 * first, before the preview path starts streaming.
391 * This is required to avoid internal FIFO overflow and
392 * a need for CAMIF software reset.
393 */
394 spin_lock_irqsave(&camif->slock, flags);
395
396 if (camif->stream_count == 0) {
397 camif_hw_reset(camif);
398 ret = s3c_camif_hw_init(camif, vp);
399 } else {
400 ret = s3c_camif_hw_vp_init(camif, vp);
401 }
402 spin_unlock_irqrestore(&camif->slock, flags);
403
404 if (ret < 0) {
405 camif_reinitialize(vp);
406 return ret;
407 }
408
409 spin_lock_irqsave(&camif->slock, flags);
410 vp->frame_sequence = 0;
411 vp->state |= ST_VP_PENDING;
412
413 if (!list_empty(&vp->pending_buf_q) &&
414 (!(vp->state & ST_VP_STREAMING) ||
415 !(vp->state & ST_VP_SENSOR_STREAMING))) {
416
417 camif_hw_enable_scaler(vp, vp->scaler.enable);
418 camif_hw_enable_capture(vp);
419 vp->state |= ST_VP_STREAMING;
420
421 if (!(vp->state & ST_VP_SENSOR_STREAMING)) {
422 vp->state |= ST_VP_SENSOR_STREAMING;
423 spin_unlock_irqrestore(&camif->slock, flags);
424 ret = sensor_set_streaming(camif, 1);
425 if (ret)
426 v4l2_err(&vp->vdev, "Sensor s_stream failed\n");
427 if (debug)
428 camif_hw_dump_regs(camif, __func__);
429
430 return ret;
431 }
432 }
433
434 spin_unlock_irqrestore(&camif->slock, flags);
435 return 0;
436}
437
438static int stop_streaming(struct vb2_queue *vq)
439{
440 struct camif_vp *vp = vb2_get_drv_priv(vq);
441 return camif_stop_capture(vp);
442}
443
444static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *pfmt,
445 unsigned int *num_buffers, unsigned int *num_planes,
446 unsigned int sizes[], void *allocators[])
447{
448 const struct v4l2_pix_format *pix = NULL;
449 struct camif_vp *vp = vb2_get_drv_priv(vq);
450 struct camif_dev *camif = vp->camif;
451 struct camif_frame *frame = &vp->out_frame;
452 const struct camif_fmt *fmt = vp->out_fmt;
453 unsigned int size;
454
455 if (pfmt) {
456 pix = &pfmt->fmt.pix;
457 fmt = s3c_camif_find_format(vp, &pix->pixelformat, -1);
458 size = (pix->width * pix->height * fmt->depth) / 8;
459 } else {
460 size = (frame->f_width * frame->f_height * fmt->depth) / 8;
461 }
462
463 if (fmt == NULL)
464 return -EINVAL;
465 *num_planes = 1;
466
467 if (pix)
468 sizes[0] = max(size, pix->sizeimage);
469 else
470 sizes[0] = size;
471 allocators[0] = camif->alloc_ctx;
472
473 pr_debug("size: %u\n", sizes[0]);
474 return 0;
475}
476
477static int buffer_prepare(struct vb2_buffer *vb)
478{
479 struct camif_vp *vp = vb2_get_drv_priv(vb->vb2_queue);
480
481 if (vp->out_fmt == NULL)
482 return -EINVAL;
483
484 if (vb2_plane_size(vb, 0) < vp->payload) {
485 v4l2_err(&vp->vdev, "buffer too small: %lu, required: %u\n",
486 vb2_plane_size(vb, 0), vp->payload);
487 return -EINVAL;
488 }
489 vb2_set_plane_payload(vb, 0, vp->payload);
490
491 return 0;
492}
493
494static void buffer_queue(struct vb2_buffer *vb)
495{
496 struct camif_buffer *buf = container_of(vb, struct camif_buffer, vb);
497 struct camif_vp *vp = vb2_get_drv_priv(vb->vb2_queue);
498 struct camif_dev *camif = vp->camif;
499 unsigned long flags;
500
501 spin_lock_irqsave(&camif->slock, flags);
502 WARN_ON(camif_prepare_addr(vp, &buf->vb, &buf->paddr));
503
504 if (!(vp->state & ST_VP_STREAMING) && vp->active_buffers < 2) {
505 /* Schedule an empty buffer in H/W */
506 buf->index = vp->buf_index;
507
508 camif_hw_set_output_addr(vp, &buf->paddr, buf->index);
509 camif_hw_set_output_addr(vp, &buf->paddr, buf->index + 2);
510
511 camif_active_queue_add(vp, buf);
512 vp->buf_index = !vp->buf_index;
513 } else {
514 camif_pending_queue_add(vp, buf);
515 }
516
517 if (vb2_is_streaming(&vp->vb_queue) && !list_empty(&vp->pending_buf_q)
518 && !(vp->state & ST_VP_STREAMING)) {
519
520 vp->state |= ST_VP_STREAMING;
521 camif_hw_enable_scaler(vp, vp->scaler.enable);
522 camif_hw_enable_capture(vp);
523 spin_unlock_irqrestore(&camif->slock, flags);
524
525 if (!(vp->state & ST_VP_SENSOR_STREAMING)) {
526 if (sensor_set_streaming(camif, 1) == 0)
527 vp->state |= ST_VP_SENSOR_STREAMING;
528 else
529 v4l2_err(&vp->vdev, "Sensor s_stream failed\n");
530
531 if (debug)
532 camif_hw_dump_regs(camif, __func__);
533 }
534 return;
535 }
536 spin_unlock_irqrestore(&camif->slock, flags);
537}
538
539static void camif_lock(struct vb2_queue *vq)
540{
541 struct camif_vp *vp = vb2_get_drv_priv(vq);
542 mutex_lock(&vp->camif->lock);
543}
544
545static void camif_unlock(struct vb2_queue *vq)
546{
547 struct camif_vp *vp = vb2_get_drv_priv(vq);
548 mutex_unlock(&vp->camif->lock);
549}
550
551static const struct vb2_ops s3c_camif_qops = {
552 .queue_setup = queue_setup,
553 .buf_prepare = buffer_prepare,
554 .buf_queue = buffer_queue,
555 .wait_prepare = camif_unlock,
556 .wait_finish = camif_lock,
557 .start_streaming = start_streaming,
558 .stop_streaming = stop_streaming,
559};
560
561static int s3c_camif_open(struct file *file)
562{
563 struct camif_vp *vp = video_drvdata(file);
564 struct camif_dev *camif = vp->camif;
565 int ret;
566
567 pr_debug("[vp%d] state: %#x, owner: %p, pid: %d\n", vp->id,
568 vp->state, vp->owner, task_pid_nr(current));
569
570 if (mutex_lock_interruptible(&camif->lock))
571 return -ERESTARTSYS;
572
573 ret = v4l2_fh_open(file);
574 if (ret < 0)
575 goto unlock;
576
577 ret = pm_runtime_get_sync(camif->dev);
578 if (ret < 0)
579 goto err_pm;
580
581 ret = sensor_set_power(camif, 1);
582 if (!ret)
583 goto unlock;
584
585 pm_runtime_put(camif->dev);
586err_pm:
587 v4l2_fh_release(file);
588unlock:
589 mutex_unlock(&camif->lock);
590 return ret;
591}
592
593static int s3c_camif_close(struct file *file)
594{
595 struct camif_vp *vp = video_drvdata(file);
596 struct camif_dev *camif = vp->camif;
597 int ret;
598
599 pr_debug("[vp%d] state: %#x, owner: %p, pid: %d\n", vp->id,
600 vp->state, vp->owner, task_pid_nr(current));
601
602 mutex_lock(&camif->lock);
603
604 if (vp->owner == file->private_data) {
605 camif_stop_capture(vp);
606 vb2_queue_release(&vp->vb_queue);
607 vp->owner = NULL;
608 }
609
610 sensor_set_power(camif, 0);
611
612 pm_runtime_put(camif->dev);
613 ret = v4l2_fh_release(file);
614
615 mutex_unlock(&camif->lock);
616 return ret;
617}
618
619static unsigned int s3c_camif_poll(struct file *file,
620 struct poll_table_struct *wait)
621{
622 struct camif_vp *vp = video_drvdata(file);
623 struct camif_dev *camif = vp->camif;
624 int ret;
625
626 mutex_lock(&camif->lock);
627 if (vp->owner && vp->owner != file->private_data)
628 ret = -EBUSY;
629 else
630 ret = vb2_poll(&vp->vb_queue, file, wait);
631
632 mutex_unlock(&camif->lock);
633 return ret;
634}
635
636static int s3c_camif_mmap(struct file *file, struct vm_area_struct *vma)
637{
638 struct camif_vp *vp = video_drvdata(file);
639 int ret;
640
641 if (vp->owner && vp->owner != file->private_data)
642 ret = -EBUSY;
643 else
644 ret = vb2_mmap(&vp->vb_queue, vma);
645
646 return ret;
647}
648
649static const struct v4l2_file_operations s3c_camif_fops = {
650 .owner = THIS_MODULE,
651 .open = s3c_camif_open,
652 .release = s3c_camif_close,
653 .poll = s3c_camif_poll,
654 .unlocked_ioctl = video_ioctl2,
655 .mmap = s3c_camif_mmap,
656};
657
658/*
659 * Video node IOCTLs
660 */
661
662static int s3c_camif_vidioc_querycap(struct file *file, void *priv,
663 struct v4l2_capability *cap)
664{
665 struct camif_vp *vp = video_drvdata(file);
666
667 strlcpy(cap->driver, S3C_CAMIF_DRIVER_NAME, sizeof(cap->driver));
668 strlcpy(cap->card, S3C_CAMIF_DRIVER_NAME, sizeof(cap->card));
669 snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s.%d",
670 dev_name(vp->camif->dev), vp->id);
671
672 cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE;
673 cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
674
675 return 0;
676}
677
678static int s3c_camif_vidioc_enum_input(struct file *file, void *priv,
679 struct v4l2_input *input)
680{
681 struct camif_vp *vp = video_drvdata(file);
682 struct v4l2_subdev *sensor = vp->camif->sensor.sd;
683
684 if (input->index || sensor == NULL)
685 return -EINVAL;
686
687 input->type = V4L2_INPUT_TYPE_CAMERA;
688 strlcpy(input->name, sensor->name, sizeof(input->name));
689 return 0;
690}
691
692static int s3c_camif_vidioc_s_input(struct file *file, void *priv,
693 unsigned int i)
694{
695 return i == 0 ? 0 : -EINVAL;
696}
697
698static int s3c_camif_vidioc_g_input(struct file *file, void *priv,
699 unsigned int *i)
700{
701 *i = 0;
702 return 0;
703}
704
705static int s3c_camif_vidioc_enum_fmt(struct file *file, void *priv,
706 struct v4l2_fmtdesc *f)
707{
708 struct camif_vp *vp = video_drvdata(file);
709 const struct camif_fmt *fmt;
710
711 fmt = s3c_camif_find_format(vp, NULL, f->index);
712 if (!fmt)
713 return -EINVAL;
714
715 strlcpy(f->description, fmt->name, sizeof(f->description));
716 f->pixelformat = fmt->fourcc;
717
718 pr_debug("fmt(%d): %s\n", f->index, f->description);
719 return 0;
720}
721
722static int s3c_camif_vidioc_g_fmt(struct file *file, void *priv,
723 struct v4l2_format *f)
724{
725 struct camif_vp *vp = video_drvdata(file);
726 struct v4l2_pix_format *pix = &f->fmt.pix;
727 struct camif_frame *frame = &vp->out_frame;
728 const struct camif_fmt *fmt = vp->out_fmt;
729
730 pix->bytesperline = frame->f_width * fmt->ybpp;
731 pix->sizeimage = vp->payload;
732
733 pix->pixelformat = fmt->fourcc;
734 pix->width = frame->f_width;
735 pix->height = frame->f_height;
736 pix->field = V4L2_FIELD_NONE;
737 pix->colorspace = V4L2_COLORSPACE_JPEG;
738
739 return 0;
740}
741
742static int __camif_video_try_format(struct camif_vp *vp,
743 struct v4l2_pix_format *pix,
744 const struct camif_fmt **ffmt)
745{
746 struct camif_dev *camif = vp->camif;
747 struct v4l2_rect *crop = &camif->camif_crop;
748 unsigned int wmin, hmin, sc_hrmax, sc_vrmax;
749 const struct vp_pix_limits *pix_lim;
750 const struct camif_fmt *fmt;
751
752 fmt = s3c_camif_find_format(vp, &pix->pixelformat, 0);
753
754 if (WARN_ON(fmt == NULL))
755 return -EINVAL;
756
757 if (ffmt)
758 *ffmt = fmt;
759
760 pix_lim = &camif->variant->vp_pix_limits[vp->id];
761
762 pr_debug("fmt: %ux%u, crop: %ux%u, bytesperline: %u\n",
763 pix->width, pix->height, crop->width, crop->height,
764 pix->bytesperline);
765 /*
766 * Calculate minimum width and height according to the configured
767 * camera input interface crop rectangle and the resizer's capabilities.
768 */
769 sc_hrmax = min(SCALER_MAX_RATIO, 1 << (ffs(crop->width) - 3));
770 sc_vrmax = min(SCALER_MAX_RATIO, 1 << (ffs(crop->height) - 1));
771
772 wmin = max_t(u32, pix_lim->min_out_width, crop->width / sc_hrmax);
773 wmin = round_up(wmin, pix_lim->out_width_align);
774 hmin = max_t(u32, 8, crop->height / sc_vrmax);
775 hmin = round_up(hmin, 8);
776
777 v4l_bound_align_image(&pix->width, wmin, pix_lim->max_sc_out_width,
778 ffs(pix_lim->out_width_align) - 1,
779 &pix->height, hmin, pix_lim->max_height, 0, 0);
780
781 pix->bytesperline = pix->width * fmt->ybpp;
782 pix->sizeimage = (pix->width * pix->height * fmt->depth) / 8;
783 pix->pixelformat = fmt->fourcc;
784 pix->colorspace = V4L2_COLORSPACE_JPEG;
785 pix->field = V4L2_FIELD_NONE;
786
787 pr_debug("%ux%u, wmin: %d, hmin: %d, sc_hrmax: %d, sc_vrmax: %d\n",
788 pix->width, pix->height, wmin, hmin, sc_hrmax, sc_vrmax);
789
790 return 0;
791}
792
793static int s3c_camif_vidioc_try_fmt(struct file *file, void *priv,
794 struct v4l2_format *f)
795{
796 struct camif_vp *vp = video_drvdata(file);
797 return __camif_video_try_format(vp, &f->fmt.pix, NULL);
798}
799
800static int s3c_camif_vidioc_s_fmt(struct file *file, void *priv,
801 struct v4l2_format *f)
802{
803 struct v4l2_pix_format *pix = &f->fmt.pix;
804 struct camif_vp *vp = video_drvdata(file);
805 struct camif_frame *out_frame = &vp->out_frame;
806 const struct camif_fmt *fmt = NULL;
807 int ret;
808
809 pr_debug("[vp%d]\n", vp->id);
810
811 if (vb2_is_busy(&vp->vb_queue))
812 return -EBUSY;
813
814 ret = __camif_video_try_format(vp, &f->fmt.pix, &fmt);
815 if (ret < 0)
816 return ret;
817
818 vp->out_fmt = fmt;
819 vp->payload = pix->sizeimage;
820 out_frame->f_width = pix->width;
821 out_frame->f_height = pix->height;
822
823 /* Reset composition rectangle */
824 out_frame->rect.width = pix->width;
825 out_frame->rect.height = pix->height;
826 out_frame->rect.left = 0;
827 out_frame->rect.top = 0;
828
829 if (vp->owner == NULL)
830 vp->owner = priv;
831
832 pr_debug("%ux%u. payload: %u. fmt: %s. %d %d. sizeimage: %d. bpl: %d\n",
833 out_frame->f_width, out_frame->f_height, vp->payload, fmt->name,
834 pix->width * pix->height * fmt->depth, fmt->depth,
835 pix->sizeimage, pix->bytesperline);
836
837 return 0;
838}
839
840/* Only check pixel formats at the sensor and the camif subdev pads */
841static int camif_pipeline_validate(struct camif_dev *camif)
842{
843 struct v4l2_subdev_format src_fmt;
844 struct media_pad *pad;
845 int ret;
846
847 /* Retrieve format at the sensor subdev source pad */
848 pad = media_entity_remote_source(&camif->pads[0]);
849 if (!pad || media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
850 return -EPIPE;
851
852 src_fmt.pad = pad->index;
853 src_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
854 ret = v4l2_subdev_call(camif->sensor.sd, pad, get_fmt, NULL, &src_fmt);
855 if (ret < 0 && ret != -ENOIOCTLCMD)
856 return -EPIPE;
857
858 if (src_fmt.format.width != camif->mbus_fmt.width ||
859 src_fmt.format.height != camif->mbus_fmt.height ||
860 src_fmt.format.code != camif->mbus_fmt.code)
861 return -EPIPE;
862
863 return 0;
864}
865
866static int s3c_camif_streamon(struct file *file, void *priv,
867 enum v4l2_buf_type type)
868{
869 struct camif_vp *vp = video_drvdata(file);
870 struct camif_dev *camif = vp->camif;
871 struct media_entity *sensor = &camif->sensor.sd->entity;
872 int ret;
873
874 pr_debug("[vp%d]\n", vp->id);
875
876 if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
877 return -EINVAL;
878
879 if (vp->owner && vp->owner != priv)
880 return -EBUSY;
881
882 if (s3c_vp_active(vp))
883 return 0;
884
885 ret = media_entity_pipeline_start(sensor, camif->m_pipeline);
886 if (ret < 0)
887 return ret;
888
889 ret = camif_pipeline_validate(camif);
890 if (ret < 0) {
891 media_entity_pipeline_stop(sensor);
892 return ret;
893 }
894
895 return vb2_streamon(&vp->vb_queue, type);
896}
897
898static int s3c_camif_streamoff(struct file *file, void *priv,
899 enum v4l2_buf_type type)
900{
901 struct camif_vp *vp = video_drvdata(file);
902 struct camif_dev *camif = vp->camif;
903 int ret;
904
905 pr_debug("[vp%d]\n", vp->id);
906
907 if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
908 return -EINVAL;
909
910 if (vp->owner && vp->owner != priv)
911 return -EBUSY;
912
913 ret = vb2_streamoff(&vp->vb_queue, type);
914 if (ret == 0)
915 media_entity_pipeline_stop(&camif->sensor.sd->entity);
916 return ret;
917}
918
919static int s3c_camif_reqbufs(struct file *file, void *priv,
920 struct v4l2_requestbuffers *rb)
921{
922 struct camif_vp *vp = video_drvdata(file);
923 int ret;
924
925 pr_debug("[vp%d] rb count: %d, owner: %p, priv: %p\n",
926 vp->id, rb->count, vp->owner, priv);
927
928 if (vp->owner && vp->owner != priv)
929 return -EBUSY;
930
931 if (rb->count)
932 rb->count = max_t(u32, CAMIF_REQ_BUFS_MIN, rb->count);
933 else
934 vp->owner = NULL;
935
936 ret = vb2_reqbufs(&vp->vb_queue, rb);
937 if (!ret) {
938 vp->reqbufs_count = rb->count;
939 if (vp->owner == NULL && rb->count > 0)
940 vp->owner = priv;
941 }
942
943 return ret;
944}
945
946static int s3c_camif_querybuf(struct file *file, void *priv,
947 struct v4l2_buffer *buf)
948{
949 struct camif_vp *vp = video_drvdata(file);
950 return vb2_querybuf(&vp->vb_queue, buf);
951}
952
953static int s3c_camif_qbuf(struct file *file, void *priv,
954 struct v4l2_buffer *buf)
955{
956 struct camif_vp *vp = video_drvdata(file);
957
958 pr_debug("[vp%d]\n", vp->id);
959
960 if (vp->owner && vp->owner != priv)
961 return -EBUSY;
962
963 return vb2_qbuf(&vp->vb_queue, buf);
964}
965
966static int s3c_camif_dqbuf(struct file *file, void *priv,
967 struct v4l2_buffer *buf)
968{
969 struct camif_vp *vp = video_drvdata(file);
970
971 pr_debug("[vp%d] sequence: %d\n", vp->id, vp->frame_sequence);
972
973 if (vp->owner && vp->owner != priv)
974 return -EBUSY;
975
976 return vb2_dqbuf(&vp->vb_queue, buf, file->f_flags & O_NONBLOCK);
977}
978
979static int s3c_camif_create_bufs(struct file *file, void *priv,
980 struct v4l2_create_buffers *create)
981{
982 struct camif_vp *vp = video_drvdata(file);
983 int ret;
984
985 if (vp->owner && vp->owner != priv)
986 return -EBUSY;
987
988 create->count = max_t(u32, 1, create->count);
989 ret = vb2_create_bufs(&vp->vb_queue, create);
990
991 if (!ret && vp->owner == NULL)
992 vp->owner = priv;
993
994 return ret;
995}
996
997static int s3c_camif_prepare_buf(struct file *file, void *priv,
998 struct v4l2_buffer *b)
999{
1000 struct camif_vp *vp = video_drvdata(file);
1001 return vb2_prepare_buf(&vp->vb_queue, b);
1002}
1003
1004static int s3c_camif_g_selection(struct file *file, void *priv,
1005 struct v4l2_selection *sel)
1006{
1007 struct camif_vp *vp = video_drvdata(file);
1008
1009 if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1010 return -EINVAL;
1011
1012 switch (sel->target) {
1013 case V4L2_SEL_TGT_COMPOSE_BOUNDS:
1014 case V4L2_SEL_TGT_COMPOSE_DEFAULT:
1015 sel->r.left = 0;
1016 sel->r.top = 0;
1017 sel->r.width = vp->out_frame.f_width;
1018 sel->r.height = vp->out_frame.f_height;
1019 return 0;
1020
1021 case V4L2_SEL_TGT_COMPOSE:
1022 sel->r = vp->out_frame.rect;
1023 return 0;
1024 }
1025
1026 return -EINVAL;
1027}
1028
1029static void __camif_try_compose(struct camif_dev *camif, struct camif_vp *vp,
1030 struct v4l2_rect *r)
1031{
1032 /* s3c244x doesn't support composition */
1033 if (camif->variant->ip_revision == S3C244X_CAMIF_IP_REV) {
1034 *r = vp->out_frame.rect;
1035 return;
1036 }
1037
1038 /* TODO: s3c64xx */
1039}
1040
1041static int s3c_camif_s_selection(struct file *file, void *priv,
1042 struct v4l2_selection *sel)
1043{
1044 struct camif_vp *vp = video_drvdata(file);
1045 struct camif_dev *camif = vp->camif;
1046 struct v4l2_rect rect = sel->r;
1047 unsigned long flags;
1048
1049 if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
1050 sel->target != V4L2_SEL_TGT_COMPOSE)
1051 return -EINVAL;
1052
1053 __camif_try_compose(camif, vp, &rect);
1054
1055 sel->r = rect;
1056 spin_lock_irqsave(&camif->slock, flags);
1057 vp->out_frame.rect = rect;
1058 vp->state |= ST_VP_CONFIG;
1059 spin_unlock_irqrestore(&camif->slock, flags);
1060
1061 pr_debug("type: %#x, target: %#x, flags: %#x, (%d,%d)/%dx%d\n",
1062 sel->type, sel->target, sel->flags,
1063 sel->r.left, sel->r.top, sel->r.width, sel->r.height);
1064
1065 return 0;
1066}
1067
1068static const struct v4l2_ioctl_ops s3c_camif_ioctl_ops = {
1069 .vidioc_querycap = s3c_camif_vidioc_querycap,
1070 .vidioc_enum_input = s3c_camif_vidioc_enum_input,
1071 .vidioc_g_input = s3c_camif_vidioc_g_input,
1072 .vidioc_s_input = s3c_camif_vidioc_s_input,
1073 .vidioc_enum_fmt_vid_cap = s3c_camif_vidioc_enum_fmt,
1074 .vidioc_try_fmt_vid_cap = s3c_camif_vidioc_try_fmt,
1075 .vidioc_s_fmt_vid_cap = s3c_camif_vidioc_s_fmt,
1076 .vidioc_g_fmt_vid_cap = s3c_camif_vidioc_g_fmt,
1077 .vidioc_g_selection = s3c_camif_g_selection,
1078 .vidioc_s_selection = s3c_camif_s_selection,
1079 .vidioc_reqbufs = s3c_camif_reqbufs,
1080 .vidioc_querybuf = s3c_camif_querybuf,
1081 .vidioc_prepare_buf = s3c_camif_prepare_buf,
1082 .vidioc_create_bufs = s3c_camif_create_bufs,
1083 .vidioc_qbuf = s3c_camif_qbuf,
1084 .vidioc_dqbuf = s3c_camif_dqbuf,
1085 .vidioc_streamon = s3c_camif_streamon,
1086 .vidioc_streamoff = s3c_camif_streamoff,
1087 .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
1088 .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
1089 .vidioc_log_status = v4l2_ctrl_log_status,
1090};
1091
1092/*
1093 * Video node controls
1094 */
1095static int s3c_camif_video_s_ctrl(struct v4l2_ctrl *ctrl)
1096{
1097 struct camif_vp *vp = ctrl->priv;
1098 struct camif_dev *camif = vp->camif;
1099 unsigned long flags;
1100
1101 pr_debug("[vp%d] ctrl: %s, value: %d\n", vp->id,
1102 ctrl->name, ctrl->val);
1103
1104 spin_lock_irqsave(&camif->slock, flags);
1105
1106 switch (ctrl->id) {
1107 case V4L2_CID_HFLIP:
1108 vp->hflip = ctrl->val;
1109 break;
1110
1111 case V4L2_CID_VFLIP:
1112 vp->vflip = ctrl->val;
1113 break;
1114 }
1115
1116 vp->state |= ST_VP_CONFIG;
1117 spin_unlock_irqrestore(&camif->slock, flags);
1118 return 0;
1119}
1120
1121/* Codec and preview video node control ops */
1122static const struct v4l2_ctrl_ops s3c_camif_video_ctrl_ops = {
1123 .s_ctrl = s3c_camif_video_s_ctrl,
1124};
1125
1126int s3c_camif_register_video_node(struct camif_dev *camif, int idx)
1127{
1128 struct camif_vp *vp = &camif->vp[idx];
1129 struct vb2_queue *q = &vp->vb_queue;
1130 struct video_device *vfd = &vp->vdev;
1131 struct v4l2_ctrl *ctrl;
1132 int ret;
1133
1134 memset(vfd, 0, sizeof(*vfd));
1135 snprintf(vfd->name, sizeof(vfd->name), "camif-%s",
1136 vp->id == 0 ? "codec" : "preview");
1137
1138 vfd->fops = &s3c_camif_fops;
1139 vfd->ioctl_ops = &s3c_camif_ioctl_ops;
1140 vfd->v4l2_dev = &camif->v4l2_dev;
1141 vfd->minor = -1;
1142 vfd->release = video_device_release_empty;
1143 vfd->lock = &camif->lock;
1144 vp->reqbufs_count = 0;
1145
1146 INIT_LIST_HEAD(&vp->pending_buf_q);
1147 INIT_LIST_HEAD(&vp->active_buf_q);
1148
1149 memset(q, 0, sizeof(*q));
1150 q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1151 q->io_modes = VB2_MMAP | VB2_USERPTR;
1152 q->ops = &s3c_camif_qops;
1153 q->mem_ops = &vb2_dma_contig_memops;
1154 q->buf_struct_size = sizeof(struct camif_buffer);
1155 q->drv_priv = vp;
1156
1157 ret = vb2_queue_init(q);
1158 if (ret)
1159 goto err_vd_rel;
1160
1161 vp->pad.flags = MEDIA_PAD_FL_SINK;
1162 ret = media_entity_init(&vfd->entity, 1, &vp->pad, 0);
1163 if (ret)
1164 goto err_vd_rel;
1165
1166 video_set_drvdata(vfd, vp);
1167 set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
1168
1169 v4l2_ctrl_handler_init(&vp->ctrl_handler, 1);
1170 ctrl = v4l2_ctrl_new_std(&vp->ctrl_handler, &s3c_camif_video_ctrl_ops,
1171 V4L2_CID_HFLIP, 0, 1, 1, 0);
1172 if (ctrl)
1173 ctrl->priv = vp;
1174 ctrl = v4l2_ctrl_new_std(&vp->ctrl_handler, &s3c_camif_video_ctrl_ops,
1175 V4L2_CID_VFLIP, 0, 1, 1, 0);
1176 if (ctrl)
1177 ctrl->priv = vp;
1178
1179 ret = vp->ctrl_handler.error;
1180 if (ret < 0)
1181 goto err_me_cleanup;
1182
1183 vfd->ctrl_handler = &vp->ctrl_handler;
1184
1185 ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
1186 if (ret)
1187 goto err_ctrlh_free;
1188
1189 v4l2_info(&camif->v4l2_dev, "registered %s as /dev/%s\n",
1190 vfd->name, video_device_node_name(vfd));
1191 return 0;
1192
1193err_ctrlh_free:
1194 v4l2_ctrl_handler_free(&vp->ctrl_handler);
1195err_me_cleanup:
1196 media_entity_cleanup(&vfd->entity);
1197err_vd_rel:
1198 video_device_release(vfd);
1199 return ret;
1200}
1201
1202void s3c_camif_unregister_video_node(struct camif_dev *camif, int idx)
1203{
1204 struct video_device *vfd = &camif->vp[idx].vdev;
1205
1206 if (video_is_registered(vfd)) {
1207 video_unregister_device(vfd);
1208 media_entity_cleanup(&vfd->entity);
1209 v4l2_ctrl_handler_free(vfd->ctrl_handler);
1210 }
1211}
1212
1213/* Media bus pixel formats supported at the camif input */
1214static const enum v4l2_mbus_pixelcode camif_mbus_formats[] = {
1215 V4L2_MBUS_FMT_YUYV8_2X8,
1216 V4L2_MBUS_FMT_YVYU8_2X8,
1217 V4L2_MBUS_FMT_UYVY8_2X8,
1218 V4L2_MBUS_FMT_VYUY8_2X8,
1219};
1220
1221/*
1222 * Camera input interface subdev operations
1223 */
1224
1225static int s3c_camif_subdev_enum_mbus_code(struct v4l2_subdev *sd,
1226 struct v4l2_subdev_fh *fh,
1227 struct v4l2_subdev_mbus_code_enum *code)
1228{
1229 if (code->index >= ARRAY_SIZE(camif_mbus_formats))
1230 return -EINVAL;
1231
1232 code->code = camif_mbus_formats[code->index];
1233 return 0;
1234}
1235
1236static int s3c_camif_subdev_get_fmt(struct v4l2_subdev *sd,
1237 struct v4l2_subdev_fh *fh,
1238 struct v4l2_subdev_format *fmt)
1239{
1240 struct camif_dev *camif = v4l2_get_subdevdata(sd);
1241 struct v4l2_mbus_framefmt *mf = &fmt->format;
1242
1243 if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
1244 mf = v4l2_subdev_get_try_format(fh, fmt->pad);
1245 fmt->format = *mf;
1246 return 0;
1247 }
1248
1249 mutex_lock(&camif->lock);
1250
1251 switch (fmt->pad) {
1252 case CAMIF_SD_PAD_SINK:
1253 /* full camera input pixel size */
1254 *mf = camif->mbus_fmt;
1255 break;
1256
1257 case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
1258 /* crop rectangle at camera interface input */
1259 mf->width = camif->camif_crop.width;
1260 mf->height = camif->camif_crop.height;
1261 mf->code = camif->mbus_fmt.code;
1262 break;
1263 }
1264
1265 mutex_unlock(&camif->lock);
1266 mf->colorspace = V4L2_COLORSPACE_JPEG;
1267 return 0;
1268}
1269
1270static void __camif_subdev_try_format(struct camif_dev *camif,
1271 struct v4l2_mbus_framefmt *mf, int pad)
1272{
1273 const struct s3c_camif_variant *variant = camif->variant;
1274 const struct vp_pix_limits *pix_lim;
1275 int i = ARRAY_SIZE(camif_mbus_formats);
1276
1277 /* FIXME: constraints against codec or preview path ? */
1278 pix_lim = &variant->vp_pix_limits[VP_CODEC];
1279
1280 while (i-- >= 0)
1281 if (camif_mbus_formats[i] == mf->code)
1282 break;
1283
1284 mf->code = camif_mbus_formats[i];
1285
1286 if (pad == CAMIF_SD_PAD_SINK) {
1287 v4l_bound_align_image(&mf->width, 8, CAMIF_MAX_PIX_WIDTH,
1288 ffs(pix_lim->out_width_align) - 1,
1289 &mf->height, 8, CAMIF_MAX_PIX_HEIGHT, 0,
1290 0);
1291 } else {
1292 struct v4l2_rect *crop = &camif->camif_crop;
1293 v4l_bound_align_image(&mf->width, 8, crop->width,
1294 ffs(pix_lim->out_width_align) - 1,
1295 &mf->height, 8, crop->height,
1296 0, 0);
1297 }
1298
1299 v4l2_dbg(1, debug, &camif->subdev, "%ux%u\n", mf->width, mf->height);
1300}
1301
1302static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd,
1303 struct v4l2_subdev_fh *fh,
1304 struct v4l2_subdev_format *fmt)
1305{
1306 struct camif_dev *camif = v4l2_get_subdevdata(sd);
1307 struct v4l2_mbus_framefmt *mf = &fmt->format;
1308 struct v4l2_rect *crop = &camif->camif_crop;
1309 int i;
1310
1311 v4l2_dbg(1, debug, sd, "pad%d: code: 0x%x, %ux%u\n",
1312 fmt->pad, mf->code, mf->width, mf->height);
1313
1314 mf->colorspace = V4L2_COLORSPACE_JPEG;
1315 mutex_lock(&camif->lock);
1316
1317 /*
1318 * No pixel format change at the camera input is allowed
1319 * while streaming.
1320 */
1321 if (vb2_is_busy(&camif->vp[VP_CODEC].vb_queue) ||
1322 vb2_is_busy(&camif->vp[VP_PREVIEW].vb_queue)) {
1323 mutex_unlock(&camif->lock);
1324 return -EBUSY;
1325 }
1326
1327 __camif_subdev_try_format(camif, mf, fmt->pad);
1328
1329 if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
1330 mf = v4l2_subdev_get_try_format(fh, fmt->pad);
1331 *mf = fmt->format;
1332 mutex_unlock(&camif->lock);
1333 return 0;
1334 }
1335
1336 switch (fmt->pad) {
1337 case CAMIF_SD_PAD_SINK:
1338 camif->mbus_fmt = *mf;
1339 /* Reset sink crop rectangle. */
1340 crop->width = mf->width;
1341 crop->height = mf->height;
1342 crop->left = 0;
1343 crop->top = 0;
1344 /*
1345 * Reset source format (the camif's crop rectangle)
1346 * and the video output resolution.
1347 */
1348 for (i = 0; i < CAMIF_VP_NUM; i++) {
1349 struct camif_frame *frame = &camif->vp[i].out_frame;
1350 frame->rect = *crop;
1351 frame->f_width = mf->width;
1352 frame->f_height = mf->height;
1353 }
1354 break;
1355
1356 case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
1357 /* Pixel format can be only changed on the sink pad. */
1358 mf->code = camif->mbus_fmt.code;
1359 mf->width = crop->width;
1360 mf->height = crop->height;
1361 break;
1362 }
1363
1364 mutex_unlock(&camif->lock);
1365 return 0;
1366}
1367
1368static int s3c_camif_subdev_get_selection(struct v4l2_subdev *sd,
1369 struct v4l2_subdev_fh *fh,
1370 struct v4l2_subdev_selection *sel)
1371{
1372 struct camif_dev *camif = v4l2_get_subdevdata(sd);
1373 struct v4l2_rect *crop = &camif->camif_crop;
1374 struct v4l2_mbus_framefmt *mf = &camif->mbus_fmt;
1375
1376 if ((sel->target != V4L2_SEL_TGT_CROP &&
1377 sel->target != V4L2_SEL_TGT_CROP_BOUNDS) ||
1378 sel->pad != CAMIF_SD_PAD_SINK)
1379 return -EINVAL;
1380
1381 if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
1382 sel->r = *v4l2_subdev_get_try_crop(fh, sel->pad);
1383 return 0;
1384 }
1385
1386 mutex_lock(&camif->lock);
1387
1388 if (sel->target == V4L2_SEL_TGT_CROP) {
1389 sel->r = *crop;
1390 } else { /* crop bounds */
1391 sel->r.width = mf->width;
1392 sel->r.height = mf->height;
1393 sel->r.left = 0;
1394 sel->r.top = 0;
1395 }
1396
1397 mutex_unlock(&camif->lock);
1398
1399 v4l2_dbg(1, debug, sd, "%s: crop: (%d,%d) %dx%d, size: %ux%u\n",
1400 __func__, crop->left, crop->top, crop->width,
1401 crop->height, mf->width, mf->height);
1402
1403 return 0;
1404}
1405
1406static void __camif_try_crop(struct camif_dev *camif, struct v4l2_rect *r)
1407{
1408 struct v4l2_mbus_framefmt *mf = &camif->mbus_fmt;
1409 const struct camif_pix_limits *pix_lim = &camif->variant->pix_limits;
1410 unsigned int left = 2 * r->left;
1411 unsigned int top = 2 * r->top;
1412
1413 /*
1414 * Following constraints must be met:
1415 * - r->width + 2 * r->left = mf->width;
1416 * - r->height + 2 * r->top = mf->height;
1417 * - crop rectangle size and position must be aligned
1418 * to 8 or 2 pixels, depending on SoC version.
1419 */
1420 v4l_bound_align_image(&r->width, 0, mf->width,
1421 ffs(pix_lim->win_hor_offset_align) - 1,
1422 &r->height, 0, mf->height, 1, 0);
1423
1424 v4l_bound_align_image(&left, 0, mf->width - r->width,
1425 ffs(pix_lim->win_hor_offset_align),
1426 &top, 0, mf->height - r->height, 2, 0);
1427
1428 r->left = left / 2;
1429 r->top = top / 2;
1430 r->width = mf->width - left;
1431 r->height = mf->height - top;
1432 /*
1433 * Make sure we either downscale or upscale both the pixel
1434 * width and height. Just return current crop rectangle if
1435 * this scaler constraint is not met.
1436 */
1437 if (camif->variant->ip_revision == S3C244X_CAMIF_IP_REV &&
1438 camif_is_streaming(camif)) {
1439 unsigned int i;
1440
1441 for (i = 0; i < CAMIF_VP_NUM; i++) {
1442 struct v4l2_rect *or = &camif->vp[i].out_frame.rect;
1443 if ((or->width > r->width) == (or->height > r->height))
1444 continue;
1445 *r = camif->camif_crop;
1446 pr_debug("Width/height scaling direction limitation\n");
1447 break;
1448 }
1449 }
1450
1451 v4l2_dbg(1, debug, &camif->v4l2_dev, "crop: (%d,%d)/%dx%d, fmt: %ux%u\n",
1452 r->left, r->top, r->width, r->height, mf->width, mf->height);
1453}
1454
1455static int s3c_camif_subdev_set_selection(struct v4l2_subdev *sd,
1456 struct v4l2_subdev_fh *fh,
1457 struct v4l2_subdev_selection *sel)
1458{
1459 struct camif_dev *camif = v4l2_get_subdevdata(sd);
1460 struct v4l2_rect *crop = &camif->camif_crop;
1461 struct camif_scaler scaler;
1462
1463 if (sel->target != V4L2_SEL_TGT_CROP || sel->pad != CAMIF_SD_PAD_SINK)
1464 return -EINVAL;
1465
1466 mutex_lock(&camif->lock);
1467 __camif_try_crop(camif, &sel->r);
1468
1469 if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
1470 *v4l2_subdev_get_try_crop(fh, sel->pad) = sel->r;
1471 } else {
1472 unsigned long flags;
1473 unsigned int i;
1474
1475 spin_lock_irqsave(&camif->slock, flags);
1476 *crop = sel->r;
1477
1478 for (i = 0; i < CAMIF_VP_NUM; i++) {
1479 struct camif_vp *vp = &camif->vp[i];
1480 scaler = vp->scaler;
1481 if (s3c_camif_get_scaler_config(vp, &scaler))
1482 continue;
1483 vp->scaler = scaler;
1484 vp->state |= ST_VP_CONFIG;
1485 }
1486
1487 spin_unlock_irqrestore(&camif->slock, flags);
1488 }
1489 mutex_unlock(&camif->lock);
1490
1491 v4l2_dbg(1, debug, sd, "%s: (%d,%d) %dx%d, f_w: %u, f_h: %u\n",
1492 __func__, crop->left, crop->top, crop->width, crop->height,
1493 camif->mbus_fmt.width, camif->mbus_fmt.height);
1494
1495 return 0;
1496}
1497
1498static const struct v4l2_subdev_pad_ops s3c_camif_subdev_pad_ops = {
1499 .enum_mbus_code = s3c_camif_subdev_enum_mbus_code,
1500 .get_selection = s3c_camif_subdev_get_selection,
1501 .set_selection = s3c_camif_subdev_set_selection,
1502 .get_fmt = s3c_camif_subdev_get_fmt,
1503 .set_fmt = s3c_camif_subdev_set_fmt,
1504};
1505
1506static struct v4l2_subdev_ops s3c_camif_subdev_ops = {
1507 .pad = &s3c_camif_subdev_pad_ops,
1508};
1509
1510static int s3c_camif_subdev_s_ctrl(struct v4l2_ctrl *ctrl)
1511{
1512 struct camif_dev *camif = container_of(ctrl->handler, struct camif_dev,
1513 ctrl_handler);
1514 unsigned long flags;
1515
1516 spin_lock_irqsave(&camif->slock, flags);
1517
1518 switch (ctrl->id) {
1519 case V4L2_CID_COLORFX:
1520 camif->colorfx = camif->ctrl_colorfx->val;
1521 /* Set Cb, Cr */
1522 switch (ctrl->val) {
1523 case V4L2_COLORFX_SEPIA:
1524 camif->colorfx_cb = 115;
1525 camif->colorfx_cr = 145;
1526 break;
1527 case V4L2_COLORFX_SET_CBCR:
1528 camif->colorfx_cb = camif->ctrl_colorfx_cbcr->val >> 8;
1529 camif->colorfx_cr = camif->ctrl_colorfx_cbcr->val & 0xff;
1530 break;
1531 default:
1532 /* for V4L2_COLORFX_BW and others */
1533 camif->colorfx_cb = 128;
1534 camif->colorfx_cr = 128;
1535 }
1536 break;
1537 case V4L2_CID_TEST_PATTERN:
1538 camif->test_pattern = camif->ctrl_test_pattern->val;
1539 break;
1540 default:
1541 WARN_ON(1);
1542 }
1543
1544 camif->vp[VP_CODEC].state |= ST_VP_CONFIG;
1545 camif->vp[VP_PREVIEW].state |= ST_VP_CONFIG;
1546 spin_unlock_irqrestore(&camif->slock, flags);
1547
1548 return 0;
1549}
1550
1551static const struct v4l2_ctrl_ops s3c_camif_subdev_ctrl_ops = {
1552 .s_ctrl = s3c_camif_subdev_s_ctrl,
1553};
1554
1555static const char * const s3c_camif_test_pattern_menu[] = {
1556 "Disabled",
1557 "Color bars",
1558 "Horizontal increment",
1559 "Vertical increment",
1560};
1561
1562int s3c_camif_create_subdev(struct camif_dev *camif)
1563{
1564 struct v4l2_ctrl_handler *handler = &camif->ctrl_handler;
1565 struct v4l2_subdev *sd = &camif->subdev;
1566 int ret;
1567
1568 v4l2_subdev_init(sd, &s3c_camif_subdev_ops);
1569 sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
1570 strlcpy(sd->name, "S3C-CAMIF", sizeof(sd->name));
1571
1572 camif->pads[CAMIF_SD_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
1573 camif->pads[CAMIF_SD_PAD_SOURCE_C].flags = MEDIA_PAD_FL_SOURCE;
1574 camif->pads[CAMIF_SD_PAD_SOURCE_P].flags = MEDIA_PAD_FL_SOURCE;
1575
1576 ret = media_entity_init(&sd->entity, CAMIF_SD_PADS_NUM,
1577 camif->pads, 0);
1578 if (ret)
1579 return ret;
1580
1581 v4l2_ctrl_handler_init(handler, 3);
1582 camif->ctrl_test_pattern = v4l2_ctrl_new_std_menu_items(handler,
1583 &s3c_camif_subdev_ctrl_ops, V4L2_CID_TEST_PATTERN,
1584 ARRAY_SIZE(s3c_camif_test_pattern_menu) - 1, 0, 0,
1585 s3c_camif_test_pattern_menu);
1586
1587 camif->ctrl_colorfx = v4l2_ctrl_new_std_menu(handler,
1588 &s3c_camif_subdev_ctrl_ops,
1589 V4L2_CID_COLORFX, V4L2_COLORFX_SET_CBCR,
1590 ~0x981f, V4L2_COLORFX_NONE);
1591
1592 camif->ctrl_colorfx_cbcr = v4l2_ctrl_new_std(handler,
1593 &s3c_camif_subdev_ctrl_ops,
1594 V4L2_CID_COLORFX_CBCR, 0, 0xffff, 1, 0);
1595 if (handler->error) {
1596 v4l2_ctrl_handler_free(handler);
1597 media_entity_cleanup(&sd->entity);
1598 return handler->error;
1599 }
1600
1601 v4l2_ctrl_auto_cluster(2, &camif->ctrl_colorfx,
1602 V4L2_COLORFX_SET_CBCR, false);
1603 if (!camif->variant->has_img_effect) {
1604 camif->ctrl_colorfx->flags |= V4L2_CTRL_FLAG_DISABLED;
1605 camif->ctrl_colorfx_cbcr->flags |= V4L2_CTRL_FLAG_DISABLED;
1606 }
1607 sd->ctrl_handler = handler;
1608 v4l2_set_subdevdata(sd, camif);
1609
1610 return 0;
1611}
1612
1613void s3c_camif_unregister_subdev(struct camif_dev *camif)
1614{
1615 struct v4l2_subdev *sd = &camif->subdev;
1616
1617 /* Return if not registered */
1618 if (v4l2_get_subdevdata(sd) == NULL)
1619 return;
1620
1621 v4l2_device_unregister_subdev(sd);
1622 media_entity_cleanup(&sd->entity);
1623 v4l2_ctrl_handler_free(&camif->ctrl_handler);
1624 v4l2_set_subdevdata(sd, NULL);
1625}
1626
1627int s3c_camif_set_defaults(struct camif_dev *camif)
1628{
1629 unsigned int ip_rev = camif->variant->ip_revision;
1630 int i;
1631
1632 for (i = 0; i < CAMIF_VP_NUM; i++) {
1633 struct camif_vp *vp = &camif->vp[i];
1634 struct camif_frame *f = &vp->out_frame;
1635
1636 vp->camif = camif;
1637 vp->id = i;
1638 vp->offset = camif->variant->vp_offset;
1639
1640 if (ip_rev == S3C244X_CAMIF_IP_REV)
1641 vp->fmt_flags = i ? FMT_FL_S3C24XX_PREVIEW :
1642 FMT_FL_S3C24XX_CODEC;
1643 else
1644 vp->fmt_flags = FMT_FL_S3C64XX;
1645
1646 vp->out_fmt = s3c_camif_find_format(vp, NULL, 0);
1647 BUG_ON(vp->out_fmt == NULL);
1648
1649 memset(f, 0, sizeof(*f));
1650 f->f_width = CAMIF_DEF_WIDTH;
1651 f->f_height = CAMIF_DEF_HEIGHT;
1652 f->rect.width = CAMIF_DEF_WIDTH;
1653 f->rect.height = CAMIF_DEF_HEIGHT;
1654
1655 /* Scaler is always enabled */
1656 vp->scaler.enable = 1;
1657
1658 vp->payload = (f->f_width * f->f_height *
1659 vp->out_fmt->depth) / 8;
1660 }
1661
1662 memset(&camif->mbus_fmt, 0, sizeof(camif->mbus_fmt));
1663 camif->mbus_fmt.width = CAMIF_DEF_WIDTH;
1664 camif->mbus_fmt.height = CAMIF_DEF_HEIGHT;
1665 camif->mbus_fmt.code = camif_mbus_formats[0];
1666
1667 memset(&camif->camif_crop, 0, sizeof(camif->camif_crop));
1668 camif->camif_crop.width = CAMIF_DEF_WIDTH;
1669 camif->camif_crop.height = CAMIF_DEF_HEIGHT;
1670
1671 return 0;
1672}
diff --git a/drivers/media/platform/s3c-camif/camif-core.c b/drivers/media/platform/s3c-camif/camif-core.c
new file mode 100644
index 000000000000..0dd65376c067
--- /dev/null
+++ b/drivers/media/platform/s3c-camif/camif-core.c
@@ -0,0 +1,662 @@
1/*
2 * s3c24xx/s3c64xx SoC series Camera Interface (CAMIF) driver
3 *
4 * Copyright (C) 2012 Sylwester Nawrocki <sylvester.nawrocki@gmail.com>
5 * Copyright (C) 2012 Tomasz Figa <tomasz.figa@gmail.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 as published
9 * by the Free Software Foundation, either version 2 of the License,
10 * or (at your option) any later version.
11 */
12#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__
13
14#include <linux/bug.h>
15#include <linux/clk.h>
16#include <linux/delay.h>
17#include <linux/device.h>
18#include <linux/errno.h>
19#include <linux/gpio.h>
20#include <linux/i2c.h>
21#include <linux/interrupt.h>
22#include <linux/io.h>
23#include <linux/kernel.h>
24#include <linux/list.h>
25#include <linux/module.h>
26#include <linux/platform_device.h>
27#include <linux/pm_runtime.h>
28#include <linux/slab.h>
29#include <linux/types.h>
30
31#include <media/media-device.h>
32#include <media/v4l2-ctrls.h>
33#include <media/v4l2-ioctl.h>
34#include <media/videobuf2-core.h>
35#include <media/videobuf2-dma-contig.h>
36
37#include "camif-core.h"
38
39static char *camif_clocks[CLK_MAX_NUM] = {
40 /* HCLK CAMIF clock */
41 [CLK_GATE] = "camif",
42 /* CAMIF / external camera sensor master clock */
43 [CLK_CAM] = "camera",
44};
45
46static const struct camif_fmt camif_formats[] = {
47 {
48 .name = "YUV 4:2:2 planar, Y/Cb/Cr",
49 .fourcc = V4L2_PIX_FMT_YUV422P,
50 .depth = 16,
51 .ybpp = 1,
52 .color = IMG_FMT_YCBCR422P,
53 .colplanes = 3,
54 .flags = FMT_FL_S3C24XX_CODEC |
55 FMT_FL_S3C64XX,
56 }, {
57 .name = "YUV 4:2:0 planar, Y/Cb/Cr",
58 .fourcc = V4L2_PIX_FMT_YUV420,
59 .depth = 12,
60 .ybpp = 1,
61 .color = IMG_FMT_YCBCR420,
62 .colplanes = 3,
63 .flags = FMT_FL_S3C24XX_CODEC |
64 FMT_FL_S3C64XX,
65 }, {
66 .name = "YVU 4:2:0 planar, Y/Cr/Cb",
67 .fourcc = V4L2_PIX_FMT_YVU420,
68 .depth = 12,
69 .ybpp = 1,
70 .color = IMG_FMT_YCRCB420,
71 .colplanes = 3,
72 .flags = FMT_FL_S3C24XX_CODEC |
73 FMT_FL_S3C64XX,
74 }, {
75 .name = "RGB565, 16 bpp",
76 .fourcc = V4L2_PIX_FMT_RGB565X,
77 .depth = 16,
78 .ybpp = 2,
79 .color = IMG_FMT_RGB565,
80 .colplanes = 1,
81 .flags = FMT_FL_S3C24XX_PREVIEW |
82 FMT_FL_S3C64XX,
83 }, {
84 .name = "XRGB8888, 32 bpp",
85 .fourcc = V4L2_PIX_FMT_RGB32,
86 .depth = 32,
87 .ybpp = 4,
88 .color = IMG_FMT_XRGB8888,
89 .colplanes = 1,
90 .flags = FMT_FL_S3C24XX_PREVIEW |
91 FMT_FL_S3C64XX,
92 }, {
93 .name = "BGR666",
94 .fourcc = V4L2_PIX_FMT_BGR666,
95 .depth = 32,
96 .ybpp = 4,
97 .color = IMG_FMT_RGB666,
98 .colplanes = 1,
99 .flags = FMT_FL_S3C64XX,
100 }
101};
102
103/**
104 * s3c_camif_find_format() - lookup camif color format by fourcc or an index
105 * @pixelformat: fourcc to match, ignored if null
106 * @index: index to the camif_formats array, ignored if negative
107 */
108const struct camif_fmt *s3c_camif_find_format(struct camif_vp *vp,
109 const u32 *pixelformat,
110 int index)
111{
112 const struct camif_fmt *fmt, *def_fmt = NULL;
113 unsigned int i;
114 int id = 0;
115
116 if (index >= (int)ARRAY_SIZE(camif_formats))
117 return NULL;
118
119 for (i = 0; i < ARRAY_SIZE(camif_formats); ++i) {
120 fmt = &camif_formats[i];
121 if (vp && !(vp->fmt_flags & fmt->flags))
122 continue;
123 if (pixelformat && fmt->fourcc == *pixelformat)
124 return fmt;
125 if (index == id)
126 def_fmt = fmt;
127 id++;
128 }
129 return def_fmt;
130}
131
132static int camif_get_scaler_factor(u32 src, u32 tar, u32 *ratio, u32 *shift)
133{
134 unsigned int sh = 6;
135
136 if (src >= 64 * tar)
137 return -EINVAL;
138
139 while (sh--) {
140 unsigned int tmp = 1 << sh;
141 if (src >= tar * tmp) {
142 *shift = sh, *ratio = tmp;
143 return 0;
144 }
145 }
146 *shift = 0, *ratio = 1;
147 return 0;
148}
149
150int s3c_camif_get_scaler_config(struct camif_vp *vp,
151 struct camif_scaler *scaler)
152{
153 struct v4l2_rect *camif_crop = &vp->camif->camif_crop;
154 int source_x = camif_crop->width;
155 int source_y = camif_crop->height;
156 int target_x = vp->out_frame.rect.width;
157 int target_y = vp->out_frame.rect.height;
158 int ret;
159
160 if (vp->rotation == 90 || vp->rotation == 270)
161 swap(target_x, target_y);
162
163 ret = camif_get_scaler_factor(source_x, target_x, &scaler->pre_h_ratio,
164 &scaler->h_shift);
165 if (ret < 0)
166 return ret;
167
168 ret = camif_get_scaler_factor(source_y, target_y, &scaler->pre_v_ratio,
169 &scaler->v_shift);
170 if (ret < 0)
171 return ret;
172
173 scaler->pre_dst_width = source_x / scaler->pre_h_ratio;
174 scaler->pre_dst_height = source_y / scaler->pre_v_ratio;
175
176 scaler->main_h_ratio = (source_x << 8) / (target_x << scaler->h_shift);
177 scaler->main_v_ratio = (source_y << 8) / (target_y << scaler->v_shift);
178
179 scaler->scaleup_h = (target_x >= source_x);
180 scaler->scaleup_v = (target_y >= source_y);
181
182 scaler->copy = 0;
183
184 pr_debug("H: ratio: %u, shift: %u. V: ratio: %u, shift: %u.\n",
185 scaler->pre_h_ratio, scaler->h_shift,
186 scaler->pre_v_ratio, scaler->v_shift);
187
188 pr_debug("Source: %dx%d, Target: %dx%d, scaleup_h/v: %d/%d\n",
189 source_x, source_y, target_x, target_y,
190 scaler->scaleup_h, scaler->scaleup_v);
191
192 return 0;
193}
194
195static int camif_register_sensor(struct camif_dev *camif)
196{
197 struct s3c_camif_sensor_info *sensor = &camif->pdata.sensor;
198 struct v4l2_device *v4l2_dev = &camif->v4l2_dev;
199 struct i2c_adapter *adapter;
200 struct v4l2_subdev_format format;
201 struct v4l2_subdev *sd;
202 int ret;
203
204 camif->sensor.sd = NULL;
205
206 if (sensor->i2c_board_info.addr == 0)
207 return -EINVAL;
208
209 adapter = i2c_get_adapter(sensor->i2c_bus_num);
210 if (adapter == NULL) {
211 v4l2_warn(v4l2_dev, "failed to get I2C adapter %d\n",
212 sensor->i2c_bus_num);
213 return -EPROBE_DEFER;
214 }
215
216 sd = v4l2_i2c_new_subdev_board(v4l2_dev, adapter,
217 &sensor->i2c_board_info, NULL);
218 if (sd == NULL) {
219 i2c_put_adapter(adapter);
220 v4l2_warn(v4l2_dev, "failed to acquire subdev %s\n",
221 sensor->i2c_board_info.type);
222 return -EPROBE_DEFER;
223 }
224 camif->sensor.sd = sd;
225
226 v4l2_info(v4l2_dev, "registered sensor subdevice %s\n", sd->name);
227
228 /* Get initial pixel format and set it at the camif sink pad */
229 format.pad = 0;
230 format.which = V4L2_SUBDEV_FORMAT_ACTIVE;
231 ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &format);
232
233 if (ret < 0)
234 return 0;
235
236 format.pad = CAMIF_SD_PAD_SINK;
237 v4l2_subdev_call(&camif->subdev, pad, set_fmt, NULL, &format);
238
239 v4l2_info(sd, "Initial format from sensor: %dx%d, %#x\n",
240 format.format.width, format.format.height,
241 format.format.code);
242 return 0;
243}
244
245static void camif_unregister_sensor(struct camif_dev *camif)
246{
247 struct v4l2_subdev *sd = camif->sensor.sd;
248 struct i2c_client *client = sd ? v4l2_get_subdevdata(sd) : NULL;
249 struct i2c_adapter *adapter;
250
251 if (client == NULL)
252 return;
253
254 adapter = client->adapter;
255 v4l2_device_unregister_subdev(sd);
256 camif->sensor.sd = NULL;
257 i2c_unregister_device(client);
258 if (adapter)
259 i2c_put_adapter(adapter);
260}
261
262static int camif_create_media_links(struct camif_dev *camif)
263{
264 int i, ret;
265
266 ret = media_entity_create_link(&camif->sensor.sd->entity, 0,
267 &camif->subdev.entity, CAMIF_SD_PAD_SINK,
268 MEDIA_LNK_FL_IMMUTABLE |
269 MEDIA_LNK_FL_ENABLED);
270 if (ret)
271 return ret;
272
273 for (i = 1; i < CAMIF_SD_PADS_NUM && !ret; i++) {
274 ret = media_entity_create_link(&camif->subdev.entity, i,
275 &camif->vp[i - 1].vdev.entity, 0,
276 MEDIA_LNK_FL_IMMUTABLE |
277 MEDIA_LNK_FL_ENABLED);
278 }
279
280 return ret;
281}
282
283static int camif_register_video_nodes(struct camif_dev *camif)
284{
285 int ret = s3c_camif_register_video_node(camif, VP_CODEC);
286 if (ret < 0)
287 return ret;
288
289 return s3c_camif_register_video_node(camif, VP_PREVIEW);
290}
291
292static void camif_unregister_video_nodes(struct camif_dev *camif)
293{
294 s3c_camif_unregister_video_node(camif, VP_CODEC);
295 s3c_camif_unregister_video_node(camif, VP_PREVIEW);
296}
297
298static void camif_unregister_media_entities(struct camif_dev *camif)
299{
300 camif_unregister_video_nodes(camif);
301 camif_unregister_sensor(camif);
302 s3c_camif_unregister_subdev(camif);
303}
304
305/*
306 * Media device
307 */
308static int camif_media_dev_register(struct camif_dev *camif)
309{
310 struct media_device *md = &camif->media_dev;
311 struct v4l2_device *v4l2_dev = &camif->v4l2_dev;
312 unsigned int ip_rev = camif->variant->ip_revision;
313 int ret;
314
315 memset(md, 0, sizeof(*md));
316 snprintf(md->model, sizeof(md->model), "SAMSUNG S3C%s CAMIF",
317 ip_rev == S3C6410_CAMIF_IP_REV ? "6410" : "244X");
318 strlcpy(md->bus_info, "platform", sizeof(md->bus_info));
319 md->hw_revision = ip_rev;
320 md->driver_version = KERNEL_VERSION(1, 0, 0);
321
322 md->dev = camif->dev;
323
324 strlcpy(v4l2_dev->name, "s3c-camif", sizeof(v4l2_dev->name));
325 v4l2_dev->mdev = md;
326
327 ret = v4l2_device_register(camif->dev, v4l2_dev);
328 if (ret < 0)
329 return ret;
330
331 ret = media_device_register(md);
332 if (ret < 0)
333 v4l2_device_unregister(v4l2_dev);
334
335 return ret;
336}
337
338static void camif_clk_put(struct camif_dev *camif)
339{
340 int i;
341
342 for (i = 0; i < CLK_MAX_NUM; i++) {
343 if (IS_ERR_OR_NULL(camif->clock[i]))
344 continue;
345 clk_unprepare(camif->clock[i]);
346 clk_put(camif->clock[i]);
347 }
348}
349
350static int camif_clk_get(struct camif_dev *camif)
351{
352 int ret, i;
353
354 for (i = 0; i < CLK_MAX_NUM; i++) {
355 camif->clock[i] = clk_get(camif->dev, camif_clocks[i]);
356 if (IS_ERR(camif->clock[i])) {
357 ret = PTR_ERR(camif->clock[i]);
358 goto err;
359 }
360 ret = clk_prepare(camif->clock[i]);
361 if (ret < 0) {
362 clk_put(camif->clock[i]);
363 camif->clock[i] = NULL;
364 goto err;
365 }
366 }
367 return 0;
368err:
369 camif_clk_put(camif);
370 dev_err(camif->dev, "failed to get clock: %s\n",
371 camif_clocks[i]);
372 return ret;
373}
374
375/*
376 * The CAMIF device has two relatively independent data processing paths
377 * that can source data from memory or the common camera input frontend.
378 * Register interrupts for each data processing path (camif_vp).
379 */
380static int camif_request_irqs(struct platform_device *pdev,
381 struct camif_dev *camif)
382{
383 int irq, ret, i;
384
385 for (i = 0; i < CAMIF_VP_NUM; i++) {
386 struct camif_vp *vp = &camif->vp[i];
387
388 init_waitqueue_head(&vp->irq_queue);
389
390 irq = platform_get_irq(pdev, i);
391 if (irq <= 0) {
392 dev_err(&pdev->dev, "failed to get IRQ %d\n", i);
393 return -ENXIO;
394 }
395
396 ret = devm_request_irq(&pdev->dev, irq, s3c_camif_irq_handler,
397 0, dev_name(&pdev->dev), vp);
398 if (ret < 0) {
399 dev_err(&pdev->dev, "failed to install IRQ: %d\n", ret);
400 break;
401 }
402 }
403
404 return ret;
405}
406
407static int s3c_camif_probe(struct platform_device *pdev)
408{
409 struct device *dev = &pdev->dev;
410 struct s3c_camif_plat_data *pdata = dev->platform_data;
411 struct s3c_camif_drvdata *drvdata;
412 struct camif_dev *camif;
413 struct resource *mres;
414 int ret = 0;
415
416 camif = devm_kzalloc(dev, sizeof(*camif), GFP_KERNEL);
417 if (!camif)
418 return -ENOMEM;
419
420 spin_lock_init(&camif->slock);
421 mutex_init(&camif->lock);
422
423 camif->dev = dev;
424
425 if (!pdata || !pdata->gpio_get || !pdata->gpio_put) {
426 dev_err(dev, "wrong platform data\n");
427 return -EINVAL;
428 }
429
430 camif->pdata = *pdata;
431 drvdata = (void *)platform_get_device_id(pdev)->driver_data;
432 camif->variant = drvdata->variant;
433
434 mres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
435
436 camif->io_base = devm_request_and_ioremap(dev, mres);
437 if (!camif->io_base) {
438 dev_err(dev, "failed to obtain I/O memory\n");
439 return -ENOENT;
440 }
441
442 ret = camif_request_irqs(pdev, camif);
443 if (ret < 0)
444 return ret;
445
446 ret = pdata->gpio_get();
447 if (ret < 0)
448 return ret;
449
450 ret = s3c_camif_create_subdev(camif);
451 if (ret < 0)
452 goto err_sd;
453
454 ret = camif_clk_get(camif);
455 if (ret < 0)
456 goto err_clk;
457
458 platform_set_drvdata(pdev, camif);
459 clk_set_rate(camif->clock[CLK_CAM],
460 camif->pdata.sensor.clock_frequency);
461
462 dev_info(dev, "sensor clock frequency: %lu\n",
463 clk_get_rate(camif->clock[CLK_CAM]));
464 /*
465 * Set initial pixel format, resolution and crop rectangle.
466 * Must be done before a sensor subdev is registered as some
467 * settings are overrode with values from sensor subdev.
468 */
469 s3c_camif_set_defaults(camif);
470
471 pm_runtime_enable(dev);
472
473 ret = pm_runtime_get_sync(dev);
474 if (ret < 0)
475 goto err_pm;
476
477 /* Initialize contiguous memory allocator */
478 camif->alloc_ctx = vb2_dma_contig_init_ctx(dev);
479 if (IS_ERR(camif->alloc_ctx)) {
480 ret = PTR_ERR(camif->alloc_ctx);
481 goto err_alloc;
482 }
483
484 ret = camif_media_dev_register(camif);
485 if (ret < 0)
486 goto err_mdev;
487
488 ret = camif_register_sensor(camif);
489 if (ret < 0)
490 goto err_sens;
491
492 ret = v4l2_device_register_subdev(&camif->v4l2_dev, &camif->subdev);
493 if (ret < 0)
494 goto err_sens;
495
496 mutex_lock(&camif->media_dev.graph_mutex);
497
498 ret = v4l2_device_register_subdev_nodes(&camif->v4l2_dev);
499 if (ret < 0)
500 goto err_unlock;
501
502 ret = camif_register_video_nodes(camif);
503 if (ret < 0)
504 goto err_unlock;
505
506 ret = camif_create_media_links(camif);
507 if (ret < 0)
508 goto err_unlock;
509
510 mutex_unlock(&camif->media_dev.graph_mutex);
511 pm_runtime_put(dev);
512 return 0;
513
514err_unlock:
515 mutex_unlock(&camif->media_dev.graph_mutex);
516err_sens:
517 v4l2_device_unregister(&camif->v4l2_dev);
518 media_device_unregister(&camif->media_dev);
519 camif_unregister_media_entities(camif);
520err_mdev:
521 vb2_dma_contig_cleanup_ctx(camif->alloc_ctx);
522err_alloc:
523 pm_runtime_put(dev);
524 pm_runtime_disable(dev);
525err_pm:
526 camif_clk_put(camif);
527err_clk:
528 s3c_camif_unregister_subdev(camif);
529err_sd:
530 pdata->gpio_put();
531 return ret;
532}
533
534static int __devexit s3c_camif_remove(struct platform_device *pdev)
535{
536 struct camif_dev *camif = platform_get_drvdata(pdev);
537 struct s3c_camif_plat_data *pdata = &camif->pdata;
538
539 media_device_unregister(&camif->media_dev);
540 camif_unregister_media_entities(camif);
541 v4l2_device_unregister(&camif->v4l2_dev);
542
543 pm_runtime_disable(&pdev->dev);
544 camif_clk_put(camif);
545 pdata->gpio_put();
546
547 return 0;
548}
549
550static int s3c_camif_runtime_resume(struct device *dev)
551{
552 struct camif_dev *camif = dev_get_drvdata(dev);
553
554 clk_enable(camif->clock[CLK_GATE]);
555 /* null op on s3c244x */
556 clk_enable(camif->clock[CLK_CAM]);
557 return 0;
558}
559
560static int s3c_camif_runtime_suspend(struct device *dev)
561{
562 struct camif_dev *camif = dev_get_drvdata(dev);
563
564 /* null op on s3c244x */
565 clk_disable(camif->clock[CLK_CAM]);
566
567 clk_disable(camif->clock[CLK_GATE]);
568 return 0;
569}
570
571static const struct s3c_camif_variant s3c244x_camif_variant = {
572 .vp_pix_limits = {
573 [VP_CODEC] = {
574 .max_out_width = 4096,
575 .max_sc_out_width = 2048,
576 .out_width_align = 16,
577 .min_out_width = 16,
578 .max_height = 4096,
579 },
580 [VP_PREVIEW] = {
581 .max_out_width = 640,
582 .max_sc_out_width = 640,
583 .out_width_align = 16,
584 .min_out_width = 16,
585 .max_height = 480,
586 }
587 },
588 .pix_limits = {
589 .win_hor_offset_align = 8,
590 },
591 .ip_revision = S3C244X_CAMIF_IP_REV,
592};
593
594static struct s3c_camif_drvdata s3c244x_camif_drvdata = {
595 .variant = &s3c244x_camif_variant,
596 .bus_clk_freq = 24000000UL,
597};
598
599static const struct s3c_camif_variant s3c6410_camif_variant = {
600 .vp_pix_limits = {
601 [VP_CODEC] = {
602 .max_out_width = 4096,
603 .max_sc_out_width = 2048,
604 .out_width_align = 16,
605 .min_out_width = 16,
606 .max_height = 4096,
607 },
608 [VP_PREVIEW] = {
609 .max_out_width = 4096,
610 .max_sc_out_width = 720,
611 .out_width_align = 16,
612 .min_out_width = 16,
613 .max_height = 4096,
614 }
615 },
616 .pix_limits = {
617 .win_hor_offset_align = 8,
618 },
619 .ip_revision = S3C6410_CAMIF_IP_REV,
620 .has_img_effect = 1,
621 .vp_offset = 0x20,
622};
623
624static struct s3c_camif_drvdata s3c6410_camif_drvdata = {
625 .variant = &s3c6410_camif_variant,
626 .bus_clk_freq = 133000000UL,
627};
628
629static struct platform_device_id s3c_camif_driver_ids[] = {
630 {
631 .name = "s3c2440-camif",
632 .driver_data = (unsigned long)&s3c244x_camif_drvdata,
633 }, {
634 .name = "s3c6410-camif",
635 .driver_data = (unsigned long)&s3c6410_camif_drvdata,
636 },
637 { /* sentinel */ },
638};
639MODULE_DEVICE_TABLE(platform, s3c_camif_driver_ids);
640
641static const struct dev_pm_ops s3c_camif_pm_ops = {
642 .runtime_suspend = s3c_camif_runtime_suspend,
643 .runtime_resume = s3c_camif_runtime_resume,
644};
645
646static struct platform_driver s3c_camif_driver = {
647 .probe = s3c_camif_probe,
648 .remove = __devexit_p(s3c_camif_remove),
649 .id_table = s3c_camif_driver_ids,
650 .driver = {
651 .name = S3C_CAMIF_DRIVER_NAME,
652 .owner = THIS_MODULE,
653 .pm = &s3c_camif_pm_ops,
654 }
655};
656
657module_platform_driver(s3c_camif_driver);
658
659MODULE_AUTHOR("Sylwester Nawrocki <sylvester.nawrocki@gmail.com>");
660MODULE_AUTHOR("Tomasz Figa <tomasz.figa@gmail.com>");
661MODULE_DESCRIPTION("S3C24XX/S3C64XX SoC camera interface driver");
662MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/s3c-camif/camif-core.h b/drivers/media/platform/s3c-camif/camif-core.h
new file mode 100644
index 000000000000..261134baa655
--- /dev/null
+++ b/drivers/media/platform/s3c-camif/camif-core.h
@@ -0,0 +1,393 @@
1/*
2 * s3c24xx/s3c64xx SoC series Camera Interface (CAMIF) driver
3 *
4 * Copyright (C) 2012 Sylwester Nawrocki <sylvester.nawrocki@gmail.com>
5 * Copyright (C) 2012 Tomasz Figa <tomasz.figa@gmail.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 CAMIF_CORE_H_
13#define CAMIF_CORE_H_
14
15#include <linux/io.h>
16#include <linux/irq.h>
17#include <linux/platform_device.h>
18#include <linux/sched.h>
19#include <linux/spinlock.h>
20#include <linux/types.h>
21#include <linux/videodev2.h>
22
23#include <media/media-entity.h>
24#include <media/v4l2-ctrls.h>
25#include <media/v4l2-dev.h>
26#include <media/v4l2-device.h>
27#include <media/v4l2-mediabus.h>
28#include <media/videobuf2-core.h>
29#include <media/s3c_camif.h>
30
31#define S3C_CAMIF_DRIVER_NAME "s3c-camif"
32#define CAMIF_REQ_BUFS_MIN 3
33#define CAMIF_MAX_OUT_BUFS 4
34#define CAMIF_MAX_PIX_WIDTH 4096
35#define CAMIF_MAX_PIX_HEIGHT 4096
36#define SCALER_MAX_RATIO 64
37#define CAMIF_DEF_WIDTH 640
38#define CAMIF_DEF_HEIGHT 480
39#define CAMIF_STOP_TIMEOUT 1500 /* ms */
40
41#define S3C244X_CAMIF_IP_REV 0x20 /* 2.0 */
42#define S3C2450_CAMIF_IP_REV 0x30 /* 3.0 - not implemented, not tested */
43#define S3C6400_CAMIF_IP_REV 0x31 /* 3.1 - not implemented, not tested */
44#define S3C6410_CAMIF_IP_REV 0x32 /* 3.2 */
45
46/* struct camif_vp::state */
47
48#define ST_VP_PENDING (1 << 0)
49#define ST_VP_RUNNING (1 << 1)
50#define ST_VP_STREAMING (1 << 2)
51#define ST_VP_SENSOR_STREAMING (1 << 3)
52
53#define ST_VP_ABORTING (1 << 4)
54#define ST_VP_OFF (1 << 5)
55#define ST_VP_LASTIRQ (1 << 6)
56
57#define ST_VP_CONFIG (1 << 8)
58
59#define CAMIF_SD_PAD_SINK 0
60#define CAMIF_SD_PAD_SOURCE_C 1
61#define CAMIF_SD_PAD_SOURCE_P 2
62#define CAMIF_SD_PADS_NUM 3
63
64enum img_fmt {
65 IMG_FMT_RGB565 = 0x0010,
66 IMG_FMT_RGB666,
67 IMG_FMT_XRGB8888,
68 IMG_FMT_YCBCR420 = 0x0020,
69 IMG_FMT_YCRCB420,
70 IMG_FMT_YCBCR422P,
71 IMG_FMT_YCBYCR422 = 0x0040,
72 IMG_FMT_YCRYCB422,
73 IMG_FMT_CBYCRY422,
74 IMG_FMT_CRYCBY422,
75};
76
77#define img_fmt_is_rgb(x) ((x) & 0x10)
78#define img_fmt_is_ycbcr(x) ((x) & 0x60)
79
80/* Possible values for struct camif_fmt::flags */
81#define FMT_FL_S3C24XX_CODEC (1 << 0)
82#define FMT_FL_S3C24XX_PREVIEW (1 << 1)
83#define FMT_FL_S3C64XX (1 << 2)
84
85/**
86 * struct camif_fmt - pixel format description
87 * @fourcc: fourcc code for this format, 0 if not applicable
88 * @color: a corresponding enum img_fmt
89 * @colplanes: number of physically contiguous data planes
90 * @flags: indicate for which SoCs revisions this format is valid
91 * @depth: bits per pixel (total)
92 * @ybpp: number of luminance bytes per pixel
93 */
94struct camif_fmt {
95 char *name;
96 u32 fourcc;
97 u32 color;
98 u16 colplanes;
99 u16 flags;
100 u8 depth;
101 u8 ybpp;
102};
103
104/**
105 * struct camif_dma_offset - pixel offset information for DMA
106 * @initial: offset (in pixels) to first pixel
107 * @line: offset (in pixels) from end of line to start of next line
108 */
109struct camif_dma_offset {
110 int initial;
111 int line;
112};
113
114/**
115 * struct camif_frame - source/target frame properties
116 * @f_width: full pixel width
117 * @f_height: full pixel height
118 * @rect: crop/composition rectangle
119 * @dma_offset: DMA offset configuration
120 */
121struct camif_frame {
122 u16 f_width;
123 u16 f_height;
124 struct v4l2_rect rect;
125 struct camif_dma_offset dma_offset;
126};
127
128/* CAMIF clocks enumeration */
129enum {
130 CLK_GATE,
131 CLK_CAM,
132 CLK_MAX_NUM,
133};
134
135struct vp_pix_limits {
136 u16 max_out_width;
137 u16 max_sc_out_width;
138 u16 out_width_align;
139 u16 max_height;
140 u8 min_out_width;
141 u16 out_hor_offset_align;
142};
143
144struct camif_pix_limits {
145 u16 win_hor_offset_align;
146};
147
148/**
149 * struct s3c_camif_variant - CAMIF variant structure
150 * @vp_pix_limits: pixel limits for the codec and preview paths
151 * @camif_pix_limits: pixel limits for the camera input interface
152 * @ip_revision: the CAMIF IP revision: 0x20 for s3c244x, 0x32 for s3c6410
153 */
154struct s3c_camif_variant {
155 struct vp_pix_limits vp_pix_limits[2];
156 struct camif_pix_limits pix_limits;
157 u8 ip_revision;
158 u8 has_img_effect;
159 unsigned int vp_offset;
160};
161
162struct s3c_camif_drvdata {
163 const struct s3c_camif_variant *variant;
164 unsigned long bus_clk_freq;
165};
166
167struct camif_scaler {
168 u8 scaleup_h;
169 u8 scaleup_v;
170 u8 copy;
171 u8 enable;
172 u32 h_shift;
173 u32 v_shift;
174 u32 pre_h_ratio;
175 u32 pre_v_ratio;
176 u32 pre_dst_width;
177 u32 pre_dst_height;
178 u32 main_h_ratio;
179 u32 main_v_ratio;
180};
181
182struct camif_dev;
183
184/**
185 * struct camif_vp - CAMIF data processing path structure (codec/preview)
186 * @irq_queue: interrupt handling waitqueue
187 * @irq: interrupt number for this data path
188 * @camif: pointer to the camif structure
189 * @pad: media pad for the video node
190 * @vdev video device
191 * @ctrl_handler: video node controls handler
192 * @owner: file handle that own the streaming
193 * @pending_buf_q: pending (empty) buffers queue head
194 * @active_buf_q: active (being written) buffers queue head
195 * @active_buffers: counter of buffer set up at the DMA engine
196 * @buf_index: identifier of a last empty buffer set up in H/W
197 * @frame_sequence: image frame sequence counter
198 * @reqbufs_count: the number of buffers requested
199 * @scaler: the scaler structure
200 * @out_fmt: pixel format at this video path output
201 * @payload: the output data frame payload size
202 * @out_frame: the output pixel resolution
203 * @state: the video path's state
204 * @fmt_flags: flags determining supported pixel formats
205 * @id: CAMIF id, 0 - codec, 1 - preview
206 * @rotation: current image rotation value
207 * @hflip: apply horizontal flip if set
208 * @vflip: apply vertical flip if set
209 */
210struct camif_vp {
211 wait_queue_head_t irq_queue;
212 int irq;
213 struct camif_dev *camif;
214 struct media_pad pad;
215 struct video_device vdev;
216 struct v4l2_ctrl_handler ctrl_handler;
217 struct v4l2_fh *owner;
218 struct vb2_queue vb_queue;
219 struct list_head pending_buf_q;
220 struct list_head active_buf_q;
221 unsigned int active_buffers;
222 unsigned int buf_index;
223 unsigned int frame_sequence;
224 unsigned int reqbufs_count;
225 struct camif_scaler scaler;
226 const struct camif_fmt *out_fmt;
227 unsigned int payload;
228 struct camif_frame out_frame;
229 unsigned int state;
230 u16 fmt_flags;
231 u8 id;
232 u8 rotation;
233 u8 hflip;
234 u8 vflip;
235 unsigned int offset;
236};
237
238/* Video processing path enumeration */
239#define VP_CODEC 0
240#define VP_PREVIEW 1
241#define CAMIF_VP_NUM 2
242
243/**
244 * struct camif_dev - the CAMIF driver private data structure
245 * @media_dev: top-level media device structure
246 * @v4l2_dev: root v4l2_device
247 * @subdev: camera interface ("catchcam") subdev
248 * @mbus_fmt: camera input media bus format
249 * @camif_crop: camera input interface crop rectangle
250 * @pads: the camif subdev's media pads
251 * @stream_count: the camera interface streaming reference counter
252 * @sensor: image sensor data structure
253 * @m_pipeline: video entity pipeline description
254 * @ctrl_handler: v4l2 control handler (owned by @subdev)
255 * @test_pattern: test pattern controls
256 * @vp: video path (DMA) description (codec/preview)
257 * @alloc_ctx: memory buffer allocator context
258 * @variant: variant information for this device
259 * @dev: pointer to the CAMIF device struct
260 * @pdata: a copy of the driver's platform data
261 * @clock: clocks required for the CAMIF operation
262 * @lock: mutex protecting this data structure
263 * @slock: spinlock protecting CAMIF registers
264 * @io_base: start address of the mmaped CAMIF registers
265 */
266struct camif_dev {
267 struct media_device media_dev;
268 struct v4l2_device v4l2_dev;
269 struct v4l2_subdev subdev;
270 struct v4l2_mbus_framefmt mbus_fmt;
271 struct v4l2_rect camif_crop;
272 struct media_pad pads[CAMIF_SD_PADS_NUM];
273 int stream_count;
274
275 struct cam_sensor {
276 struct v4l2_subdev *sd;
277 short power_count;
278 short stream_count;
279 } sensor;
280 struct media_pipeline *m_pipeline;
281
282 struct v4l2_ctrl_handler ctrl_handler;
283 struct v4l2_ctrl *ctrl_test_pattern;
284 struct {
285 struct v4l2_ctrl *ctrl_colorfx;
286 struct v4l2_ctrl *ctrl_colorfx_cbcr;
287 };
288 u8 test_pattern;
289 u8 colorfx;
290 u8 colorfx_cb;
291 u8 colorfx_cr;
292
293 struct camif_vp vp[CAMIF_VP_NUM];
294 struct vb2_alloc_ctx *alloc_ctx;
295
296 const struct s3c_camif_variant *variant;
297 struct device *dev;
298 struct s3c_camif_plat_data pdata;
299 struct clk *clock[CLK_MAX_NUM];
300 struct mutex lock;
301 spinlock_t slock;
302 void __iomem *io_base;
303};
304
305/**
306 * struct camif_addr - Y/Cb/Cr DMA start address structure
307 * @y: luminance plane dma address
308 * @cb: Cb plane dma address
309 * @cr: Cr plane dma address
310 */
311struct camif_addr {
312 dma_addr_t y;
313 dma_addr_t cb;
314 dma_addr_t cr;
315};
316
317/**
318 * struct camif_buffer - the camif video buffer structure
319 * @vb: vb2 buffer
320 * @list: list head for the buffers queue
321 * @paddr: DMA start addresses
322 * @index: an identifier of this buffer at the DMA engine
323 */
324struct camif_buffer {
325 struct vb2_buffer vb;
326 struct list_head list;
327 struct camif_addr paddr;
328 unsigned int index;
329};
330
331const struct camif_fmt *s3c_camif_find_format(struct camif_vp *vp,
332 const u32 *pixelformat, int index);
333int s3c_camif_register_video_node(struct camif_dev *camif, int idx);
334void s3c_camif_unregister_video_node(struct camif_dev *camif, int idx);
335irqreturn_t s3c_camif_irq_handler(int irq, void *priv);
336int s3c_camif_create_subdev(struct camif_dev *camif);
337void s3c_camif_unregister_subdev(struct camif_dev *camif);
338int s3c_camif_set_defaults(struct camif_dev *camif);
339int s3c_camif_get_scaler_config(struct camif_vp *vp,
340 struct camif_scaler *scaler);
341
342static inline void camif_active_queue_add(struct camif_vp *vp,
343 struct camif_buffer *buf)
344{
345 list_add_tail(&buf->list, &vp->active_buf_q);
346 vp->active_buffers++;
347}
348
349static inline struct camif_buffer *camif_active_queue_pop(
350 struct camif_vp *vp)
351{
352 struct camif_buffer *buf = list_first_entry(&vp->active_buf_q,
353 struct camif_buffer, list);
354 list_del(&buf->list);
355 vp->active_buffers--;
356 return buf;
357}
358
359static inline struct camif_buffer *camif_active_queue_peek(
360 struct camif_vp *vp, int index)
361{
362 struct camif_buffer *tmp, *buf;
363
364 if (WARN_ON(list_empty(&vp->active_buf_q)))
365 return NULL;
366
367 list_for_each_entry_safe(buf, tmp, &vp->active_buf_q, list) {
368 if (buf->index == index) {
369 list_del(&buf->list);
370 vp->active_buffers--;
371 return buf;
372 }
373 }
374
375 return NULL;
376}
377
378static inline void camif_pending_queue_add(struct camif_vp *vp,
379 struct camif_buffer *buf)
380{
381 list_add_tail(&buf->list, &vp->pending_buf_q);
382}
383
384static inline struct camif_buffer *camif_pending_queue_pop(
385 struct camif_vp *vp)
386{
387 struct camif_buffer *buf = list_first_entry(&vp->pending_buf_q,
388 struct camif_buffer, list);
389 list_del(&buf->list);
390 return buf;
391}
392
393#endif /* CAMIF_CORE_H_ */
diff --git a/drivers/media/platform/s3c-camif/camif-regs.c b/drivers/media/platform/s3c-camif/camif-regs.c
new file mode 100644
index 000000000000..1a3b4fc05ec6
--- /dev/null
+++ b/drivers/media/platform/s3c-camif/camif-regs.c
@@ -0,0 +1,606 @@
1/*
2 * Samsung s3c24xx/s3c64xx SoC CAMIF driver
3 *
4 * Copyright (C) 2012 Sylwester Nawrocki <sylvester.nawrocki@gmail.com>
5 * Copyright (C) 2012 Tomasz Figa <tomasz.figa@gmail.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#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__
12
13#include <linux/delay.h>
14#include "camif-regs.h"
15
16#define camif_write(_camif, _off, _val) writel(_val, (_camif)->io_base + (_off))
17#define camif_read(_camif, _off) readl((_camif)->io_base + (_off))
18
19void camif_hw_reset(struct camif_dev *camif)
20{
21 u32 cfg;
22
23 cfg = camif_read(camif, S3C_CAMIF_REG_CISRCFMT);
24 cfg |= CISRCFMT_ITU601_8BIT;
25 camif_write(camif, S3C_CAMIF_REG_CISRCFMT, cfg);
26
27 /* S/W reset */
28 cfg = camif_read(camif, S3C_CAMIF_REG_CIGCTRL);
29 cfg |= CIGCTRL_SWRST;
30 if (camif->variant->ip_revision == S3C6410_CAMIF_IP_REV)
31 cfg |= CIGCTRL_IRQ_LEVEL;
32 camif_write(camif, S3C_CAMIF_REG_CIGCTRL, cfg);
33 udelay(10);
34
35 cfg = camif_read(camif, S3C_CAMIF_REG_CIGCTRL);
36 cfg &= ~CIGCTRL_SWRST;
37 camif_write(camif, S3C_CAMIF_REG_CIGCTRL, cfg);
38 udelay(10);
39}
40
41void camif_hw_clear_pending_irq(struct camif_vp *vp)
42{
43 u32 cfg = camif_read(vp->camif, S3C_CAMIF_REG_CIGCTRL);
44 cfg |= CIGCTRL_IRQ_CLR(vp->id);
45 camif_write(vp->camif, S3C_CAMIF_REG_CIGCTRL, cfg);
46}
47
48/*
49 * Sets video test pattern (off, color bar, horizontal or vertical gradient).
50 * External sensor pixel clock must be active for the test pattern to work.
51 */
52void camif_hw_set_test_pattern(struct camif_dev *camif, unsigned int pattern)
53{
54 u32 cfg = camif_read(camif, S3C_CAMIF_REG_CIGCTRL);
55 cfg &= ~CIGCTRL_TESTPATTERN_MASK;
56 cfg |= (pattern << 27);
57 camif_write(camif, S3C_CAMIF_REG_CIGCTRL, cfg);
58}
59
60void camif_hw_set_effect(struct camif_dev *camif, unsigned int effect,
61 unsigned int cr, unsigned int cb)
62{
63 static const struct v4l2_control colorfx[] = {
64 { V4L2_COLORFX_NONE, CIIMGEFF_FIN_BYPASS },
65 { V4L2_COLORFX_BW, CIIMGEFF_FIN_ARBITRARY },
66 { V4L2_COLORFX_SEPIA, CIIMGEFF_FIN_ARBITRARY },
67 { V4L2_COLORFX_NEGATIVE, CIIMGEFF_FIN_NEGATIVE },
68 { V4L2_COLORFX_ART_FREEZE, CIIMGEFF_FIN_ARTFREEZE },
69 { V4L2_COLORFX_EMBOSS, CIIMGEFF_FIN_EMBOSSING },
70 { V4L2_COLORFX_SILHOUETTE, CIIMGEFF_FIN_SILHOUETTE },
71 { V4L2_COLORFX_SET_CBCR, CIIMGEFF_FIN_ARBITRARY },
72 };
73 unsigned int i, cfg;
74
75 for (i = 0; i < ARRAY_SIZE(colorfx); i++)
76 if (colorfx[i].id == effect)
77 break;
78
79 if (i == ARRAY_SIZE(colorfx))
80 return;
81
82 cfg = camif_read(camif, S3C_CAMIF_REG_CIIMGEFF(camif->vp->offset));
83 /* Set effect */
84 cfg &= ~CIIMGEFF_FIN_MASK;
85 cfg |= colorfx[i].value;
86 /* Set both paths */
87 if (camif->variant->ip_revision >= S3C6400_CAMIF_IP_REV) {
88 if (effect == V4L2_COLORFX_NONE)
89 cfg &= ~CIIMGEFF_IE_ENABLE_MASK;
90 else
91 cfg |= CIIMGEFF_IE_ENABLE_MASK;
92 }
93 cfg &= ~CIIMGEFF_PAT_CBCR_MASK;
94 cfg |= cr | (cb << 13);
95 camif_write(camif, S3C_CAMIF_REG_CIIMGEFF(camif->vp->offset), cfg);
96}
97
98static const u32 src_pixfmt_map[8][2] = {
99 { V4L2_MBUS_FMT_YUYV8_2X8, CISRCFMT_ORDER422_YCBYCR },
100 { V4L2_MBUS_FMT_YVYU8_2X8, CISRCFMT_ORDER422_YCRYCB },
101 { V4L2_MBUS_FMT_UYVY8_2X8, CISRCFMT_ORDER422_CBYCRY },
102 { V4L2_MBUS_FMT_VYUY8_2X8, CISRCFMT_ORDER422_CRYCBY },
103};
104
105/* Set camera input pixel format and resolution */
106void camif_hw_set_source_format(struct camif_dev *camif)
107{
108 struct v4l2_mbus_framefmt *mf = &camif->mbus_fmt;
109 unsigned int i = ARRAY_SIZE(src_pixfmt_map);
110 u32 cfg;
111
112 while (i-- >= 0) {
113 if (src_pixfmt_map[i][0] == mf->code)
114 break;
115 }
116
117 if (i == 0 && src_pixfmt_map[i][0] != mf->code) {
118 dev_err(camif->dev,
119 "Unsupported pixel code, falling back to %#08x\n",
120 src_pixfmt_map[i][0]);
121 }
122
123 cfg = camif_read(camif, S3C_CAMIF_REG_CISRCFMT);
124 cfg &= ~(CISRCFMT_ORDER422_MASK | CISRCFMT_SIZE_CAM_MASK);
125 cfg |= (mf->width << 16) | mf->height;
126 cfg |= src_pixfmt_map[i][1];
127 camif_write(camif, S3C_CAMIF_REG_CISRCFMT, cfg);
128}
129
130/* Set the camera host input window offsets (cropping) */
131void camif_hw_set_camera_crop(struct camif_dev *camif)
132{
133 struct v4l2_mbus_framefmt *mf = &camif->mbus_fmt;
134 struct v4l2_rect *crop = &camif->camif_crop;
135 u32 hoff2, voff2;
136 u32 cfg;
137
138 /* Note: s3c244x requirement: left = f_width - rect.width / 2 */
139 cfg = camif_read(camif, S3C_CAMIF_REG_CIWDOFST);
140 cfg &= ~(CIWDOFST_OFST_MASK | CIWDOFST_WINOFSEN);
141 cfg |= (crop->left << 16) | crop->top;
142 if (crop->left != 0 || crop->top != 0)
143 cfg |= CIWDOFST_WINOFSEN;
144 camif_write(camif, S3C_CAMIF_REG_CIWDOFST, cfg);
145
146 if (camif->variant->ip_revision == S3C6410_CAMIF_IP_REV) {
147 hoff2 = mf->width - crop->width - crop->left;
148 voff2 = mf->height - crop->height - crop->top;
149 cfg = (hoff2 << 16) | voff2;
150 camif_write(camif, S3C_CAMIF_REG_CIWDOFST2, cfg);
151 }
152}
153
154void camif_hw_clear_fifo_overflow(struct camif_vp *vp)
155{
156 struct camif_dev *camif = vp->camif;
157 u32 cfg;
158
159 cfg = camif_read(camif, S3C_CAMIF_REG_CIWDOFST);
160 if (vp->id == 0)
161 cfg |= (CIWDOFST_CLROVCOFIY | CIWDOFST_CLROVCOFICB |
162 CIWDOFST_CLROVCOFICR);
163 else
164 cfg |= (/* CIWDOFST_CLROVPRFIY | */ CIWDOFST_CLROVPRFICB |
165 CIWDOFST_CLROVPRFICR);
166 camif_write(camif, S3C_CAMIF_REG_CIWDOFST, cfg);
167}
168
169/* Set video bus signals polarity */
170void camif_hw_set_camera_bus(struct camif_dev *camif)
171{
172 unsigned int flags = camif->pdata.sensor.flags;
173
174 u32 cfg = camif_read(camif, S3C_CAMIF_REG_CIGCTRL);
175
176 cfg &= ~(CIGCTRL_INVPOLPCLK | CIGCTRL_INVPOLVSYNC |
177 CIGCTRL_INVPOLHREF | CIGCTRL_INVPOLFIELD);
178
179 if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
180 cfg |= CIGCTRL_INVPOLPCLK;
181
182 if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
183 cfg |= CIGCTRL_INVPOLVSYNC;
184 /*
185 * HREF is normally high during frame active data
186 * transmission and low during horizontal synchronization
187 * period. Thus HREF active high means HSYNC active low.
188 */
189 if (flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
190 cfg |= CIGCTRL_INVPOLHREF; /* HREF active low */
191
192 if (camif->variant->ip_revision == S3C6410_CAMIF_IP_REV) {
193 if (flags & V4L2_MBUS_FIELD_EVEN_LOW)
194 cfg |= CIGCTRL_INVPOLFIELD;
195 cfg |= CIGCTRL_FIELDMODE;
196 }
197
198 pr_debug("Setting CIGCTRL to: %#x\n", cfg);
199
200 camif_write(camif, S3C_CAMIF_REG_CIGCTRL, cfg);
201}
202
203void camif_hw_set_output_addr(struct camif_vp *vp,
204 struct camif_addr *paddr, int i)
205{
206 struct camif_dev *camif = vp->camif;
207
208 camif_write(camif, S3C_CAMIF_REG_CIYSA(vp->id, i), paddr->y);
209 if (camif->variant->ip_revision == S3C6410_CAMIF_IP_REV
210 || vp->id == VP_CODEC) {
211 camif_write(camif, S3C_CAMIF_REG_CICBSA(vp->id, i),
212 paddr->cb);
213 camif_write(camif, S3C_CAMIF_REG_CICRSA(vp->id, i),
214 paddr->cr);
215 }
216
217 pr_debug("dst_buf[%d]: %#X, cb: %#X, cr: %#X\n",
218 i, paddr->y, paddr->cb, paddr->cr);
219}
220
221static void camif_hw_set_out_dma_size(struct camif_vp *vp)
222{
223 struct camif_frame *frame = &vp->out_frame;
224 u32 cfg;
225
226 cfg = camif_read(vp->camif, S3C_CAMIF_REG_CITRGFMT(vp->id, vp->offset));
227 cfg &= ~CITRGFMT_TARGETSIZE_MASK;
228 cfg |= (frame->f_width << 16) | frame->f_height;
229 camif_write(vp->camif, S3C_CAMIF_REG_CITRGFMT(vp->id, vp->offset), cfg);
230}
231
232static void camif_get_dma_burst(u32 width, u32 ybpp, u32 *mburst, u32 *rburst)
233{
234 unsigned int nwords = width * ybpp / 4;
235 unsigned int div, rem;
236
237 if (WARN_ON(width < 8 || (width * ybpp) & 7))
238 return;
239
240 for (div = 16; div >= 2; div /= 2) {
241 if (nwords < div)
242 continue;
243
244 rem = nwords & (div - 1);
245 if (rem == 0) {
246 *mburst = div;
247 *rburst = div;
248 break;
249 }
250 if (rem == div / 2 || rem == div / 4) {
251 *mburst = div;
252 *rburst = rem;
253 break;
254 }
255 }
256}
257
258void camif_hw_set_output_dma(struct camif_vp *vp)
259{
260 struct camif_dev *camif = vp->camif;
261 struct camif_frame *frame = &vp->out_frame;
262 const struct camif_fmt *fmt = vp->out_fmt;
263 unsigned int ymburst = 0, yrburst = 0;
264 u32 cfg;
265
266 camif_hw_set_out_dma_size(vp);
267
268 if (camif->variant->ip_revision == S3C6410_CAMIF_IP_REV) {
269 struct camif_dma_offset *offset = &frame->dma_offset;
270 /* Set the input dma offsets. */
271 cfg = S3C_CISS_OFFS_INITIAL(offset->initial);
272 cfg |= S3C_CISS_OFFS_LINE(offset->line);
273 camif_write(camif, S3C_CAMIF_REG_CISSY(vp->id), cfg);
274 camif_write(camif, S3C_CAMIF_REG_CISSCB(vp->id), cfg);
275 camif_write(camif, S3C_CAMIF_REG_CISSCR(vp->id), cfg);
276 }
277
278 /* Configure DMA burst values */
279 camif_get_dma_burst(frame->rect.width, fmt->ybpp, &ymburst, &yrburst);
280
281 cfg = camif_read(camif, S3C_CAMIF_REG_CICTRL(vp->id, vp->offset));
282 cfg &= ~CICTRL_BURST_MASK;
283
284 cfg |= CICTRL_YBURST1(ymburst) | CICTRL_YBURST2(yrburst);
285 cfg |= CICTRL_CBURST1(ymburst / 2) | CICTRL_CBURST2(yrburst / 2);
286
287 camif_write(camif, S3C_CAMIF_REG_CICTRL(vp->id, vp->offset), cfg);
288
289 pr_debug("ymburst: %u, yrburst: %u\n", ymburst, yrburst);
290}
291
292void camif_hw_set_input_path(struct camif_vp *vp)
293{
294 u32 cfg = camif_read(vp->camif, S3C_CAMIF_REG_MSCTRL(vp->id));
295 cfg &= ~MSCTRL_SEL_DMA_CAM;
296 camif_write(vp->camif, S3C_CAMIF_REG_MSCTRL(vp->id), cfg);
297}
298
299void camif_hw_set_target_format(struct camif_vp *vp)
300{
301 struct camif_dev *camif = vp->camif;
302 struct camif_frame *frame = &vp->out_frame;
303 u32 cfg;
304
305 pr_debug("fw: %d, fh: %d color: %d\n", frame->f_width,
306 frame->f_height, vp->out_fmt->color);
307
308 cfg = camif_read(camif, S3C_CAMIF_REG_CITRGFMT(vp->id, vp->offset));
309 cfg &= ~CITRGFMT_TARGETSIZE_MASK;
310
311 if (camif->variant->ip_revision == S3C244X_CAMIF_IP_REV) {
312 /* We currently support only YCbCr 4:2:2 at the camera input */
313 cfg |= CITRGFMT_IN422;
314 cfg &= ~CITRGFMT_OUT422;
315 if (vp->out_fmt->color == IMG_FMT_YCBCR422P)
316 cfg |= CITRGFMT_OUT422;
317 } else {
318 cfg &= ~CITRGFMT_OUTFORMAT_MASK;
319 switch (vp->out_fmt->color) {
320 case IMG_FMT_RGB565...IMG_FMT_XRGB8888:
321 cfg |= CITRGFMT_OUTFORMAT_RGB;
322 break;
323 case IMG_FMT_YCBCR420...IMG_FMT_YCRCB420:
324 cfg |= CITRGFMT_OUTFORMAT_YCBCR420;
325 break;
326 case IMG_FMT_YCBCR422P:
327 cfg |= CITRGFMT_OUTFORMAT_YCBCR422;
328 break;
329 case IMG_FMT_YCBYCR422...IMG_FMT_CRYCBY422:
330 cfg |= CITRGFMT_OUTFORMAT_YCBCR422I;
331 break;
332 }
333 }
334
335 /* Rotation is only supported by s3c64xx */
336 if (vp->rotation == 90 || vp->rotation == 270)
337 cfg |= (frame->f_height << 16) | frame->f_width;
338 else
339 cfg |= (frame->f_width << 16) | frame->f_height;
340 camif_write(camif, S3C_CAMIF_REG_CITRGFMT(vp->id, vp->offset), cfg);
341
342 /* Target area, output pixel width * height */
343 cfg = camif_read(camif, S3C_CAMIF_REG_CITAREA(vp->id, vp->offset));
344 cfg &= ~CITAREA_MASK;
345 cfg |= (frame->f_width * frame->f_height);
346 camif_write(camif, S3C_CAMIF_REG_CITAREA(vp->id, vp->offset), cfg);
347}
348
349void camif_hw_set_flip(struct camif_vp *vp)
350{
351 u32 cfg = camif_read(vp->camif,
352 S3C_CAMIF_REG_CITRGFMT(vp->id, vp->offset));
353
354 cfg &= ~CITRGFMT_FLIP_MASK;
355
356 if (vp->hflip)
357 cfg |= CITRGFMT_FLIP_Y_MIRROR;
358 if (vp->vflip)
359 cfg |= CITRGFMT_FLIP_X_MIRROR;
360
361 camif_write(vp->camif, S3C_CAMIF_REG_CITRGFMT(vp->id, vp->offset), cfg);
362}
363
364static void camif_hw_set_prescaler(struct camif_vp *vp)
365{
366 struct camif_dev *camif = vp->camif;
367 struct camif_scaler *sc = &vp->scaler;
368 u32 cfg, shfactor, addr;
369
370 addr = S3C_CAMIF_REG_CISCPRERATIO(vp->id, vp->offset);
371
372 shfactor = 10 - (sc->h_shift + sc->v_shift);
373 cfg = shfactor << 28;
374
375 cfg |= (sc->pre_h_ratio << 16) | sc->pre_v_ratio;
376 camif_write(camif, addr, cfg);
377
378 cfg = (sc->pre_dst_width << 16) | sc->pre_dst_height;
379 camif_write(camif, S3C_CAMIF_REG_CISCPREDST(vp->id, vp->offset), cfg);
380}
381
382void camif_s3c244x_hw_set_scaler(struct camif_vp *vp)
383{
384 struct camif_dev *camif = vp->camif;
385 struct camif_scaler *scaler = &vp->scaler;
386 unsigned int color = vp->out_fmt->color;
387 u32 cfg;
388
389 camif_hw_set_prescaler(vp);
390
391 cfg = camif_read(camif, S3C_CAMIF_REG_CISCCTRL(vp->id, vp->offset));
392
393 cfg &= ~(CISCCTRL_SCALEUP_MASK | CISCCTRL_SCALERBYPASS |
394 CISCCTRL_MAIN_RATIO_MASK | CIPRSCCTRL_RGB_FORMAT_24BIT);
395
396 if (scaler->enable) {
397 if (scaler->scaleup_h) {
398 if (vp->id == VP_CODEC)
399 cfg |= CISCCTRL_SCALEUP_H;
400 else
401 cfg |= CIPRSCCTRL_SCALEUP_H;
402 }
403 if (scaler->scaleup_v) {
404 if (vp->id == VP_CODEC)
405 cfg |= CISCCTRL_SCALEUP_V;
406 else
407 cfg |= CIPRSCCTRL_SCALEUP_V;
408 }
409 } else {
410 if (vp->id == VP_CODEC)
411 cfg |= CISCCTRL_SCALERBYPASS;
412 }
413
414 cfg |= ((scaler->main_h_ratio & 0x1ff) << 16);
415 cfg |= scaler->main_v_ratio & 0x1ff;
416
417 if (vp->id == VP_PREVIEW) {
418 if (color == IMG_FMT_XRGB8888)
419 cfg |= CIPRSCCTRL_RGB_FORMAT_24BIT;
420 cfg |= CIPRSCCTRL_SAMPLE;
421 }
422
423 camif_write(camif, S3C_CAMIF_REG_CISCCTRL(vp->id, vp->offset), cfg);
424
425 pr_debug("main: h_ratio: %#x, v_ratio: %#x",
426 scaler->main_h_ratio, scaler->main_v_ratio);
427}
428
429void camif_s3c64xx_hw_set_scaler(struct camif_vp *vp)
430{
431 struct camif_dev *camif = vp->camif;
432 struct camif_scaler *scaler = &vp->scaler;
433 unsigned int color = vp->out_fmt->color;
434 u32 cfg;
435
436 camif_hw_set_prescaler(vp);
437
438 cfg = camif_read(camif, S3C_CAMIF_REG_CISCCTRL(vp->id, vp->offset));
439
440 cfg &= ~(CISCCTRL_CSCR2Y_WIDE | CISCCTRL_CSCY2R_WIDE
441 | CISCCTRL_SCALEUP_H | CISCCTRL_SCALEUP_V
442 | CISCCTRL_SCALERBYPASS | CISCCTRL_ONE2ONE
443 | CISCCTRL_INRGB_FMT_MASK | CISCCTRL_OUTRGB_FMT_MASK
444 | CISCCTRL_INTERLACE | CISCCTRL_EXTRGB_EXTENSION
445 | CISCCTRL_MAIN_RATIO_MASK);
446
447 cfg |= (CISCCTRL_CSCR2Y_WIDE | CISCCTRL_CSCY2R_WIDE);
448
449 if (!scaler->enable) {
450 cfg |= CISCCTRL_SCALERBYPASS;
451 } else {
452 if (scaler->scaleup_h)
453 cfg |= CISCCTRL_SCALEUP_H;
454 if (scaler->scaleup_v)
455 cfg |= CISCCTRL_SCALEUP_V;
456 if (scaler->copy)
457 cfg |= CISCCTRL_ONE2ONE;
458 }
459
460 switch (color) {
461 case IMG_FMT_RGB666:
462 cfg |= CISCCTRL_OUTRGB_FMT_RGB666;
463 break;
464 case IMG_FMT_XRGB8888:
465 cfg |= CISCCTRL_OUTRGB_FMT_RGB888;
466 break;
467 }
468
469 cfg |= (scaler->main_h_ratio & 0x1ff) << 16;
470 cfg |= scaler->main_v_ratio & 0x1ff;
471
472 camif_write(camif, S3C_CAMIF_REG_CISCCTRL(vp->id, vp->offset), cfg);
473
474 pr_debug("main: h_ratio: %#x, v_ratio: %#x",
475 scaler->main_h_ratio, scaler->main_v_ratio);
476}
477
478void camif_hw_set_scaler(struct camif_vp *vp)
479{
480 unsigned int ip_rev = vp->camif->variant->ip_revision;
481
482 if (ip_rev == S3C244X_CAMIF_IP_REV)
483 camif_s3c244x_hw_set_scaler(vp);
484 else
485 camif_s3c64xx_hw_set_scaler(vp);
486}
487
488void camif_hw_enable_scaler(struct camif_vp *vp, bool on)
489{
490 u32 addr = S3C_CAMIF_REG_CISCCTRL(vp->id, vp->offset);
491 u32 cfg;
492
493 cfg = camif_read(vp->camif, addr);
494 if (on)
495 cfg |= CISCCTRL_SCALERSTART;
496 else
497 cfg &= ~CISCCTRL_SCALERSTART;
498 camif_write(vp->camif, addr, cfg);
499}
500
501void camif_hw_set_lastirq(struct camif_vp *vp, int enable)
502{
503 u32 addr = S3C_CAMIF_REG_CICTRL(vp->id, vp->offset);
504 u32 cfg;
505
506 cfg = camif_read(vp->camif, addr);
507 if (enable)
508 cfg |= CICTRL_LASTIRQ_ENABLE;
509 else
510 cfg &= ~CICTRL_LASTIRQ_ENABLE;
511 camif_write(vp->camif, addr, cfg);
512}
513
514void camif_hw_enable_capture(struct camif_vp *vp)
515{
516 struct camif_dev *camif = vp->camif;
517 u32 cfg;
518
519 cfg = camif_read(camif, S3C_CAMIF_REG_CIIMGCPT(vp->offset));
520 camif->stream_count++;
521
522 if (camif->variant->ip_revision == S3C6410_CAMIF_IP_REV)
523 cfg |= CIIMGCPT_CPT_FREN_ENABLE(vp->id);
524
525 if (vp->scaler.enable)
526 cfg |= CIIMGCPT_IMGCPTEN_SC(vp->id);
527
528 if (camif->stream_count == 1)
529 cfg |= CIIMGCPT_IMGCPTEN;
530
531 camif_write(camif, S3C_CAMIF_REG_CIIMGCPT(vp->offset), cfg);
532
533 pr_debug("CIIMGCPT: %#x, camif->stream_count: %d\n",
534 cfg, camif->stream_count);
535}
536
537void camif_hw_disable_capture(struct camif_vp *vp)
538{
539 struct camif_dev *camif = vp->camif;
540 u32 cfg;
541
542 cfg = camif_read(camif, S3C_CAMIF_REG_CIIMGCPT(vp->offset));
543 cfg &= ~CIIMGCPT_IMGCPTEN_SC(vp->id);
544
545 if (WARN_ON(--(camif->stream_count) < 0))
546 camif->stream_count = 0;
547
548 if (camif->stream_count == 0)
549 cfg &= ~CIIMGCPT_IMGCPTEN;
550
551 pr_debug("CIIMGCPT: %#x, camif->stream_count: %d\n",
552 cfg, camif->stream_count);
553
554 camif_write(camif, S3C_CAMIF_REG_CIIMGCPT(vp->offset), cfg);
555}
556
557void camif_hw_dump_regs(struct camif_dev *camif, const char *label)
558{
559 struct {
560 u32 offset;
561 const char * const name;
562 } registers[] = {
563 { S3C_CAMIF_REG_CISRCFMT, "CISRCFMT" },
564 { S3C_CAMIF_REG_CIWDOFST, "CIWDOFST" },
565 { S3C_CAMIF_REG_CIGCTRL, "CIGCTRL" },
566 { S3C_CAMIF_REG_CIWDOFST2, "CIWDOFST2" },
567 { S3C_CAMIF_REG_CIYSA(0, 0), "CICOYSA0" },
568 { S3C_CAMIF_REG_CICBSA(0, 0), "CICOCBSA0" },
569 { S3C_CAMIF_REG_CICRSA(0, 0), "CICOCRSA0" },
570 { S3C_CAMIF_REG_CIYSA(0, 1), "CICOYSA1" },
571 { S3C_CAMIF_REG_CICBSA(0, 1), "CICOCBSA1" },
572 { S3C_CAMIF_REG_CICRSA(0, 1), "CICOCRSA1" },
573 { S3C_CAMIF_REG_CIYSA(0, 2), "CICOYSA2" },
574 { S3C_CAMIF_REG_CICBSA(0, 2), "CICOCBSA2" },
575 { S3C_CAMIF_REG_CICRSA(0, 2), "CICOCRSA2" },
576 { S3C_CAMIF_REG_CIYSA(0, 3), "CICOYSA3" },
577 { S3C_CAMIF_REG_CICBSA(0, 3), "CICOCBSA3" },
578 { S3C_CAMIF_REG_CICRSA(0, 3), "CICOCRSA3" },
579 { S3C_CAMIF_REG_CIYSA(1, 0), "CIPRYSA0" },
580 { S3C_CAMIF_REG_CIYSA(1, 1), "CIPRYSA1" },
581 { S3C_CAMIF_REG_CIYSA(1, 2), "CIPRYSA2" },
582 { S3C_CAMIF_REG_CIYSA(1, 3), "CIPRYSA3" },
583 { S3C_CAMIF_REG_CITRGFMT(0, 0), "CICOTRGFMT" },
584 { S3C_CAMIF_REG_CITRGFMT(1, 0), "CIPRTRGFMT" },
585 { S3C_CAMIF_REG_CICTRL(0, 0), "CICOCTRL" },
586 { S3C_CAMIF_REG_CICTRL(1, 0), "CIPRCTRL" },
587 { S3C_CAMIF_REG_CISCPREDST(0, 0), "CICOSCPREDST" },
588 { S3C_CAMIF_REG_CISCPREDST(1, 0), "CIPRSCPREDST" },
589 { S3C_CAMIF_REG_CISCPRERATIO(0, 0), "CICOSCPRERATIO" },
590 { S3C_CAMIF_REG_CISCPRERATIO(1, 0), "CIPRSCPRERATIO" },
591 { S3C_CAMIF_REG_CISCCTRL(0, 0), "CICOSCCTRL" },
592 { S3C_CAMIF_REG_CISCCTRL(1, 0), "CIPRSCCTRL" },
593 { S3C_CAMIF_REG_CITAREA(0, 0), "CICOTAREA" },
594 { S3C_CAMIF_REG_CITAREA(1, 0), "CIPRTAREA" },
595 { S3C_CAMIF_REG_CISTATUS(0, 0), "CICOSTATUS" },
596 { S3C_CAMIF_REG_CISTATUS(1, 0), "CIPRSTATUS" },
597 { S3C_CAMIF_REG_CIIMGCPT(0), "CIIMGCPT" },
598 };
599 u32 i;
600
601 pr_info("--- %s ---\n", label);
602 for (i = 0; i < ARRAY_SIZE(registers); i++) {
603 u32 cfg = readl(camif->io_base + registers[i].offset);
604 printk(KERN_INFO "%s:\t0x%08x\n", registers[i].name, cfg);
605 }
606}
diff --git a/drivers/media/platform/s3c-camif/camif-regs.h b/drivers/media/platform/s3c-camif/camif-regs.h
new file mode 100644
index 000000000000..af2d472ea1dd
--- /dev/null
+++ b/drivers/media/platform/s3c-camif/camif-regs.h
@@ -0,0 +1,269 @@
1/*
2 * Register definition file for s3c24xx/s3c64xx SoC CAMIF driver
3 *
4 * Copyright (C) 2012 Sylwester Nawrocki <sylvester.nawrocki@gmail.com>
5 * Copyright (C) 2012 Tomasz Figa <tomasz.figa@gmail.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 CAMIF_REGS_H_
13#define CAMIF_REGS_H_
14
15#include "camif-core.h"
16#include <media/s3c_camif.h>
17
18/*
19 * The id argument indicates the processing path:
20 * id = 0 - codec (FIMC C), 1 - preview (FIMC P).
21 */
22
23/* Camera input format */
24#define S3C_CAMIF_REG_CISRCFMT 0x00
25#define CISRCFMT_ITU601_8BIT (1 << 31)
26#define CISRCFMT_ITU656_8BIT (0 << 31)
27#define CISRCFMT_ORDER422_YCBYCR (0 << 14)
28#define CISRCFMT_ORDER422_YCRYCB (1 << 14)
29#define CISRCFMT_ORDER422_CBYCRY (2 << 14)
30#define CISRCFMT_ORDER422_CRYCBY (3 << 14)
31#define CISRCFMT_ORDER422_MASK (3 << 14)
32#define CISRCFMT_SIZE_CAM_MASK (0x1fff << 16 | 0x1fff)
33
34/* Window offset */
35#define S3C_CAMIF_REG_CIWDOFST 0x04
36#define CIWDOFST_WINOFSEN (1 << 31)
37#define CIWDOFST_CLROVCOFIY (1 << 30)
38#define CIWDOFST_CLROVRLB_PR (1 << 28)
39/* #define CIWDOFST_CLROVPRFIY (1 << 27) */
40#define CIWDOFST_CLROVCOFICB (1 << 15)
41#define CIWDOFST_CLROVCOFICR (1 << 14)
42#define CIWDOFST_CLROVPRFICB (1 << 13)
43#define CIWDOFST_CLROVPRFICR (1 << 12)
44#define CIWDOFST_OFST_MASK (0x7ff << 16 | 0x7ff)
45
46/* Window offset 2 */
47#define S3C_CAMIF_REG_CIWDOFST2 0x14
48#define CIWDOFST2_OFST2_MASK (0xfff << 16 | 0xfff)
49
50/* Global control */
51#define S3C_CAMIF_REG_CIGCTRL 0x08
52#define CIGCTRL_SWRST (1 << 31)
53#define CIGCTRL_CAMRST (1 << 30)
54#define CIGCTRL_TESTPATTERN_NORMAL (0 << 27)
55#define CIGCTRL_TESTPATTERN_COLOR_BAR (1 << 27)
56#define CIGCTRL_TESTPATTERN_HOR_INC (2 << 27)
57#define CIGCTRL_TESTPATTERN_VER_INC (3 << 27)
58#define CIGCTRL_TESTPATTERN_MASK (3 << 27)
59#define CIGCTRL_INVPOLPCLK (1 << 26)
60#define CIGCTRL_INVPOLVSYNC (1 << 25)
61#define CIGCTRL_INVPOLHREF (1 << 24)
62#define CIGCTRL_IRQ_OVFEN (1 << 22)
63#define CIGCTRL_HREF_MASK (1 << 21)
64#define CIGCTRL_IRQ_LEVEL (1 << 20)
65/* IRQ_CLR_C, IRQ_CLR_P */
66#define CIGCTRL_IRQ_CLR(id) (1 << (19 - (id)))
67#define CIGCTRL_FIELDMODE (1 << 2)
68#define CIGCTRL_INVPOLFIELD (1 << 1)
69#define CIGCTRL_CAM_INTERLACE (1 << 0)
70
71/* Y DMA output frame start address. n = 0..3. */
72#define S3C_CAMIF_REG_CIYSA(id, n) (0x18 + (id) * 0x54 + (n) * 4)
73/* Cb plane output DMA start address. n = 0..3. Only codec path. */
74#define S3C_CAMIF_REG_CICBSA(id, n) (0x28 + (id) * 0x54 + (n) * 4)
75/* Cr plane output DMA start address. n = 0..3. Only codec path. */
76#define S3C_CAMIF_REG_CICRSA(id, n) (0x38 + (id) * 0x54 + (n) * 4)
77
78/* CICOTRGFMT, CIPRTRGFMT - Target format */
79#define S3C_CAMIF_REG_CITRGFMT(id, _offs) (0x48 + (id) * (0x34 + (_offs)))
80#define CITRGFMT_IN422 (1 << 31) /* only for s3c24xx */
81#define CITRGFMT_OUT422 (1 << 30) /* only for s3c24xx */
82#define CITRGFMT_OUTFORMAT_YCBCR420 (0 << 29) /* only for s3c6410 */
83#define CITRGFMT_OUTFORMAT_YCBCR422 (1 << 29) /* only for s3c6410 */
84#define CITRGFMT_OUTFORMAT_YCBCR422I (2 << 29) /* only for s3c6410 */
85#define CITRGFMT_OUTFORMAT_RGB (3 << 29) /* only for s3c6410 */
86#define CITRGFMT_OUTFORMAT_MASK (3 << 29) /* only for s3c6410 */
87#define CITRGFMT_TARGETHSIZE(x) ((x) << 16)
88#define CITRGFMT_FLIP_NORMAL (0 << 14)
89#define CITRGFMT_FLIP_X_MIRROR (1 << 14)
90#define CITRGFMT_FLIP_Y_MIRROR (2 << 14)
91#define CITRGFMT_FLIP_180 (3 << 14)
92#define CITRGFMT_FLIP_MASK (3 << 14)
93/* Preview path only */
94#define CITRGFMT_ROT90_PR (1 << 13)
95#define CITRGFMT_TARGETVSIZE(x) ((x) << 0)
96#define CITRGFMT_TARGETSIZE_MASK ((0x1fff << 16) | 0x1fff)
97
98/* CICOCTRL, CIPRCTRL. Output DMA control. */
99#define S3C_CAMIF_REG_CICTRL(id, _offs) (0x4c + (id) * (0x34 + (_offs)))
100#define CICTRL_BURST_MASK (0xfffff << 4)
101/* xBURSTn - 5-bits width */
102#define CICTRL_YBURST1(x) ((x) << 19)
103#define CICTRL_YBURST2(x) ((x) << 14)
104#define CICTRL_RGBBURST1(x) ((x) << 19)
105#define CICTRL_RGBBURST2(x) ((x) << 14)
106#define CICTRL_CBURST1(x) ((x) << 9)
107#define CICTRL_CBURST2(x) ((x) << 4)
108#define CICTRL_LASTIRQ_ENABLE (1 << 2)
109#define CICTRL_ORDER422_MASK (3 << 0)
110
111/* CICOSCPRERATIO, CIPRSCPRERATIO. Pre-scaler control 1. */
112#define S3C_CAMIF_REG_CISCPRERATIO(id, _offs) (0x50 + (id) * (0x34 + (_offs)))
113
114/* CICOSCPREDST, CIPRSCPREDST. Pre-scaler control 2. */
115#define S3C_CAMIF_REG_CISCPREDST(id, _offs) (0x54 + (id) * (0x34 + (_offs)))
116
117/* CICOSCCTRL, CIPRSCCTRL. Main scaler control. */
118#define S3C_CAMIF_REG_CISCCTRL(id, _offs) (0x58 + (id) * (0x34 + (_offs)))
119#define CISCCTRL_SCALERBYPASS (1 << 31)
120/* s3c244x preview path only, s3c64xx both */
121#define CIPRSCCTRL_SAMPLE (1 << 31)
122/* 0 - 16-bit RGB, 1 - 24-bit RGB */
123#define CIPRSCCTRL_RGB_FORMAT_24BIT (1 << 30) /* only for s3c244x */
124#define CIPRSCCTRL_SCALEUP_H (1 << 29) /* only for s3c244x */
125#define CIPRSCCTRL_SCALEUP_V (1 << 28) /* only for s3c244x */
126/* s3c64xx */
127#define CISCCTRL_SCALEUP_H (1 << 30)
128#define CISCCTRL_SCALEUP_V (1 << 29)
129#define CISCCTRL_SCALEUP_MASK (0x3 << 29)
130#define CISCCTRL_CSCR2Y_WIDE (1 << 28)
131#define CISCCTRL_CSCY2R_WIDE (1 << 27)
132#define CISCCTRL_LCDPATHEN_FIFO (1 << 26)
133#define CISCCTRL_INTERLACE (1 << 25)
134#define CISCCTRL_SCALERSTART (1 << 15)
135#define CISCCTRL_INRGB_FMT_RGB565 (0 << 13)
136#define CISCCTRL_INRGB_FMT_RGB666 (1 << 13)
137#define CISCCTRL_INRGB_FMT_RGB888 (2 << 13)
138#define CISCCTRL_INRGB_FMT_MASK (3 << 13)
139#define CISCCTRL_OUTRGB_FMT_RGB565 (0 << 11)
140#define CISCCTRL_OUTRGB_FMT_RGB666 (1 << 11)
141#define CISCCTRL_OUTRGB_FMT_RGB888 (2 << 11)
142#define CISCCTRL_OUTRGB_FMT_MASK (3 << 11)
143#define CISCCTRL_EXTRGB_EXTENSION (1 << 10)
144#define CISCCTRL_ONE2ONE (1 << 9)
145#define CISCCTRL_MAIN_RATIO_MASK (0x1ff << 16 | 0x1ff)
146
147/* CICOTAREA, CIPRTAREA. Target area for DMA (Hsize x Vsize). */
148#define S3C_CAMIF_REG_CITAREA(id, _offs) (0x5c + (id) * (0x34 + (_offs)))
149#define CITAREA_MASK 0xfffffff
150
151/* Codec (id = 0) or preview (id = 1) path status. */
152#define S3C_CAMIF_REG_CISTATUS(id, _offs) (0x64 + (id) * (0x34 + (_offs)))
153#define CISTATUS_OVFIY_STATUS (1 << 31)
154#define CISTATUS_OVFICB_STATUS (1 << 30)
155#define CISTATUS_OVFICR_STATUS (1 << 29)
156#define CISTATUS_OVF_MASK (0x7 << 29)
157#define CIPRSTATUS_OVF_MASK (0x3 << 30)
158#define CISTATUS_VSYNC_STATUS (1 << 28)
159#define CISTATUS_FRAMECNT_MASK (3 << 26)
160#define CISTATUS_FRAMECNT(__reg) (((__reg) >> 26) & 0x3)
161#define CISTATUS_WINOFSTEN_STATUS (1 << 25)
162#define CISTATUS_IMGCPTEN_STATUS (1 << 22)
163#define CISTATUS_IMGCPTENSC_STATUS (1 << 21)
164#define CISTATUS_VSYNC_A_STATUS (1 << 20)
165#define CISTATUS_FRAMEEND_STATUS (1 << 19) /* 17 on s3c64xx */
166
167/* Image capture enable */
168#define S3C_CAMIF_REG_CIIMGCPT(_offs) (0xa0 + (_offs))
169#define CIIMGCPT_IMGCPTEN (1 << 31)
170#define CIIMGCPT_IMGCPTEN_SC(id) (1 << (30 - (id)))
171/* Frame control: 1 - one-shot, 0 - free run */
172#define CIIMGCPT_CPT_FREN_ENABLE(id) (1 << (25 - (id)))
173#define CIIMGCPT_CPT_FRMOD_ENABLE (0 << 18)
174#define CIIMGCPT_CPT_FRMOD_CNT (1 << 18)
175
176/* Capture sequence */
177#define S3C_CAMIF_REG_CICPTSEQ 0xc4
178
179/* Image effects */
180#define S3C_CAMIF_REG_CIIMGEFF(_offs) (0xb0 + (_offs))
181#define CIIMGEFF_IE_ENABLE(id) (1 << (30 + (id)))
182#define CIIMGEFF_IE_ENABLE_MASK (3 << 30)
183/* Image effect: 1 - after scaler, 0 - before scaler */
184#define CIIMGEFF_IE_AFTER_SC (1 << 29)
185#define CIIMGEFF_FIN_MASK (7 << 26)
186#define CIIMGEFF_FIN_BYPASS (0 << 26)
187#define CIIMGEFF_FIN_ARBITRARY (1 << 26)
188#define CIIMGEFF_FIN_NEGATIVE (2 << 26)
189#define CIIMGEFF_FIN_ARTFREEZE (3 << 26)
190#define CIIMGEFF_FIN_EMBOSSING (4 << 26)
191#define CIIMGEFF_FIN_SILHOUETTE (5 << 26)
192#define CIIMGEFF_PAT_CBCR_MASK ((0xff << 13) | 0xff)
193#define CIIMGEFF_PAT_CB(x) ((x) << 13)
194#define CIIMGEFF_PAT_CR(x) (x)
195
196/* MSCOY0SA, MSPRY0SA. Y/Cb/Cr frame start address for input DMA. */
197#define S3C_CAMIF_REG_MSY0SA(id) (0xd4 + ((id) * 0x2c))
198#define S3C_CAMIF_REG_MSCB0SA(id) (0xd8 + ((id) * 0x2c))
199#define S3C_CAMIF_REG_MSCR0SA(id) (0xdc + ((id) * 0x2c))
200
201/* MSCOY0END, MSCOY0END. Y/Cb/Cr frame end address for input DMA. */
202#define S3C_CAMIF_REG_MSY0END(id) (0xe0 + ((id) * 0x2c))
203#define S3C_CAMIF_REG_MSCB0END(id) (0xe4 + ((id) * 0x2c))
204#define S3C_CAMIF_REG_MSCR0END(id) (0xe8 + ((id) * 0x2c))
205
206/* MSPRYOFF, MSPRYOFF. Y/Cb/Cr offset. n: 0 - codec, 1 - preview. */
207#define S3C_CAMIF_REG_MSYOFF(id) (0x118 + ((id) * 0x2c))
208#define S3C_CAMIF_REG_MSCBOFF(id) (0x11c + ((id) * 0x2c))
209#define S3C_CAMIF_REG_MSCROFF(id) (0x120 + ((id) * 0x2c))
210
211/* Real input DMA data size. n = 0 - codec, 1 - preview. */
212#define S3C_CAMIF_REG_MSWIDTH(id) (0xf8 + (id) * 0x2c)
213#define AUTOLOAD_ENABLE (1 << 31)
214#define ADDR_CH_DIS (1 << 30)
215#define MSHEIGHT(x) (((x) & 0x3ff) << 16)
216#define MSWIDTH(x) ((x) & 0x3ff)
217
218/* Input DMA control. n = 0 - codec, 1 - preview */
219#define S3C_CAMIF_REG_MSCTRL(id) (0xfc + (id) * 0x2c)
220#define MSCTRL_ORDER422_M_YCBYCR (0 << 4)
221#define MSCTRL_ORDER422_M_YCRYCB (1 << 4)
222#define MSCTRL_ORDER422_M_CBYCRY (2 << 4)
223#define MSCTRL_ORDER422_M_CRYCBY (3 << 4)
224/* 0 - camera, 1 - DMA */
225#define MSCTRL_SEL_DMA_CAM (1 << 3)
226#define MSCTRL_INFORMAT_M_YCBCR420 (0 << 1)
227#define MSCTRL_INFORMAT_M_YCBCR422 (1 << 1)
228#define MSCTRL_INFORMAT_M_YCBCR422I (2 << 1)
229#define MSCTRL_INFORMAT_M_RGB (3 << 1)
230#define MSCTRL_ENVID_M (1 << 0)
231
232/* CICOSCOSY, CIPRSCOSY. Scan line Y/Cb/Cr offset. */
233#define S3C_CAMIF_REG_CISSY(id) (0x12c + (id) * 0x0c)
234#define S3C_CAMIF_REG_CISSCB(id) (0x130 + (id) * 0x0c)
235#define S3C_CAMIF_REG_CISSCR(id) (0x134 + (id) * 0x0c)
236#define S3C_CISS_OFFS_INITIAL(x) ((x) << 16)
237#define S3C_CISS_OFFS_LINE(x) ((x) << 0)
238
239/* ------------------------------------------------------------------ */
240
241void camif_hw_reset(struct camif_dev *camif);
242void camif_hw_clear_pending_irq(struct camif_vp *vp);
243void camif_hw_clear_fifo_overflow(struct camif_vp *vp);
244void camif_hw_set_lastirq(struct camif_vp *vp, int enable);
245void camif_hw_set_input_path(struct camif_vp *vp);
246void camif_hw_enable_scaler(struct camif_vp *vp, bool on);
247void camif_hw_enable_capture(struct camif_vp *vp);
248void camif_hw_disable_capture(struct camif_vp *vp);
249void camif_hw_set_camera_bus(struct camif_dev *camif);
250void camif_hw_set_source_format(struct camif_dev *camif);
251void camif_hw_set_camera_crop(struct camif_dev *camif);
252void camif_hw_set_scaler(struct camif_vp *vp);
253void camif_hw_set_flip(struct camif_vp *vp);
254void camif_hw_set_output_dma(struct camif_vp *vp);
255void camif_hw_set_target_format(struct camif_vp *vp);
256void camif_hw_set_test_pattern(struct camif_dev *camif, unsigned int pattern);
257void camif_hw_set_effect(struct camif_dev *camif, unsigned int effect,
258 unsigned int cr, unsigned int cb);
259void camif_hw_set_output_addr(struct camif_vp *vp, struct camif_addr *paddr,
260 int index);
261void camif_hw_dump_regs(struct camif_dev *camif, const char *label);
262
263static inline u32 camif_hw_get_status(struct camif_vp *vp)
264{
265 return readl(vp->camif->io_base + S3C_CAMIF_REG_CISTATUS(vp->id,
266 vp->offset));
267}
268
269#endif /* CAMIF_REGS_H_ */
diff --git a/include/media/s3c_camif.h b/include/media/s3c_camif.h
new file mode 100644
index 000000000000..df96c2c789b4
--- /dev/null
+++ b/include/media/s3c_camif.h
@@ -0,0 +1,45 @@
1/*
2 * s3c24xx/s3c64xx SoC series Camera Interface (CAMIF) driver
3 *
4 * Copyright (C) 2012 Sylwester Nawrocki <sylvester.nawrocki@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9*/
10
11#ifndef MEDIA_S3C_CAMIF_
12#define MEDIA_S3C_CAMIF_
13
14#include <linux/i2c.h>
15#include <media/v4l2-mediabus.h>
16
17/**
18 * struct s3c_camif_sensor_info - an image sensor description
19 * @i2c_board_info: pointer to an I2C sensor subdevice board info
20 * @clock_frequency: frequency of the clock the host provides to a sensor
21 * @mbus_type: media bus type
22 * @i2c_bus_num: i2c control bus id the sensor is attached to
23 * @flags: the parallel bus flags defining signals polarity (V4L2_MBUS_*)
24 * @use_field: 1 if parallel bus FIELD signal is used (only s3c64xx)
25 */
26struct s3c_camif_sensor_info {
27 struct i2c_board_info i2c_board_info;
28 unsigned long clock_frequency;
29 enum v4l2_mbus_type mbus_type;
30 u16 i2c_bus_num;
31 u16 flags;
32 u8 use_field;
33};
34
35struct s3c_camif_plat_data {
36 struct s3c_camif_sensor_info sensor;
37 int (*gpio_get)(void);
38 int (*gpio_put)(void);
39};
40
41/* Platform default helper functions */
42int s3c_camif_gpio_get(void);
43int s3c_camif_gpio_put(void);
44
45#endif /* MEDIA_S3C_CAMIF_ */