/drivers/media/video/samsung/fimc/fimc_capture.c
https://github.com/dastin1015/android_kernel_samsung_smdk4210 · C · 3475 lines · 2789 code · 511 blank · 175 comment · 619 complexity · d33bd73fb31f967958d3b8e70bb8acec MD5 · raw file
Large files are truncated click here to view the full file
- /* linux/drivers/media/video/samsung/fimc_capture.c
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * V4L2 Capture device support file for Samsung Camera Interface (FIMC) driver
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
- #include <linux/slab.h>
- #include <linux/bootmem.h>
- #include <linux/string.h>
- #include <linux/platform_device.h>
- #include <linux/videodev2.h>
- #include <linux/videodev2_exynos_media.h>
- #include <linux/videodev2_exynos_camera.h>
- #include <linux/clk.h>
- #include <linux/mm.h>
- #include <linux/dma-mapping.h>
- #include <linux/io.h>
- #include <linux/uaccess.h>
- #include <plat/media.h>
- #include <plat/clock.h>
- #include <plat/fimc.h>
- #include <linux/delay.h>
- #include <asm/cacheflush.h>
- #include <linux/pm_qos_params.h>
- #include "fimc.h"
- static struct pm_qos_request_list bus_qos_pm_qos_req;
- static const struct v4l2_fmtdesc capture_fmts[] = {
- {
- .index = 0,
- .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- .flags = FORMAT_FLAGS_PACKED,
- .description = "RGB-5-6-5",
- .pixelformat = V4L2_PIX_FMT_RGB565,
- }, {
- .index = 1,
- .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- .flags = FORMAT_FLAGS_PACKED,
- .description = "RGB-8-8-8, unpacked 24 bpp",
- .pixelformat = V4L2_PIX_FMT_RGB32,
- }, {
- .index = 2,
- .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- .flags = FORMAT_FLAGS_PACKED,
- .description = "YUV 4:2:2 packed, YCbYCr",
- .pixelformat = V4L2_PIX_FMT_YUYV,
- }, {
- .index = 3,
- .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- .flags = FORMAT_FLAGS_PACKED,
- .description = "YUV 4:2:2 packed, CbYCrY",
- .pixelformat = V4L2_PIX_FMT_UYVY,
- }, {
- .index = 4,
- .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- .flags = FORMAT_FLAGS_PACKED,
- .description = "YUV 4:2:2 packed, CrYCbY",
- .pixelformat = V4L2_PIX_FMT_VYUY,
- }, {
- .index = 5,
- .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- .flags = FORMAT_FLAGS_PACKED,
- .description = "YUV 4:2:2 packed, YCrYCb",
- .pixelformat = V4L2_PIX_FMT_YVYU,
- }, {
- .index = 6,
- .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- .flags = FORMAT_FLAGS_PLANAR,
- .description = "YUV 4:2:2 planar, Y/Cb/Cr",
- .pixelformat = V4L2_PIX_FMT_YUV422P,
- }, {
- .index = 7,
- .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- .flags = FORMAT_FLAGS_PLANAR,
- .description = "YUV 4:2:0 planar, Y/CbCr",
- .pixelformat = V4L2_PIX_FMT_NV12,
- }, {
- .index = 8,
- .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- .flags = FORMAT_FLAGS_PLANAR,
- .description = "YUV 4:2:0 planar, Y/CbCr, Tiled",
- .pixelformat = V4L2_PIX_FMT_NV12T,
- }, {
- .index = 9,
- .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- .flags = FORMAT_FLAGS_PLANAR,
- .description = "YUV 4:2:0 planar, Y/CrCb",
- .pixelformat = V4L2_PIX_FMT_NV21,
- }, {
- .index = 10,
- .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- .flags = FORMAT_FLAGS_PLANAR,
- .description = "YUV 4:2:2 planar, Y/CbCr",
- .pixelformat = V4L2_PIX_FMT_NV16,
- }, {
- .index = 11,
- .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- .flags = FORMAT_FLAGS_PLANAR,
- .description = "YUV 4:2:2 planar, Y/CrCb",
- .pixelformat = V4L2_PIX_FMT_NV61,
- }, {
- .index = 12,
- .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- .flags = FORMAT_FLAGS_PLANAR,
- .description = "YUV 4:2:0 planar, Y/Cb/Cr",
- .pixelformat = V4L2_PIX_FMT_YUV420,
- }, {
- .index = 13,
- .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- .flags = FORMAT_FLAGS_PLANAR,
- .description = "YUV 4:2:0 planar, Y/Cr/Cb",
- .pixelformat = V4L2_PIX_FMT_YVU420,
- }, {
- .index = 14,
- .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- .description = "JPEG encoded data",
- .pixelformat = V4L2_PIX_FMT_JPEG,
- }, {
- .index = 15,
- .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- .description = "Interleaved data",
- .pixelformat = V4L2_PIX_FMT_INTERLEAVED,
- },
- };
- static const struct v4l2_queryctrl fimc_controls[] = {
- {
- .id = V4L2_CID_ROTATION,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Roataion",
- .minimum = 0,
- .maximum = 270,
- .step = 90,
- .default_value = 0,
- }, {
- .id = V4L2_CID_HFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Horizontal Flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- }, {
- .id = V4L2_CID_VFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Vertical Flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- }, {
- .id = V4L2_CID_PADDR_Y,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Physical address Y",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- .flags = V4L2_CTRL_FLAG_READ_ONLY,
- }, {
- .id = V4L2_CID_PADDR_CB,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Physical address Cb",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- .flags = V4L2_CTRL_FLAG_READ_ONLY,
- }, {
- .id = V4L2_CID_PADDR_CR,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Physical address Cr",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- .flags = V4L2_CTRL_FLAG_READ_ONLY,
- }, {
- .id = V4L2_CID_PADDR_CBCR,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Physical address CbCr",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- .flags = V4L2_CTRL_FLAG_READ_ONLY,
- }, {
- .id = V4L2_CID_CACHEABLE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Cacheable",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- };
- #ifdef CONFIG_MACH_GC1
- static bool leave_power;
- #endif
- #ifndef CONFIG_VIDEO_FIMC_MIPI
- void s3c_csis_start(int csis_id, int lanes, int settle, \
- int align, int width, int height, int pixel_format) {}
- void s3c_csis_stop(int csis_id) {}
- void s3c_csis_enable_pktdata(int csis_id, bool enable) {}
- #endif
- static int fimc_init_camera(struct fimc_control *ctrl)
- {
- struct fimc_global *fimc = get_fimc_dev();
- struct s3c_platform_fimc *pdata;
- struct s3c_platform_camera *cam;
- int ret = 0, retry_cnt = 0;
- #if (defined(CONFIG_EXYNOS_DEV_PD) && defined(CONFIG_PM_RUNTIME))
- struct platform_device *pdev = to_platform_device(ctrl->dev);
- #endif
- pdata = to_fimc_plat(ctrl->dev);
- cam = ctrl->cam;
- /* do nothing if already initialized */
- if (ctrl->cam->initialized)
- return 0;
- #if (defined(CONFIG_EXYNOS_DEV_PD) && defined(CONFIG_PM_RUNTIME))
- if (ctrl->power_status == FIMC_POWER_OFF) {
- pm_runtime_get_sync(&pdev->dev);
- }
- #endif
- /*
- * WriteBack mode doesn't need to set clock and power,
- * but it needs to set source width, height depend on LCD resolution.
- */
- if ((cam->id == CAMERA_WB) || (cam->id == CAMERA_WB_B)) {
- ret = s3cfb_direct_ioctl(0, S3CFB_GET_LCD_WIDTH,
- (unsigned long)&cam->width);
- if (ret) {
- fimc_err("fail to get LCD size\n");
- #if (defined(CONFIG_EXYNOS_DEV_PD) && defined(CONFIG_PM_RUNTIME))
- pm_runtime_put_sync(&pdev->dev);
- #endif
- return ret;
- }
- ret = s3cfb_direct_ioctl(0, S3CFB_GET_LCD_HEIGHT,
- (unsigned long)&cam->height);
- if (ret) {
- fimc_err("fail to get LCD size\n");
- #if (defined(CONFIG_EXYNOS_DEV_PD) && defined(CONFIG_PM_RUNTIME))
- pm_runtime_put_sync(&pdev->dev);
- #endif
- return ret;
- }
- cam->window.width = cam->width;
- cam->window.height = cam->height;
- cam->initialized = 1;
- return ret;
- }
- retry:
- /* set rate for mclk */
- #ifndef CONFIG_MACH_GC1
- if ((clk_get_rate(cam->clk)) && (fimc->mclk_status == CAM_MCLK_OFF)) {
- #else
- if ((clk_get_rate(cam->clk)) && (fimc->mclk_status == CAM_MCLK_OFF)
- && !leave_power) {
- #endif
- clk_set_rate(cam->clk, cam->clk_rate);
- clk_enable(cam->clk);
- fimc->mclk_status = CAM_MCLK_ON;
- fimc_info1("clock for camera: %d\n", cam->clk_rate);
- }
- /* enable camera power if needed */
- if (cam->cam_power) {
- #ifndef CONFIG_MACH_GC1
- ret = cam->cam_power(1);
- #else
- if (!leave_power)
- ret = cam->cam_power(1);
- leave_power = false;
- #endif
- if (unlikely(ret < 0)) {
- fimc_err("\nfail to power on\n");
- if (fimc->mclk_status == CAM_MCLK_ON) {
- clk_disable(ctrl->cam->clk);
- fimc->mclk_status = CAM_MCLK_OFF;
- }
- #if (defined(CONFIG_EXYNOS_DEV_PD) && defined(CONFIG_PM_RUNTIME))
- pm_runtime_put_sync(&pdev->dev);
- #endif
- return ret;
- }
- }
- #ifndef CONFIG_MACH_GC1
- /* "0" argument means preview init for s5k4ea */
- ret = v4l2_subdev_call(cam->sd, core, init, 0);
- #endif
- /* Retry camera power-up if first i2c fails. */
- if (unlikely(ret < 0)) {
- if (cam->cam_power)
- cam->cam_power(0);
- if (fimc->mclk_status == CAM_MCLK_ON) {
- clk_disable(ctrl->cam->clk);
- fimc->mclk_status = CAM_MCLK_OFF;
- }
- if (retry_cnt++ < 3) {
- msleep(100);
- fimc_err("Retry power on(%d/3)\n\n", retry_cnt);
- goto retry;
- } else {
- fimc_err("Camera power/init failed!!!!\n\n");
- #if (defined(CONFIG_EXYNOS_DEV_PD) && defined(CONFIG_PM_RUNTIME))
- if (ctrl->power_status == FIMC_POWER_ON) {
- pm_runtime_put_sync(&pdev->dev);
- }
- #endif
- }
- } else {
- /* Apply things to interface register */
- fimc_hwset_reset(ctrl);
- cam->initialized = 1;
- }
- return ret;
- }
- static int fimc_camera_get_jpeg_memsize(struct fimc_control *ctrl)
- {
- int ret = 0;
- struct v4l2_control cam_ctrl;
- cam_ctrl.id = V4L2_CID_CAM_JPEG_MEMSIZE;
- ret = v4l2_subdev_call(ctrl->cam->sd, core, g_ctrl, &cam_ctrl);
- if (ret < 0) {
- fimc_err("%s: Subdev doesn't support JEPG encoding.\n", \
- __func__);
- return 0;
- }
- return cam_ctrl.value;
- }
- static int fimc_capture_scaler_info(struct fimc_control *ctrl)
- {
- struct fimc_scaler *sc = &ctrl->sc;
- struct v4l2_rect *window = &ctrl->cam->window;
- int tx, ty, sx, sy;
- struct s3c_platform_fimc *pdata = to_fimc_plat(ctrl->dev);
- int rot = 0;
- if (!ctrl->cam->use_isp) {
- sx = window->width;
- sy = window->height;
- } else {
- sx = ctrl->is.fmt.width;
- sy = ctrl->is.fmt.height;
- }
- sc->real_width = sx;
- sc->real_height = sy;
- rot = fimc_mapping_rot_flip(ctrl->cap->rotate, ctrl->cap->flip);
- if (rot & FIMC_ROT) {
- tx = ctrl->cap->fmt.height;
- ty = ctrl->cap->fmt.width;
- } else {
- tx = ctrl->cap->fmt.width;
- ty = ctrl->cap->fmt.height;
- }
- fimc_dbg("%s: CamOut (%d, %d), TargetOut (%d, %d)\n",
- __func__, sx, sy, tx, ty);
- if (sx <= 0 || sy <= 0) {
- fimc_err("%s: invalid source size\n", __func__);
- return -EINVAL;
- }
- if (tx <= 0 || ty <= 0) {
- fimc_err("%s: invalid target size\n", __func__);
- return -EINVAL;
- }
- fimc_get_scaler_factor(sx, tx, &sc->pre_hratio, &sc->hfactor);
- fimc_get_scaler_factor(sy, ty, &sc->pre_vratio, &sc->vfactor);
- if (sx == sy) {
- if (sx*10/tx >= 15 && sx*10/tx < 20) {
- sc->pre_hratio = 2;
- sc->hfactor = 1;
- }
- if (sy*10/ty >= 15 && sy*10/ty < 20) {
- sc->pre_vratio = 2;
- sc->vfactor = 1;
- }
- }
- sc->pre_dst_width = sx / sc->pre_hratio;
- sc->pre_dst_height = sy / sc->pre_vratio;
- if (pdata->hw_ver >= 0x50) {
- sc->main_hratio = (sx << 14) / (tx << sc->hfactor);
- sc->main_vratio = (sy << 14) / (ty << sc->vfactor);
- } else {
- sc->main_hratio = (sx << 8) / (tx << sc->hfactor);
- sc->main_vratio = (sy << 8) / (ty << sc->vfactor);
- }
- sc->scaleup_h = (tx >= sx) ? 1 : 0;
- sc->scaleup_v = (ty >= sy) ? 1 : 0;
- return 0;
- }
- static int fimc_capture_change_scaler_info(struct fimc_control *ctrl)
- {
- struct fimc_scaler *sc = &ctrl->sc;
- struct v4l2_rect *window = &ctrl->cam->window;
- int tx, ty, sx, sy;
- struct s3c_platform_fimc *pdata = to_fimc_plat(ctrl->dev);
- int rot = 0;
- if (!ctrl->cam->use_isp) {
- sx = window->width;
- sy = window->height;
- } else {
- sx = ctrl->is.zoom_in_width;
- sy = ctrl->is.zoom_in_height;
- }
- sc->real_width = sx;
- sc->real_height = sy;
- rot = fimc_mapping_rot_flip(ctrl->cap->rotate, ctrl->cap->flip);
- if (rot & FIMC_ROT) {
- tx = ctrl->cap->fmt.height;
- ty = ctrl->cap->fmt.width;
- } else {
- tx = ctrl->cap->fmt.width;
- ty = ctrl->cap->fmt.height;
- }
- fimc_dbg("%s: CamOut (%d, %d), TargetOut (%d, %d)\n",
- __func__, sx, sy, tx, ty);
- if (sx <= 0 || sy <= 0) {
- fimc_err("%s: invalid source size\n", __func__);
- return -EINVAL;
- }
- if (tx <= 0 || ty <= 0) {
- fimc_err("%s: invalid target size\n", __func__);
- return -EINVAL;
- }
- fimc_get_scaler_factor(sx, tx, &sc->pre_hratio, &sc->hfactor);
- fimc_get_scaler_factor(sy, ty, &sc->pre_vratio, &sc->vfactor);
- sc->pre_dst_width = sx / sc->pre_hratio;
- sc->pre_dst_height = sy / sc->pre_vratio;
- if (pdata->hw_ver >= 0x50) {
- sc->main_hratio = (sx << 14) / (tx << sc->hfactor);
- sc->main_vratio = (sy << 14) / (ty << sc->vfactor);
- } else {
- sc->main_hratio = (sx << 8) / (tx << sc->hfactor);
- sc->main_vratio = (sy << 8) / (ty << sc->vfactor);
- }
- sc->scaleup_h = (tx >= sx) ? 1 : 0;
- sc->scaleup_v = (ty >= sy) ? 1 : 0;
- return 0;
- }
- int fimc_start_zoom_capture(struct fimc_control *ctrl)
- {
- fimc_dbg("%s\n", __func__);
- fimc_hwset_start_scaler(ctrl);
- fimc_hwset_enable_capture(ctrl, ctrl->sc.bypass);
- fimc_hwset_disable_frame_end_irq(ctrl);
- return 0;
- }
- int fimc_stop_zoom_capture(struct fimc_control *ctrl)
- {
- fimc_dbg("%s\n", __func__);
- if (!ctrl->cam) {
- fimc_err("%s: No capture device.\n", __func__);
- return -ENODEV;
- }
- if (!ctrl->cap) {
- fimc_err("%s: No cappure format.\n", __func__);
- return -ENODEV;
- }
- if (ctrl->cap->lastirq) {
- fimc_hwset_enable_lastirq(ctrl);
- fimc_hwset_disable_capture(ctrl);
- fimc_hwset_disable_lastirq(ctrl);
- } else {
- fimc_hwset_disable_capture(ctrl);
- fimc_hwset_enable_frame_end_irq(ctrl);
- }
- fimc_hwset_stop_scaler(ctrl);
- return 0;
- }
- static int fimc_add_inqueue(struct fimc_control *ctrl, int i)
- {
- struct fimc_capinfo *cap = ctrl->cap;
- struct fimc_buf_set *tmp_buf;
- struct list_head *count;
- /* PINGPONG_2ADDR_MODE Only */
- list_for_each(count, &cap->inq) {
- tmp_buf = list_entry(count, struct fimc_buf_set, list);
- /* skip list_add_tail if already buffer is in cap->inq list*/
- if (tmp_buf->id == i)
- return 0;
- }
- list_add_tail(&cap->bufs[i].list, &cap->inq);
- return 0;
- }
- static int fimc_add_outqueue(struct fimc_control *ctrl, int i)
- {
- struct fimc_capinfo *cap = ctrl->cap;
- struct fimc_buf_set *buf;
- unsigned int mask = 0x2;
- /* PINGPONG_2ADDR_MODE Only */
- /* pair_buf_index stands for pair index of i. (0<->2) (1<->3) */
- int pair_buf_index = (i^mask);
- /* FIMC have 4 h/w registers */
- if (i < 0 || i >= FIMC_PHYBUFS) {
- fimc_err("%s: invalid queue index : %d\n", __func__, i);
- return -ENOENT;
- }
- if (list_empty(&cap->inq))
- return -ENOENT;
- buf = list_first_entry(&cap->inq, struct fimc_buf_set, list);
- /* pair index buffer should be allocated first */
- cap->outq[pair_buf_index] = buf->id;
- fimc_hwset_output_address(ctrl, buf, pair_buf_index);
- cap->outq[i] = buf->id;
- fimc_hwset_output_address(ctrl, buf, i);
- list_del(&buf->list);
- return 0;
- }
- int fimc_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
- {
- struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;
- int ret = 0;
- fimc_dbg("%s\n", __func__);
- /* WriteBack doesn't have subdev_call */
- if ((ctrl->cam->id == CAMERA_WB) || (ctrl->cam->id == CAMERA_WB_B))
- return 0;
- mutex_lock(&ctrl->v4l2_lock);
- ret = v4l2_subdev_call(ctrl->cam->sd, video, g_parm, a);
- mutex_unlock(&ctrl->v4l2_lock);
- return ret;
- }
- int fimc_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
- {
- struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;
- struct s3c_platform_fimc *pdata = to_fimc_plat(ctrl->dev);
- int ret = 0;
- int new_fps = a->parm.capture.timeperframe.denominator /
- a->parm.capture.timeperframe.numerator;
- fimc_info2("%s fimc%d, %d\n", __func__, ctrl->id, new_fps);
- /* WriteBack doesn't have subdev_call */
- if ((ctrl->cam->id == CAMERA_WB) || (ctrl->cam->id == CAMERA_WB_B))
- return 0;
- mutex_lock(&ctrl->v4l2_lock);
- if (ctrl->cam->sd && fimc_cam_use)
- ret = v4l2_subdev_call(ctrl->cam->sd, video, s_parm, a);
- else if (ctrl->is.sd && fimc_cam_use)
- ret = v4l2_subdev_call(ctrl->is.sd, video, s_parm, a);
- mutex_unlock(&ctrl->v4l2_lock);
- return ret;
- }
- /* Enumerate controls */
- int fimc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qc)
- {
- struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;
- int i, ret;
- fimc_dbg("%s\n", __func__);
- for (i = 0; i < ARRAY_SIZE(fimc_controls); i++) {
- if (fimc_controls[i].id == qc->id) {
- memcpy(qc, &fimc_controls[i], sizeof(struct v4l2_queryctrl));
- return 0;
- }
- }
- mutex_lock(&ctrl->v4l2_lock);
- ret = v4l2_subdev_call(ctrl->cam->sd, core, queryctrl, qc);
- mutex_unlock(&ctrl->v4l2_lock);
- return ret;
- }
- /* Menu control items */
- int fimc_querymenu(struct file *file, void *fh, struct v4l2_querymenu *qm)
- {
- struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;
- int ret = 0;
- fimc_dbg("%s\n", __func__);
- mutex_lock(&ctrl->v4l2_lock);
- ret = v4l2_subdev_call(ctrl->cam->sd, core, querymenu, qm);
- mutex_unlock(&ctrl->v4l2_lock);
- return ret;
- }
- int fimc_enum_input(struct file *file, void *fh, struct v4l2_input *inp)
- {
- struct fimc_global *fimc = get_fimc_dev();
- struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;
- fimc_dbg("%s: index %d\n", __func__, inp->index);
- if (inp->index >= FIMC_MAXCAMS) {
- fimc_err("%s: invalid input index, received = %d\n",
- __func__, inp->index);
- return -EINVAL;
- }
- if (!fimc->camera_isvalid[inp->index])
- return -EINVAL;
- mutex_lock(&ctrl->v4l2_lock);
- if (fimc->camera[inp->index]->use_isp && !(fimc->camera[inp->index]->info))
- strcpy(inp->name, "ISP Camera");
- else
- strcpy(inp->name, fimc->camera[inp->index]->info->type);
- inp->type = V4L2_INPUT_TYPE_CAMERA;
- mutex_unlock(&ctrl->v4l2_lock);
- return 0;
- }
- int fimc_g_input(struct file *file, void *fh, unsigned int *i)
- {
- struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;
- struct fimc_global *fimc = get_fimc_dev();
- /* In case of isueing g_input before s_input */
- if (!ctrl->cam) {
- fimc_err("no camera device selected yet. do VIDIOC_S_INPUT first\n");
- return -ENODEV;
- }
- mutex_lock(&ctrl->v4l2_lock);
- *i = (unsigned int) fimc->active_camera;
- mutex_unlock(&ctrl->v4l2_lock);
- fimc_dbg("%s: index %d\n", __func__, *i);
- return 0;
- }
- int fimc_release_subdev(struct fimc_control *ctrl)
- {
- struct fimc_global *fimc = get_fimc_dev();
- struct i2c_client *client;
- struct s3c_platform_fimc *pdata = to_fimc_plat(ctrl->dev);
- int ret;
- if (ctrl->cam->sd && fimc_cam_use) {
- fimc_dbg("%s called\n", __func__);
- /* WriteBack doesn't need clock setting */
- if ((ctrl->cam->id == CAMERA_WB) ||
- (ctrl->cam->id == CAMERA_WB_B)) {
- ctrl->cam->initialized = 0;
- ctrl->cam = NULL;
- fimc->active_camera = -1;
- return 0;
- }
- client = v4l2_get_subdevdata(ctrl->cam->sd);
- i2c_unregister_device(client);
- ctrl->cam->sd = NULL;
- #ifndef CONFIG_MACH_GC1
- if (ctrl->cam->cam_power)
- #else
- if (ctrl->cam->cam_power && !leave_power)
- #endif
- ctrl->cam->cam_power(0);
- /* shutdown the MCLK */
- #ifndef CONFIG_MACH_GC1
- if (fimc->mclk_status == CAM_MCLK_ON) {
- #else
- if (fimc->mclk_status == CAM_MCLK_ON && !leave_power) {
- #endif
- clk_disable(ctrl->cam->clk);
- fimc->mclk_status = CAM_MCLK_OFF;
- }
- ctrl->cam->initialized = 0;
- ctrl->cam = NULL;
- fimc->active_camera = -1;
- } else if (ctrl->cam->sd) {
- ctrl->cam->initialized = 0;
- ctrl->cam = NULL;
- fimc->active_camera = -1;
- }
- if (ctrl->flite_sd && fimc_cam_use) {
- ret = v4l2_subdev_call(ctrl->flite_sd, core, s_power, 0);
- if (ret)
- fimc_err("s_power failed: %d", ret);
- ctrl->flite_sd = NULL;
- }
- return 0;
- }
- static int fimc_configure_subdev(struct fimc_control *ctrl)
- {
- struct i2c_adapter *i2c_adap;
- struct i2c_board_info *i2c_info;
- struct i2c_client *client;
- struct v4l2_subdev *sd;
- unsigned short addr;
- char *name;
- int ret = 0;
- i2c_adap = i2c_get_adapter(ctrl->cam->get_i2c_busnum());
- if (!i2c_adap) {
- fimc_err("subdev i2c_adapter missing-skip registration\n");
- return -ENODEV;
- }
- i2c_info = ctrl->cam->info;
- if (!i2c_info) {
- fimc_err("%s: subdev i2c board info missing\n", __func__);
- return -ENODEV;
- }
- name = i2c_info->type;
- if (!name) {
- fimc_err("subdev i2c driver name missing-skip registration\n");
- return -ENODEV;
- }
- addr = i2c_info->addr;
- if (!addr) {
- fimc_err("subdev i2c address missing-skip registration\n");
- return -ENODEV;
- }
- /*
- * NOTE: first time subdev being registered,
- * s_config is called and try to initialize subdev device
- * but in this point, we are not giving MCLK and power to subdev
- * so nothing happens but pass platform data through
- */
- sd = v4l2_i2c_new_subdev_board(&ctrl->v4l2_dev, i2c_adap,
- i2c_info, &addr);
- if (!sd) {
- fimc_err("%s: v4l2 subdev board registering failed\n",
- __func__);
- }
- /* Assign subdev to proper camera device pointer */
- ctrl->cam->sd = sd;
- if (!ctrl->cam->initialized) {
- ret = fimc_init_camera(ctrl);
- if (ret < 0) {
- fimc_err("%s: fail to initialize subdev\n", __func__);
- #ifndef CONFIG_MACH_GC1
- client = v4l2_get_subdevdata(sd);
- i2c_unregister_device(client);
- ctrl->cam->sd = NULL;
- #endif
- return ret;
- }
- }
- return 0;
- }
- static int flite_register_callback(struct device *dev, void *p)
- {
- struct v4l2_subdev **sd_list = p;
- struct v4l2_subdev *sd = NULL;
- sd = dev_get_drvdata(dev);
- if (sd) {
- struct platform_device *pdev = v4l2_get_subdev_hostdata(sd);
- *(sd_list + pdev->id) = sd;
- }
- return 0; /* non-zero value stops iteration */
- }
- static struct v4l2_subdev *exynos_flite_get_subdev(int id)
- {
- const char *module_name = "exynos-fimc-lite";
- struct device_driver *drv;
- struct v4l2_subdev *sd[FLITE_MAX_NUM] = {NULL,};
- int ret;
- drv = driver_find(module_name, &platform_bus_type);
- if (!drv) {
- request_module(module_name);
- drv = driver_find(module_name, &platform_bus_type);
- }
- if (!drv)
- return ERR_PTR(-ENODEV);
- ret = driver_for_each_device(drv, NULL, &sd[0],
- flite_register_callback);
- put_driver(drv);
- return ret ? NULL : sd[id];
- }
- int fimc_subdev_attatch(struct fimc_control *ctrl)
- {
- int ret = 0;
- struct s3c_platform_fimc *pdata = to_fimc_plat(ctrl->dev);
- ctrl->flite_sd = exynos_flite_get_subdev(ctrl->cam->flite_id);
- if (IS_ERR_OR_NULL(ctrl->flite_sd)) {
- ctrl->flite_sd = NULL;
- return PTR_ERR(ctrl->flite_sd);
- } else {
- if (fimc_cam_use) {
- ret = v4l2_subdev_call(ctrl->flite_sd, core, s_power, 1);
- if (ret)
- fimc_err("s_power failed: %d", ret);
- }
- }
- return 0;
- }
- static int fimc_is_register_callback(struct device *dev, void *p)
- {
- struct v4l2_subdev **sd = p;
- *sd = dev_get_drvdata(dev);
- if (!*sd)
- return -EINVAL;
- return 0; /* non-zero value stops iteration */
- }
- int fimc_is_release_subdev(struct fimc_control *ctrl)
- {
- int ret;
- struct fimc_global *fimc = get_fimc_dev();
- struct s3c_platform_fimc *pdata = to_fimc_plat(ctrl->dev);
- if (ctrl->is.sd && ctrl->cam && fimc_cam_use) {
- if (ctrl->cam->cam_power)
- ctrl->cam->cam_power(0);
- /* shutdown the MCLK */
- if (fimc->mclk_status == CAM_MCLK_ON) {
- clk_disable(ctrl->cam->clk);
- fimc->mclk_status = CAM_MCLK_OFF;
- }
- ret = v4l2_subdev_call(ctrl->is.sd, core, s_power, 0);
- if (ret < 0) {
- fimc_dbg("FIMC-IS init failed");
- return -ENODEV;
- }
- v4l2_device_unregister_subdev(ctrl->is.sd);
- ctrl->is.sd = NULL;
- ctrl->cam->initialized = 0;
- ctrl->cam = NULL;
- fimc->active_camera = -1;
- } else if (ctrl->is.sd && ctrl->cam) {
- ctrl->is.sd = NULL;
- ctrl->cam->initialized = 0;
- ctrl->cam = NULL;
- fimc->active_camera = -1;
- }
- return 0;
- }
- static struct v4l2_subdev *fimc_is_get_subdev(int id)
- {
- const char *module_name = "exynos4-fimc-is";
- struct device_driver *drv;
- struct v4l2_subdev *sd = NULL;
- int ret;
- drv = driver_find(module_name, &platform_bus_type);
- if (!drv) {
- request_module(module_name);
- drv = driver_find(module_name, &platform_bus_type);
- }
- if (!drv)
- return ERR_PTR(-ENODEV);
- ret = driver_for_each_device(drv, NULL, &sd,
- fimc_is_register_callback);
- put_driver(drv);
- return ret ? NULL : sd;
- }
- static int fimc_is_init_cam(struct fimc_control *ctrl)
- {
- struct fimc_global *fimc = get_fimc_dev();
- struct s3c_platform_camera *cam;
- int ret = 0;
- #if (defined(CONFIG_EXYNOS_DEV_PD) && defined(CONFIG_PM_RUNTIME))
- struct platform_device *pdev = to_platform_device(ctrl->dev);
- #endif
- cam = ctrl->cam;
- /* Do noting if already initialized */
- if (ctrl->cam->initialized)
- return 0;
- #if (defined(CONFIG_EXYNOS_DEV_PD) && defined(CONFIG_PM_RUNTIME))
- if (ctrl->power_status == FIMC_POWER_OFF)
- pm_runtime_get_sync(&pdev->dev);
- #endif
- /* set rate for mclk */
- if ((clk_get_rate(cam->clk)) && (fimc->mclk_status == CAM_MCLK_OFF)) {
- clk_set_rate(cam->clk, cam->clk_rate);
- clk_enable(cam->clk);
- fimc->mclk_status = CAM_MCLK_ON;
- fimc_info1("clock for camera (FIMC-IS): %d\n", cam->clk_rate);
- }
- /* enable camera power if needed */
- if (cam->cam_power) {
- ret = cam->cam_power(1);
- if (unlikely(ret < 0))
- fimc_err("\nfail to power on\n");
- }
- /* Retry camera power-up if first i2c fails. */
- if (unlikely(ret < 0)) {
- if (cam->cam_power)
- cam->cam_power(0);
- if (fimc->mclk_status == CAM_MCLK_ON) {
- clk_disable(ctrl->cam->clk);
- fimc->mclk_status = CAM_MCLK_OFF;
- }
- fimc_err("Camera power/init failed!!!!\n\n");
- #if (defined(CONFIG_EXYNOS_DEV_PD) && defined(CONFIG_PM_RUNTIME))
- if (ctrl->power_status == FIMC_POWER_ON)
- pm_runtime_put_sync(&pdev->dev);
- #endif
- } else {
- /* Apply things to interface register */
- fimc_hwset_reset(ctrl);
- cam->initialized = 1;
- }
- return ret;
- }
- int fimc_s_input(struct file *file, void *fh, unsigned int i)
- {
- struct fimc_global *fimc = get_fimc_dev();
- struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;
- struct fimc_capinfo *cap = ctrl->cap;
- struct s3c_platform_fimc *pdata = to_fimc_plat(ctrl->dev);
- int ret = 0;
- #if (defined(CONFIG_EXYNOS_DEV_PD) && defined(CONFIG_PM_RUNTIME))
- struct platform_device *pdev = to_platform_device(ctrl->dev);
- #endif
- fimc_dbg("%s: index %d\n", __func__, i);
- if (i >= FIMC_MAXCAMS) {
- fimc_err("%s: invalid input index\n", __func__);
- return -EINVAL;
- }
- if (!fimc->camera_isvalid[i])
- return -EINVAL;
- if (fimc->camera[i]->sd && fimc_cam_use) {
- fimc_err("%s: Camera already in use.\n", __func__);
- return -EBUSY;
- }
- mutex_lock(&ctrl->v4l2_lock);
- /* If ctrl->cam is not NULL, there is one subdev already registered.
- * We need to unregister that subdev first. */
- if (i != fimc->active_camera) {
- fimc_info1("\n\nfimc_s_input activating subdev\n");
- if (ctrl->cam && (ctrl->cam->sd || ctrl->flite_sd))
- fimc_release_subdev(ctrl);
- else if (ctrl->is.sd)
- fimc_is_release_subdev(ctrl);
- ctrl->cam = fimc->camera[i];
- if ((ctrl->cam->id != CAMERA_WB) && (ctrl->cam->id !=
- CAMERA_WB_B) && (!ctrl->cam->use_isp) && fimc_cam_use) {
- ret = fimc_configure_subdev(ctrl);
- if (ret < 0) {
- #ifdef CONFIG_MACH_GC1
- if (ret == -ENOSYS) {
- /* return no error If firmware is bad.
- Because F/W update app should access the sensor through HAL instance */
- fimc_err("%s: please update the F/W\n", __func__);
- } else {
- ctrl->cam = NULL;
- mutex_unlock(&ctrl->v4l2_lock);
- fimc_err("%s: Could not register camera" \
- " sensor with V4L2.\n", __func__);
- return -ENODEV;
- }
- #else
- ctrl->cam = NULL;
- mutex_unlock(&ctrl->v4l2_lock);
- fimc_err("%s: Could not register camera" \
- " sensor with V4L2.\n", __func__);
- return -ENODEV;
- #endif
- }
- }
- fimc->active_camera = i;
- fimc_info2("fimc_s_input activated subdev = %d\n", i);
- }
- if (!fimc_cam_use) {
- if (i == fimc->active_camera) {
- ctrl->cam = fimc->camera[i];
- fimc_info2("fimc_s_input activating subdev FIMC%d\n",
- ctrl->id);
- } else {
- mutex_unlock(&ctrl->v4l2_lock);
- return -EINVAL;
- }
- #if (defined(CONFIG_EXYNOS_DEV_PD) && defined(CONFIG_PM_RUNTIME))
- #ifdef CONFIG_DRM_EXYNOS_FIMD_WB
- if ((ctrl->cam->id != CAMERA_WB) &&
- (ctrl->cam->id != CAMERA_WB_B) &&
- (ctrl->power_status == FIMC_POWER_OFF)) {
- #else
- if (ctrl->power_status == FIMC_POWER_OFF) {
- #endif
- pm_runtime_get_sync(&pdev->dev);
- }
- fimc_hwset_reset(ctrl);
- #endif
- }
- if (ctrl->cam->use_isp) {
- /* fimc-lite attatch */
- ret = fimc_subdev_attatch(ctrl);
- if (ret) {
- fimc_err("subdev_attatch failed\n");
- mutex_unlock(&ctrl->v4l2_lock);
- return -ENODEV;
- }
- /* fimc-is attatch */
- ctrl->is.sd = fimc_is_get_subdev(i);
- if (IS_ERR_OR_NULL(ctrl->is.sd)) {
- fimc_err("fimc-is subdev_attatch failed\n");
- mutex_unlock(&ctrl->v4l2_lock);
- return -ENODEV;
- }
- ctrl->is.fmt.width = ctrl->cam->width;
- ctrl->is.fmt.height = ctrl->cam->height;
- ctrl->is.frame_count = 0;
- if (fimc_cam_use) {
- ret = fimc_is_init_cam(ctrl);
- if (ret < 0) {
- fimc_dbg("FIMC-IS init clock failed");
- mutex_unlock(&ctrl->v4l2_lock);
- return -ENODEV;
- }
- ret = v4l2_subdev_call(ctrl->is.sd, core, s_power, 1);
- if (ret < 0) {
- fimc_err("FIMC-IS init s_power failed");
- mutex_unlock(&ctrl->v4l2_lock);
- return -ENODEV;
- }
- ret = v4l2_subdev_call(ctrl->is.sd, core, load_fw);
- if (ret < 0) {
- fimc_err("FIMC-IS init load_fw failed");
- mutex_unlock(&ctrl->v4l2_lock);
- if (!cap) {
- cap = kzalloc(sizeof(*cap), GFP_KERNEL);
- if (!cap) {
- fimc_err("%s: no memory for "
- "capture device info\n", __func__);
- return -ENOMEM;
- }
- /* assign to ctrl */
- ctrl->cap = cap;
- }
- return -ENODEV;
- }
- ret = v4l2_subdev_call(ctrl->is.sd, core, init, ctrl->cam->sensor_index);
- if (ret < 0) {
- fimc_err("FIMC-IS init failed");
- mutex_unlock(&ctrl->v4l2_lock);
- if (!cap) {
- cap = kzalloc(sizeof(*cap), GFP_KERNEL);
- if (!cap) {
- fimc_err("%s: no memory for "
- "capture device info\n", __func__);
- return -ENOMEM;
- }
- /* assign to ctrl */
- ctrl->cap = cap;
- }
- return -ENODEV;
- }
- }
- }
- /*
- * The first time alloc for struct cap_info, and will be
- * released at the file close.
- * Anyone has better idea to do this?
- */
- if (!cap) {
- cap = kzalloc(sizeof(*cap), GFP_KERNEL);
- if (!cap) {
- fimc_err("%s: no memory for "
- "capture device info\n", __func__);
- return -ENOMEM;
- }
- /* assign to ctrl */
- ctrl->cap = cap;
- #if (defined(CONFIG_EXYNOS_DEV_PD) && defined(CONFIG_PM_RUNTIME))
- if (ctrl->power_status == FIMC_POWER_OFF)
- pm_runtime_get_sync(&pdev->dev);
- #endif
- } else {
- memset(cap, 0, sizeof(*cap));
- }
- mutex_unlock(&ctrl->v4l2_lock);
- return 0;
- }
- int fimc_enum_fmt_vid_capture(struct file *file, void *fh,
- struct v4l2_fmtdesc *f)
- {
- struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;
- int i = f->index;
- fimc_dbg("%s\n", __func__);
- if (i >= ARRAY_SIZE(capture_fmts)) {
- fimc_err("%s: There is no support format index %d\n", __func__, i);
- return -EINVAL;
- }
- mutex_lock(&ctrl->v4l2_lock);
- memset(f, 0, sizeof(*f));
- memcpy(f, &capture_fmts[i], sizeof(*f));
- mutex_unlock(&ctrl->v4l2_lock);
- return 0;
- }
- #ifdef CONFIG_SLP_DMABUF
- /*
- * figures out the depth of requested format
- */
- static int fimc_fmt_depth_mplane(struct fimc_control *ctrl,
- struct v4l2_format *f, int depth[])
- {
- int ret = 0;
- /* handles only supported pixelformats */
- switch (f->fmt.pix_mp.pixelformat) {
- case V4L2_PIX_FMT_NV12:
- case V4L2_PIX_FMT_NV12T:
- case V4L2_PIX_FMT_NV21:
- f->fmt.pix_mp.num_planes = 2;
- depth[0] = 8;
- depth[1] = 4;
- break;
- case V4L2_PIX_FMT_YUV420:
- case V4L2_PIX_FMT_YVU420:
- f->fmt.pix_mp.num_planes = 3;
- depth[0] = 8;
- depth[1] = 2;
- depth[2] = 2;
- break;
- case V4L2_PIX_FMT_JPEG:
- case V4L2_PIX_FMT_INTERLEAVED:
- f->fmt.pix_mp.num_planes = 1;
- depth[0] = -1;
- fimc_dbg("Compressed format.\n");
- break;
- default:
- fimc_dbg("why am I here?\n");
- ret = -EINVAL;
- break;
- }
- return ret;
- }
- static int fimc_g_fmt_vid_capture_mplane(struct fimc_control *ctrl,
- struct v4l2_format *f)
- {
- int depth[VIDEO_MAX_PLANES];
- int ret;
- int i;
- /*
- * Note that expecting format only can be with
- * available output format from FIMC
- * Following items should be handled in driver
- * bytesperline = width * depth / 8
- * sizeimage = bytesperline * height
- */
- f->fmt.pix_mp.pixelformat = ctrl->cap->fmt.pixelformat;
- f->fmt.pix_mp.width = ctrl->cap->fmt.width;
- f->fmt.pix_mp.height = ctrl->cap->fmt.height;
- ret = fimc_fmt_depth_mplane(ctrl, f, depth);
- if (ret < 0) {
- fimc_err("Invaild format\n");
- return ret;
- }
- for (i = 0; i < f->fmt.pix_mp.num_planes; ++i) {
- f->fmt.pix_mp.plane_fmt[i].bytesperline = (f->fmt.pix_mp.width *
- depth[i]) >> 3;
- f->fmt.pix_mp.plane_fmt[i].sizeimage =
- (f->fmt.pix_mp.plane_fmt[i].bytesperline *
- f->fmt.pix_mp.width);
- }
- return 0;
- }
- #endif
- int fimc_g_fmt_vid_capture(struct file *file, void *fh, struct v4l2_format *f)
- {
- struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;
- fimc_dbg("%s\n", __func__);
- if (!ctrl->cap) {
- fimc_err("%s: no capture device info\n", __func__);
- return -EINVAL;
- }
- mutex_lock(&ctrl->v4l2_lock);
- #ifdef CONFIG_SLP_DMABUF
- if (V4L2_TYPE_IS_MULTIPLANAR(f->type))
- if (fimc_g_fmt_vid_capture_mplane(ctrl, f) < 0) {
- mutex_unlock(&ctrl->v4l2_lock);
- return -EINVAL;
- }
- else {
- memset(&f->fmt.pix, 0, sizeof(f->fmt.pix));
- memcpy(&f->fmt.pix, &ctrl->cap->fmt, sizeof(f->fmt.pix));
- }
- #else
- memset(&f->fmt.pix, 0, sizeof(f->fmt.pix));
- memcpy(&f->fmt.pix, &ctrl->cap->fmt, sizeof(f->fmt.pix));
- #endif
- mutex_unlock(&ctrl->v4l2_lock);
- return 0;
- }
- /*
- * Check for whether the requested format
- * can be streamed out from FIMC
- * depends on FIMC node
- */
- static int fimc_fmt_avail(struct fimc_control *ctrl,
- struct v4l2_pix_format *f)
- {
- int i;
- /*
- * TODO: check for which FIMC is used.
- * Available fmt should be varied for each FIMC
- */
- for (i = 0; i < ARRAY_SIZE(capture_fmts); i++) {
- if (capture_fmts[i].pixelformat == f->pixelformat)
- return 0;
- }
- fimc_info1("Not supported pixelformat requested\n");
- return -1;
- }
- /*
- * figures out the depth of requested format
- */
- static int fimc_fmt_depth(struct fimc_control *ctrl, struct v4l2_pix_format *f)
- {
- int err, depth = 0;
- /* First check for available format or not */
- err = fimc_fmt_avail(ctrl, f);
- if (err < 0)
- return -1;
- /* handles only supported pixelformats */
- switch (f->pixelformat) {
- case V4L2_PIX_FMT_RGB32:
- depth = 32;
- fimc_dbg("32bpp\n");
- break;
- case V4L2_PIX_FMT_RGB565:
- case V4L2_PIX_FMT_YUYV:
- case V4L2_PIX_FMT_UYVY:
- case V4L2_PIX_FMT_VYUY:
- case V4L2_PIX_FMT_YVYU:
- case V4L2_PIX_FMT_YUV422P:
- case V4L2_PIX_FMT_NV16:
- case V4L2_PIX_FMT_NV61:
- depth = 16;
- fimc_dbg("16bpp\n");
- break;
- case V4L2_PIX_FMT_NV12:
- case V4L2_PIX_FMT_NV12T:
- case V4L2_PIX_FMT_NV21:
- case V4L2_PIX_FMT_YUV420:
- case V4L2_PIX_FMT_YVU420:
- depth = 12;
- fimc_dbg("12bpp\n");
- break;
- case V4L2_PIX_FMT_JPEG:
- case V4L2_PIX_FMT_INTERLEAVED:
- depth = -1;
- fimc_dbg("Compressed format.\n");
- break;
- default:
- fimc_dbg("why am I here?\n");
- break;
- }
- return depth;
- }
- int fimc_s_fmt_vid_private(struct file *file, void *fh, struct v4l2_format *f)
- {
- struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;
- struct s3c_platform_fimc *pdata = to_fimc_plat(ctrl->dev);
- struct v4l2_mbus_framefmt *mbus_fmt;
- int ret = 0;
- fimc_dbg("%s\n", __func__);
- if (ctrl->cam->sd) {
- struct v4l2_pix_format *pix = &f->fmt.pix;
- int depth;
- fimc_info1("%s %d:\n", __func__, __LINE__);
- mbus_fmt = &ctrl->cap->mbus_fmt;
- mbus_fmt->width = pix->width;
- mbus_fmt->height = pix->height;
- #ifdef CONFIG_MACH_P4NOTE
- /* Unfortuntely, we have to use pix->field (not pix->priv) since
- * pix.field is already used in the below else condtion statement
- * (in case that sub-devices are not registered)
- */
- mbus_fmt->field = pix->field;
- #endif
- #if defined(CONFIG_MACH_GC1)
- mbus_fmt->field = pix->priv;
- #endif
- printk(KERN_INFO "%s mbus_fmt->width = %d, height = %d,\n",
- __func__,mbus_fmt->width ,mbus_fmt->height);
- depth = fimc_fmt_depth(ctrl, pix);
- if (depth == 0) {
- fimc_err("%s: Invalid pixel format\n", __func__);
- return -EINVAL;
- } else if (depth < 0) { /* JPEG */
- mbus_fmt->code = V4L2_MBUS_FMT_JPEG_1X8;
- mbus_fmt->colorspace = V4L2_COLORSPACE_JPEG;
- } else {
- mbus_fmt->code = V4L2_MBUS_FMT_VYUY8_2X8;
- }
- if (fimc_cam_use) {
- ret = v4l2_subdev_call(ctrl->cam->sd, video,
- s_mbus_fmt, mbus_fmt);
- if (ret) {
- fimc_err("%s: fail to s_mbus_fmt\n", __func__);
- return ret;
- }
- }
- return 0;
- } else {
- mbus_fmt = kzalloc(sizeof(*mbus_fmt), GFP_KERNEL);
- if (!mbus_fmt) {
- fimc_err("%s: no memory for "
- "mbus_fmt\n", __func__);
- return -ENOMEM;
- }
- ctrl->is.fmt.width = f->fmt.pix.width;
- ctrl->is.fmt.height = f->fmt.pix.height;
- ctrl->is.fmt.pixelformat = f->fmt.pix.pixelformat;
- mbus_fmt->width = f->fmt.pix.width;
- mbus_fmt->height = f->fmt.pix.height;
- mbus_fmt->code = V4L2_MBUS_FMT_YUYV8_2X8; /*dummy*/
- mbus_fmt->field = f->fmt.pix.field;
- mbus_fmt->colorspace = V4L2_COLORSPACE_SRGB;
- printk(KERN_INFO "%s mbus_fmt->width = %d, height = %d, \n",
- __func__,mbus_fmt->width ,mbus_fmt->height);
- if (fimc_cam_use)
- ret = v4l2_subdev_call(ctrl->is.sd, video,
- s_mbus_fmt, mbus_fmt);
- kfree(mbus_fmt);
- return ret;
- }
- return -EINVAL;
- }
- int fimc_s_fmt_vid_capture(struct file *file, void *fh, struct v4l2_format *f)
- {
- struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;
- struct fimc_capinfo *cap = ctrl->cap;
- struct s3c_platform_fimc *pdata = to_fimc_plat(ctrl->dev);
- int ret = 0;
- int depth;
- struct v4l2_control is_ctrl;
- is_ctrl.id = 0;
- is_ctrl.value = 0;
- printk(KERN_INFO "%s\n", __func__);
- if (!ctrl->cap) {
- fimc_err("%s: No capture structure." \
- "you have to call s_input first.\n", __func__);
- return -ENODEV;
- }
- /* rotaton, flip, dtp_mode, movie_mode and vt_mode,
- * sensor_output_width,height should be maintained.(by TN) */
- memset(cap, 0, sizeof(*cap) - sizeof(u32) * 7);
- mutex_lock(&ctrl->v4l2_lock);
- memset(&cap->fmt, 0, sizeof(cap->fmt));
- #ifdef CONFIG_SLP_DMABUF
- if (V4L2_TYPE_IS_MULTIPLANAR(f->type)) {
- cap->fmt.pixelformat = f->fmt.pix_mp.pixelformat;
- cap->fmt.width = f->fmt.pix_mp.width;
- cap->fmt.height = f->fmt.pix_mp.height;
- cap->fmt.pixelformat = f->fmt.pix_mp.pixelformat;
- } else
- memcpy(&cap->fmt, &f->fmt.pix, sizeof(cap->fmt));
- #else
- memcpy(&cap->fmt, &f->fmt.pix, sizeof(cap->fmt));
- #endif
- /*
- * Note that expecting format only can be with
- * available output format from FIMC
- * Following items should be handled in driver
- * bytesperline = width * depth / 8
- * sizeimage = bytesperline * height
- */
- /* This function may return 0 or -1 in case of error,
- * hence need to check here.
- */
- depth = fimc_fmt_depth(ctrl, &cap->fmt);
- if (depth == 0) {
- mutex_unlock(&ctrl->v4l2_lock);
- fimc_err("%s: Invalid pixel format\n", __func__);
- return -EINVAL;
- } else if (depth < 0) {
- /*
- * When the pixelformat is JPEG,
- * the application is requesting for data
- * in JPEG compressed format
- */
- cap->fmt.colorspace = V4L2_COLORSPACE_JPEG;
- } else {
- cap->fmt.bytesperline = (cap->fmt.width * depth) >> 3;
- cap->fmt.sizeimage = (cap->fmt.bytesperline * cap->fmt.height);
- }
- if (cap->fmt.pixelformat == V4L2_PIX_FMT_JPEG ||
- cap->fmt.pixelformat == V4L2_PIX_FMT_INTERLEAVED) {
- ctrl->sc.bypass = 1;
- cap->lastirq = 0;
- fimc_info1("fimc_s_fmt_vid_capture V4L2_COLORSPACE_JPEG or INTERLEAVED\n");
- } else {
- #ifdef CONFIG_MACH_GC1
- /*
- Fimc scaler input Hsize is restricted to 4224 pixels.
- So, GC1 has to bypass fimc scaler to use more than 12M YUV.
- */
- if (cap->fmt.width > ctrl->limit->pre_dst_w)
- ctrl->sc.bypass = 1;
- else
- ctrl->sc.bypass = 0;
- #else
- ctrl->sc.bypass = 0;
- #endif
- cap->lastirq = 0;
- }
- printk(KERN_INFO "fimc%d s_fmt width = %d, height = %d\n", ctrl->id, \
- cap->fmt.width, cap->fmt.height);
- /* WriteBack doesn't have subdev_call */
- if (ctrl->cam->id == CAMERA_WB || ctrl->cam->id == CAMERA_WB_B) {
- mutex_unlock(&ctrl->v4l2_lock);
- return 0;
- }
- if (ctrl->is.sd && fimc_cam_use) {
- ctrl->is.mbus_fmt.code = V4L2_MBUS_FMT_SGRBG10_1X10;
- is_ctrl.id = V4L2_CID_IS_GET_SENSOR_WIDTH;
- is_ctrl.value = 0;
- v4l2_subdev_call(ctrl->is.sd, core, g_ctrl, &is_ctrl);
- ctrl->is.fmt.width = ctrl->is.mbus_fmt.width = is_ctrl.value;
- is_ctrl.id = V4L2_CID_IS_GET_SENSOR_HEIGHT;
- is_ctrl.value = 0;
- v4l2_subdev_call(ctrl->is.sd, core, g_ctrl, &is_ctrl);
- ctrl->is.fmt.height = ctrl->is.mbus_fmt.height = is_ctrl.value;
- /* default offset values */
- ctrl->is.offset_x = 16;
- ctrl->is.offset_y = 12;
- }
- fimc_hwset_reset(ctrl);
- mutex_unlock(&ctrl->v4l2_lock);
- printk(KERN_INFO "%s -- FIMC%d\n", __func__, ctrl->id);
- return ret;
- }
- int fimc_try_fmt_vid_capture(struct file *file, void *fh, struct v4l2_format *f)
- {
- /* Not implement */
- return -ENOTTY;
- }
- static int fimc_alloc_buffers(struct fimc_control *ctrl,
- int plane, int size, int align, int bpp, int use_paddingbuf, int pad_size)
- {
- struct fimc_capinfo *cap = ctrl->cap;
- int i, j;
- int plane_length[4] = {0, };
- #ifdef CONFIG_VIDEO_SAMSUNG_USE_DMA_MEM
- int alloc_size, err;
- struct cma_info mem_info;
- #endif
- switch (plane) {
- case 1:
- if (align) {
- plane_length[0] = PAGE_ALIGN((size*bpp) >> 3);
- plane_length[1] = 0;
- plane_length[2] = 0;
- } else {
- plane_length[0] = (size*bpp) >> 3;
- plane_length[1] = 0;
- plane_length[2] = 0;
- }
- break;
- /* In case of 2, only NV12 and NV12T is supported. */
- case 2:
- if (align) {
- plane_length[0] = PAGE_ALIGN((size*8) >> 3);
- plane_length[1] = PAGE_ALIGN((size*(bpp-8)) >> 3);
- plane_length[2] = 0;
- fimc_info2("plane_length[0] = %d, plane_length[1] = %d\n" \
- , plane_length[0], plane_length[1]);
- } else {
- plane_length[0] = ((size*8) >> 3);
- plane_length[1] = ((size*(bpp-8)) >> 3);
- plane_length[2] = 0;
- fimc_info2("plane_length[0] = %d, plane_length[1] = %d\n" \
- , plane_length[0], plane_length[1]);
- }
- break;
- /* In case of 3
- * YUV422 : 8 / 4 / 4 (bits)
- * YUV420 : 8 / 2 / 2 (bits)
- * 3rd plane have to consider page align for mmap */
- case 3:
- if (align) {
- plane_length[0] = (size*8) >> 3;
- plane_length[1] = (size*((bpp-8)/2)) >> 3;
- plane_length[2] = PAGE_ALIGN((size*bpp)>>3) - plane_length[0]
- - plane_length[1];
- } else {
- plane_length[0] = (size*8) >> 3;
- plane_length[1] = (size*((bpp-8)/2)) >> 3;
- plane_length[2] = ((size*bpp)>>3) - plane_length[0]
- - plane_length[1];
- }
- break;
- default:
- fimc_err("impossible!\n");
- return -ENOMEM;
- }
- if (use_paddingbuf) {
- plane_length[plane] = pad_size;
- cap->pktdata_plane = plane;
- } else
- plane_length[plane] = 0;
- #ifdef CONFIG_VIDEO_SAMSUNG_USE_DMA_MEM
- if (align) {
- alloc_size = (ALIGN(plane_length[0], align) +
- ALIGN(plane_length[1], align)
- + ALIGN(plane_length[2], align))
- * cap->nr_bufs;
- } else {
- alloc_size = (plane_length[0] + plane_length[1] +
- plane_length[2]) * cap->nr_bufs;
- }
- err = cma_info(&mem_info, ctrl->dev, 0);
- printk(KERN_DEBUG "%s : [cma_info] start_addr : 0x%x, end_addr : 0x%x, "
- "total_size : 0x%x, free_size : 0x%x req_size : 0x%x\n",
- __func__, mem_info.lower_bound, mem_info.upper_bound,
- mem_info.total_size, mem_info.free_size, alloc_size);
- if (err || (mem_info.free_size < alloc_size)) {
- fimc_err("%s: get cma info failed\n", __func__);
- ctrl->mem.size = 0;
- ctrl->mem.base = 0;
- return -ENOMEM;
- } else {
- ctrl->mem.size = alloc_size;
- ctrl->mem.base = (dma_addr_t)cma_alloc
- (ctrl->dev, ctrl->cma_name, (size_t) alloc_size, align);
- }
- ctrl->mem.curr = ctrl->mem.base;
- #endif
- for (i = 0; i < cap->nr_bufs; i++) {
- for (j = 0; j < plane; j++) {
- cap->bufs[i].length[j] = plane_length[j];
- fimc_dma_alloc(ctrl, &cap->bufs[i], j, align);
- if (!cap->bufs[i].base[j])
- goto err_alloc;
- }
- if (use_paddingbuf) {
- cap->bufs[i].length[plane] = plane_length[plane];
- fimc_dma_alloc(ctrl, &cap->bufs[i], plane, align);
- cap->bufs[i].vaddr_pktdata = phys_to_virt(cap->bufs[i].base[plane]);
- /* printk(KERN_INFO "pktdata address = 0x%x, 0x%x\n"
- ,cap->bufs[i].base[1], cap->bufs[i].vaddr_pktdata ); */
- if (!cap->bufs[i].base[plane])
- goto err_alloc;
- }
- cap->bufs[i].state = VIDEOBUF_PREPARED;
- }
- return 0;
- err_alloc:
- for (i = 0; i < cap->nr_bufs; i++) {
- for (j = 0; j < plane; j++) {
- if (cap->bufs[i].base[j])
- fimc_dma_free(ctrl, &cap->bufs[i], j);
- }
- if (use_paddingbuf) {
- if (cap->bufs[i].base[plane])
- fimc_dma_free(ctrl, &cap->bufs[i], plane);
- }
- memset(&cap->bufs[i], 0, sizeof(cap->bufs[i]));
- }
- return -ENOMEM;
- }
- static void fimc_free_buffers(struct fimc_control *ctrl)
- {
- struct fimc_capinfo *cap;
- int i;
- if (ctrl && ctrl->cap)
- cap = ctrl->cap;
- else
- return;
- for (i = 0; i < FIMC_PHYBUFS; i++) {
- memset(&cap->bufs[i], 0, sizeof(cap->bufs[i]));
- cap->bufs[i].state = VIDEOBUF_NEEDS_INIT;
- }
- ctrl->mem.curr = ctrl->mem.base;
- }
- #ifdef CONFIG_SLP_DMABUF
- static int fimc_set_cap_num_plane(struct fimc_control *ctrl)
- {
- struct fimc_capinfo *cap = ctrl->cap;
- switch (cap->fmt.pixelformat) {
- case V4L2_PIX_FMT_RGB32: /* fall through */
- case V4L2_PIX_FMT_RGB565: /* fall through */
- case V4L2_PIX_FMT_YUYV: /* fall through */
- case V4L2_PIX_FMT_UYVY: /* fall through */
- case V4L2_PIX_FMT_VYUY: /* fall through */
- case V4L2_PIX_FMT_YVYU: /* fall through */
- case V4L2_PIX_FMT_NV16: /* fall through */
- case V4L2_PIX_FMT_NV61: /* fall through */
- case V4L2_PIX_FMT_JPEG:
- case V4L2_PIX_FMT_INTERLEAVED:
- return PLANE_1;
- case V4L2_PIX_FMT_NV21:
- case V4L2_PIX_FMT_NV12:
- case V4L2_PIX_FMT_NV12T:
- return PLANE_2;
- case V4L2_PIX_FMT_YUV422P: /* fall through */
- case V4L2_PIX_FMT_YUV420:
- case V4L2_PIX_FMT_YVU420:
- return PLANE_3;
- default:
- fimc_err("%s: Undefined format\n", __func__);
- break;
- }
- return 0;
- }
- #endif
- int fimc_reqbufs_capture_mmap(void *fh, struct v4l2_requestbuffers *b)
- {
- struct fimc_control *ctrl = fh;
- struct fimc_capinfo *cap = ctrl->cap;
- struct s3c_platform_fimc *pdata = to_fimc_plat(ctrl->dev);
- #if (defined(CONFIG_EXYNOS_DEV_PD) && defined(CONFIG_PM_RUNTIME))
- struct platform_device *pdev = to_platform_device(ctrl->dev);
- #endif
- int ret = 0, i;
- int bpp = 0;
- int size = 0;
- if (!cap) {
- fimc_err("%s: no capture device info\n", __func__);
- return -ENODEV;
- }
- mutex_lock(&ctrl->v4l2_lock);
- /* A count value of zero frees all buffers */
- if ((b->count == 0) || (b->count >= FIMC_CAPBUFS)) {
- /* aborting or finishing any DMA in progress */
- if (ctrl->status == FIMC_STREAMON)
- fimc_streamoff_capture(fh);
- for (i = 0; i < FIMC_CAPBUFS; i++) {
- fimc_dma_free(ctrl, &ctrl->cap->bufs[i], 0);
- fimc_dma_free(ctrl, &ctrl->cap->bufs[i], 1);
- fimc_dma_free(ctrl, &ctrl->cap->bufs[i], 2);
- }
- #ifdef CONFIG_VIDEO_SAMSUNG_USE_DMA_MEM
- if (ctrl->mem.base) {
- cma_free(ctrl->mem.base);
- ctrl->mem.base = 0;
- ctrl->mem.size = 0;
- }
- #endif
- mutex_unlock(&ctrl->v4l2_lock);
- return 0;
- }
- /* free previous buffers */
- if ((cap->nr_bufs >= 0) && (cap->nr_bufs < FIMC_CAPBUFS)) {
- fimc_info1("%s : remained previous buffer count is %d\n", __func__,
- cap->nr_bufs);
- for (i = 0; i < cap->nr_bufs; i++) {
- fimc_dma_free(ctrl, &cap->bufs[i], 0);
- fimc_dma_free(ctrl, &cap->bufs[i], 1);
- fimc_dma_free(ctrl, &cap->bufs[i], 2);
- fimc_dma_free(ctrl, &cap->bufs[i], 3);
- }
- #ifdef CONFIG_VIDEO_SAMSUNG_USE_DMA_MEM
- if (ctrl->mem.base) {
- cma_free(ctrl->mem.base);
- ctrl->mem.base = 0;
- ctrl->mem.size = 0;
- }
- #endif
- }
- fimc_free_buffers(ctrl);
- cap->nr_bufs = b->count;
- if (pdata->hw_ver >= 0x51) {
- #if (defined(CONFIG_EXYNOS_DEV_PD) && defined(CONFIG_PM_RUNTIME))
- if (ctrl->power_status == FIMC_POWER_OFF) {
- pm_runtime_get_sync(&pdev->dev);
- }
- #endif
- fimc_hw_reset_output_buf_sequence(ctrl);
- for (i = 0; i < cap->nr_bufs; i++) {
- fimc_hwset_output_buf_sequence(ctrl, i, 1);
- cap->bufs[i].id = i;
- cap->bufs[i].state = VIDEOBUF_NEEDS_INIT;
- /* initialize list */
- INIT_LIST_HEAD(&cap->bufs[i].list);
- }
- fimc_info1("%s: requested %d buffers\n", __func__, b->count);
- fimc_info1("%s: sequence[%d]\n", __func__,
- fimc_hwget_output_buf_sequence(ctrl));
- INIT_LIST_HEAD(&cap->outgoing_q);
- }
- if (pdata->hw_ver < 0x51) {
- INIT_LIST_HEAD(&cap->inq);
- for (i = 0; i < cap->nr_bufs; i++) {
- cap->bufs[i].id = i;
- cap->bufs[i].state = VIDEOBUF_NEEDS_INIT;
- /* initialize list */
- INIT_LIST_HEAD(&cap->bufs[i].list);
- }
- }
- if (cap->pktdata_enable)
- cap->pktdata_size = 0x1000;
- bpp = fimc_fmt_depth(ctrl, &cap->fmt);
- switch (cap->fmt.pixelformat) {
- case V4L2_PIX_FMT_RGB32: /* fall through */
- case V4L2_PIX_FMT_RGB565: /* fall through */
- case V4L2_PIX_FMT_YUYV: /* fall through */
- case V4L2_PIX_FMT_UYVY: /* fall through */
- case V4L2_PIX_FMT_VYUY: /* fall through */
- case V4L2_PIX_FMT_YVYU: /* fall through */
- case V4L2_PIX_FMT_NV16: /* fall through */
- case V4L2_PIX_FMT_NV61: /* fall through */
- fimc_info1("%s : 1plane\n", __func__);
- ret = fimc_alloc_buffers(ctrl, 1,
- cap->fmt.width * cap->fmt.height, SZ_4K, bpp, cap->pktdata_enable, cap->pktdata_size);
- break;
- case V4L2_PIX_FMT_NV21:
- fimc_info1("%s : 2plane for NV21 w %d h %d\n", __func__,
- cap->fmt.width, cap->fmt.height);
- ret = fimc_alloc_buffers(ctrl, 2,
- cap->fmt.width * cap->fmt.height, 0, bpp, cap->pktdata_enable, cap->pktdata_size);
- break;
- case V4L2_PIX_FMT_NV12:
- fimc_info1("%s : 2plane for NV12\n", __func__);
- ret = fimc_alloc_buffers(ctrl, 2,
- cap->fmt.width * cap->fmt.height, SZ_64K, bpp, cap->pktdata_enable, cap->pktdata_size);
- break;
- case V4L2_PIX_FMT_NV12T:
- fimc_info1("%s : 2plane for NV12T\n", __func__);
- ret = fimc_alloc_buffers(ctrl, 2,
- ALIGN(cap->fmt.width, 128) * ALIGN(cap->fmt.height, 32),
- SZ_64K, bpp, cap->pktdata_enable, cap->pktdata_size);
- break;
- case V4L2_PIX_FMT_YUV422P: /* fall through */
- case V4L2_PIX_FMT_YUV420:
- case V4L2_PIX_FMT_YVU420:
- fimc_info1("%s : 3plane\n", __func__);
- ret = fimc_alloc_buffers(ctrl, 3,
- cap->fmt.width * cap->fmt.height, 0, bpp, cap->pktdata_enable, cap->pktdata_size);
- break;
- case V4L2_PIX_FMT_JPEG:
- fimc_info1("%s : JPEG 1plane\n", __func__);
- size = fimc_camera_get_jpeg_memsize(ctrl);
- fimc_info2("%s : JPEG 1plane size = %x\n", __func__, size);
- ret = fimc_alloc_buffers(ctrl, 1, size, 0, 8, cap->pktdata_enable, cap->pktdata_size);
- break;
- case V4L2_PIX_FMT_INTERLEAVED:
- fimc_info1("%s : Interleaved Format\n", __func__);
- size = fimc_camera_get_jpeg_memsize(ctrl); /*0xA00000*/
- fimc_info2("%s : Interleaved size = %x\n", __func__, size);
- ret = fimc…