blob: b64297ba35d31631d9920c9f43cc87c46ba68354 [file] [log] [blame]
Sylwester Nawrocki4af81312012-04-27 05:29:05 -03001/*
2 * Samsung EXYNOS FIMC-LITE (camera host interface) driver
3*
4 * Copyright (C) 2012 Samsung Electronics Co., Ltd.
5 * Sylwester Nawrocki <s.nawrocki@samsung.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__
12
13#include <linux/bug.h>
14#include <linux/device.h>
15#include <linux/errno.h>
16#include <linux/interrupt.h>
17#include <linux/kernel.h>
18#include <linux/list.h>
19#include <linux/module.h>
20#include <linux/types.h>
21#include <linux/platform_device.h>
22#include <linux/pm_runtime.h>
23#include <linux/slab.h>
24#include <linux/videodev2.h>
25
26#include <media/v4l2-device.h>
27#include <media/v4l2-ioctl.h>
28#include <media/v4l2-mem2mem.h>
29#include <media/videobuf2-core.h>
30#include <media/videobuf2-dma-contig.h>
Sylwester Nawrockib9ee31e2012-08-14 10:46:58 -030031#include <media/s5p_fimc.h>
Sylwester Nawrocki4af81312012-04-27 05:29:05 -030032
33#include "fimc-mdevice.h"
34#include "fimc-core.h"
Sylwester Nawrockib9ee31e2012-08-14 10:46:58 -030035#include "fimc-lite.h"
Sylwester Nawrocki4af81312012-04-27 05:29:05 -030036#include "fimc-lite-reg.h"
37
38static int debug;
39module_param(debug, int, 0644);
40
41static const struct fimc_fmt fimc_lite_formats[] = {
42 {
43 .name = "YUV 4:2:2 packed, YCbYCr",
44 .fourcc = V4L2_PIX_FMT_YUYV,
45 .depth = { 16 },
46 .color = FIMC_FMT_YCBYCR422,
47 .memplanes = 1,
48 .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8,
49 }, {
50 .name = "YUV 4:2:2 packed, CbYCrY",
51 .fourcc = V4L2_PIX_FMT_UYVY,
52 .depth = { 16 },
53 .color = FIMC_FMT_CBYCRY422,
54 .memplanes = 1,
55 .mbus_code = V4L2_MBUS_FMT_UYVY8_2X8,
56 }, {
57 .name = "YUV 4:2:2 packed, CrYCbY",
58 .fourcc = V4L2_PIX_FMT_VYUY,
59 .depth = { 16 },
60 .color = FIMC_FMT_CRYCBY422,
61 .memplanes = 1,
62 .mbus_code = V4L2_MBUS_FMT_VYUY8_2X8,
63 }, {
64 .name = "YUV 4:2:2 packed, YCrYCb",
65 .fourcc = V4L2_PIX_FMT_YVYU,
66 .depth = { 16 },
67 .color = FIMC_FMT_YCRYCB422,
68 .memplanes = 1,
69 .mbus_code = V4L2_MBUS_FMT_YVYU8_2X8,
70 }, {
71 .name = "RAW8 (GRBG)",
72 .fourcc = V4L2_PIX_FMT_SGRBG8,
73 .depth = { 8 },
74 .color = FIMC_FMT_RAW8,
75 .memplanes = 1,
76 .mbus_code = V4L2_MBUS_FMT_SGRBG8_1X8,
77 }, {
78 .name = "RAW10 (GRBG)",
79 .fourcc = V4L2_PIX_FMT_SGRBG10,
80 .depth = { 10 },
81 .color = FIMC_FMT_RAW10,
82 .memplanes = 1,
83 .mbus_code = V4L2_MBUS_FMT_SGRBG10_1X10,
84 }, {
85 .name = "RAW12 (GRBG)",
86 .fourcc = V4L2_PIX_FMT_SGRBG12,
87 .depth = { 12 },
88 .color = FIMC_FMT_RAW12,
89 .memplanes = 1,
90 .mbus_code = V4L2_MBUS_FMT_SGRBG12_1X12,
91 },
92};
93
94/**
95 * fimc_lite_find_format - lookup fimc color format by fourcc or media bus code
96 * @pixelformat: fourcc to match, ignored if null
97 * @mbus_code: media bus code to match, ignored if null
98 * @index: index to the fimc_lite_formats array, ignored if negative
99 */
100static const struct fimc_fmt *fimc_lite_find_format(const u32 *pixelformat,
101 const u32 *mbus_code, int index)
102{
103 const struct fimc_fmt *fmt, *def_fmt = NULL;
104 unsigned int i;
105 int id = 0;
106
107 if (index >= (int)ARRAY_SIZE(fimc_lite_formats))
108 return NULL;
109
110 for (i = 0; i < ARRAY_SIZE(fimc_lite_formats); ++i) {
111 fmt = &fimc_lite_formats[i];
112 if (pixelformat && fmt->fourcc == *pixelformat)
113 return fmt;
114 if (mbus_code && fmt->mbus_code == *mbus_code)
115 return fmt;
116 if (index == id)
117 def_fmt = fmt;
118 id++;
119 }
120 return def_fmt;
121}
122
Sylwester Nawrocki6319d6a2012-11-28 15:41:01 -0300123static int fimc_lite_hw_init(struct fimc_lite *fimc, bool isp_output)
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300124{
125 struct fimc_pipeline *pipeline = &fimc->pipeline;
Sylwester Nawrocki6319d6a2012-11-28 15:41:01 -0300126 struct v4l2_subdev *sensor;
127 struct fimc_sensor_info *si;
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300128 unsigned long flags;
129
Sylwester Nawrocki6319d6a2012-11-28 15:41:01 -0300130 sensor = isp_output ? fimc->sensor : pipeline->subdevs[IDX_SENSOR];
131
132 if (sensor == NULL)
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300133 return -ENXIO;
134
135 if (fimc->fmt == NULL)
136 return -EINVAL;
137
Sylwester Nawrocki6319d6a2012-11-28 15:41:01 -0300138 /* Get sensor configuration data from the sensor subdev */
139 si = v4l2_get_subdev_hostdata(sensor);
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300140 spin_lock_irqsave(&fimc->slock, flags);
141
Sylwester Nawrocki6319d6a2012-11-28 15:41:01 -0300142 flite_hw_set_camera_bus(fimc, &si->pdata);
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300143 flite_hw_set_source_format(fimc, &fimc->inp_frame);
144 flite_hw_set_window_offset(fimc, &fimc->inp_frame);
Sylwester Nawrocki6319d6a2012-11-28 15:41:01 -0300145 flite_hw_set_output_dma(fimc, &fimc->out_frame, !isp_output);
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300146 flite_hw_set_interrupt_mask(fimc);
147 flite_hw_set_test_pattern(fimc, fimc->test_pattern->val);
148
149 if (debug > 0)
150 flite_hw_dump_regs(fimc, __func__);
151
152 spin_unlock_irqrestore(&fimc->slock, flags);
153 return 0;
154}
155
156/*
157 * Reinitialize the driver so it is ready to start the streaming again.
158 * Set fimc->state to indicate stream off and the hardware shut down state.
159 * If not suspending (@suspend is false), return any buffers to videobuf2.
160 * Otherwise put any owned buffers onto the pending buffers queue, so they
161 * can be re-spun when the device is being resumed. Also perform FIMC
162 * software reset and disable streaming on the whole pipeline if required.
163 */
164static int fimc_lite_reinit(struct fimc_lite *fimc, bool suspend)
165{
166 struct flite_buffer *buf;
167 unsigned long flags;
168 bool streaming;
169
170 spin_lock_irqsave(&fimc->slock, flags);
171 streaming = fimc->state & (1 << ST_SENSOR_STREAM);
172
173 fimc->state &= ~(1 << ST_FLITE_RUN | 1 << ST_FLITE_OFF |
174 1 << ST_FLITE_STREAM | 1 << ST_SENSOR_STREAM);
175 if (suspend)
176 fimc->state |= (1 << ST_FLITE_SUSPENDED);
177 else
178 fimc->state &= ~(1 << ST_FLITE_PENDING |
179 1 << ST_FLITE_SUSPENDED);
180
181 /* Release unused buffers */
182 while (!suspend && !list_empty(&fimc->pending_buf_q)) {
183 buf = fimc_lite_pending_queue_pop(fimc);
184 vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
185 }
186 /* If suspending put unused buffers onto pending queue */
187 while (!list_empty(&fimc->active_buf_q)) {
188 buf = fimc_lite_active_queue_pop(fimc);
189 if (suspend)
190 fimc_lite_pending_queue_add(fimc, buf);
191 else
192 vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
193 }
194
195 spin_unlock_irqrestore(&fimc->slock, flags);
196
197 flite_hw_reset(fimc);
198
199 if (!streaming)
200 return 0;
201
Sylwester Nawrockib9ee31e2012-08-14 10:46:58 -0300202 return fimc_pipeline_call(fimc, set_stream, &fimc->pipeline, 0);
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300203}
204
205static int fimc_lite_stop_capture(struct fimc_lite *fimc, bool suspend)
206{
207 unsigned long flags;
208
209 if (!fimc_lite_active(fimc))
210 return 0;
211
212 spin_lock_irqsave(&fimc->slock, flags);
213 set_bit(ST_FLITE_OFF, &fimc->state);
214 flite_hw_capture_stop(fimc);
215 spin_unlock_irqrestore(&fimc->slock, flags);
216
217 wait_event_timeout(fimc->irq_queue,
218 !test_bit(ST_FLITE_OFF, &fimc->state),
219 (2*HZ/10)); /* 200 ms */
220
221 return fimc_lite_reinit(fimc, suspend);
222}
223
224/* Must be called with fimc.slock spinlock held. */
225static void fimc_lite_config_update(struct fimc_lite *fimc)
226{
227 flite_hw_set_window_offset(fimc, &fimc->inp_frame);
228 flite_hw_set_dma_window(fimc, &fimc->out_frame);
229 flite_hw_set_test_pattern(fimc, fimc->test_pattern->val);
230 clear_bit(ST_FLITE_CONFIG, &fimc->state);
231}
232
233static irqreturn_t flite_irq_handler(int irq, void *priv)
234{
235 struct fimc_lite *fimc = priv;
236 struct flite_buffer *vbuf;
237 unsigned long flags;
238 struct timeval *tv;
239 struct timespec ts;
240 u32 intsrc;
241
242 spin_lock_irqsave(&fimc->slock, flags);
243
244 intsrc = flite_hw_get_interrupt_source(fimc);
245 flite_hw_clear_pending_irq(fimc);
246
247 if (test_and_clear_bit(ST_FLITE_OFF, &fimc->state)) {
248 wake_up(&fimc->irq_queue);
249 goto done;
250 }
251
252 if (intsrc & FLITE_REG_CISTATUS_IRQ_SRC_OVERFLOW) {
253 clear_bit(ST_FLITE_RUN, &fimc->state);
254 fimc->events.data_overflow++;
255 }
256
257 if (intsrc & FLITE_REG_CISTATUS_IRQ_SRC_LASTCAPEND) {
258 flite_hw_clear_last_capture_end(fimc);
259 clear_bit(ST_FLITE_STREAM, &fimc->state);
260 wake_up(&fimc->irq_queue);
261 }
262
Sylwester Nawrocki03878bb2013-01-18 12:02:32 -0300263 if (atomic_read(&fimc->out_path) != FIMC_IO_DMA)
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300264 goto done;
265
266 if ((intsrc & FLITE_REG_CISTATUS_IRQ_SRC_FRMSTART) &&
267 test_bit(ST_FLITE_RUN, &fimc->state) &&
268 !list_empty(&fimc->active_buf_q) &&
269 !list_empty(&fimc->pending_buf_q)) {
270 vbuf = fimc_lite_active_queue_pop(fimc);
271 ktime_get_ts(&ts);
272 tv = &vbuf->vb.v4l2_buf.timestamp;
273 tv->tv_sec = ts.tv_sec;
274 tv->tv_usec = ts.tv_nsec / NSEC_PER_USEC;
275 vbuf->vb.v4l2_buf.sequence = fimc->frame_count++;
276 vb2_buffer_done(&vbuf->vb, VB2_BUF_STATE_DONE);
277
278 vbuf = fimc_lite_pending_queue_pop(fimc);
279 flite_hw_set_output_addr(fimc, vbuf->paddr);
280 fimc_lite_active_queue_add(fimc, vbuf);
281 }
282
283 if (test_bit(ST_FLITE_CONFIG, &fimc->state))
284 fimc_lite_config_update(fimc);
285
286 if (list_empty(&fimc->pending_buf_q)) {
287 flite_hw_capture_stop(fimc);
288 clear_bit(ST_FLITE_STREAM, &fimc->state);
289 }
290done:
291 set_bit(ST_FLITE_RUN, &fimc->state);
292 spin_unlock_irqrestore(&fimc->slock, flags);
293 return IRQ_HANDLED;
294}
295
296static int start_streaming(struct vb2_queue *q, unsigned int count)
297{
298 struct fimc_lite *fimc = q->drv_priv;
299 int ret;
300
301 fimc->frame_count = 0;
302
Sylwester Nawrocki6319d6a2012-11-28 15:41:01 -0300303 ret = fimc_lite_hw_init(fimc, false);
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300304 if (ret) {
305 fimc_lite_reinit(fimc, false);
306 return ret;
307 }
308
309 set_bit(ST_FLITE_PENDING, &fimc->state);
310
311 if (!list_empty(&fimc->active_buf_q) &&
312 !test_and_set_bit(ST_FLITE_STREAM, &fimc->state)) {
313 flite_hw_capture_start(fimc);
314
315 if (!test_and_set_bit(ST_SENSOR_STREAM, &fimc->state))
Sylwester Nawrockib9ee31e2012-08-14 10:46:58 -0300316 fimc_pipeline_call(fimc, set_stream,
317 &fimc->pipeline, 1);
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300318 }
319 if (debug > 0)
320 flite_hw_dump_regs(fimc, __func__);
321
322 return 0;
323}
324
325static int stop_streaming(struct vb2_queue *q)
326{
327 struct fimc_lite *fimc = q->drv_priv;
328
329 if (!fimc_lite_active(fimc))
330 return -EINVAL;
331
332 return fimc_lite_stop_capture(fimc, false);
333}
334
335static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *pfmt,
336 unsigned int *num_buffers, unsigned int *num_planes,
337 unsigned int sizes[], void *allocators[])
338{
339 const struct v4l2_pix_format_mplane *pixm = NULL;
340 struct fimc_lite *fimc = vq->drv_priv;
341 struct flite_frame *frame = &fimc->out_frame;
342 const struct fimc_fmt *fmt = fimc->fmt;
343 unsigned long wh;
344 int i;
345
346 if (pfmt) {
347 pixm = &pfmt->fmt.pix_mp;
348 fmt = fimc_lite_find_format(&pixm->pixelformat, NULL, -1);
349 wh = pixm->width * pixm->height;
350 } else {
351 wh = frame->f_width * frame->f_height;
352 }
353
354 if (fmt == NULL)
355 return -EINVAL;
356
357 *num_planes = fmt->memplanes;
358
359 for (i = 0; i < fmt->memplanes; i++) {
360 unsigned int size = (wh * fmt->depth[i]) / 8;
361 if (pixm)
362 sizes[i] = max(size, pixm->plane_fmt[i].sizeimage);
363 else
364 sizes[i] = size;
365 allocators[i] = fimc->alloc_ctx;
366 }
367
368 return 0;
369}
370
371static int buffer_prepare(struct vb2_buffer *vb)
372{
373 struct vb2_queue *vq = vb->vb2_queue;
374 struct fimc_lite *fimc = vq->drv_priv;
375 int i;
376
377 if (fimc->fmt == NULL)
378 return -EINVAL;
379
380 for (i = 0; i < fimc->fmt->memplanes; i++) {
381 unsigned long size = fimc->payload[i];
382
383 if (vb2_plane_size(vb, i) < size) {
Sylwester Nawrocki1bcd7042012-07-26 07:13:08 -0300384 v4l2_err(&fimc->vfd,
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300385 "User buffer too small (%ld < %ld)\n",
386 vb2_plane_size(vb, i), size);
387 return -EINVAL;
388 }
389 vb2_set_plane_payload(vb, i, size);
390 }
391
392 return 0;
393}
394
395static void buffer_queue(struct vb2_buffer *vb)
396{
397 struct flite_buffer *buf
398 = container_of(vb, struct flite_buffer, vb);
399 struct fimc_lite *fimc = vb2_get_drv_priv(vb->vb2_queue);
400 unsigned long flags;
401
402 spin_lock_irqsave(&fimc->slock, flags);
403 buf->paddr = vb2_dma_contig_plane_dma_addr(vb, 0);
404
405 if (!test_bit(ST_FLITE_SUSPENDED, &fimc->state) &&
406 !test_bit(ST_FLITE_STREAM, &fimc->state) &&
407 list_empty(&fimc->active_buf_q)) {
408 flite_hw_set_output_addr(fimc, buf->paddr);
409 fimc_lite_active_queue_add(fimc, buf);
410 } else {
411 fimc_lite_pending_queue_add(fimc, buf);
412 }
413
414 if (vb2_is_streaming(&fimc->vb_queue) &&
415 !list_empty(&fimc->pending_buf_q) &&
416 !test_and_set_bit(ST_FLITE_STREAM, &fimc->state)) {
417 flite_hw_capture_start(fimc);
418 spin_unlock_irqrestore(&fimc->slock, flags);
419
420 if (!test_and_set_bit(ST_SENSOR_STREAM, &fimc->state))
Sylwester Nawrockib9ee31e2012-08-14 10:46:58 -0300421 fimc_pipeline_call(fimc, set_stream,
422 &fimc->pipeline, 1);
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300423 return;
424 }
425 spin_unlock_irqrestore(&fimc->slock, flags);
426}
427
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300428static const struct vb2_ops fimc_lite_qops = {
429 .queue_setup = queue_setup,
430 .buf_prepare = buffer_prepare,
431 .buf_queue = buffer_queue,
Sylwester Nawrockiee12b042013-03-25 16:43:08 -0300432 .wait_prepare = vb2_ops_wait_prepare,
433 .wait_finish = vb2_ops_wait_finish,
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300434 .start_streaming = start_streaming,
435 .stop_streaming = stop_streaming,
436};
437
438static void fimc_lite_clear_event_counters(struct fimc_lite *fimc)
439{
440 unsigned long flags;
441
442 spin_lock_irqsave(&fimc->slock, flags);
443 memset(&fimc->events, 0, sizeof(fimc->events));
444 spin_unlock_irqrestore(&fimc->slock, flags);
445}
446
447static int fimc_lite_open(struct file *file)
448{
449 struct fimc_lite *fimc = video_drvdata(file);
Sylwester Nawrocki740ad922012-12-06 10:26:19 -0300450 struct media_entity *me = &fimc->vfd.entity;
Sylwester Nawrockie3fc82e2012-05-17 14:22:10 -0300451 int ret;
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300452
Sylwester Nawrocki740ad922012-12-06 10:26:19 -0300453 mutex_lock(&me->parent->graph_mutex);
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300454
Sylwester Nawrocki740ad922012-12-06 10:26:19 -0300455 mutex_lock(&fimc->lock);
Sylwester Nawrocki03878bb2013-01-18 12:02:32 -0300456 if (atomic_read(&fimc->out_path) != FIMC_IO_DMA) {
Sylwester Nawrocki6319d6a2012-11-28 15:41:01 -0300457 ret = -EBUSY;
Sylwester Nawrockiee12b042013-03-25 16:43:08 -0300458 goto unlock;
Sylwester Nawrocki6319d6a2012-11-28 15:41:01 -0300459 }
460
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300461 set_bit(ST_FLITE_IN_USE, &fimc->state);
Sylwester Nawrockie3fc82e2012-05-17 14:22:10 -0300462 ret = pm_runtime_get_sync(&fimc->pdev->dev);
463 if (ret < 0)
Sylwester Nawrockiee12b042013-03-25 16:43:08 -0300464 goto unlock;
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300465
Sylwester Nawrockie3fc82e2012-05-17 14:22:10 -0300466 ret = v4l2_fh_open(file);
467 if (ret < 0)
Sylwester Nawrockiee12b042013-03-25 16:43:08 -0300468 goto err_pm;
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300469
Sylwester Nawrockiee12b042013-03-25 16:43:08 -0300470 if (!v4l2_fh_is_singular_file(file) ||
471 atomic_read(&fimc->out_path) != FIMC_IO_DMA)
472 goto unlock;
Sylwester Nawrocki4e39da02012-06-04 13:15:56 -0300473
Sylwester Nawrockiee12b042013-03-25 16:43:08 -0300474 ret = fimc_pipeline_call(fimc, open, &fimc->pipeline,
475 me, true);
476 if (!ret) {
Sylwester Nawrocki4e39da02012-06-04 13:15:56 -0300477 fimc_lite_clear_event_counters(fimc);
Sylwester Nawrockiee12b042013-03-25 16:43:08 -0300478 fimc->ref_count++;
479 goto unlock;
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300480 }
Sylwester Nawrockiee12b042013-03-25 16:43:08 -0300481
482 v4l2_fh_release(file);
483err_pm:
484 pm_runtime_put_sync(&fimc->pdev->dev);
485 clear_bit(ST_FLITE_IN_USE, &fimc->state);
486unlock:
Sylwester Nawrocki4e39da02012-06-04 13:15:56 -0300487 mutex_unlock(&fimc->lock);
Sylwester Nawrocki740ad922012-12-06 10:26:19 -0300488 mutex_unlock(&me->parent->graph_mutex);
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300489 return ret;
490}
491
Sylwester Nawrockiee12b042013-03-25 16:43:08 -0300492static int fimc_lite_release(struct file *file)
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300493{
494 struct fimc_lite *fimc = video_drvdata(file);
Sylwester Nawrocki4e39da02012-06-04 13:15:56 -0300495
Sylwester Nawrockiddc43d62012-11-22 11:13:04 -0300496 mutex_lock(&fimc->lock);
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300497
Sylwester Nawrockiee12b042013-03-25 16:43:08 -0300498 if (v4l2_fh_is_singular_file(file) &&
Sylwester Nawrocki03878bb2013-01-18 12:02:32 -0300499 atomic_read(&fimc->out_path) == FIMC_IO_DMA) {
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300500 clear_bit(ST_FLITE_IN_USE, &fimc->state);
501 fimc_lite_stop_capture(fimc, false);
Sylwester Nawrockib9ee31e2012-08-14 10:46:58 -0300502 fimc_pipeline_call(fimc, close, &fimc->pipeline);
Sylwester Nawrockiee12b042013-03-25 16:43:08 -0300503 fimc->ref_count--;
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300504 }
505
Sylwester Nawrockiee12b042013-03-25 16:43:08 -0300506 vb2_fop_release(file);
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300507 pm_runtime_put(&fimc->pdev->dev);
Sylwester Nawrockiee12b042013-03-25 16:43:08 -0300508 clear_bit(ST_FLITE_SUSPENDED, &fimc->state);
Sylwester Nawrocki4e39da02012-06-04 13:15:56 -0300509
510 mutex_unlock(&fimc->lock);
Sylwester Nawrockiee12b042013-03-25 16:43:08 -0300511 return 0;
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300512}
513
514static const struct v4l2_file_operations fimc_lite_fops = {
515 .owner = THIS_MODULE,
516 .open = fimc_lite_open,
Sylwester Nawrockiee12b042013-03-25 16:43:08 -0300517 .release = fimc_lite_release,
518 .poll = vb2_fop_poll,
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300519 .unlocked_ioctl = video_ioctl2,
Sylwester Nawrockiee12b042013-03-25 16:43:08 -0300520 .mmap = vb2_fop_mmap,
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300521};
522
523/*
524 * Format and crop negotiation helpers
525 */
526
527static const struct fimc_fmt *fimc_lite_try_format(struct fimc_lite *fimc,
528 u32 *width, u32 *height,
529 u32 *code, u32 *fourcc, int pad)
530{
531 struct flite_variant *variant = fimc->variant;
532 const struct fimc_fmt *fmt;
533
534 fmt = fimc_lite_find_format(fourcc, code, 0);
535 if (WARN_ON(!fmt))
536 return NULL;
537
538 if (code)
539 *code = fmt->mbus_code;
540 if (fourcc)
541 *fourcc = fmt->fourcc;
542
543 if (pad == FLITE_SD_PAD_SINK) {
544 v4l_bound_align_image(width, 8, variant->max_width,
545 ffs(variant->out_width_align) - 1,
546 height, 0, variant->max_height, 0, 0);
547 } else {
548 v4l_bound_align_image(width, 8, fimc->inp_frame.rect.width,
549 ffs(variant->out_width_align) - 1,
550 height, 0, fimc->inp_frame.rect.height,
551 0, 0);
552 }
553
554 v4l2_dbg(1, debug, &fimc->subdev, "code: 0x%x, %dx%d\n",
555 code ? *code : 0, *width, *height);
556
557 return fmt;
558}
559
560static void fimc_lite_try_crop(struct fimc_lite *fimc, struct v4l2_rect *r)
561{
562 struct flite_frame *frame = &fimc->inp_frame;
563
564 v4l_bound_align_image(&r->width, 0, frame->f_width, 0,
565 &r->height, 0, frame->f_height, 0, 0);
566
567 /* Adjust left/top if cropping rectangle got out of bounds */
568 r->left = clamp_t(u32, r->left, 0, frame->f_width - r->width);
569 r->left = round_down(r->left, fimc->variant->win_hor_offs_align);
570 r->top = clamp_t(u32, r->top, 0, frame->f_height - r->height);
571
Sylwester Nawrocki969e8772012-12-07 16:40:08 -0300572 v4l2_dbg(1, debug, &fimc->subdev, "(%d,%d)/%dx%d, sink fmt: %dx%d\n",
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300573 r->left, r->top, r->width, r->height,
574 frame->f_width, frame->f_height);
575}
576
577static void fimc_lite_try_compose(struct fimc_lite *fimc, struct v4l2_rect *r)
578{
579 struct flite_frame *frame = &fimc->out_frame;
580 struct v4l2_rect *crop_rect = &fimc->inp_frame.rect;
581
582 /* Scaling is not supported so we enforce compose rectangle size
583 same as size of the sink crop rectangle. */
584 r->width = crop_rect->width;
585 r->height = crop_rect->height;
586
587 /* Adjust left/top if the composing rectangle got out of bounds */
588 r->left = clamp_t(u32, r->left, 0, frame->f_width - r->width);
589 r->left = round_down(r->left, fimc->variant->out_hor_offs_align);
590 r->top = clamp_t(u32, r->top, 0, fimc->out_frame.f_height - r->height);
591
Sylwester Nawrocki969e8772012-12-07 16:40:08 -0300592 v4l2_dbg(1, debug, &fimc->subdev, "(%d,%d)/%dx%d, source fmt: %dx%d\n",
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300593 r->left, r->top, r->width, r->height,
594 frame->f_width, frame->f_height);
595}
596
597/*
598 * Video node ioctl operations
599 */
600static int fimc_vidioc_querycap_capture(struct file *file, void *priv,
601 struct v4l2_capability *cap)
602{
603 strlcpy(cap->driver, FIMC_LITE_DRV_NAME, sizeof(cap->driver));
604 cap->bus_info[0] = 0;
605 cap->card[0] = 0;
606 cap->capabilities = V4L2_CAP_STREAMING;
607 return 0;
608}
609
610static int fimc_lite_enum_fmt_mplane(struct file *file, void *priv,
611 struct v4l2_fmtdesc *f)
612{
613 const struct fimc_fmt *fmt;
614
615 if (f->index >= ARRAY_SIZE(fimc_lite_formats))
616 return -EINVAL;
617
618 fmt = &fimc_lite_formats[f->index];
619 strlcpy(f->description, fmt->name, sizeof(f->description));
620 f->pixelformat = fmt->fourcc;
621
622 return 0;
623}
624
625static int fimc_lite_g_fmt_mplane(struct file *file, void *fh,
626 struct v4l2_format *f)
627{
628 struct fimc_lite *fimc = video_drvdata(file);
629 struct v4l2_pix_format_mplane *pixm = &f->fmt.pix_mp;
630 struct v4l2_plane_pix_format *plane_fmt = &pixm->plane_fmt[0];
631 struct flite_frame *frame = &fimc->out_frame;
632 const struct fimc_fmt *fmt = fimc->fmt;
633
634 plane_fmt->bytesperline = (frame->f_width * fmt->depth[0]) / 8;
635 plane_fmt->sizeimage = plane_fmt->bytesperline * frame->f_height;
636
637 pixm->num_planes = fmt->memplanes;
638 pixm->pixelformat = fmt->fourcc;
639 pixm->width = frame->f_width;
640 pixm->height = frame->f_height;
641 pixm->field = V4L2_FIELD_NONE;
642 pixm->colorspace = V4L2_COLORSPACE_JPEG;
643 return 0;
644}
645
646static int fimc_lite_try_fmt(struct fimc_lite *fimc,
647 struct v4l2_pix_format_mplane *pixm,
648 const struct fimc_fmt **ffmt)
649{
650 struct flite_variant *variant = fimc->variant;
651 u32 bpl = pixm->plane_fmt[0].bytesperline;
652 const struct fimc_fmt *fmt;
653
654 fmt = fimc_lite_find_format(&pixm->pixelformat, NULL, 0);
655 if (WARN_ON(fmt == NULL))
656 return -EINVAL;
657 if (ffmt)
658 *ffmt = fmt;
659 v4l_bound_align_image(&pixm->width, 8, variant->max_width,
660 ffs(variant->out_width_align) - 1,
661 &pixm->height, 0, variant->max_height, 0, 0);
662
663 if ((bpl == 0 || ((bpl * 8) / fmt->depth[0]) < pixm->width))
664 pixm->plane_fmt[0].bytesperline = (pixm->width *
665 fmt->depth[0]) / 8;
666
667 if (pixm->plane_fmt[0].sizeimage == 0)
668 pixm->plane_fmt[0].sizeimage = (pixm->width * pixm->height *
669 fmt->depth[0]) / 8;
670 pixm->num_planes = fmt->memplanes;
671 pixm->pixelformat = fmt->fourcc;
672 pixm->colorspace = V4L2_COLORSPACE_JPEG;
673 pixm->field = V4L2_FIELD_NONE;
674 return 0;
675}
676
677static int fimc_lite_try_fmt_mplane(struct file *file, void *fh,
678 struct v4l2_format *f)
679{
680 struct fimc_lite *fimc = video_drvdata(file);
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300681 return fimc_lite_try_fmt(fimc, &f->fmt.pix_mp, NULL);
682}
683
684static int fimc_lite_s_fmt_mplane(struct file *file, void *priv,
685 struct v4l2_format *f)
686{
687 struct v4l2_pix_format_mplane *pixm = &f->fmt.pix_mp;
688 struct fimc_lite *fimc = video_drvdata(file);
689 struct flite_frame *frame = &fimc->out_frame;
690 const struct fimc_fmt *fmt = NULL;
691 int ret;
692
693 if (vb2_is_busy(&fimc->vb_queue))
694 return -EBUSY;
695
696 ret = fimc_lite_try_fmt(fimc, &f->fmt.pix_mp, &fmt);
697 if (ret < 0)
698 return ret;
699
700 fimc->fmt = fmt;
701 fimc->payload[0] = max((pixm->width * pixm->height * fmt->depth[0]) / 8,
702 pixm->plane_fmt[0].sizeimage);
703 frame->f_width = pixm->width;
704 frame->f_height = pixm->height;
705
706 return 0;
707}
708
709static int fimc_pipeline_validate(struct fimc_lite *fimc)
710{
711 struct v4l2_subdev *sd = &fimc->subdev;
712 struct v4l2_subdev_format sink_fmt, src_fmt;
713 struct media_pad *pad;
714 int ret;
715
716 while (1) {
717 /* Retrieve format at the sink pad */
718 pad = &sd->entity.pads[0];
719 if (!(pad->flags & MEDIA_PAD_FL_SINK))
720 break;
721 /* Don't call FIMC subdev operation to avoid nested locking */
722 if (sd == &fimc->subdev) {
723 struct flite_frame *ff = &fimc->out_frame;
724 sink_fmt.format.width = ff->f_width;
725 sink_fmt.format.height = ff->f_height;
726 sink_fmt.format.code = fimc->fmt->mbus_code;
727 } else {
728 sink_fmt.pad = pad->index;
729 sink_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
730 ret = v4l2_subdev_call(sd, pad, get_fmt, NULL,
731 &sink_fmt);
732 if (ret < 0 && ret != -ENOIOCTLCMD)
733 return -EPIPE;
734 }
735 /* Retrieve format at the source pad */
736 pad = media_entity_remote_source(pad);
737 if (pad == NULL ||
738 media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
739 break;
740
741 sd = media_entity_to_v4l2_subdev(pad->entity);
742 src_fmt.pad = pad->index;
743 src_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
744 ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &src_fmt);
745 if (ret < 0 && ret != -ENOIOCTLCMD)
746 return -EPIPE;
747
748 if (src_fmt.format.width != sink_fmt.format.width ||
749 src_fmt.format.height != sink_fmt.format.height ||
750 src_fmt.format.code != sink_fmt.format.code)
751 return -EPIPE;
752 }
753 return 0;
754}
755
756static int fimc_lite_streamon(struct file *file, void *priv,
757 enum v4l2_buf_type type)
758{
759 struct fimc_lite *fimc = video_drvdata(file);
Sylwester Nawrocki95c4a172013-03-20 10:35:43 -0300760 struct media_entity *entity = &fimc->vfd.entity;
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300761 struct fimc_pipeline *p = &fimc->pipeline;
762 int ret;
763
764 if (fimc_lite_active(fimc))
765 return -EBUSY;
766
Sylwester Nawrocki95c4a172013-03-20 10:35:43 -0300767 ret = media_entity_pipeline_start(entity, p->m_pipeline);
Sachin Kamata1a58612012-05-25 03:29:38 -0300768 if (ret < 0)
769 return ret;
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300770
771 ret = fimc_pipeline_validate(fimc);
Sylwester Nawrockiee12b042013-03-25 16:43:08 -0300772 if (ret < 0)
773 goto err_p_stop;
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300774
Sylwester Nawrockiee12b042013-03-25 16:43:08 -0300775 ret = vb2_ioctl_streamon(file, priv, type);
776 if (!ret)
777 return ret;
778err_p_stop:
779 media_entity_pipeline_stop(entity);
780 return 0;
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300781}
782
783static int fimc_lite_streamoff(struct file *file, void *priv,
784 enum v4l2_buf_type type)
785{
786 struct fimc_lite *fimc = video_drvdata(file);
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300787 int ret;
788
Sylwester Nawrockiee12b042013-03-25 16:43:08 -0300789 ret = vb2_ioctl_streamoff(file, priv, type);
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300790 if (ret == 0)
Sylwester Nawrocki95c4a172013-03-20 10:35:43 -0300791 media_entity_pipeline_stop(&fimc->vfd.entity);
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300792 return ret;
793}
794
795static int fimc_lite_reqbufs(struct file *file, void *priv,
796 struct v4l2_requestbuffers *reqbufs)
797{
798 struct fimc_lite *fimc = video_drvdata(file);
799 int ret;
800
801 reqbufs->count = max_t(u32, FLITE_REQ_BUFS_MIN, reqbufs->count);
Sylwester Nawrockiee12b042013-03-25 16:43:08 -0300802 ret = vb2_ioctl_reqbufs(file, priv, reqbufs);
Sachin Kamatf68247f2012-09-26 05:52:24 -0300803 if (!ret)
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300804 fimc->reqbufs_count = reqbufs->count;
805
806 return ret;
807}
808
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300809/* Return 1 if rectangle a is enclosed in rectangle b, or 0 otherwise. */
810static int enclosed_rectangle(struct v4l2_rect *a, struct v4l2_rect *b)
811{
812 if (a->left < b->left || a->top < b->top)
813 return 0;
814 if (a->left + a->width > b->left + b->width)
815 return 0;
816 if (a->top + a->height > b->top + b->height)
817 return 0;
818
819 return 1;
820}
821
822static int fimc_lite_g_selection(struct file *file, void *fh,
823 struct v4l2_selection *sel)
824{
825 struct fimc_lite *fimc = video_drvdata(file);
826 struct flite_frame *f = &fimc->out_frame;
827
828 if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
829 return -EINVAL;
830
831 switch (sel->target) {
832 case V4L2_SEL_TGT_COMPOSE_BOUNDS:
833 case V4L2_SEL_TGT_COMPOSE_DEFAULT:
834 sel->r.left = 0;
835 sel->r.top = 0;
836 sel->r.width = f->f_width;
837 sel->r.height = f->f_height;
838 return 0;
839
Sylwester Nawrockic1334822012-05-20 11:17:12 -0300840 case V4L2_SEL_TGT_COMPOSE:
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300841 sel->r = f->rect;
842 return 0;
843 }
844
845 return -EINVAL;
846}
847
848static int fimc_lite_s_selection(struct file *file, void *fh,
849 struct v4l2_selection *sel)
850{
851 struct fimc_lite *fimc = video_drvdata(file);
852 struct flite_frame *f = &fimc->out_frame;
853 struct v4l2_rect rect = sel->r;
854 unsigned long flags;
855
856 if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ||
Sylwester Nawrockic1334822012-05-20 11:17:12 -0300857 sel->target != V4L2_SEL_TGT_COMPOSE)
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300858 return -EINVAL;
859
860 fimc_lite_try_compose(fimc, &rect);
861
862 if ((sel->flags & V4L2_SEL_FLAG_LE) &&
863 !enclosed_rectangle(&rect, &sel->r))
864 return -ERANGE;
865
866 if ((sel->flags & V4L2_SEL_FLAG_GE) &&
867 !enclosed_rectangle(&sel->r, &rect))
868 return -ERANGE;
869
870 sel->r = rect;
871 spin_lock_irqsave(&fimc->slock, flags);
872 f->rect = rect;
873 set_bit(ST_FLITE_CONFIG, &fimc->state);
874 spin_unlock_irqrestore(&fimc->slock, flags);
875
876 return 0;
877}
878
879static const struct v4l2_ioctl_ops fimc_lite_ioctl_ops = {
880 .vidioc_querycap = fimc_vidioc_querycap_capture,
881 .vidioc_enum_fmt_vid_cap_mplane = fimc_lite_enum_fmt_mplane,
882 .vidioc_try_fmt_vid_cap_mplane = fimc_lite_try_fmt_mplane,
883 .vidioc_s_fmt_vid_cap_mplane = fimc_lite_s_fmt_mplane,
884 .vidioc_g_fmt_vid_cap_mplane = fimc_lite_g_fmt_mplane,
885 .vidioc_g_selection = fimc_lite_g_selection,
886 .vidioc_s_selection = fimc_lite_s_selection,
887 .vidioc_reqbufs = fimc_lite_reqbufs,
Sylwester Nawrockiee12b042013-03-25 16:43:08 -0300888 .vidioc_querybuf = vb2_ioctl_querybuf,
889 .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
890 .vidioc_create_bufs = vb2_ioctl_create_bufs,
891 .vidioc_qbuf = vb2_ioctl_qbuf,
892 .vidioc_dqbuf = vb2_ioctl_dqbuf,
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300893 .vidioc_streamon = fimc_lite_streamon,
894 .vidioc_streamoff = fimc_lite_streamoff,
895};
896
Sylwester Nawrocki6319d6a2012-11-28 15:41:01 -0300897/* Called with the media graph mutex held */
898static struct v4l2_subdev *__find_remote_sensor(struct media_entity *me)
899{
900 struct media_pad *pad = &me->pads[0];
901 struct v4l2_subdev *sd;
902
903 while (pad->flags & MEDIA_PAD_FL_SINK) {
904 /* source pad */
905 pad = media_entity_remote_source(pad);
906 if (pad == NULL ||
907 media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
908 break;
909
910 sd = media_entity_to_v4l2_subdev(pad->entity);
911
912 if (sd->grp_id == GRP_ID_FIMC_IS_SENSOR)
913 return sd;
914 /* sink pad */
915 pad = &sd->entity.pads[0];
916 }
917 return NULL;
918}
919
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300920/* Capture subdev media entity operations */
921static int fimc_lite_link_setup(struct media_entity *entity,
922 const struct media_pad *local,
923 const struct media_pad *remote, u32 flags)
924{
925 struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
926 struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
927 unsigned int remote_ent_type = media_entity_type(remote->entity);
Sylwester Nawrocki6319d6a2012-11-28 15:41:01 -0300928 int ret = 0;
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300929
930 if (WARN_ON(fimc == NULL))
931 return 0;
932
Sylwester Nawrocki969e8772012-12-07 16:40:08 -0300933 v4l2_dbg(1, debug, sd, "%s: %s --> %s, flags: 0x%x. source_id: 0x%x\n",
Sylwester Nawrocki6319d6a2012-11-28 15:41:01 -0300934 __func__, remote->entity->name, local->entity->name,
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300935 flags, fimc->source_subdev_grp_id);
936
Sylwester Nawrocki6319d6a2012-11-28 15:41:01 -0300937 mutex_lock(&fimc->lock);
938
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300939 switch (local->index) {
Sylwester Nawrocki6319d6a2012-11-28 15:41:01 -0300940 case FLITE_SD_PAD_SINK:
941 if (remote_ent_type != MEDIA_ENT_T_V4L2_SUBDEV) {
942 ret = -EINVAL;
943 break;
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300944 }
Sylwester Nawrocki6319d6a2012-11-28 15:41:01 -0300945 if (flags & MEDIA_LNK_FL_ENABLED) {
946 if (fimc->source_subdev_grp_id == 0)
947 fimc->source_subdev_grp_id = sd->grp_id;
948 else
949 ret = -EBUSY;
950 } else {
951 fimc->source_subdev_grp_id = 0;
952 fimc->sensor = NULL;
953 }
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300954 break;
955
Sylwester Nawrocki6319d6a2012-11-28 15:41:01 -0300956 case FLITE_SD_PAD_SOURCE_DMA:
957 if (!(flags & MEDIA_LNK_FL_ENABLED))
Sylwester Nawrocki03878bb2013-01-18 12:02:32 -0300958 atomic_set(&fimc->out_path, FIMC_IO_NONE);
Sylwester Nawrocki6319d6a2012-11-28 15:41:01 -0300959 else if (remote_ent_type == MEDIA_ENT_T_DEVNODE)
Sylwester Nawrocki03878bb2013-01-18 12:02:32 -0300960 atomic_set(&fimc->out_path, FIMC_IO_DMA);
Sylwester Nawrocki6319d6a2012-11-28 15:41:01 -0300961 else
962 ret = -EINVAL;
963 break;
964
965 case FLITE_SD_PAD_SOURCE_ISP:
966 if (!(flags & MEDIA_LNK_FL_ENABLED))
Sylwester Nawrocki03878bb2013-01-18 12:02:32 -0300967 atomic_set(&fimc->out_path, FIMC_IO_NONE);
Sylwester Nawrocki6319d6a2012-11-28 15:41:01 -0300968 else if (remote_ent_type == MEDIA_ENT_T_V4L2_SUBDEV)
Sylwester Nawrocki03878bb2013-01-18 12:02:32 -0300969 atomic_set(&fimc->out_path, FIMC_IO_ISP);
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300970 else
Sylwester Nawrocki6319d6a2012-11-28 15:41:01 -0300971 ret = -EINVAL;
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300972 break;
973
974 default:
975 v4l2_err(sd, "Invalid pad index\n");
Sylwester Nawrocki6319d6a2012-11-28 15:41:01 -0300976 ret = -EINVAL;
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300977 }
Sylwester Nawrocki03878bb2013-01-18 12:02:32 -0300978 mb();
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300979
Sylwester Nawrocki6319d6a2012-11-28 15:41:01 -0300980 mutex_unlock(&fimc->lock);
981 return ret;
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300982}
983
984static const struct media_entity_operations fimc_lite_subdev_media_ops = {
985 .link_setup = fimc_lite_link_setup,
986};
987
988static int fimc_lite_subdev_enum_mbus_code(struct v4l2_subdev *sd,
989 struct v4l2_subdev_fh *fh,
990 struct v4l2_subdev_mbus_code_enum *code)
991{
992 const struct fimc_fmt *fmt;
993
994 fmt = fimc_lite_find_format(NULL, NULL, code->index);
995 if (!fmt)
996 return -EINVAL;
997 code->code = fmt->mbus_code;
998 return 0;
999}
1000
1001static int fimc_lite_subdev_get_fmt(struct v4l2_subdev *sd,
1002 struct v4l2_subdev_fh *fh,
1003 struct v4l2_subdev_format *fmt)
1004{
1005 struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
1006 struct v4l2_mbus_framefmt *mf = &fmt->format;
1007 struct flite_frame *f = &fimc->out_frame;
1008
1009 if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
1010 mf = v4l2_subdev_get_try_format(fh, fmt->pad);
1011 fmt->format = *mf;
1012 return 0;
1013 }
1014 mf->colorspace = V4L2_COLORSPACE_JPEG;
1015
1016 mutex_lock(&fimc->lock);
1017 mf->code = fimc->fmt->mbus_code;
1018
1019 if (fmt->pad == FLITE_SD_PAD_SINK) {
1020 /* full camera input frame size */
1021 mf->width = f->f_width;
1022 mf->height = f->f_height;
1023 } else {
1024 /* crop size */
1025 mf->width = f->rect.width;
1026 mf->height = f->rect.height;
1027 }
1028 mutex_unlock(&fimc->lock);
1029 return 0;
1030}
1031
1032static int fimc_lite_subdev_set_fmt(struct v4l2_subdev *sd,
1033 struct v4l2_subdev_fh *fh,
1034 struct v4l2_subdev_format *fmt)
1035{
1036 struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
1037 struct v4l2_mbus_framefmt *mf = &fmt->format;
1038 struct flite_frame *sink = &fimc->inp_frame;
Sylwester Nawrocki9356ac72012-08-31 12:50:45 -03001039 struct flite_frame *source = &fimc->out_frame;
Sylwester Nawrocki4af81312012-04-27 05:29:05 -03001040 const struct fimc_fmt *ffmt;
1041
Sylwester Nawrocki969e8772012-12-07 16:40:08 -03001042 v4l2_dbg(1, debug, sd, "pad%d: code: 0x%x, %dx%d\n",
Sylwester Nawrocki4af81312012-04-27 05:29:05 -03001043 fmt->pad, mf->code, mf->width, mf->height);
1044
1045 mf->colorspace = V4L2_COLORSPACE_JPEG;
1046 mutex_lock(&fimc->lock);
1047
Sylwester Nawrocki03878bb2013-01-18 12:02:32 -03001048 if ((atomic_read(&fimc->out_path) == FIMC_IO_ISP &&
1049 sd->entity.stream_count > 0) ||
1050 (atomic_read(&fimc->out_path) == FIMC_IO_DMA &&
1051 vb2_is_busy(&fimc->vb_queue))) {
Sylwester Nawrocki4af81312012-04-27 05:29:05 -03001052 mutex_unlock(&fimc->lock);
1053 return -EBUSY;
1054 }
1055
1056 ffmt = fimc_lite_try_format(fimc, &mf->width, &mf->height,
1057 &mf->code, NULL, fmt->pad);
1058
1059 if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
1060 mf = v4l2_subdev_get_try_format(fh, fmt->pad);
1061 *mf = fmt->format;
1062 mutex_unlock(&fimc->lock);
1063 return 0;
1064 }
1065
1066 if (fmt->pad == FLITE_SD_PAD_SINK) {
1067 sink->f_width = mf->width;
1068 sink->f_height = mf->height;
1069 fimc->fmt = ffmt;
1070 /* Set sink crop rectangle */
1071 sink->rect.width = mf->width;
1072 sink->rect.height = mf->height;
1073 sink->rect.left = 0;
1074 sink->rect.top = 0;
Sylwester Nawrocki9356ac72012-08-31 12:50:45 -03001075 /* Reset source format and crop rectangle */
1076 source->rect = sink->rect;
1077 source->f_width = mf->width;
1078 source->f_height = mf->height;
Sylwester Nawrocki4af81312012-04-27 05:29:05 -03001079 } else {
1080 /* Allow changing format only on sink pad */
1081 mf->code = fimc->fmt->mbus_code;
1082 mf->width = sink->rect.width;
1083 mf->height = sink->rect.height;
1084 }
1085
1086 mutex_unlock(&fimc->lock);
1087 return 0;
1088}
1089
1090static int fimc_lite_subdev_get_selection(struct v4l2_subdev *sd,
1091 struct v4l2_subdev_fh *fh,
1092 struct v4l2_subdev_selection *sel)
1093{
1094 struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
1095 struct flite_frame *f = &fimc->inp_frame;
1096
Sakari Ailus5689b282012-05-18 09:31:18 -03001097 if ((sel->target != V4L2_SEL_TGT_CROP &&
1098 sel->target != V4L2_SEL_TGT_CROP_BOUNDS) ||
1099 sel->pad != FLITE_SD_PAD_SINK)
Sylwester Nawrocki4af81312012-04-27 05:29:05 -03001100 return -EINVAL;
1101
1102 if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
1103 sel->r = *v4l2_subdev_get_try_crop(fh, sel->pad);
1104 return 0;
1105 }
1106
1107 mutex_lock(&fimc->lock);
Sakari Ailus5689b282012-05-18 09:31:18 -03001108 if (sel->target == V4L2_SEL_TGT_CROP) {
Sylwester Nawrocki4af81312012-04-27 05:29:05 -03001109 sel->r = f->rect;
1110 } else {
1111 sel->r.left = 0;
1112 sel->r.top = 0;
1113 sel->r.width = f->f_width;
1114 sel->r.height = f->f_height;
1115 }
1116 mutex_unlock(&fimc->lock);
1117
Sylwester Nawrocki969e8772012-12-07 16:40:08 -03001118 v4l2_dbg(1, debug, sd, "%s: (%d,%d) %dx%d, f_w: %d, f_h: %d\n",
Sylwester Nawrocki4af81312012-04-27 05:29:05 -03001119 __func__, f->rect.left, f->rect.top, f->rect.width,
1120 f->rect.height, f->f_width, f->f_height);
1121
1122 return 0;
1123}
1124
1125static int fimc_lite_subdev_set_selection(struct v4l2_subdev *sd,
1126 struct v4l2_subdev_fh *fh,
1127 struct v4l2_subdev_selection *sel)
1128{
1129 struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
1130 struct flite_frame *f = &fimc->inp_frame;
1131 int ret = 0;
1132
Sakari Ailus5689b282012-05-18 09:31:18 -03001133 if (sel->target != V4L2_SEL_TGT_CROP || sel->pad != FLITE_SD_PAD_SINK)
Sylwester Nawrocki4af81312012-04-27 05:29:05 -03001134 return -EINVAL;
1135
1136 mutex_lock(&fimc->lock);
1137 fimc_lite_try_crop(fimc, &sel->r);
1138
1139 if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
1140 *v4l2_subdev_get_try_crop(fh, sel->pad) = sel->r;
1141 } else {
1142 unsigned long flags;
1143 spin_lock_irqsave(&fimc->slock, flags);
1144 f->rect = sel->r;
1145 /* Same crop rectangle on the source pad */
1146 fimc->out_frame.rect = sel->r;
1147 set_bit(ST_FLITE_CONFIG, &fimc->state);
1148 spin_unlock_irqrestore(&fimc->slock, flags);
1149 }
1150 mutex_unlock(&fimc->lock);
1151
Sylwester Nawrocki969e8772012-12-07 16:40:08 -03001152 v4l2_dbg(1, debug, sd, "%s: (%d,%d) %dx%d, f_w: %d, f_h: %d\n",
Sylwester Nawrocki4af81312012-04-27 05:29:05 -03001153 __func__, f->rect.left, f->rect.top, f->rect.width,
1154 f->rect.height, f->f_width, f->f_height);
1155
1156 return ret;
1157}
1158
1159static int fimc_lite_subdev_s_stream(struct v4l2_subdev *sd, int on)
1160{
1161 struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
Sylwester Nawrocki6319d6a2012-11-28 15:41:01 -03001162 unsigned long flags;
1163 int ret;
Sylwester Nawrocki4af81312012-04-27 05:29:05 -03001164
Sylwester Nawrocki6319d6a2012-11-28 15:41:01 -03001165 /*
1166 * Find sensor subdev linked to FIMC-LITE directly or through
1167 * MIPI-CSIS. This is required for configuration where FIMC-LITE
1168 * is used as a subdev only and feeds data internally to FIMC-IS.
1169 * The pipeline links are protected through entity.stream_count
1170 * so there is no need to take the media graph mutex here.
1171 */
1172 fimc->sensor = __find_remote_sensor(&sd->entity);
1173
Sylwester Nawrocki03878bb2013-01-18 12:02:32 -03001174 if (atomic_read(&fimc->out_path) != FIMC_IO_ISP)
Sylwester Nawrocki4af81312012-04-27 05:29:05 -03001175 return -ENOIOCTLCMD;
1176
Sylwester Nawrocki03878bb2013-01-18 12:02:32 -03001177 mutex_lock(&fimc->lock);
Sylwester Nawrocki6319d6a2012-11-28 15:41:01 -03001178 if (on) {
1179 flite_hw_reset(fimc);
1180 ret = fimc_lite_hw_init(fimc, true);
1181 if (!ret) {
1182 spin_lock_irqsave(&fimc->slock, flags);
1183 flite_hw_capture_start(fimc);
1184 spin_unlock_irqrestore(&fimc->slock, flags);
1185 }
1186 } else {
1187 set_bit(ST_FLITE_OFF, &fimc->state);
Sylwester Nawrocki4af81312012-04-27 05:29:05 -03001188
Sylwester Nawrocki6319d6a2012-11-28 15:41:01 -03001189 spin_lock_irqsave(&fimc->slock, flags);
1190 flite_hw_capture_stop(fimc);
1191 spin_unlock_irqrestore(&fimc->slock, flags);
1192
1193 ret = wait_event_timeout(fimc->irq_queue,
1194 !test_bit(ST_FLITE_OFF, &fimc->state),
1195 msecs_to_jiffies(200));
1196 if (ret == 0)
1197 v4l2_err(sd, "s_stream(0) timeout\n");
1198 clear_bit(ST_FLITE_RUN, &fimc->state);
1199 }
1200
1201 mutex_unlock(&fimc->lock);
1202 return ret;
Sylwester Nawrocki4af81312012-04-27 05:29:05 -03001203}
1204
Sylwester Nawrocki4af81312012-04-27 05:29:05 -03001205static int fimc_lite_log_status(struct v4l2_subdev *sd)
1206{
1207 struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
1208
1209 flite_hw_dump_regs(fimc, __func__);
1210 return 0;
1211}
1212
1213static int fimc_lite_subdev_registered(struct v4l2_subdev *sd)
1214{
1215 struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
1216 struct vb2_queue *q = &fimc->vb_queue;
Sylwester Nawrocki1bcd7042012-07-26 07:13:08 -03001217 struct video_device *vfd = &fimc->vfd;
Sylwester Nawrocki4af81312012-04-27 05:29:05 -03001218 int ret;
1219
Sylwester Nawrocki1bcd7042012-07-26 07:13:08 -03001220 memset(vfd, 0, sizeof(*vfd));
1221
Sylwester Nawrocki4af81312012-04-27 05:29:05 -03001222 fimc->fmt = &fimc_lite_formats[0];
Sylwester Nawrocki03878bb2013-01-18 12:02:32 -03001223 atomic_set(&fimc->out_path, FIMC_IO_DMA);
Sylwester Nawrocki4af81312012-04-27 05:29:05 -03001224
Sylwester Nawrocki4af81312012-04-27 05:29:05 -03001225 snprintf(vfd->name, sizeof(vfd->name), "fimc-lite.%d.capture",
1226 fimc->index);
1227
1228 vfd->fops = &fimc_lite_fops;
1229 vfd->ioctl_ops = &fimc_lite_ioctl_ops;
1230 vfd->v4l2_dev = sd->v4l2_dev;
1231 vfd->minor = -1;
Sylwester Nawrocki1bcd7042012-07-26 07:13:08 -03001232 vfd->release = video_device_release_empty;
Sylwester Nawrockiee12b042013-03-25 16:43:08 -03001233 vfd->queue = q;
Sylwester Nawrocki4af81312012-04-27 05:29:05 -03001234 fimc->reqbufs_count = 0;
1235
1236 INIT_LIST_HEAD(&fimc->pending_buf_q);
1237 INIT_LIST_HEAD(&fimc->active_buf_q);
1238
1239 memset(q, 0, sizeof(*q));
1240 q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1241 q->io_modes = VB2_MMAP | VB2_USERPTR;
1242 q->ops = &fimc_lite_qops;
1243 q->mem_ops = &vb2_dma_contig_memops;
1244 q->buf_struct_size = sizeof(struct flite_buffer);
1245 q->drv_priv = fimc;
Kamil Debski6aa69f92013-01-25 06:29:57 -03001246 q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
Sylwester Nawrockiee12b042013-03-25 16:43:08 -03001247 q->lock = &fimc->lock;
Sylwester Nawrocki4af81312012-04-27 05:29:05 -03001248
Sylwester Nawrocki41fd0872012-10-19 08:24:18 -03001249 ret = vb2_queue_init(q);
1250 if (ret < 0)
1251 return ret;
Sylwester Nawrocki4af81312012-04-27 05:29:05 -03001252
1253 fimc->vd_pad.flags = MEDIA_PAD_FL_SINK;
1254 ret = media_entity_init(&vfd->entity, 1, &fimc->vd_pad, 0);
Sylwester Nawrocki1bcd7042012-07-26 07:13:08 -03001255 if (ret < 0)
1256 return ret;
Sylwester Nawrocki4af81312012-04-27 05:29:05 -03001257
1258 video_set_drvdata(vfd, fimc);
Sylwester Nawrocki97d66c42012-11-22 06:17:19 -03001259 fimc->pipeline_ops = v4l2_get_subdev_hostdata(sd);
Sylwester Nawrocki4af81312012-04-27 05:29:05 -03001260
1261 ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
Sylwester Nawrocki1bcd7042012-07-26 07:13:08 -03001262 if (ret < 0) {
1263 media_entity_cleanup(&vfd->entity);
Sylwester Nawrocki97d66c42012-11-22 06:17:19 -03001264 fimc->pipeline_ops = NULL;
Sylwester Nawrocki1bcd7042012-07-26 07:13:08 -03001265 return ret;
1266 }
Sylwester Nawrocki4af81312012-04-27 05:29:05 -03001267
1268 v4l2_info(sd->v4l2_dev, "Registered %s as /dev/%s\n",
1269 vfd->name, video_device_node_name(vfd));
1270 return 0;
Sylwester Nawrocki4af81312012-04-27 05:29:05 -03001271}
1272
1273static void fimc_lite_subdev_unregistered(struct v4l2_subdev *sd)
1274{
1275 struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
1276
1277 if (fimc == NULL)
1278 return;
1279
Sylwester Nawrocki1bcd7042012-07-26 07:13:08 -03001280 if (video_is_registered(&fimc->vfd)) {
1281 video_unregister_device(&fimc->vfd);
1282 media_entity_cleanup(&fimc->vfd.entity);
Sylwester Nawrocki97d66c42012-11-22 06:17:19 -03001283 fimc->pipeline_ops = NULL;
Sylwester Nawrocki4af81312012-04-27 05:29:05 -03001284 }
1285}
1286
1287static const struct v4l2_subdev_internal_ops fimc_lite_subdev_internal_ops = {
1288 .registered = fimc_lite_subdev_registered,
1289 .unregistered = fimc_lite_subdev_unregistered,
1290};
1291
1292static const struct v4l2_subdev_pad_ops fimc_lite_subdev_pad_ops = {
1293 .enum_mbus_code = fimc_lite_subdev_enum_mbus_code,
1294 .get_selection = fimc_lite_subdev_get_selection,
1295 .set_selection = fimc_lite_subdev_set_selection,
1296 .get_fmt = fimc_lite_subdev_get_fmt,
1297 .set_fmt = fimc_lite_subdev_set_fmt,
1298};
1299
1300static const struct v4l2_subdev_video_ops fimc_lite_subdev_video_ops = {
1301 .s_stream = fimc_lite_subdev_s_stream,
1302};
1303
1304static const struct v4l2_subdev_core_ops fimc_lite_core_ops = {
Sylwester Nawrocki4af81312012-04-27 05:29:05 -03001305 .log_status = fimc_lite_log_status,
1306};
1307
1308static struct v4l2_subdev_ops fimc_lite_subdev_ops = {
1309 .core = &fimc_lite_core_ops,
1310 .video = &fimc_lite_subdev_video_ops,
1311 .pad = &fimc_lite_subdev_pad_ops,
1312};
1313
1314static int fimc_lite_s_ctrl(struct v4l2_ctrl *ctrl)
1315{
1316 struct fimc_lite *fimc = container_of(ctrl->handler, struct fimc_lite,
1317 ctrl_handler);
1318 set_bit(ST_FLITE_CONFIG, &fimc->state);
1319 return 0;
1320}
1321
1322static const struct v4l2_ctrl_ops fimc_lite_ctrl_ops = {
1323 .s_ctrl = fimc_lite_s_ctrl,
1324};
1325
1326static const struct v4l2_ctrl_config fimc_lite_ctrl = {
1327 .ops = &fimc_lite_ctrl_ops,
1328 .id = V4L2_CTRL_CLASS_USER | 0x1001,
1329 .type = V4L2_CTRL_TYPE_BOOLEAN,
1330 .name = "Test Pattern 640x480",
1331};
1332
1333static int fimc_lite_create_capture_subdev(struct fimc_lite *fimc)
1334{
1335 struct v4l2_ctrl_handler *handler = &fimc->ctrl_handler;
1336 struct v4l2_subdev *sd = &fimc->subdev;
1337 int ret;
1338
1339 v4l2_subdev_init(sd, &fimc_lite_subdev_ops);
1340 sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
1341 snprintf(sd->name, sizeof(sd->name), "FIMC-LITE.%d", fimc->index);
1342
Sylwester Nawrocki6319d6a2012-11-28 15:41:01 -03001343 fimc->subdev_pads[FLITE_SD_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
1344 fimc->subdev_pads[FLITE_SD_PAD_SOURCE_DMA].flags = MEDIA_PAD_FL_SOURCE;
1345 fimc->subdev_pads[FLITE_SD_PAD_SOURCE_ISP].flags = MEDIA_PAD_FL_SOURCE;
1346 ret = media_entity_init(&sd->entity, FLITE_SD_PADS_NUM,
Sylwester Nawrocki4af81312012-04-27 05:29:05 -03001347 fimc->subdev_pads, 0);
1348 if (ret)
1349 return ret;
1350
1351 v4l2_ctrl_handler_init(handler, 1);
1352 fimc->test_pattern = v4l2_ctrl_new_custom(handler, &fimc_lite_ctrl,
1353 NULL);
1354 if (handler->error) {
1355 media_entity_cleanup(&sd->entity);
1356 return handler->error;
1357 }
1358
1359 sd->ctrl_handler = handler;
1360 sd->internal_ops = &fimc_lite_subdev_internal_ops;
1361 sd->entity.ops = &fimc_lite_subdev_media_ops;
1362 v4l2_set_subdevdata(sd, fimc);
1363
1364 return 0;
1365}
1366
1367static void fimc_lite_unregister_capture_subdev(struct fimc_lite *fimc)
1368{
1369 struct v4l2_subdev *sd = &fimc->subdev;
1370
1371 v4l2_device_unregister_subdev(sd);
1372 media_entity_cleanup(&sd->entity);
1373 v4l2_ctrl_handler_free(&fimc->ctrl_handler);
1374 v4l2_set_subdevdata(sd, NULL);
1375}
1376
1377static void fimc_lite_clk_put(struct fimc_lite *fimc)
1378{
1379 if (IS_ERR_OR_NULL(fimc->clock))
1380 return;
1381
1382 clk_unprepare(fimc->clock);
1383 clk_put(fimc->clock);
1384 fimc->clock = NULL;
1385}
1386
1387static int fimc_lite_clk_get(struct fimc_lite *fimc)
1388{
1389 int ret;
1390
1391 fimc->clock = clk_get(&fimc->pdev->dev, FLITE_CLK_NAME);
1392 if (IS_ERR(fimc->clock))
1393 return PTR_ERR(fimc->clock);
1394
1395 ret = clk_prepare(fimc->clock);
1396 if (ret < 0) {
1397 clk_put(fimc->clock);
1398 fimc->clock = NULL;
1399 }
1400 return ret;
1401}
1402
Greg Kroah-Hartman4c62e972012-12-21 13:17:53 -08001403static int fimc_lite_probe(struct platform_device *pdev)
Sylwester Nawrocki4af81312012-04-27 05:29:05 -03001404{
1405 struct flite_drvdata *drv_data = fimc_lite_get_drvdata(pdev);
1406 struct fimc_lite *fimc;
1407 struct resource *res;
1408 int ret;
1409
1410 fimc = devm_kzalloc(&pdev->dev, sizeof(*fimc), GFP_KERNEL);
1411 if (!fimc)
1412 return -ENOMEM;
1413
1414 fimc->index = pdev->id;
1415 fimc->variant = drv_data->variant[fimc->index];
1416 fimc->pdev = pdev;
1417
1418 init_waitqueue_head(&fimc->irq_queue);
1419 spin_lock_init(&fimc->slock);
1420 mutex_init(&fimc->lock);
1421
1422 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Thierry Redingf23999e2013-01-21 06:09:07 -03001423 fimc->regs = devm_ioremap_resource(&pdev->dev, res);
1424 if (IS_ERR(fimc->regs))
1425 return PTR_ERR(fimc->regs);
Sylwester Nawrocki4af81312012-04-27 05:29:05 -03001426
1427 res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
1428 if (res == NULL) {
1429 dev_err(&pdev->dev, "Failed to get IRQ resource\n");
1430 return -ENXIO;
1431 }
1432
1433 ret = fimc_lite_clk_get(fimc);
1434 if (ret)
1435 return ret;
1436
1437 ret = devm_request_irq(&pdev->dev, res->start, flite_irq_handler,
1438 0, dev_name(&pdev->dev), fimc);
1439 if (ret) {
1440 dev_err(&pdev->dev, "Failed to install irq (%d)\n", ret);
1441 goto err_clk;
1442 }
1443
1444 /* The video node will be created within the subdev's registered() op */
1445 ret = fimc_lite_create_capture_subdev(fimc);
1446 if (ret)
1447 goto err_clk;
1448
1449 platform_set_drvdata(pdev, fimc);
1450 pm_runtime_enable(&pdev->dev);
1451 ret = pm_runtime_get_sync(&pdev->dev);
1452 if (ret < 0)
1453 goto err_sd;
1454
1455 fimc->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
1456 if (IS_ERR(fimc->alloc_ctx)) {
1457 ret = PTR_ERR(fimc->alloc_ctx);
1458 goto err_pm;
1459 }
1460 pm_runtime_put(&pdev->dev);
1461
1462 dev_dbg(&pdev->dev, "FIMC-LITE.%d registered successfully\n",
1463 fimc->index);
1464 return 0;
1465err_pm:
1466 pm_runtime_put(&pdev->dev);
1467err_sd:
1468 fimc_lite_unregister_capture_subdev(fimc);
1469err_clk:
1470 fimc_lite_clk_put(fimc);
1471 return ret;
1472}
1473
1474static int fimc_lite_runtime_resume(struct device *dev)
1475{
1476 struct fimc_lite *fimc = dev_get_drvdata(dev);
1477
1478 clk_enable(fimc->clock);
1479 return 0;
1480}
1481
1482static int fimc_lite_runtime_suspend(struct device *dev)
1483{
1484 struct fimc_lite *fimc = dev_get_drvdata(dev);
1485
1486 clk_disable(fimc->clock);
1487 return 0;
1488}
1489
1490#ifdef CONFIG_PM_SLEEP
1491static int fimc_lite_resume(struct device *dev)
1492{
1493 struct fimc_lite *fimc = dev_get_drvdata(dev);
1494 struct flite_buffer *buf;
1495 unsigned long flags;
1496 int i;
1497
1498 spin_lock_irqsave(&fimc->slock, flags);
1499 if (!test_and_clear_bit(ST_LPM, &fimc->state) ||
1500 !test_bit(ST_FLITE_IN_USE, &fimc->state)) {
1501 spin_unlock_irqrestore(&fimc->slock, flags);
1502 return 0;
1503 }
1504 flite_hw_reset(fimc);
1505 spin_unlock_irqrestore(&fimc->slock, flags);
1506
1507 if (!test_and_clear_bit(ST_FLITE_SUSPENDED, &fimc->state))
1508 return 0;
1509
1510 INIT_LIST_HEAD(&fimc->active_buf_q);
Sylwester Nawrockib9ee31e2012-08-14 10:46:58 -03001511 fimc_pipeline_call(fimc, open, &fimc->pipeline,
1512 &fimc->vfd.entity, false);
Sylwester Nawrocki03878bb2013-01-18 12:02:32 -03001513 fimc_lite_hw_init(fimc, atomic_read(&fimc->out_path) == FIMC_IO_ISP);
Sylwester Nawrocki4af81312012-04-27 05:29:05 -03001514 clear_bit(ST_FLITE_SUSPENDED, &fimc->state);
1515
1516 for (i = 0; i < fimc->reqbufs_count; i++) {
1517 if (list_empty(&fimc->pending_buf_q))
1518 break;
1519 buf = fimc_lite_pending_queue_pop(fimc);
1520 buffer_queue(&buf->vb);
1521 }
1522 return 0;
1523}
1524
1525static int fimc_lite_suspend(struct device *dev)
1526{
1527 struct fimc_lite *fimc = dev_get_drvdata(dev);
1528 bool suspend = test_bit(ST_FLITE_IN_USE, &fimc->state);
1529 int ret;
1530
1531 if (test_and_set_bit(ST_LPM, &fimc->state))
1532 return 0;
1533
1534 ret = fimc_lite_stop_capture(fimc, suspend);
Sylwester Nawrocki316efab2012-05-18 13:31:28 -03001535 if (ret < 0 || !fimc_lite_active(fimc))
Sylwester Nawrocki4af81312012-04-27 05:29:05 -03001536 return ret;
1537
Sylwester Nawrockib9ee31e2012-08-14 10:46:58 -03001538 return fimc_pipeline_call(fimc, close, &fimc->pipeline);
Sylwester Nawrocki4af81312012-04-27 05:29:05 -03001539}
1540#endif /* CONFIG_PM_SLEEP */
1541
Greg Kroah-Hartman4c62e972012-12-21 13:17:53 -08001542static int fimc_lite_remove(struct platform_device *pdev)
Sylwester Nawrocki4af81312012-04-27 05:29:05 -03001543{
1544 struct fimc_lite *fimc = platform_get_drvdata(pdev);
1545 struct device *dev = &pdev->dev;
1546
1547 pm_runtime_disable(dev);
1548 pm_runtime_set_suspended(dev);
1549 fimc_lite_unregister_capture_subdev(fimc);
1550 vb2_dma_contig_cleanup_ctx(fimc->alloc_ctx);
1551 fimc_lite_clk_put(fimc);
1552
1553 dev_info(dev, "Driver unloaded\n");
1554 return 0;
1555}
1556
1557static struct flite_variant fimc_lite0_variant_exynos4 = {
1558 .max_width = 8192,
1559 .max_height = 8192,
1560 .out_width_align = 8,
1561 .win_hor_offs_align = 2,
1562 .out_hor_offs_align = 8,
1563};
1564
1565/* EXYNOS4212, EXYNOS4412 */
1566static struct flite_drvdata fimc_lite_drvdata_exynos4 = {
1567 .variant = {
1568 [0] = &fimc_lite0_variant_exynos4,
1569 [1] = &fimc_lite0_variant_exynos4,
1570 },
1571};
1572
1573static struct platform_device_id fimc_lite_driver_ids[] = {
1574 {
1575 .name = "exynos-fimc-lite",
1576 .driver_data = (unsigned long)&fimc_lite_drvdata_exynos4,
1577 },
1578 { /* sentinel */ },
1579};
1580MODULE_DEVICE_TABLE(platform, fimc_lite_driver_ids);
1581
1582static const struct dev_pm_ops fimc_lite_pm_ops = {
1583 SET_SYSTEM_SLEEP_PM_OPS(fimc_lite_suspend, fimc_lite_resume)
1584 SET_RUNTIME_PM_OPS(fimc_lite_runtime_suspend, fimc_lite_runtime_resume,
1585 NULL)
1586};
1587
1588static struct platform_driver fimc_lite_driver = {
1589 .probe = fimc_lite_probe,
Greg Kroah-Hartman4c62e972012-12-21 13:17:53 -08001590 .remove = fimc_lite_remove,
Sylwester Nawrocki4af81312012-04-27 05:29:05 -03001591 .id_table = fimc_lite_driver_ids,
1592 .driver = {
1593 .name = FIMC_LITE_DRV_NAME,
1594 .owner = THIS_MODULE,
1595 .pm = &fimc_lite_pm_ops,
1596 }
1597};
1598module_platform_driver(fimc_lite_driver);
1599MODULE_LICENSE("GPL");
1600MODULE_ALIAS("platform:" FIMC_LITE_DRV_NAME);