blob: eb5bdeec8a1186baf459aebe82bd55e35faaff0d [file] [log] [blame]
Pratap Nirujogi6e759912018-01-17 17:51:17 +05301/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/vmalloc.h>
14#include <linux/kernel.h>
15#include <linux/module.h>
16#include <linux/platform_device.h>
17#include <linux/regulator/consumer.h>
18#include <linux/spinlock.h>
19#include <linux/interrupt.h>
20#include <linux/ion.h>
21#include <linux/msm_ion.h>
22#include <media/v4l2-ioctl.h>
23#include <media/v4l2-event.h>
24#include <media/videobuf2-v4l2.h>
25#include <linux/clk/msm-clk.h>
26
27#include "msm_fd_dev.h"
28#include "msm_fd_hw.h"
29#include "msm_fd_regs.h"
30
31#define MSM_FD_DRV_NAME "msm_fd"
32
33#define MSM_FD_WORD_SIZE_BYTES 4
34
35/* Face detection thresholds definitions */
36#define MSM_FD_DEF_THRESHOLD 5
37#define MSM_FD_MAX_THRESHOLD_VALUE 9
38
39/* Face angle lookup table */
40#define MSM_FD_DEF_ANGLE_IDX 2
41static int msm_fd_angle[] = {45, 135, 359};
42
43/* Face direction lookup table */
44#define MSM_FD_DEF_DIR_IDX 0
45static int msm_fd_dir[] = {0, 90, 270, 180};
46
47/* Minimum face size lookup table */
48#define MSM_FD_DEF_MIN_SIZE_IDX 0
49static int msm_fd_min_size[] = {20, 25, 32, 40};
50
51/* Face detection size lookup table */
52static struct msm_fd_size fd_size[] = {
53 {
54 .width = 320,
55 .height = 240,
56 .reg_val = MSM_FD_IMAGE_SIZE_QVGA,
57 .work_size = (13120 * MSM_FD_WORD_SIZE_BYTES),
58 },
59 {
60 .width = 427,
61 .height = 240,
62 .reg_val = MSM_FD_IMAGE_SIZE_WQVGA,
63 .work_size = (17744 * MSM_FD_WORD_SIZE_BYTES),
64 },
65 {
66 .width = 640,
67 .height = 480,
68 .reg_val = MSM_FD_IMAGE_SIZE_VGA,
69 .work_size = (52624 * MSM_FD_WORD_SIZE_BYTES),
70 },
71 {
72 .width = 854,
73 .height = 480,
74 .reg_val = MSM_FD_IMAGE_SIZE_WVGA,
75 .work_size = (70560 * MSM_FD_WORD_SIZE_BYTES),
76 },
77};
78
79/*
80 * msm_fd_ctx_from_fh - Get fd context from v4l2 fh.
81 * @fh: Pointer to v4l2 fh.
82 */
83static inline struct fd_ctx *msm_fd_ctx_from_fh(struct v4l2_fh *fh)
84{
85 return container_of(fh, struct fd_ctx, fh);
86}
87
88/*
89 * msm_fd_get_format_index - Get format index from v4l2 format.
90 * @f: Pointer to v4l2 format struct.
91 */
92static int msm_fd_get_format_index(struct v4l2_format *f)
93{
94 int index;
95
96 for (index = 0; index < ARRAY_SIZE(fd_size); index++) {
97 if (f->fmt.pix.width <= fd_size[index].width &&
98 f->fmt.pix.height <= fd_size[index].height)
99 return index;
100 }
101 return index - 1;
102}
103
104/*
105 * msm_fd_get_idx_from_value - Get array index from value.
106 * @value: Value for which index is needed.
107 * @array: Array in which index is searched for.
108 * @array_size: Array size.
109 */
110static int msm_fd_get_idx_from_value(int value, int *array, int array_size)
111{
112 int index;
113 int i;
114
115 index = 0;
116 for (i = 1; i < array_size; i++) {
117 if (value == array[i]) {
118 index = i;
119 break;
120 }
121 if (abs(value - array[i]) < abs(value - array[index]))
122 index = i;
123 }
124 return index;
125}
126
127/*
128 * msm_fd_fill_format_from_index - Fill v4l2 format struct from size index.
129 * @f: Pointer of v4l2 struct which will be filled.
130 * @index: Size index (Format will be filled based on this index).
131 */
132static int msm_fd_fill_format_from_index(struct v4l2_format *f, int index)
133{
134 f->fmt.pix.width = fd_size[index].width;
135 f->fmt.pix.height = fd_size[index].height;
136 f->fmt.pix.pixelformat = V4L2_PIX_FMT_GREY;
137 if (f->fmt.pix.bytesperline < f->fmt.pix.width)
138 f->fmt.pix.bytesperline = f->fmt.pix.width;
139
140 f->fmt.pix.bytesperline = ALIGN(f->fmt.pix.bytesperline, 16);
141 f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height;
142 f->fmt.pix.field = V4L2_FIELD_NONE;
143
144 return 0;
145}
146
147/*
148 * msm_fd_fill_format_from_ctx - Fill v4l2 format struct from fd context.
149 * @f: Pointer of v4l2 struct which will be filled.
150 * @c: Pointer to fd context.
151 */
152static int msm_fd_fill_format_from_ctx(struct v4l2_format *f, struct fd_ctx *c)
153{
154 if (c->format.size == NULL)
155 return -EINVAL;
156
157 f->fmt.pix.width = c->format.size->width;
158 f->fmt.pix.height = c->format.size->height;
159 f->fmt.pix.pixelformat = c->format.pixelformat;
160 f->fmt.pix.bytesperline = c->format.bytesperline;
161 f->fmt.pix.sizeimage = c->format.sizeimage;
162 f->fmt.pix.field = V4L2_FIELD_NONE;
163
164 return 0;
165}
166
167/*
168 * msm_fd_queue_setup - vb2_ops queue_setup callback.
169 * @q: Pointer to vb2 queue struct.
170 * @fmt: Pointer to v4l2 format struct (NULL is valid argument).
171 * @num_buffers: Pointer of number of buffers requested.
172 * @num_planes: Pointer to number of planes requested.
173 * @sizes: Array containing sizes of planes.
174 * @alloc_ctxs: Array of allocated contexts for each plane.
175 */
176static int msm_fd_queue_setup(struct vb2_queue *q,
177// const void *parg,
178 unsigned int *num_buffers, unsigned int *num_planes,
179 unsigned int sizes[], struct device *alloc_ctxs[])
180{
181 struct fd_ctx *ctx = vb2_get_drv_priv(q);
182 //const struct v4l2_format *fmt = parg;
183 const struct v4l2_format *fmt = NULL;
184
185 *num_planes = 1;
186
187 if (fmt == NULL)
188 sizes[0] = ctx->format.sizeimage;
189 else
190 sizes[0] = fmt->fmt.pix.sizeimage;
191
192 alloc_ctxs[0] = (struct device *)&ctx->mem_pool;
193
194 return 0;
195}
196
197/*
198 * msm_fd_buf_init - vb2_ops buf_init callback.
199 * @vb: Pointer to vb2 buffer struct.
200 */
201static int msm_fd_buf_init(struct vb2_buffer *vb)
202{
203 struct msm_fd_buffer *fd_buffer =
204 (struct msm_fd_buffer *)vb;
205
206 INIT_LIST_HEAD(&fd_buffer->list);
207 atomic_set(&fd_buffer->active, 0);
208
209 return 0;
210}
211
212/*
213 * msm_fd_buf_queue - vb2_ops buf_queue callback.
214 * @vb: Pointer to vb2 buffer struct.
215 */
216static void msm_fd_buf_queue(struct vb2_buffer *vb)
217{
218 struct fd_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
219 struct msm_fd_buffer *fd_buffer =
220 (struct msm_fd_buffer *)vb;
221
222 fd_buffer->format = ctx->format;
223 fd_buffer->settings = ctx->settings;
224 fd_buffer->work_addr = ctx->work_buf.addr;
225 msm_fd_hw_add_buffer(ctx->fd_device, fd_buffer);
226
227 if (vb->vb2_queue->streaming)
228 msm_fd_hw_schedule_and_start(ctx->fd_device);
229
230}
231
232/*
233 * msm_fd_start_streaming - vb2_ops start_streaming callback.
234 * @q: Pointer to vb2 queue struct.
235 * @count: Number of buffer queued before stream on call.
236 */
237static int msm_fd_start_streaming(struct vb2_queue *q, unsigned int count)
238{
239 struct fd_ctx *ctx = vb2_get_drv_priv(q);
240 int ret;
241
242 if (ctx->work_buf.fd == -1) {
243 dev_err(ctx->fd_device->dev, "Missing working buffer\n");
244 return -EINVAL;
245 }
246
247 ret = msm_fd_hw_get(ctx->fd_device, ctx->settings.speed);
248 if (ret < 0) {
249 dev_err(ctx->fd_device->dev, "Can not acquire fd hw\n");
250 goto out;
251 }
252
253 ret = msm_fd_hw_schedule_and_start(ctx->fd_device);
254 if (ret < 0)
255 dev_err(ctx->fd_device->dev, "Can not start fd hw\n");
256
257out:
258 return ret;
259}
260
261/*
262 * msm_fd_stop_streaming - vb2_ops stop_streaming callback.
263 * @q: Pointer to vb2 queue struct.
264 */
265static void msm_fd_stop_streaming(struct vb2_queue *q)
266{
267 struct fd_ctx *ctx = vb2_get_drv_priv(q);
268
269 mutex_lock(&ctx->fd_device->recovery_lock);
270 msm_fd_hw_remove_buffers_from_queue(ctx->fd_device, q);
271 msm_fd_hw_put(ctx->fd_device);
272 mutex_unlock(&ctx->fd_device->recovery_lock);
273}
274
275/* Videobuf2 queue callbacks. */
276static struct vb2_ops msm_fd_vb2_q_ops = {
277 .queue_setup = msm_fd_queue_setup,
278 .buf_init = msm_fd_buf_init,
279 .buf_queue = msm_fd_buf_queue,
280 .start_streaming = msm_fd_start_streaming,
281 .stop_streaming = msm_fd_stop_streaming,
282};
283
284/*
285 * msm_fd_get_userptr - Map and get buffer handler for user pointer buffer.
286 * @alloc_ctx: Contexts allocated in buf_setup.
287 * @vaddr: Virtual addr passed from userpsace (in our case ion fd)
288 * @size: Size of the buffer
289 * @write: True if buffer will be used for writing the data.
290 */
291static void *msm_fd_get_userptr(struct device *alloc_ctx,
292 unsigned long vaddr, unsigned long size,
293 enum dma_data_direction dma_dir)
294{
295 struct msm_fd_mem_pool *pool = (void *)alloc_ctx;
296 struct msm_fd_buf_handle *buf;
297 int ret;
298
299 buf = kzalloc(sizeof(*buf), GFP_KERNEL);
300 if (!buf)
301 return ERR_PTR(-ENOMEM);
302
303 ret = msm_fd_hw_map_buffer(pool, vaddr, buf);
304 if (ret < 0 || buf->size < size)
305 goto error;
306
307 return buf;
308error:
309 kzfree(buf);
310 return ERR_PTR(-ENOMEM);
311}
312
313/*
314 * msm_fd_put_userptr - Unmap and free buffer handler.
315 * @buf_priv: Buffer handler allocated get_userptr callback.
316 */
317static void msm_fd_put_userptr(void *buf_priv)
318{
319 if (IS_ERR_OR_NULL(buf_priv))
320 return;
321
322 msm_fd_hw_unmap_buffer(buf_priv);
323
324 kzfree(buf_priv);
325}
326
327/* Videobuf2 memory callbacks. */
328static struct vb2_mem_ops msm_fd_vb2_mem_ops = {
329 .get_userptr = msm_fd_get_userptr,
330 .put_userptr = msm_fd_put_userptr,
331};
332
333/*
334 * msm_fd_vbif_error_handler - FD VBIF Error handler
335 * @handle: FD Device handle
336 * @error: CPP-VBIF Error code
337 */
338static int msm_fd_vbif_error_handler(void *handle, uint32_t error)
339{
340 struct fd_ctx *ctx;
341 struct msm_fd_device *fd;
342 struct msm_fd_buffer *active_buf;
343 int ret;
344
345 if (handle == NULL)
346 return 0;
347
348 ctx = (struct fd_ctx *)handle;
349 fd = (struct msm_fd_device *)ctx->fd_device;
350
351 if (error == CPP_VBIF_ERROR_HANG) {
352 mutex_lock(&fd->recovery_lock);
353 dev_err(fd->dev, "Handling FD VBIF Hang\n");
354 if (fd->state != MSM_FD_DEVICE_RUNNING) {
355 dev_err(fd->dev, "FD is not FD_DEVICE_RUNNING, %d\n",
356 fd->state);
357 mutex_unlock(&fd->recovery_lock);
358 return 0;
359 }
360 fd->recovery_mode = 1;
361
362 /* Halt and reset */
363 msm_fd_hw_put(fd);
364 msm_fd_hw_get(fd, ctx->settings.speed);
365
366 /* Get active buffer */
367 MSM_FD_SPIN_LOCK(fd->slock, 1);
368 active_buf = msm_fd_hw_get_active_buffer(fd, 1);
369 MSM_FD_SPIN_UNLOCK(fd->slock, 1);
370
371 if (active_buf == NULL) {
372 dev_dbg(fd->dev, "no active buffer, return\n");
373 fd->recovery_mode = 0;
374 mutex_unlock(&fd->recovery_lock);
375 return 0;
376 }
377
378 dev_dbg(fd->dev, "Active Buffer present.. Start re-schedule\n");
379
380 /* Queue the buffer again */
381 msm_fd_hw_add_buffer(fd, active_buf);
382
383 /* Schedule and restart */
384 ret = msm_fd_hw_schedule_next_buffer(fd, 1);
385 if (ret) {
386 dev_err(fd->dev, "Cannot reschedule buffer, recovery failed\n");
387 fd->recovery_mode = 0;
388 mutex_unlock(&fd->recovery_lock);
389 return ret;
390 }
391 dev_dbg(fd->dev, "Restarted FD after VBIF HAng\n");
392 mutex_unlock(&fd->recovery_lock);
393 }
394 return 0;
395}
396
397/*
398 * msm_fd_open - Fd device open method.
399 * @file: Pointer to file struct.
400 */
401static int msm_fd_open(struct file *file)
402{
403 struct msm_fd_device *device = video_drvdata(file);
404 struct video_device *video = video_devdata(file);
405 struct fd_ctx *ctx;
406 int ret;
407
408 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
409 if (!ctx)
410 return -ENOMEM;
411
412 ctx->fd_device = device;
413
414 /* Initialize work buffer handler */
415 ctx->work_buf.pool = NULL;
416 ctx->work_buf.fd = -1;
417
418 /* Set ctx defaults */
419 ctx->settings.speed = ctx->fd_device->clk_rates_num - 1;
420 ctx->settings.angle_index = MSM_FD_DEF_ANGLE_IDX;
421 ctx->settings.direction_index = MSM_FD_DEF_DIR_IDX;
422 ctx->settings.min_size_index = MSM_FD_DEF_MIN_SIZE_IDX;
423 ctx->settings.threshold = MSM_FD_DEF_THRESHOLD;
424
425 atomic_set(&ctx->subscribed_for_event, 0);
426
427 v4l2_fh_init(&ctx->fh, video);
428
429 file->private_data = &ctx->fh;
430 v4l2_fh_add(&ctx->fh);
431
432 ctx->vb2_q.drv_priv = ctx;
433 ctx->vb2_q.mem_ops = &msm_fd_vb2_mem_ops;
434 ctx->vb2_q.ops = &msm_fd_vb2_q_ops;
435 ctx->vb2_q.buf_struct_size = sizeof(struct msm_fd_buffer);
436 ctx->vb2_q.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
437 ctx->vb2_q.io_modes = VB2_USERPTR;
438 ctx->vb2_q.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
439 mutex_init(&ctx->lock);
440 ret = vb2_queue_init(&ctx->vb2_q);
441 if (ret < 0) {
442 dev_err(device->dev, "Error queue init\n");
443 goto error_vb2_queue_init;
444 }
445
446 ctx->mem_pool.fd_device = ctx->fd_device;
447 ctx->stats = vmalloc(sizeof(*ctx->stats) * MSM_FD_MAX_RESULT_BUFS);
448 if (!ctx->stats) {
449 dev_err(device->dev, "No memory for face statistics\n");
450 ret = -ENOMEM;
451 goto error_stats_vmalloc;
452 }
453
454 ret = cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_FD,
455 CAM_AHB_SVS_VOTE);
456 if (ret < 0) {
457 pr_err("%s: failed to vote for AHB\n", __func__);
458 goto error_ahb_config;
459 }
460
461 /* Register with CPP VBIF error handler */
462 msm_cpp_vbif_register_error_handler((void *)ctx,
463 VBIF_CLIENT_FD, msm_fd_vbif_error_handler);
464
465 return 0;
466
467error_ahb_config:
468 vfree(ctx->stats);
469error_stats_vmalloc:
470 vb2_queue_release(&ctx->vb2_q);
471error_vb2_queue_init:
472 v4l2_fh_del(&ctx->fh);
473 v4l2_fh_exit(&ctx->fh);
474 kfree(ctx);
475 return ret;
476}
477
478/*
479 * msm_fd_release - Fd device release method.
480 * @file: Pointer to file struct.
481 */
482static int msm_fd_release(struct file *file)
483{
484 struct fd_ctx *ctx = msm_fd_ctx_from_fh(file->private_data);
485
486 /* Un-register with CPP VBIF error handler */
487 msm_cpp_vbif_register_error_handler((void *)ctx,
488 VBIF_CLIENT_FD, NULL);
489
490 mutex_lock(&ctx->lock);
491 vb2_queue_release(&ctx->vb2_q);
492 mutex_unlock(&ctx->lock);
493
494 vfree(ctx->stats);
495
496 if (ctx->work_buf.fd != -1)
497 msm_fd_hw_unmap_buffer(&ctx->work_buf);
498
499 v4l2_fh_del(&ctx->fh);
500 v4l2_fh_exit(&ctx->fh);
501
502 kfree(ctx);
503
504 if (cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_FD,
505 CAM_AHB_SUSPEND_VOTE) < 0)
506 pr_err("%s: failed to remove vote for AHB\n", __func__);
507
508 return 0;
509}
510
511/*
512 * msm_fd_poll - Fd device pool method.
513 * @file: Pointer to file struct.
514 * @wait: Pointer to pool table struct.
515 */
516static unsigned int msm_fd_poll(struct file *file,
517 struct poll_table_struct *wait)
518{
519 struct fd_ctx *ctx = msm_fd_ctx_from_fh(file->private_data);
520 unsigned int ret;
521
522 mutex_lock(&ctx->lock);
523 ret = vb2_poll(&ctx->vb2_q, file, wait);
524 mutex_unlock(&ctx->lock);
525
526 if (atomic_read(&ctx->subscribed_for_event)) {
527 poll_wait(file, &ctx->fh.wait, wait);
528 if (v4l2_event_pending(&ctx->fh))
529 ret |= POLLPRI;
530 }
531
532 return ret;
533}
534
535/*
536 * msm_fd_private_ioctl - V4l2 private ioctl handler.
537 * @file: Pointer to file struct.
538 * @fd: V4l2 device file handle.
539 * @valid_prio: Priority ioctl valid flag.
540 * @cmd: Ioctl command.
541 * @arg: Ioctl argument.
542 */
543static long msm_fd_private_ioctl(struct file *file, void *fh,
544 bool valid_prio, unsigned int cmd, void *arg)
545{
546 struct msm_fd_result *req_result = arg;
547 struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh);
548 struct msm_fd_stats *stats;
549 int stats_idx;
550 int ret = 0;
551 int i;
552
553 switch (cmd) {
554 case VIDIOC_MSM_FD_GET_RESULT:
555 if (req_result->frame_id == 0) {
556 dev_err(ctx->fd_device->dev, "Invalid frame id\n");
557 return -EINVAL;
558 }
559
560 stats_idx = req_result->frame_id % MSM_FD_MAX_RESULT_BUFS;
561 stats = &ctx->stats[stats_idx];
562 if (req_result->frame_id != atomic_read(&stats->frame_id)) {
563 dev_err(ctx->fd_device->dev, "Stats not available\n");
564 return -EINVAL;
565 }
566
567 if (req_result->face_cnt > stats->face_cnt)
568 req_result->face_cnt = stats->face_cnt;
569
570 for (i = 0; i < req_result->face_cnt; i++) {
571 ret = copy_to_user((void __user *)
572 &req_result->face_data[i],
573 &stats->face_data[i],
574 sizeof(struct msm_fd_face_data));
575 if (ret) {
576 dev_err(ctx->fd_device->dev, "Copy to user\n");
577 return -EFAULT;
578 }
579 }
580
581 if (req_result->frame_id != atomic_read(&stats->frame_id)) {
582 dev_err(ctx->fd_device->dev, "Erroneous buffer\n");
583 return -EINVAL;
584 }
585 break;
586 default:
587 dev_err(ctx->fd_device->dev, "Wrong ioctl type %x\n", cmd);
588 ret = -ENOTTY;
589 break;
590 }
591
592 return ret;
593}
594
595#ifdef CONFIG_COMPAT
596/*
597 * msm_fd_compat_ioctl32 - Compat ioctl handler function.
598 * @file: Pointer to file struct.
599 * @cmd: Ioctl command.
600 * @arg: Ioctl argument.
601 */
602static long msm_fd_compat_ioctl32(struct file *file,
603 unsigned int cmd, unsigned long arg)
604{
605 long ret;
606
607 switch (cmd) {
608 case VIDIOC_MSM_FD_GET_RESULT32:
609 {
610 struct msm_fd_result32 result32;
611 struct msm_fd_result result;
612
613 if (copy_from_user(&result32, (void __user *)arg,
614 sizeof(result32)))
615 return -EFAULT;
616
617 result.frame_id = result32.frame_id;
618 result.face_cnt = result32.face_cnt;
619 result.face_data = compat_ptr(result32.face_data);
620
621 ret = msm_fd_private_ioctl(file, file->private_data,
622 0, VIDIOC_MSM_FD_GET_RESULT, (void *)&result);
623
624 result32.frame_id = result.frame_id;
625 result32.face_cnt = result.face_cnt;
626
627 if (copy_to_user((void __user *)arg, &result32,
628 sizeof(result32)))
629 return -EFAULT;
630
631 break;
632 }
633 default:
634 ret = -ENOIOCTLCMD;
635 break;
636
637 }
638
639 return ret;
640}
641#endif
642
643/* Fd device file operations callbacks */
644static const struct v4l2_file_operations fd_fops = {
645 .owner = THIS_MODULE,
646 .open = msm_fd_open,
647 .release = msm_fd_release,
648 .poll = msm_fd_poll,
649 .unlocked_ioctl = video_ioctl2,
650#ifdef CONFIG_COMPAT
651 .compat_ioctl32 = msm_fd_compat_ioctl32,
652#endif
653};
654
655/*
656 * msm_fd_querycap - V4l2 ioctl query capability handler.
657 * @file: Pointer to file struct.
658 * @fh: V4l2 File handle.
659 * @cap: Pointer to v4l2_capability struct need to be filled.
660 */
661static int msm_fd_querycap(struct file *file,
662 void *fh, struct v4l2_capability *cap)
663{
664 cap->bus_info[0] = 0;
665 strlcpy(cap->driver, MSM_FD_DRV_NAME, sizeof(cap->driver));
666 strlcpy(cap->card, MSM_FD_DRV_NAME, sizeof(cap->card));
667 cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_OUTPUT;
668
669 return 0;
670}
671
672/*
673 * msm_fd_enum_fmt_vid_out - V4l2 ioctl enumerate format handler.
674 * @file: Pointer to file struct.
675 * @fh: V4l2 File handle.
676 * @f: Pointer to v4l2_fmtdesc struct need to be filled.
677 */
678static int msm_fd_enum_fmt_vid_out(struct file *file,
679 void *fh, struct v4l2_fmtdesc *f)
680{
681 if (f->index > 0)
682 return -EINVAL;
683
684 f->pixelformat = V4L2_PIX_FMT_GREY;
685 strlcpy(f->description, "8 Greyscale",
686 sizeof(f->description));
687
688 return 0;
689}
690
691/*
692 * msm_fd_g_fmt - V4l2 ioctl get format handler.
693 * @file: Pointer to file struct.
694 * @fh: V4l2 File handle.
695 * @f: Pointer to v4l2_format struct need to be filled.
696 */
697static int msm_fd_g_fmt(struct file *file, void *fh, struct v4l2_format *f)
698{
699 struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh);
700
701 return msm_fd_fill_format_from_ctx(f, ctx);
702}
703
704/*
705 * msm_fd_try_fmt_vid_out - V4l2 ioctl try format handler.
706 * @file: Pointer to file struct.
707 * @fh: V4l2 File handle.
708 * @f: Pointer to v4l2_format struct.
709 */
710static int msm_fd_try_fmt_vid_out(struct file *file,
711 void *fh, struct v4l2_format *f)
712{
713 int index;
714
715 index = msm_fd_get_format_index(f);
716
717 return msm_fd_fill_format_from_index(f, index);
718}
719
720/*
721 * msm_fd_s_fmt_vid_out - V4l2 ioctl set format handler.
722 * @file: Pointer to file struct.
723 * @fh: V4l2 File handle.
724 * @f: Pointer to v4l2_format struct.
725 */
726static int msm_fd_s_fmt_vid_out(struct file *file,
727 void *fh, struct v4l2_format *f)
728{
729 struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh);
730 int index;
731
732 index = msm_fd_get_format_index(f);
733
734 msm_fd_fill_format_from_index(f, index);
735
736 ctx->format.size = &fd_size[index];
737 ctx->format.pixelformat = f->fmt.pix.pixelformat;
738 ctx->format.bytesperline = f->fmt.pix.bytesperline;
739 ctx->format.sizeimage = f->fmt.pix.sizeimage;
740
741 /* Initialize crop */
742 ctx->format.crop.top = 0;
743 ctx->format.crop.left = 0;
744 ctx->format.crop.width = fd_size[index].width;
745 ctx->format.crop.height = fd_size[index].height;
746
747 return 0;
748}
749
750/*
751 * msm_fd_reqbufs - V4l2 ioctl request buffers handler.
752 * @file: Pointer to file struct.
753 * @fh: V4l2 File handle.
754 * @req: Pointer to v4l2_requestbuffer struct.
755 */
756static int msm_fd_reqbufs(struct file *file,
757 void *fh, struct v4l2_requestbuffers *req)
758{
759 int ret;
760 struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh);
761
762 mutex_lock(&ctx->lock);
763 ret = vb2_reqbufs(&ctx->vb2_q, req);
764 mutex_unlock(&ctx->lock);
765 return ret;
766}
767
768/*
769 * msm_fd_qbuf - V4l2 ioctl queue buffer handler.
770 * @file: Pointer to file struct.
771 * @fh: V4l2 File handle.
772 * @pb: Pointer to v4l2_buffer struct.
773 */
774static int msm_fd_qbuf(struct file *file, void *fh,
775 struct v4l2_buffer *pb)
776{
777 int ret;
778 struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh);
779
780 mutex_lock(&ctx->lock);
781 ret = vb2_qbuf(&ctx->vb2_q, pb);
782 mutex_unlock(&ctx->lock);
783 return ret;
784
785}
786
787/*
788 * msm_fd_dqbuf - V4l2 ioctl dequeue buffer handler.
789 * @file: Pointer to file struct.
790 * @fh: V4l2 File handle.
791 * @pb: Pointer to v4l2_buffer struct.
792 */
793static int msm_fd_dqbuf(struct file *file,
794 void *fh, struct v4l2_buffer *pb)
795{
796 int ret;
797 struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh);
798
799 mutex_lock(&ctx->lock);
800 ret = vb2_dqbuf(&ctx->vb2_q, pb, file->f_flags & O_NONBLOCK);
801 mutex_unlock(&ctx->lock);
802 return ret;
803}
804
805/*
806 * msm_fd_streamon - V4l2 ioctl stream on handler.
807 * @file: Pointer to file struct.
808 * @fh: V4l2 File handle.
809 * @buf_type: V4l2 buffer type.
810 */
811static int msm_fd_streamon(struct file *file,
812 void *fh, enum v4l2_buf_type buf_type)
813{
814 struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh);
815 int ret;
816
817 mutex_lock(&ctx->lock);
818 ret = vb2_streamon(&ctx->vb2_q, buf_type);
819 mutex_unlock(&ctx->lock);
820 if (ret < 0)
821 dev_err(ctx->fd_device->dev, "Stream on fails\n");
822
823 return ret;
824}
825
826/*
827 * msm_fd_streamoff - V4l2 ioctl stream off handler.
828 * @file: Pointer to file struct.
829 * @fh: V4l2 File handle.
830 * @buf_type: V4l2 buffer type.
831 */
832static int msm_fd_streamoff(struct file *file,
833 void *fh, enum v4l2_buf_type buf_type)
834{
835 struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh);
836 int ret;
837
838 mutex_lock(&ctx->lock);
839 ret = vb2_streamoff(&ctx->vb2_q, buf_type);
840 mutex_unlock(&ctx->lock);
841 if (ret < 0)
842 dev_err(ctx->fd_device->dev, "Stream off fails\n");
843
844 return ret;
845}
846
847/*
848 * msm_fd_subscribe_event - V4l2 ioctl subscribe for event handler.
849 * @fh: V4l2 File handle.
850 * @sub: Pointer to v4l2_event_subscription containing event information.
851 */
852static int msm_fd_subscribe_event(struct v4l2_fh *fh,
853 const struct v4l2_event_subscription *sub)
854{
855 struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh);
856 int ret;
857
858 if (sub->type != MSM_EVENT_FD)
859 return -EINVAL;
860
861 ret = v4l2_event_subscribe(fh, sub, MSM_FD_MAX_RESULT_BUFS, NULL);
862 if (!ret)
863 atomic_set(&ctx->subscribed_for_event, 1);
864
865 return ret;
866}
867
868/*
869 * msm_fd_unsubscribe_event - V4l2 ioctl unsubscribe from event handler.
870 * @fh: V4l2 File handle.
871 * @sub: Pointer to v4l2_event_subscription containing event information.
872 */
873static int msm_fd_unsubscribe_event(struct v4l2_fh *fh,
874 const struct v4l2_event_subscription *sub)
875{
876 struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh);
877 int ret;
878
879 ret = v4l2_event_unsubscribe(fh, sub);
880 if (!ret)
881 atomic_set(&ctx->subscribed_for_event, 0);
882
883 return ret;
884}
885
886/*
887 * msm_fd_guery_ctrl - V4l2 ioctl query control.
888 * @file: Pointer to file struct.
889 * @fh: V4l2 File handle.
890 * @sub: Pointer to v4l2_queryctrl struct info need to be filled based on id.
891 */
892static int msm_fd_guery_ctrl(struct file *file, void *fh,
893 struct v4l2_queryctrl *a)
894{
895 struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh);
896
897 switch (a->id) {
898 case V4L2_CID_FD_SPEED:
899 a->type = V4L2_CTRL_TYPE_INTEGER;
900 a->default_value = ctx->fd_device->clk_rates_num;
901 a->minimum = 0;
902 a->maximum = ctx->fd_device->clk_rates_num;
903 a->step = 1;
904 strlcpy(a->name, "msm fd face speed idx",
905 sizeof(a->name));
906 break;
907 case V4L2_CID_FD_FACE_ANGLE:
908 a->type = V4L2_CTRL_TYPE_INTEGER;
909 a->default_value = msm_fd_angle[MSM_FD_DEF_ANGLE_IDX];
910 a->minimum = msm_fd_angle[0];
911 a->maximum = msm_fd_angle[ARRAY_SIZE(msm_fd_angle) - 1];
912 a->step = 1;
913 strlcpy(a->name, "msm fd face angle ctrl",
914 sizeof(a->name));
915 break;
916 case V4L2_CID_FD_FACE_DIRECTION:
917 a->type = V4L2_CTRL_TYPE_INTEGER;
918 a->default_value = msm_fd_dir[MSM_FD_DEF_DIR_IDX];
919 a->minimum = msm_fd_dir[0];
920 a->maximum = msm_fd_dir[ARRAY_SIZE(msm_fd_dir) - 1];
921 a->step = 1;
922 strlcpy(a->name, "msm fd face direction ctrl",
923 sizeof(a->name));
924 break;
925 case V4L2_CID_FD_MIN_FACE_SIZE:
926 a->type = V4L2_CTRL_TYPE_INTEGER;
927 a->default_value = msm_fd_min_size[MSM_FD_DEF_MIN_SIZE_IDX];
928 a->minimum = msm_fd_min_size[0];
929 a->maximum = msm_fd_min_size[ARRAY_SIZE(msm_fd_min_size) - 1];
930 a->step = 1;
931 strlcpy(a->name, "msm fd minimum face size (pixels)",
932 sizeof(a->name));
933 break;
934 case V4L2_CID_FD_DETECTION_THRESHOLD:
935 a->type = V4L2_CTRL_TYPE_INTEGER;
936 a->default_value = MSM_FD_DEF_THRESHOLD;
937 a->minimum = 0;
938 a->maximum = MSM_FD_MAX_THRESHOLD_VALUE;
939 a->step = 1;
940 strlcpy(a->name, "msm fd detection threshold",
941 sizeof(a->name));
942 break;
943 case V4L2_CID_FD_WORK_MEMORY_SIZE:
944 a->type = V4L2_CTRL_TYPE_INTEGER;
945 a->default_value = fd_size[0].work_size;
946 a->minimum = fd_size[(ARRAY_SIZE(fd_size) - 1)].work_size;
947 a->maximum = fd_size[0].work_size;
948 a->step = 1;
949 strlcpy(a->name, "msm fd working memory size",
950 sizeof(a->name));
951 break;
952 case V4L2_CID_FD_WORK_MEMORY_FD:
953 a->type = V4L2_CTRL_TYPE_INTEGER;
954 a->default_value = -1;
955 a->minimum = 0;
956 a->maximum = INT_MAX;
957 a->step = 1;
958 strlcpy(a->name, "msm fd ion fd of working memory",
959 sizeof(a->name));
960 break;
961 default:
962 return -EINVAL;
963 }
964
965 return 0;
966}
967
968/*
969 * msm_fd_g_ctrl - V4l2 ioctl get control.
970 * @file: Pointer to file struct.
971 * @fh: V4l2 File handle.
972 * @sub: Pointer to v4l2_queryctrl struct need to be filled.
973 */
974static int msm_fd_g_ctrl(struct file *file, void *fh, struct v4l2_control *a)
975{
976 struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh);
977
978 switch (a->id) {
979 case V4L2_CID_FD_SPEED:
980 a->value = ctx->settings.speed;
981 break;
982 case V4L2_CID_FD_FACE_ANGLE:
983 a->value = msm_fd_angle[ctx->settings.angle_index];
984 break;
985 case V4L2_CID_FD_FACE_DIRECTION:
986 a->value = msm_fd_dir[ctx->settings.direction_index];
987 break;
988 case V4L2_CID_FD_MIN_FACE_SIZE:
989 a->value = msm_fd_min_size[ctx->settings.min_size_index];
990 break;
991 case V4L2_CID_FD_DETECTION_THRESHOLD:
992 a->value = ctx->settings.threshold;
993 break;
994 case V4L2_CID_FD_WORK_MEMORY_SIZE:
995 if (!ctx->format.size)
996 return -EINVAL;
997
998 a->value = ctx->format.size->work_size;
999 break;
1000 case V4L2_CID_FD_WORK_MEMORY_FD:
1001 if (ctx->work_buf.fd == -1)
1002 return -EINVAL;
1003
1004 a->value = ctx->work_buf.fd;
1005 break;
1006 default:
1007 return -EINVAL;
1008 }
1009
1010 return 0;
1011}
1012
1013/*
1014 * msm_fd_s_ctrl - V4l2 ioctl set control.
1015 * @file: Pointer to file struct.
1016 * @fh: V4l2 File handle.
1017 * @sub: Pointer to v4l2_queryctrl struct need to be set.
1018 */
1019static int msm_fd_s_ctrl(struct file *file, void *fh, struct v4l2_control *a)
1020{
1021 struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh);
1022 int idx;
1023 int ret;
1024
1025 switch (a->id) {
1026 case V4L2_CID_FD_SPEED:
1027 if (a->value > ctx->fd_device->clk_rates_num - 1)
1028 a->value = ctx->fd_device->clk_rates_num - 1;
1029 else if (a->value < 0)
1030 a->value = 0;
1031
1032 ctx->settings.speed = a->value;
1033 break;
1034 case V4L2_CID_FD_FACE_ANGLE:
1035 idx = msm_fd_get_idx_from_value(a->value, msm_fd_angle,
1036 ARRAY_SIZE(msm_fd_angle));
1037
1038 ctx->settings.angle_index = idx;
1039 a->value = msm_fd_angle[ctx->settings.angle_index];
1040 break;
1041 case V4L2_CID_FD_FACE_DIRECTION:
1042 idx = msm_fd_get_idx_from_value(a->value, msm_fd_dir,
1043 ARRAY_SIZE(msm_fd_dir));
1044
1045 ctx->settings.direction_index = idx;
1046 a->value = msm_fd_dir[ctx->settings.direction_index];
1047 break;
1048 case V4L2_CID_FD_MIN_FACE_SIZE:
1049 idx = msm_fd_get_idx_from_value(a->value, msm_fd_min_size,
1050 ARRAY_SIZE(msm_fd_min_size));
1051
1052 ctx->settings.min_size_index = idx;
1053 a->value = msm_fd_min_size[ctx->settings.min_size_index];
1054 break;
1055 case V4L2_CID_FD_DETECTION_THRESHOLD:
1056 if (a->value > MSM_FD_MAX_THRESHOLD_VALUE)
1057 a->value = MSM_FD_MAX_THRESHOLD_VALUE;
1058 else if (a->value < 0)
1059 a->value = 0;
1060
1061 ctx->settings.threshold = a->value;
1062 break;
1063 case V4L2_CID_FD_WORK_MEMORY_SIZE:
1064 if (!ctx->format.size)
1065 return -EINVAL;
1066
1067 if (a->value < ctx->format.size->work_size)
1068 a->value = ctx->format.size->work_size;
1069 break;
1070 case V4L2_CID_FD_WORK_MEMORY_FD:
1071 mutex_lock(&ctx->fd_device->recovery_lock);
1072 if (ctx->work_buf.fd != -1)
1073 msm_fd_hw_unmap_buffer(&ctx->work_buf);
1074 if (a->value >= 0) {
1075 ret = msm_fd_hw_map_buffer(&ctx->mem_pool,
1076 a->value, &ctx->work_buf);
1077 if (ret < 0) {
1078 mutex_unlock(&ctx->fd_device->recovery_lock);
1079 return ret;
1080 }
1081 }
1082 mutex_unlock(&ctx->fd_device->recovery_lock);
1083 break;
1084 default:
1085 return -EINVAL;
1086 }
1087
1088 return 0;
1089}
1090
1091/*
1092 * msm_fd_cropcap - V4l2 ioctl crop capabilities.
1093 * @file: Pointer to file struct.
1094 * @fh: V4l2 File handle.
1095 * @sub: Pointer to v4l2_cropcap struct need to be set.
1096 */
1097static int msm_fd_cropcap(struct file *file, void *fh, struct v4l2_cropcap *a)
1098{
1099 struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh);
1100
1101 if (!ctx->format.size) {
1102 dev_err(ctx->fd_device->dev, "Cropcap fails format missing\n");
1103 return -EINVAL;
1104 }
1105
1106 a->bounds.top = 0;
1107 a->bounds.left = 0;
1108 a->bounds.width = ctx->format.size->width;
1109 a->bounds.height = ctx->format.size->height;
1110
1111 a->defrect = ctx->format.crop;
1112
1113 a->pixelaspect.numerator = 1;
1114 a->pixelaspect.denominator = 1;
1115
1116 return 0;
1117}
1118
1119/*
1120 * msm_fd_g_crop - V4l2 ioctl get crop.
1121 * @file: Pointer to file struct.
1122 * @fh: V4l2 File handle.
1123 * @sub: Pointer to v4l2_crop struct need to be set.
1124 */
1125static int msm_fd_g_crop(struct file *file, void *fh, struct v4l2_crop *crop)
1126{
1127 struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh);
1128
1129 if (!ctx->format.size) {
1130 dev_err(ctx->fd_device->dev, "Get crop, format missing!\n");
1131 return -EINVAL;
1132 }
1133
1134 crop->c = ctx->format.crop;
1135
1136 return 0;
1137}
1138
1139/*
1140 * msm_fd_s_crop - V4l2 ioctl set crop.
1141 * @file: Pointer to file struct.
1142 * @fh: V4l2 File handle.
1143 * @sub: Pointer to v4l2_crop struct need to be set.
1144 */
1145static int msm_fd_s_crop(struct file *file, void *fh,
1146 const struct v4l2_crop *crop)
1147{
1148 struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh);
1149 int min_face_size;
1150
1151 if (!ctx->format.size) {
1152 dev_err(ctx->fd_device->dev, "Get crop, format missing!\n");
1153 return -EINVAL;
1154 }
1155
1156 /* First check that crop is valid */
1157 min_face_size = msm_fd_min_size[ctx->settings.min_size_index];
1158
1159 if (crop->c.width < min_face_size || crop->c.height < min_face_size)
1160 return -EINVAL;
1161
1162 if (crop->c.width + crop->c.left > ctx->format.size->width)
1163 return -EINVAL;
1164
1165 if (crop->c.height + crop->c.top > ctx->format.size->height)
1166 return -EINVAL;
1167
1168 ctx->format.crop = crop->c;
1169
1170 return 0;
1171}
1172
1173/* V4l2 ioctl handlers */
1174static const struct v4l2_ioctl_ops fd_ioctl_ops = {
1175 .vidioc_querycap = msm_fd_querycap,
1176 .vidioc_enum_fmt_vid_out = msm_fd_enum_fmt_vid_out,
1177 .vidioc_g_fmt_vid_out = msm_fd_g_fmt,
1178 .vidioc_try_fmt_vid_out = msm_fd_try_fmt_vid_out,
1179 .vidioc_s_fmt_vid_out = msm_fd_s_fmt_vid_out,
1180 .vidioc_reqbufs = msm_fd_reqbufs,
1181 .vidioc_qbuf = msm_fd_qbuf,
1182 .vidioc_dqbuf = msm_fd_dqbuf,
1183 .vidioc_streamon = msm_fd_streamon,
1184 .vidioc_streamoff = msm_fd_streamoff,
1185 .vidioc_queryctrl = msm_fd_guery_ctrl,
1186 .vidioc_s_ctrl = msm_fd_s_ctrl,
1187 .vidioc_g_ctrl = msm_fd_g_ctrl,
1188 .vidioc_cropcap = msm_fd_cropcap,
1189 .vidioc_g_crop = msm_fd_g_crop,
1190 .vidioc_s_crop = msm_fd_s_crop,
1191 .vidioc_subscribe_event = msm_fd_subscribe_event,
1192 .vidioc_unsubscribe_event = msm_fd_unsubscribe_event,
1193 .vidioc_default = msm_fd_private_ioctl,
1194};
1195
1196/*
1197 * msm_fd_fill_results - Read and fill face detection result.
1198 * @fd: Pointer to fd device.
1199 * @face: Pointer of face data which information need to be stored.
1200 * @idx: Face number index need to be filled.
1201 */
1202static void msm_fd_fill_results(struct msm_fd_device *fd,
1203 struct msm_fd_face_data *face, int idx)
1204{
1205 int half_face_size;
1206
1207 msm_fd_hw_get_result_angle_pose(fd, idx, &face->angle, &face->pose);
1208
1209 msm_fd_hw_get_result_conf_size(fd, idx, &face->confidence,
1210 &face->face.width);
1211 face->face.height = face->face.width;
1212
1213 face->face.left = msm_fd_hw_get_result_x(fd, idx);
1214 face->face.top = msm_fd_hw_get_result_y(fd, idx);
1215
1216 half_face_size = (face->face.width >> 1);
1217 if (face->face.left > half_face_size)
1218 face->face.left -= half_face_size;
1219 else
1220 face->face.left = 0;
1221
1222 half_face_size = (face->face.height >> 1);
1223 if (face->face.top > half_face_size)
1224 face->face.top -= half_face_size;
1225 else
1226 face->face.top = 0;
1227}
1228
1229/*
1230 * msm_fd_wq_handler - Fd device workqueue handler.
1231 * @work: Pointer to work struct.
1232 *
1233 * This function is bottom half of fd irq what it does:
1234 *
1235 * - Stop the fd engine.
1236 * - Getter fd result and store in stats buffer.
1237 * - If available schedule next buffer for processing.
1238 * - Sent event to v4l2.
1239 * - Release buffer from v4l2 queue.
1240 */
1241static void msm_fd_wq_handler(struct work_struct *work)
1242{
1243 struct msm_fd_buffer *active_buf;
1244 struct msm_fd_stats *stats;
1245 struct msm_fd_event *fd_event;
1246 struct msm_fd_device *fd;
1247 struct fd_ctx *ctx;
1248 struct v4l2_event event;
1249 int i;
1250
1251 fd = container_of(work, struct msm_fd_device, work);
1252 MSM_FD_SPIN_LOCK(fd->slock, 1);
1253 active_buf = msm_fd_hw_get_active_buffer(fd, 0);
1254 if (!active_buf) {
1255 /* This should never happen, something completely wrong */
1256 dev_err(fd->dev, "Oops no active buffer empty queue\n");
1257 MSM_FD_SPIN_UNLOCK(fd->slock, 1);
1258 return;
1259 }
1260 ctx = vb2_get_drv_priv(active_buf->vb_v4l2_buf.vb2_buf.vb2_queue);
1261
1262 /* Increment sequence number, 0 means sequence is not valid */
1263 ctx->sequence++;
1264 if (unlikely(!ctx->sequence))
1265 ctx->sequence = 1;
1266
1267 /* Fill face detection statistics */
1268 stats = &ctx->stats[ctx->sequence % MSM_FD_MAX_RESULT_BUFS];
1269
1270 /* First mark stats as invalid */
1271 atomic_set(&stats->frame_id, 0);
1272
1273 stats->face_cnt = msm_fd_hw_get_face_count(fd);
1274 for (i = 0; i < stats->face_cnt; i++)
1275 msm_fd_fill_results(fd, &stats->face_data[i], i);
1276
1277 /* Stats are ready, set correct frame id */
1278 atomic_set(&stats->frame_id, ctx->sequence);
1279
1280 /* If Recovery mode is on, we got IRQ after recovery, reset it */
1281 if (fd->recovery_mode) {
1282 fd->recovery_mode = 0;
1283 dev_dbg(fd->dev, "Got IRQ after Recovery\n");
1284 }
1285
1286 if (fd->state == MSM_FD_DEVICE_RUNNING) {
1287 /* We have the data from fd hw, we can start next processing */
1288 msm_fd_hw_schedule_next_buffer(fd, 0);
1289 }
1290
1291 /* Return buffer to vb queue */
1292 active_buf->vb_v4l2_buf.sequence = ctx->fh.sequence;
1293 vb2_buffer_done(&active_buf->vb_v4l2_buf.vb2_buf, VB2_BUF_STATE_DONE);
1294
1295 /* Sent event */
1296 memset(&event, 0x00, sizeof(event));
1297 event.type = MSM_EVENT_FD;
1298 fd_event = (struct msm_fd_event *)event.u.data;
1299 fd_event->face_cnt = stats->face_cnt;
1300 fd_event->buf_index = active_buf->vb_v4l2_buf.vb2_buf.index;
1301 fd_event->frame_id = ctx->sequence;
1302 v4l2_event_queue_fh(&ctx->fh, &event);
1303
1304 /* Release buffer from the device */
1305 msm_fd_hw_buffer_done(fd, active_buf, 0);
1306
1307 MSM_FD_SPIN_UNLOCK(fd->slock, 1);
1308}
1309
1310/*
1311 * fd_probe - Fd device probe method.
1312 * @pdev: Pointer fd platform device.
1313 */
1314static int fd_probe(struct platform_device *pdev)
1315{
1316 struct msm_fd_device *fd;
1317 int ret;
1318 int i;
1319
1320 /* Face detection device struct */
1321 fd = kzalloc(sizeof(struct msm_fd_device), GFP_KERNEL);
1322 if (!fd)
1323 return -ENOMEM;
1324
1325 mutex_init(&fd->lock);
1326 spin_lock_init(&fd->slock);
1327 mutex_init(&fd->recovery_lock);
1328 init_completion(&fd->hw_halt_completion);
1329 INIT_LIST_HEAD(&fd->buf_queue);
1330 fd->pdev = pdev;
1331 fd->dev = &pdev->dev;
1332
1333 /* Get resources */
1334 ret = msm_fd_hw_get_mem_resources(pdev, fd);
1335 if (ret < 0) {
1336 dev_err(&pdev->dev, "Fail get resources\n");
1337 ret = -ENODEV;
1338 goto error_mem_resources;
1339 }
1340
1341 ret = msm_camera_get_regulator_info(pdev, &fd->vdd_info,
1342 &fd->num_reg);
1343 if (ret < 0) {
1344 dev_err(&pdev->dev, "Fail to get regulators\n");
1345 goto error_get_regulator;
1346 }
1347 ret = msm_camera_get_clk_info_and_rates(pdev, &fd->clk_info,
1348 &fd->clk, &fd->clk_rates, &fd->clk_rates_num, &fd->clk_num);
1349 if (ret < 0) {
1350 dev_err(&pdev->dev, "Fail to get clocks\n");
1351 goto error_get_clocks;
1352 }
1353
1354 /*set memcore and mem periphery logic flags to 0*/
1355 for (i = 0; i < fd->clk_num; i++) {
1356 if ((strcmp(fd->clk_info[i].clk_name,
1357 "mmss_fd_core_clk") == 0) ||
1358 (strcmp(fd->clk_info[i].clk_name,
1359 "mmss_fd_core_uar_clk") == 0)) {
1360 msm_camera_set_clk_flags(fd->clk[i],
1361 CLKFLAG_NORETAIN_MEM);
1362 msm_camera_set_clk_flags(fd->clk[i],
1363 CLKFLAG_NORETAIN_PERIPH);
1364 }
1365 }
1366
1367 ret = msm_camera_register_bus_client(pdev, CAM_BUS_CLIENT_FD);
1368 if (ret < 0) {
1369 dev_err(&pdev->dev, "Fail to get bus\n");
1370 goto error_get_bus;
1371 }
1372
1373 /* Get face detect hw before read engine revision */
1374 ret = msm_fd_hw_get(fd, 0);
1375 if (ret < 0) {
1376 dev_err(&pdev->dev, "Fail to get hw\n");
1377 goto error_hw_get_request_irq;
1378 }
1379 fd->hw_revision = msm_fd_hw_get_revision(fd);
1380
1381 msm_fd_hw_put(fd);
1382
1383 ret = msm_fd_hw_request_irq(pdev, fd, msm_fd_wq_handler);
1384 if (ret < 0) {
1385 dev_err(&pdev->dev, "Fail request irq\n");
1386 goto error_hw_get_request_irq;
1387 }
1388
1389 /* v4l2 device */
1390 ret = v4l2_device_register(&pdev->dev, &fd->v4l2_dev);
1391 if (ret < 0) {
1392 dev_err(&pdev->dev, "Failed to register v4l2 device\n");
1393 ret = -ENOENT;
1394 goto error_v4l2_register;
1395 }
1396
1397 fd->video.fops = &fd_fops;
1398 fd->video.ioctl_ops = &fd_ioctl_ops;
1399 fd->video.minor = -1;
1400 fd->video.release = video_device_release;
1401 fd->video.v4l2_dev = &fd->v4l2_dev;
1402 fd->video.vfl_dir = VFL_DIR_TX;
1403 fd->video.vfl_type = VFL_TYPE_GRABBER;
1404 strlcpy(fd->video.name, MSM_FD_DRV_NAME, sizeof(fd->video.name));
1405
1406 ret = video_register_device(&fd->video, VFL_TYPE_GRABBER, -1);
1407 if (ret < 0) {
1408 v4l2_err(&fd->v4l2_dev, "Failed to register video device\n");
1409 goto error_video_register;
1410 }
1411
1412 video_set_drvdata(&fd->video, fd);
1413
1414 platform_set_drvdata(pdev, fd);
1415
1416 return 0;
1417
1418error_video_register:
1419 v4l2_device_unregister(&fd->v4l2_dev);
1420error_v4l2_register:
1421 msm_fd_hw_release_irq(fd);
1422error_hw_get_request_irq:
1423 msm_camera_unregister_bus_client(CAM_BUS_CLIENT_FD);
1424error_get_bus:
1425 msm_camera_put_clk_info_and_rates(pdev, &fd->clk_info,
1426 &fd->clk, &fd->clk_rates, fd->clk_rates_num, fd->clk_num);
1427error_get_clocks:
1428 msm_camera_put_regulators(pdev, &fd->vdd_info, fd->num_reg);
1429error_get_regulator:
1430 msm_fd_hw_release_mem_resources(fd);
1431error_mem_resources:
1432 kfree(fd);
1433 return ret;
1434}
1435
1436/*
1437 * fd_device_remove - Fd device remove method.
1438 * @pdev: Pointer fd platform device.
1439 */
1440static int fd_device_remove(struct platform_device *pdev)
1441{
1442 struct msm_fd_device *fd;
1443
1444 fd = platform_get_drvdata(pdev);
1445 if (fd == NULL) {
1446 dev_err(&pdev->dev, "Can not get fd drvdata\n");
1447 return 0;
1448 }
1449 video_unregister_device(&fd->video);
1450 v4l2_device_unregister(&fd->v4l2_dev);
1451 msm_fd_hw_release_irq(fd);
1452 msm_camera_unregister_bus_client(CAM_BUS_CLIENT_FD);
1453 msm_camera_put_clk_info_and_rates(pdev, &fd->clk_info,
1454 &fd->clk, &fd->clk_rates, fd->clk_rates_num, fd->clk_num);
1455 msm_camera_put_regulators(pdev, &fd->vdd_info, fd->num_reg);
1456 msm_fd_hw_release_mem_resources(fd);
1457 kfree(fd);
1458
1459 return 0;
1460}
1461
1462/* Device tree match struct */
1463static const struct of_device_id msm_fd_dt_match[] = {
1464 {.compatible = "qcom,face-detection"},
1465 {}
1466};
1467
1468/* Fd platform driver definition */
1469static struct platform_driver fd_driver = {
1470 .probe = fd_probe,
1471 .remove = fd_device_remove,
1472 .driver = {
1473 .name = MSM_FD_DRV_NAME,
1474 .owner = THIS_MODULE,
1475 .of_match_table = msm_fd_dt_match,
1476 },
1477};
1478
1479static int __init msm_fd_init_module(void)
1480{
1481 return platform_driver_register(&fd_driver);
1482}
1483
1484static void __exit msm_fd_exit_module(void)
1485{
1486 platform_driver_unregister(&fd_driver);
1487}
1488
1489module_init(msm_fd_init_module);
1490module_exit(msm_fd_exit_module);
1491MODULE_DESCRIPTION("MSM FD driver");
1492MODULE_LICENSE("GPL v2");