aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/s5p-fimc/fimc-capture.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/s5p-fimc/fimc-capture.c')
-rw-r--r--drivers/media/video/s5p-fimc/fimc-capture.c863
1 files changed, 764 insertions, 99 deletions
diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c
index 81b4a82..93efab3 100644
--- a/drivers/media/video/s5p-fimc/fimc-capture.c
+++ b/drivers/media/video/s5p-fimc/fimc-capture.c
@@ -16,6 +16,7 @@
#include <linux/errno.h>
#include <linux/bug.h>
#include <linux/interrupt.h>
+#include <linux/delay.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/list.h>
@@ -24,11 +25,12 @@
#include <linux/i2c.h>
#include <linux/videodev2.h>
+#include <linux/videodev2_exynos_camera.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-mem2mem.h>
#include <media/videobuf2-core.h>
-#include <media/videobuf2-dma-contig.h>
+#include <media/videobuf2-cma-phys.h>
#include "fimc-core.h"
@@ -44,7 +46,7 @@ static struct v4l2_subdev *fimc_subdev_register(struct fimc_dev *fimc,
return ERR_PTR(-ENOMEM);
sd = v4l2_i2c_new_subdev_board(&vid_cap->v4l2_dev, i2c_adap,
- isp_info->board_info, NULL);
+ isp_info->board_info, NULL);
if (!sd) {
v4l2_err(&vid_cap->v4l2_dev, "failed to acquire subdev\n");
return NULL;
@@ -71,10 +73,184 @@ static void fimc_subdev_unregister(struct fimc_dev *fimc)
i2c_put_adapter(client->adapter);
vid_cap->sd = NULL;
}
-
+ if (vid_cap->mipi_sd) {
+ v4l2_device_unregister_subdev(vid_cap->mipi_sd);
+ vid_cap->mipi_sd = NULL;
+ }
+ if (vid_cap->fb_sd) {
+ v4l2_device_unregister_subdev(vid_cap->fb_sd);
+ vid_cap->fb_sd = NULL;
+ }
+ if (vid_cap->is.sd) {
+ v4l2_device_unregister_subdev(vid_cap->is.sd);
+ vid_cap->is.sd = NULL;
+ vid_cap->is.frame_count = 0;
+ vid_cap->is.valid = 0;
+ vid_cap->is.bad_mark = 0;
+ vid_cap->is.offset_x = 0;
+ vid_cap->is.offset_y = 0;
+ }
+ if (vid_cap->flite_sd) {
+ v4l2_device_unregister_subdev(vid_cap->flite_sd);
+ vid_cap->flite_sd = NULL;
+ }
vid_cap->input_index = -1;
}
+static int mipi_csi_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_subdevdata(sd);
+ if (pdev)
+ dbg("pdev->id: %d", pdev->id);
+ *(sd_list + pdev->id) = sd;
+ }
+
+ return 0; /* non-zero value stops iteration */
+}
+
+static struct v4l2_subdev *s5p_mipi_get_subdev(int id)
+{
+ const char *module_name = "s5p-mipi-csis";
+ struct device_driver *drv;
+ struct v4l2_subdev *sd[FIMC_MAX_CSIS_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],
+ mipi_csi_register_callback);
+ put_driver(drv);
+
+ return ret ? NULL : sd[id];
+}
+
+static int s3cfb_register_callback(struct device *dev, void *p)
+{
+ struct v4l2_subdev **sd = p;
+
+ /*
+ * FIXME: detect platform device id and handle multiple
+ * MIPI-CSI devices.
+ */
+ *sd = dev_get_drvdata(dev);
+
+ if (*sd) {
+ struct platform_device *pdev = v4l2_get_subdevdata(*sd);
+ if (pdev)
+ dbg("pdev->id: %d", pdev->id);
+ }
+
+ return 0; /* non-zero value stops iteration */
+}
+
+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_subdevdata(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];
+}
+
+static int fimc_is_register_callback(struct device *dev, void *p)
+{
+ struct v4l2_subdev **sd = p;
+ struct platform_device *pdev;
+
+ *sd = dev_get_drvdata(dev);
+
+ if (*sd)
+ pdev = v4l2_get_subdevdata(*sd);
+
+ return 0; /* non-zero value stops iteration */
+}
+
+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 struct v4l2_subdev *s3c_fb_get_subdev(int id)
+{
+ const char *module_name = FIMD_MODULE_NAME;
+ 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);
+ /*
+ * FIXME: detect platform device id and handle multiple
+ * MIPI-CSI devices. Now always a subdev from the last
+ * found device is returned.
+ */
+ ret = driver_for_each_device(drv, NULL, &sd,
+ s3cfb_register_callback);
+ put_driver(drv);
+
+ return ret ? NULL : sd;
+}
+
/**
* fimc_subdev_attach - attach v4l2_subdev to camera host interface
*
@@ -89,18 +265,62 @@ static int fimc_subdev_attach(struct fimc_dev *fimc, int index)
struct s5p_platform_fimc *pdata = fimc->pdata;
struct s5p_fimc_isp_info *isp_info;
struct v4l2_subdev *sd;
- int i;
-
- for (i = 0; i < pdata->num_clients; ++i) {
- isp_info = &pdata->isp_info[i];
+ int i, ret;
- if (index >= 0 && i != index)
+ for (i = 0; i < FIMC_MAX_CAMIF_CLIENTS; ++i) {
+ isp_info = pdata->isp_info[i];
+ if (!isp_info || (index >= 0 && i != index))
continue;
+ if (isp_info->bus_type == FIMC_MIPI_CSI2) {
+ vid_cap->mipi_sd = s5p_mipi_get_subdev(isp_info->mux_id);
+ if (IS_ERR_OR_NULL(vid_cap->mipi_sd)) {
+ fimc->vid_cap.mipi_sd = NULL;
+ return PTR_ERR(vid_cap->mipi_sd);
+ }
+ } else if (isp_info->bus_type == FIMC_LCD_WB) {
+ vid_cap->fb_sd = s3c_fb_get_subdev(0);
+ if (IS_ERR_OR_NULL(vid_cap->fb_sd))
+ return PTR_ERR(vid_cap->fb_sd);
+ vid_cap->ctx->in_path = FIMC_LCD_WB;
+ vid_cap->input_index = i;
- sd = fimc_subdev_register(fimc, isp_info);
- if (!IS_ERR_OR_NULL(sd)) {
- vid_cap->sd = sd;
+ return 0;
+ }
+
+ if (!isp_info->use_isp) {
+ sd = fimc_subdev_register(fimc, isp_info);
+ if (sd) {
+ vid_cap->sd = sd;
+ vid_cap->input_index = i;
+
+ return 0;
+ }
+ } else {
+ /* Register FIMC-Lite */
+ vid_cap->flite_sd = exynos_flite_get_subdev(isp_info->flite_id);
+ if (IS_ERR_OR_NULL(vid_cap->flite_sd)) {
+ vid_cap->flite_sd = NULL;
+ return PTR_ERR(vid_cap->flite_sd);
+ } else {
+ if (fimc_cam_use(index)) {
+ ret = v4l2_subdev_call(vid_cap->flite_sd, core, s_power, 1);
+ if (ret)
+ err("s_power failed: %d", ret);
+ }
+
+ }
+ dbg("FIMC%d Register FIMC-Lite subdev\n", fimc->id);
+ /* Register FIMC-IS*/
+ vid_cap->is.sd = fimc_is_get_subdev(index);
+ if (IS_ERR_OR_NULL(vid_cap->is.sd)) {
+ vid_cap->is.sd = NULL;
+ return PTR_ERR(vid_cap->is.sd);
+ }
vid_cap->input_index = i;
+ dbg("FIMC%d Register FIMC-IS subdev\n", fimc->id);
+ vid_cap->is.fmt.width = 0;
+ vid_cap->is.fmt.height = 0;
+ vid_cap->is.frame_count = 0;
return 0;
}
@@ -116,32 +336,165 @@ static int fimc_subdev_attach(struct fimc_dev *fimc, int index)
static int fimc_isp_subdev_init(struct fimc_dev *fimc, unsigned int index)
{
struct s5p_fimc_isp_info *isp_info;
- struct s5p_platform_fimc *pdata = fimc->pdata;
int ret;
+ if (index >= FIMC_MAX_CAMIF_CLIENTS)
+ return -EINVAL;
- if (index >= pdata->num_clients)
+ isp_info = fimc->pdata->isp_info[index];
+ if (!isp_info)
return -EINVAL;
- isp_info = &pdata->isp_info[index];
+ if (isp_info->clk_frequency && isp_info->use_cam) {
+ if (isp_info->mux_id == 0) {
+ fimc->vid_cap.mux_id = 0;
+ fimc->clock[CLK_CAM0] =
+ clk_get(&fimc->pdev->dev, CLK_NAME_CAM0);
+ ret = fimc_clk_setrate(fimc, CLK_CAM0, isp_info);
+ if (!ret)
+ clk_enable(fimc->clock[CLK_CAM0]);
+ } else {
+ fimc->vid_cap.mux_id = 1;
+ fimc->clock[CLK_CAM1] =
+ clk_get(&fimc->pdev->dev, CLK_NAME_CAM1);
+ ret = fimc_clk_setrate(fimc, CLK_CAM1, isp_info);
+ if (!ret)
+ clk_enable(fimc->clock[CLK_CAM1]);
+ }
+ if (ret < 0)
+ return -EINVAL;
+ }
- if (isp_info->clk_frequency)
- clk_set_rate(fimc->clock[CLK_CAM], isp_info->clk_frequency);
+ if (isp_info->use_cam) {
+ dbg("FIMC%d try to attatch sensor\n", fimc->id);
+ ret = fimc_subdev_attach(fimc, index);
+ if (ret)
+ return ret;
+ fimc->vid_cap.is.camcording = 0;
+ } else {
+ dbg("FIMC%d didn't try to attatch sensor\n", fimc->id);
+ fimc->vid_cap.input_index = index;
+ fimc->vid_cap.mux_id = -1;
+ if (isp_info->use_isp)
+ fimc->vid_cap.is.camcording = 1;
+ else
+ fimc->vid_cap.is.camcording = 0;
+ }
- ret = clk_enable(fimc->clock[CLK_CAM]);
+ ret = fimc_hw_set_camera_polarity(fimc, isp_info);
if (ret)
return ret;
- ret = fimc_subdev_attach(fimc, index);
- if (ret)
- return ret;
+ if (fimc->vid_cap.mipi_sd)
+ ret = v4l2_subdev_call(fimc->vid_cap.mipi_sd, core, s_power, 1);
- ret = fimc_hw_set_camera_polarity(fimc, isp_info);
- if (ret)
- return ret;
+ if (fimc->vid_cap.sd)
+ ret = v4l2_subdev_call(fimc->vid_cap.sd, core, s_power, 1);
- ret = v4l2_subdev_call(fimc->vid_cap.sd, core, s_power, 1);
- if (!ret)
+ if (fimc->vid_cap.fb_sd) {
+ unsigned int wb_on = 1;
+ dbg("write-back mode\n");
+ ret = v4l2_subdev_call(fimc->vid_cap.fb_sd, core, ioctl,
+ (unsigned int)NULL, &wb_on);
+ }
+
+ if (fimc->vid_cap.is.sd) {
+ dbg("FIMC-IS Init sequence\n");
+ ret = isp_info->cam_power(1);
+ if (unlikely(ret < 0))
+ err("Fail to power on\n");
+ ret = v4l2_subdev_call(fimc->vid_cap.is.sd, core, s_power, 1);
+ if (ret < 0) {
+ err("FIMC-IS init failed - power on");
+ return -ENODEV;
+ }
+ ret = v4l2_subdev_call(fimc->vid_cap.is.sd, core, load_fw);
+ if (ret < 0) {
+ err("FIMC-IS init failed - load fw");
+ return -ENODEV;
+ }
+
+ if (strcmp(&isp_info->board_info->type[0], "S5K3H2") == 0) {
+ switch (isp_info->mux_id) {
+ case 0:
+ ret = v4l2_subdev_call(fimc->vid_cap.is.sd, core, init, 1);
+ if (ret < 0) {
+ err("FIMC-IS init failed - open sensor");
+ return -ENODEV;
+ }
+ break;
+ case 1:
+ ret = v4l2_subdev_call(fimc->vid_cap.is.sd, core, init, 101);
+ if (ret < 0) {
+ err("FIMC-IS init failed - open sensor");
+ return -ENODEV;
+ }
+ break;
+ default:
+ break;
+ }
+ } else if (strcmp(&isp_info->board_info->type[0], "S5K4E5") == 0) {
+ switch (isp_info->mux_id) {
+ case 0:
+ ret = v4l2_subdev_call(fimc->vid_cap.is.sd, core, init, 3);
+ if (ret < 0) {
+ err("FIMC-IS init failed - open sensor");
+ return -ENODEV;
+ }
+ break;
+ case 1:
+ ret = v4l2_subdev_call(fimc->vid_cap.is.sd, core, init, 103);
+ if (ret < 0) {
+ err("FIMC-IS init failed - open sensor");
+ return -ENODEV;
+ }
+ break;
+ default:
+ break;
+ }
+ } else if (strcmp(&isp_info->board_info->type[0], "S5K3H7") == 0) {
+ switch (isp_info->mux_id) {
+ case 0:
+ ret = v4l2_subdev_call(fimc->vid_cap.is.sd, core, init, 4);
+ if (ret < 0) {
+ err("FIMC-IS init failed - open sensor");
+ return -ENODEV;
+ }
+ break;
+ case 1:
+ ret = v4l2_subdev_call(fimc->vid_cap.is.sd, core, init, 104);
+ if (ret < 0) {
+ err("FIMC-IS init failed - open sensor");
+ return -ENODEV;
+ }
+ break;
+ default:
+ break;
+ }
+ } else if (strcmp(&isp_info->board_info->type[0], "S5K6A3") == 0) {
+ switch (isp_info->mux_id) {
+ case 0:
+ ret = v4l2_subdev_call(fimc->vid_cap.is.sd, core, init, 2);
+ if (ret < 0) {
+ err("FIMC-IS init failed - open sensor");
+ return -ENODEV;
+ }
+ break;
+ case 1:
+ ret = v4l2_subdev_call(fimc->vid_cap.is.sd, core, init, 102);
+ if (ret < 0) {
+ err("FIMC-IS init failed - open sensor");
+ return -ENODEV;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ if (!ret) {
return ret;
+ }
/* enabling power failed so unregister subdev */
fimc_subdev_unregister(fimc);
@@ -157,7 +510,7 @@ static int fimc_stop_capture(struct fimc_dev *fimc)
unsigned long flags;
struct fimc_vid_cap *cap;
struct fimc_vid_buffer *buf;
-
+ int ret = 0;
cap = &fimc->vid_cap;
if (!fimc_capture_active(fimc))
@@ -168,15 +521,26 @@ static int fimc_stop_capture(struct fimc_dev *fimc)
fimc_deactivate_capture(fimc);
spin_unlock_irqrestore(&fimc->slock, flags);
- wait_event_timeout(fimc->irq_queue,
- !test_bit(ST_CAPT_SHUT, &fimc->state),
- FIMC_SHUTDOWN_TIMEOUT);
+ ret = fimc_wait_disable_capture(fimc);
+ if (ret < 0)
+ err("wait stop seq fail");
+
+ if (cap->sd)
+ v4l2_subdev_call(cap->sd, video, s_stream, 0);
+
+ if (cap->is.sd)
+ v4l2_subdev_call(fimc->vid_cap.is.sd, video, s_stream, 0);
- v4l2_subdev_call(cap->sd, video, s_stream, 0);
+ if (cap->flite_sd)
+ v4l2_subdev_call(fimc->vid_cap.flite_sd, video, s_stream, 0);
+
+ if (cap->mipi_sd)
+ v4l2_subdev_call(fimc->vid_cap.mipi_sd, video, s_stream, 0);
spin_lock_irqsave(&fimc->slock, flags);
fimc->state &= ~(1 << ST_CAPT_RUN | 1 << ST_CAPT_PEND |
- 1 << ST_CAPT_SHUT | 1 << ST_CAPT_STREAM);
+ 1 << ST_CAPT_SHUT | 1 << ST_CAPT_STREAM |
+ 1 << ST_CAPT_SENS_STREAM);
fimc->vid_cap.active_buf_cnt = 0;
@@ -202,29 +566,61 @@ static int start_streaming(struct vb2_queue *q)
struct fimc_ctx *ctx = q->drv_priv;
struct fimc_dev *fimc = ctx->fimc_dev;
struct s5p_fimc_isp_info *isp_info;
- int ret;
+ int ret = 0;
- fimc_hw_reset(fimc);
+ if (!test_and_set_bit(ST_PWR_ON, &fimc->state))
+ pm_runtime_get_sync(&fimc->pdev->dev);
- ret = v4l2_subdev_call(fimc->vid_cap.sd, video, s_stream, 1);
- if (ret && ret != -ENOIOCTLCMD)
- return ret;
+ if (fimc->vid_cap.mipi_sd) {
+ ret = v4l2_subdev_call(fimc->vid_cap.mipi_sd, video, s_stream, 1);
+ if (ret) {
+ err("mipi s_stream error");
+ return ret;
+ }
+ }
ret = fimc_prepare_config(ctx, ctx->state);
if (ret)
return ret;
- isp_info = &fimc->pdata->isp_info[fimc->vid_cap.input_index];
+ isp_info = fimc->pdata->isp_info[fimc->vid_cap.input_index];
fimc_hw_set_camera_type(fimc, isp_info);
+
+ if (ctx->in_path == FIMC_LCD_WB) {
+ if (isp_info->mux_id == 0)
+ fimc_hwset_sysreg_camblk_fimd0_wb(fimc);
+ else
+ fimc_hwset_sysreg_camblk_fimd1_wb(fimc);
+ }
+
+ if (fimc->vid_cap.is.sd) {
+ struct platform_device *pdev = fimc->pdev;
+ struct clk *pxl_async = NULL;
+
+ dbg("FIMC-IS pixel async setting\n");
+ pxl_async = clk_get(&pdev->dev, "pxl_async1");
+ if (IS_ERR(pxl_async)) {
+ err("failed to get pxl_async\n");
+ return -ENODEV;
+ }
+
+ clk_enable(pxl_async);
+ clk_put(pxl_async);
+ fimc_hwset_sysreg_camblk_isp_wb(fimc);
+ }
+
+ if (fimc->vid_cap.flite_sd) {
+ dbg("FIMC-Lite stream on..\n");
+ v4l2_subdev_call(fimc->vid_cap.flite_sd, video, s_stream, 1);
+ }
+
fimc_hw_set_camera_source(fimc, isp_info);
fimc_hw_set_camera_offset(fimc, &ctx->s_frame);
if (ctx->state & FIMC_PARAMS) {
ret = fimc_set_scaler_info(ctx);
- if (ret) {
+ if (ret)
err("Scaler setup error");
- return ret;
- }
fimc_hw_set_input_path(ctx);
fimc_hw_set_prescaler(ctx);
fimc_hw_set_mainscaler(ctx);
@@ -235,12 +631,14 @@ static int start_streaming(struct vb2_queue *q)
fimc_hw_set_output_path(ctx);
fimc_hw_set_out_dma(ctx);
+ /* for zero shuterlack at Exynos4210 EVT1 */
+ fimc_hwset_enable_lastend(fimc);
INIT_LIST_HEAD(&fimc->vid_cap.pending_buf_q);
INIT_LIST_HEAD(&fimc->vid_cap.active_buf_q);
fimc->vid_cap.active_buf_cnt = 0;
fimc->vid_cap.frame_count = 0;
- fimc->vid_cap.buf_index = 0;
+ fimc->vid_cap.buf_index = fimc_hw_get_frame_index(fimc);
set_bit(ST_CAPT_PEND, &fimc->state);
@@ -252,17 +650,28 @@ static int stop_streaming(struct vb2_queue *q)
struct fimc_ctx *ctx = q->drv_priv;
struct fimc_dev *fimc = ctx->fimc_dev;
+ if (!test_and_set_bit(ST_PWR_ON, &fimc->state))
+ pm_runtime_get_sync(&fimc->pdev->dev);
+
if (!fimc_capture_active(fimc))
return -EINVAL;
- return fimc_stop_capture(fimc);
+ fimc_stop_capture(fimc);
+ fimc_hw_reset(fimc);
+ fimc->vb2->suspend(fimc->alloc_ctx);
+
+ if (test_and_clear_bit(ST_PWR_ON, &fimc->state))
+ pm_runtime_put_sync(&fimc->pdev->dev);
+
+ return 0;
}
static unsigned int get_plane_size(struct fimc_frame *fr, unsigned int plane)
{
if (!fr || plane >= fr->fmt->memplanes)
return 0;
- return fr->f_width * fr->f_height * fr->fmt->depth[plane] / 8;
+
+ return fr->payload[plane];
}
static int queue_setup(struct vb2_queue *vq, unsigned int *num_buffers,
@@ -290,6 +699,8 @@ static int buffer_prepare(struct vb2_buffer *vb)
{
struct vb2_queue *vq = vb->vb2_queue;
struct fimc_ctx *ctx = vq->drv_priv;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+ struct fimc_frame *frame = &ctx->d_frame;
struct v4l2_device *v4l2_dev = &ctx->fimc_dev->m2m.v4l2_dev;
int i;
@@ -300,7 +711,7 @@ static int buffer_prepare(struct vb2_buffer *vb)
unsigned long size = get_plane_size(&ctx->d_frame, i);
if (vb2_plane_size(vb, i) < size) {
- v4l2_err(v4l2_dev, "User buffer too small (%ld < %ld)\n",
+ v4l2_err(v4l2_dev, "User buffer too small(%ld < %ld)\n",
vb2_plane_size(vb, i), size);
return -EINVAL;
}
@@ -308,28 +719,41 @@ static int buffer_prepare(struct vb2_buffer *vb)
vb2_set_plane_payload(vb, i, size);
}
+ if (ctx->d_frame.cacheable)
+ fimc->vb2->cache_flush(vb, frame->fmt->memplanes);
+
return 0;
}
static void buffer_queue(struct vb2_buffer *vb)
{
- struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
- struct fimc_dev *fimc = ctx->fimc_dev;
struct fimc_vid_buffer *buf
= container_of(vb, struct fimc_vid_buffer, vb);
+ struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+ struct fimc_dev *fimc = ctx->fimc_dev;
struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
+ struct fimc_fmt *fmt = vid_cap->ctx->d_frame.fmt;
unsigned long flags;
int min_bufs;
spin_lock_irqsave(&fimc->slock, flags);
fimc_prepare_addr(ctx, &buf->vb, &ctx->d_frame, &buf->paddr);
+ if (fmt->fourcc == V4L2_PIX_FMT_YVU420 ||
+ fmt->fourcc == V4L2_PIX_FMT_YVU420M) {
+ u32 t_cb = buf->paddr.cb;
+ buf->paddr.cb = buf->paddr.cr;
+ buf->paddr.cr = t_cb;
+ }
+
+ if (!test_and_set_bit(ST_PWR_ON, &fimc->state))
+ pm_runtime_get_sync(&fimc->pdev->dev);
+
if (!test_bit(ST_CAPT_STREAM, &fimc->state)
&& vid_cap->active_buf_cnt < FIMC_MAX_OUT_BUFS) {
/* Setup the buffer directly for processing. */
int buf_id = (vid_cap->reqbufs_count == 1) ? -1 :
vid_cap->buf_index;
-
fimc_hw_set_output_addr(fimc, &buf->paddr, buf_id);
buf->index = vid_cap->buf_index;
active_queue_add(vid_cap, buf);
@@ -342,23 +766,46 @@ static void buffer_queue(struct vb2_buffer *vb)
min_bufs = vid_cap->reqbufs_count > 1 ? 2 : 1;
+ if (!test_bit(ST_CAPT_RUN, &fimc->state)) {
+ if (vid_cap->active_buf_cnt == 1)
+ fimc->vb2->resume(fimc->alloc_ctx);
+ }
if (vid_cap->active_buf_cnt >= min_bufs &&
- !test_and_set_bit(ST_CAPT_STREAM, &fimc->state))
+ !test_and_set_bit(ST_CAPT_STREAM, &fimc->state)) {
+ int ret = 0;
fimc_activate_capture(ctx);
+ spin_unlock_irqrestore(&fimc->slock, flags);
+
+ if (!test_and_set_bit(ST_CAPT_SENS_STREAM, &fimc->state)) {
+ if (fimc->vid_cap.is.sd)
+ ret = v4l2_subdev_call(fimc->vid_cap.is.sd,
+ video, s_stream, 1);
+ else
+ ret = v4l2_subdev_call(fimc->vid_cap.sd, video,
+ s_stream, 1);
+ }
+ return; /* ret = -ENOIOCTLCMD ? 0 : ret; */
+ }
spin_unlock_irqrestore(&fimc->slock, flags);
+
+ return;
}
static void fimc_lock(struct vb2_queue *vq)
{
+#ifdef FOR_DIFF_VER
struct fimc_ctx *ctx = vb2_get_drv_priv(vq);
mutex_lock(&ctx->fimc_dev->lock);
+#endif
}
static void fimc_unlock(struct vb2_queue *vq)
{
+#ifdef FOR_DIFF_VER
struct fimc_ctx *ctx = vb2_get_drv_priv(vq);
mutex_unlock(&ctx->fimc_dev->lock);
+#endif
}
static struct vb2_ops fimc_capture_qops = {
@@ -374,24 +821,26 @@ static struct vb2_ops fimc_capture_qops = {
static int fimc_capture_open(struct file *file)
{
struct fimc_dev *fimc = video_drvdata(file);
- int ret = 0;
dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state);
+ if (!test_and_set_bit(ST_PWR_ON, &fimc->state))
+ pm_runtime_get_sync(&fimc->pdev->dev);
+
+ fimc_hw_reset(fimc);
+ fimc_hw_set_irq_level(fimc);
+
+ if (fimc->variant->out_buf_count > 4)
+ fimc_hw_set_dma_seq(fimc, 0xF);
/* Return if the corresponding video mem2mem node is already opened. */
if (fimc_m2m_active(fimc))
return -EBUSY;
- if (++fimc->vid_cap.refcnt == 1) {
- ret = fimc_isp_subdev_init(fimc, 0);
- if (ret) {
- fimc->vid_cap.refcnt--;
- return -EIO;
- }
- }
-
file->private_data = fimc->vid_cap.ctx;
+ if (test_and_clear_bit(ST_PWR_ON, &fimc->state))
+ pm_runtime_put_sync(&fimc->pdev->dev);
+
return 0;
}
@@ -401,17 +850,40 @@ static int fimc_capture_close(struct file *file)
dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state);
+ if (!test_and_set_bit(ST_PWR_ON, &fimc->state))
+ pm_runtime_get_sync(&fimc->pdev->dev);
+
if (--fimc->vid_cap.refcnt == 0) {
fimc_stop_capture(fimc);
vb2_queue_release(&fimc->vid_cap.vbq);
v4l2_err(&fimc->vid_cap.v4l2_dev, "releasing ISP\n");
- v4l2_subdev_call(fimc->vid_cap.sd, core, s_power, 0);
- clk_disable(fimc->clock[CLK_CAM]);
+ if (fimc->vid_cap.sd)
+ v4l2_subdev_call(fimc->vid_cap.sd, core, s_power, 0);
+
+ if (fimc->vid_cap.is.sd)
+ v4l2_subdev_call(fimc->vid_cap.is.sd, core, s_power, 0);
+
+ if (fimc->vid_cap.flite_sd)
+ v4l2_subdev_call(fimc->vid_cap.flite_sd, core, s_power, 0);
+
+ if (fimc->vid_cap.mipi_sd)
+ v4l2_subdev_call(fimc->vid_cap.mipi_sd, core, s_power, 0);
+
+ if (fimc->vid_cap.mux_id == 0) {
+ clk_put(fimc->clock[CLK_CAM0]);
+ clk_disable(fimc->clock[CLK_CAM0]);
+ } else if (fimc->vid_cap.mux_id == 1) {
+ clk_put(fimc->clock[CLK_CAM1]);
+ clk_disable(fimc->clock[CLK_CAM1]);
+ }
fimc_subdev_unregister(fimc);
}
+ if (test_and_clear_bit(ST_PWR_ON, &fimc->state))
+ pm_runtime_put_sync(&fimc->pdev->dev);
+
return 0;
}
@@ -459,29 +931,88 @@ static int fimc_vidioc_querycap_capture(struct file *file, void *priv,
}
/* Synchronize formats of the camera interface input and attached sensor. */
-static int sync_capture_fmt(struct fimc_ctx *ctx)
+static int sync_capture_fmt(struct fimc_ctx *ctx, struct v4l2_rect *r)
{
- struct fimc_frame *frame = &ctx->s_frame;
+ struct fimc_frame *frame = &ctx->d_frame;
struct fimc_dev *fimc = ctx->fimc_dev;
struct v4l2_mbus_framefmt *fmt = &fimc->vid_cap.fmt;
+ struct fimc_pix_limit *plim = fimc->variant->pix_limit;
int ret;
+ int max_w, max_h;
+
+ fmt->width = r->width;
+ fmt->height = r->height;
+ max_w = ctx->scaler.enabled ? plim->scaler_en_w : plim->scaler_dis_w;
+ max_h = fimc_fmt_is_jpeg(frame->fmt->color) ? 0xFFFF : plim->in_rot_en_h;
+
+ v4l_bound_align_image(&fmt->width, 16, max_w, 4,
+ &fmt->height, 2, max_h, 1, 0);
+
+ dbg("%dx%d", fmt->width, fmt->height);
+ /*
+ * Try to match image sensor pixel format to the color format
+ * of the capture image to avoid color conversion when possible.
+ * If fimc destination is jpeg, sensor should be jpeg mbus code,
+ * and others should be yuv type although fimc'output is rgb.
+ */
+ if (frame->fmt->fourcc == V4L2_PIX_FMT_JPEG)
+ fmt->code = frame->fmt->mbus_code;
+ else
+ fmt->code = DEFAULT_ISP_PIXCODE;
+
+ dbg("frame->fmt->mbus_code : 0x%x", frame->fmt->mbus_code);
+ dbg("frame->fmt->name : %s", frame->fmt->name);
+ dbg("frame->fmt->fourcc : 0x%x", frame->fmt->fourcc);
+ dbg("frame->fmt->color : 0x%x", frame->fmt->color);
+ dbg("frame->fmt->memplanes : 0x%x", frame->fmt->memplanes);
+ dbg("frame->fmt->colplanes : 0x%x", frame->fmt->colplanes);
+
+ dbg("fmt->code : 0x%x", fmt->code);
+ dbg("fmt->colorspace : 0x%x", fmt->colorspace);
+
+ if (fimc->vid_cap.sd)
+ ret = v4l2_subdev_call(fimc->vid_cap.sd, video, s_mbus_fmt, fmt);
- fmt->width = ctx->d_frame.o_width;
- fmt->height = ctx->d_frame.o_height;
+ if (ret) {
+ err("s_mbus_fmt failed");
+ return ret;
+ }
+
+ err("IS : w= %d, h= %d", fimc->vid_cap.is.mbus_fmt.width, fimc->vid_cap.is.mbus_fmt.height);
+ if (fimc->vid_cap.mipi_sd) {
+ if (fimc->vid_cap.is.sd)
+ ret = v4l2_subdev_call(fimc->vid_cap.mipi_sd, video, s_mbus_fmt, &fimc->vid_cap.is.mbus_fmt);
+ else
+ ret = v4l2_subdev_call(fimc->vid_cap.mipi_sd, video, s_mbus_fmt, fmt);
+ if (ret) {
+ err("s_mbus_fmt failed: %d", ret);
+ return ret;
+ }
+ }
- ret = v4l2_subdev_call(fimc->vid_cap.sd, video, s_mbus_fmt, fmt);
- if (ret == -ENOIOCTLCMD) {
+ if (fimc->vid_cap.flite_sd)
+ ret = v4l2_subdev_call(fimc->vid_cap.flite_sd, video, s_mbus_fmt, &fimc->vid_cap.is.mbus_fmt);
+
+ if (ret) {
err("s_mbus_fmt failed");
return ret;
}
- dbg("w: %d, h: %d, code= %d", fmt->width, fmt->height, fmt->code);
+
+ dbg("w= %d, h= %d, code= %d", fmt->width, fmt->height, fmt->code);
+
+ frame = &ctx->s_frame;
frame->fmt = find_mbus_format(fmt, FMT_FLAGS_CAM);
if (!frame->fmt) {
- err("fimc source format not found\n");
+ v4l2_err(&fimc->vid_cap.v4l2_dev,
+ "fimc source format not found\n");
return -EINVAL;
}
+ /* Color conversion to JPEG is not supported */
+ if (ctx->d_frame.fmt->color == S5P_FIMC_JPEG &&
+ fmt->code != V4L2_MBUS_FMT_JPEG_1X8)
+ return -EINVAL;
frame->f_width = fmt->width;
frame->f_height = fmt->height;
frame->width = fmt->width;
@@ -491,6 +1022,10 @@ static int sync_capture_fmt(struct fimc_ctx *ctx)
frame->offs_h = 0;
frame->offs_v = 0;
+ dbg("frame->width : %d, frame->f_height : %d, frame->width : %d,\
+ frame->height : %d, frame->o_width : %d, frame->o_height :\
+ %d\n", frame->width, frame->f_height, frame->width,\
+ frame->height, frame->o_width, frame->o_height);
return 0;
}
@@ -501,17 +1036,22 @@ static int fimc_cap_s_fmt_mplane(struct file *file, void *priv,
struct fimc_dev *fimc = ctx->fimc_dev;
struct fimc_frame *frame;
struct v4l2_pix_format_mplane *pix;
+ struct v4l2_rect r;
int ret;
int i;
+ struct v4l2_control is_ctrl;
if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
return -EINVAL;
+ r.width = f->fmt.pix_mp.width;
+ r.height = f->fmt.pix_mp.height;
+
ret = fimc_vidioc_try_fmt_mplane(file, priv, f);
if (ret)
return ret;
- if (vb2_is_busy(&fimc->vid_cap.vbq) || fimc_capture_active(fimc))
+ if (vb2_is_streaming(&fimc->vid_cap.vbq) || fimc_capture_active(fimc))
return -EBUSY;
frame = &ctx->d_frame;
@@ -523,25 +1063,71 @@ static int fimc_cap_s_fmt_mplane(struct file *file, void *priv,
return -EINVAL;
}
- for (i = 0; i < frame->fmt->colplanes; i++) {
- frame->payload[i] =
- (pix->width * pix->height * frame->fmt->depth[i]) >> 3;
- }
+ for (i = 0; i < frame->fmt->colplanes; i++)
+ frame->payload[i] = pix->plane_fmt[i].sizeimage;
- /* Output DMA frame pixel size and offsets. */
- frame->f_width = pix->plane_fmt[0].bytesperline * 8
- / frame->fmt->depth[0];
- frame->f_height = pix->height;
- frame->width = pix->width;
- frame->height = pix->height;
- frame->o_width = pix->width;
- frame->o_height = pix->height;
- frame->offs_h = 0;
- frame->offs_v = 0;
+ fimc_set_frame_size_mp(frame, f);
ctx->state |= (FIMC_PARAMS | FIMC_DST_FMT);
- ret = sync_capture_fmt(ctx);
+ if (!test_and_set_bit(ST_PWR_ON, &fimc->state))
+ pm_runtime_get_sync(&fimc->pdev->dev);
+
+ /* for returning preview size for FIMC-Lite */
+ if (fimc->vid_cap.is.sd) {
+ fimc->vid_cap.is.mbus_fmt.code = V4L2_MBUS_FMT_SGRBG10_1X10;
+ is_ctrl.id = V4L2_CID_IS_GET_SENSOR_WIDTH;
+ v4l2_subdev_call(fimc->vid_cap.is.sd, core, g_ctrl, &is_ctrl);
+ fimc->vid_cap.is.fmt.width = fimc->vid_cap.is.mbus_fmt.width = is_ctrl.value;
+
+ is_ctrl.id = V4L2_CID_IS_GET_SENSOR_HEIGHT;
+ v4l2_subdev_call(fimc->vid_cap.is.sd, core, g_ctrl, &is_ctrl);
+ fimc->vid_cap.is.fmt.height = fimc->vid_cap.is.mbus_fmt.height = is_ctrl.value;
+ /* default offset values */
+ fimc->vid_cap.is.offset_x = 16;
+ fimc->vid_cap.is.offset_y = 12;
+ fimc->vid_cap.is.mbus_fmt.width += fimc->vid_cap.is.offset_x;
+ fimc->vid_cap.is.mbus_fmt.height += fimc->vid_cap.is.offset_y;
+ }
+ ret = sync_capture_fmt(ctx, &r);
+
+ /* Scaling is not supported with JPEG color format. */
+ ctx->scaler.enabled = !fimc_fmt_is_jpeg(ctx->d_frame.fmt->color);
+
+ return ret;
+}
+
+static int fimc_s_fmt_vid_private(struct file *file, void *fh, struct v4l2_format *f)
+{
+ struct fimc_ctx *ctx = file->private_data;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+ struct v4l2_mbus_framefmt *mbus_fmt;
+ int ret = 0;
+
+ dbg("%s\n", __func__);
+ mbus_fmt = kzalloc(sizeof(*mbus_fmt), GFP_KERNEL);
+ if (!mbus_fmt) {
+ err("%s: no memory for "
+ "mbus_fmt\n", __func__);
+ return -ENOMEM;
+ }
+ fimc->vid_cap.is.fmt.width = f->fmt.pix.width;
+ fimc->vid_cap.is.fmt.height = f->fmt.pix.height;
+ fimc->vid_cap.is.fmt.pixelformat = f->fmt.pix.pixelformat;
+ fimc->vid_cap.is.mbus_fmt.width = f->fmt.pix.width + 16;
+ fimc->vid_cap.is.mbus_fmt.height = f->fmt.pix.height + 12;
+ fimc->vid_cap.is.mbus_fmt.code = V4L2_MBUS_FMT_SGRBG10_1X10;
+ fimc->vid_cap.is.mbus_fmt.colorspace = V4L2_COLORSPACE_SRGB;
+
+ 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;
+ if (fimc->vid_cap.is.sd)
+ ret = v4l2_subdev_call(fimc->vid_cap.is.sd, video,
+ s_mbus_fmt, mbus_fmt);
+ kfree(mbus_fmt);
return ret;
}
@@ -552,10 +1138,12 @@ static int fimc_cap_enum_input(struct file *file, void *priv,
struct s5p_platform_fimc *pldata = ctx->fimc_dev->pdata;
struct s5p_fimc_isp_info *isp_info;
- if (i->index >= pldata->num_clients)
+ if (i->index >= FIMC_MAX_CAMIF_CLIENTS)
return -EINVAL;
- isp_info = &pldata->isp_info[i->index];
+ isp_info = pldata->isp_info[i->index];
+ if (isp_info == NULL)
+ return -EINVAL;
i->type = V4L2_INPUT_TYPE_CAMERA;
strncpy(i->name, isp_info->board_info->type, 32);
@@ -568,26 +1156,54 @@ static int fimc_cap_s_input(struct file *file, void *priv,
struct fimc_ctx *ctx = priv;
struct fimc_dev *fimc = ctx->fimc_dev;
struct s5p_platform_fimc *pdata = fimc->pdata;
+ int ret;
if (fimc_capture_active(ctx->fimc_dev))
return -EBUSY;
- if (i >= pdata->num_clients)
+ if (i >= FIMC_MAX_CAMIF_CLIENTS || !pdata->isp_info[i]) {
+ err("error max client or pdata");
return -EINVAL;
+ }
+ if (fimc->vid_cap.mipi_sd) {
+ ret = v4l2_subdev_call(fimc->vid_cap.mipi_sd, core, s_power, 0);
+ if (ret)
+ err("s_power failed: %d", ret);
+ }
if (fimc->vid_cap.sd) {
- int ret = v4l2_subdev_call(fimc->vid_cap.sd, core, s_power, 0);
+ ret = v4l2_subdev_call(fimc->vid_cap.sd, core, s_power, 0);
if (ret)
err("s_power failed: %d", ret);
+ }
+ /* FIMC-IS power of */
+ if (fimc->vid_cap.is.sd) {
+ ret = v4l2_subdev_call(fimc->vid_cap.is.sd, core, s_power, 0);
+ if (ret)
+ err("s_power failed: %d", ret);
+ }
- clk_disable(fimc->clock[CLK_CAM]);
+ if (fimc->vid_cap.flite_sd) {
+ ret = v4l2_subdev_call(fimc->vid_cap.flite_sd, core, s_power, 0);
+ if (ret)
+ err("s_power failed: %d", ret);
}
+ dbg("Release the attached sensor subdevice");
/* Release the attached sensor subdevice. */
fimc_subdev_unregister(fimc);
- return fimc_isp_subdev_init(fimc, i);
+ if (!test_and_set_bit(ST_PWR_ON, &fimc->state))
+ pm_runtime_get_sync(&fimc->pdev->dev);
+
+ ret = fimc_isp_subdev_init(fimc, i);
+ if (ret)
+ err("subdev init failed");
+
+ fimc->vid_cap.refcnt++;
+
+ return ret;
}
static int fimc_cap_g_input(struct file *file, void *priv,
@@ -606,9 +1222,6 @@ static int fimc_cap_streamon(struct file *file, void *priv,
struct fimc_ctx *ctx = priv;
struct fimc_dev *fimc = ctx->fimc_dev;
- if (fimc_capture_active(fimc) || !fimc->vid_cap.sd)
- return -EBUSY;
-
if (!(ctx->state & FIMC_DST_FMT)) {
v4l2_err(&fimc->vid_cap.v4l2_dev, "Format is not set\n");
return -EINVAL;
@@ -630,9 +1243,14 @@ static int fimc_cap_reqbufs(struct file *file, void *priv,
struct v4l2_requestbuffers *reqbufs)
{
struct fimc_ctx *ctx = priv;
+ struct fimc_dev *fimc = ctx->fimc_dev;
struct fimc_vid_cap *cap = &ctx->fimc_dev->vid_cap;
+ struct fimc_frame *frame;
int ret;
+ frame = ctx_get_frame(ctx, reqbufs->type);
+ frame->cacheable = ctx->cacheable;
+ fimc->vb2->set_cacheable(fimc->alloc_ctx, frame->cacheable);
ret = vb2_reqbufs(&cap->vbq, reqbufs);
if (!ret)
@@ -655,6 +1273,7 @@ static int fimc_cap_qbuf(struct file *file, void *priv,
{
struct fimc_ctx *ctx = priv;
struct fimc_vid_cap *cap = &ctx->fimc_dev->vid_cap;
+
return vb2_qbuf(&cap->vbq, buf);
}
@@ -683,9 +1302,12 @@ static int fimc_cap_s_ctrl(struct file *file, void *priv,
ctx->state |= FIMC_PARAMS;
}
}
- if (ret == -EINVAL)
+ if (ret == -EINVAL && ctx->fimc_dev->vid_cap.sd)
ret = v4l2_subdev_call(ctx->fimc_dev->vid_cap.sd,
core, s_ctrl, ctrl);
+ if (ctx->fimc_dev->vid_cap.is.sd)
+ ret = v4l2_subdev_call(ctx->fimc_dev->vid_cap.is.sd,
+ core, s_ctrl, ctrl);
return ret;
}
@@ -747,11 +1369,11 @@ static int fimc_cap_s_crop(struct file *file, void *fh,
f = &ctx->s_frame;
/* Check for the pixel scaling ratio when cropping input image. */
- ret = fimc_check_scaler_ratio(cr->c.width, cr->c.height,
+ ret = fimc_check_scaler_ratio(ctx, cr->c.width, cr->c.height,
ctx->d_frame.width, ctx->d_frame.height,
ctx->rotation);
if (ret) {
- v4l2_err(&fimc->vid_cap.v4l2_dev, "Out of the scaler range\n");
+ v4l2_err(&fimc->vid_cap.v4l2_dev, "Out of the scaler range");
return ret;
}
@@ -771,6 +1393,7 @@ static const struct v4l2_ioctl_ops fimc_capture_ioctl_ops = {
.vidioc_try_fmt_vid_cap_mplane = fimc_vidioc_try_fmt_mplane,
.vidioc_s_fmt_vid_cap_mplane = fimc_cap_s_fmt_mplane,
.vidioc_g_fmt_vid_cap_mplane = fimc_vidioc_g_fmt_mplane,
+ .vidioc_s_fmt_type_private = fimc_s_fmt_vid_private,
.vidioc_reqbufs = fimc_cap_reqbufs,
.vidioc_querybuf = fimc_cap_querybuf,
@@ -794,6 +1417,34 @@ static const struct v4l2_ioctl_ops fimc_capture_ioctl_ops = {
.vidioc_g_input = fimc_cap_g_input,
};
+/*
+ * The End Of Frame notification sent by sensor subdev in its still capture
+ * mode. If there is only a single VSYNC generated by the sensor, FIMC does
+ * not issue the LastIrq (end of frame) interrupt. And this notification
+ * is used to complete a frame capture and passing it to userspace.
+ */
+void fimc_v4l2_dev_notify(struct v4l2_subdev *sd, unsigned int notification,
+ void *arg)
+{
+ struct fimc_vid_cap *cap = container_of(sd->v4l2_dev,
+ struct fimc_vid_cap, v4l2_dev);
+ struct fimc_dev *fimc = container_of(cap, struct fimc_dev, vid_cap);
+ struct fimc_vid_buffer *buf;
+ unsigned long flags;
+
+ dbg("bytesused: %d", notification);
+
+ spin_lock_irqsave(&fimc->slock, flags);
+ buf = list_entry(cap->active_buf_q.next, struct fimc_vid_buffer, list);
+
+ vb2_set_plane_payload(&buf->vb, 0, notification);
+
+ fimc_capture_irq_handler(fimc);
+ fimc_deactivate_capture(fimc);
+
+ spin_unlock_irqrestore(&fimc->slock, flags);
+}
+
/* fimc->lock must be already initialized */
int fimc_register_capture_device(struct fimc_dev *fimc)
{
@@ -826,6 +1477,8 @@ int fimc_register_capture_device(struct fimc_dev *fimc)
snprintf(v4l2_dev->name, sizeof(v4l2_dev->name),
"%s.capture", dev_name(&fimc->pdev->dev));
+ v4l2_dev->notify = fimc_v4l2_dev_notify;
+
ret = v4l2_device_register(NULL, v4l2_dev);
if (ret)
goto err_info;
@@ -843,7 +1496,9 @@ int fimc_register_capture_device(struct fimc_dev *fimc)
vfd->ioctl_ops = &fimc_capture_ioctl_ops;
vfd->minor = -1;
vfd->release = video_device_release;
+#ifdef FOR_DIFF_VER
vfd->lock = &fimc->lock;
+#endif
video_set_drvdata(vfd, fimc);
vid_cap = &fimc->vid_cap;
@@ -851,8 +1506,18 @@ int fimc_register_capture_device(struct fimc_dev *fimc)
vid_cap->active_buf_cnt = 0;
vid_cap->reqbufs_count = 0;
vid_cap->refcnt = 0;
- /* Default color format for image sensor */
- vid_cap->fmt.code = V4L2_MBUS_FMT_YUYV8_2X8;
+ vid_cap->sd = NULL;
+ vid_cap->fb_sd = NULL;
+ vid_cap->mipi_sd = NULL;
+ vid_cap->is.sd = NULL;
+ vid_cap->is.frame_count = 0;
+ vid_cap->is.valid = 0;
+ vid_cap->is.bad_mark = 0;
+ vid_cap->is.offset_x = 0;
+ vid_cap->is.offset_y = 0;
+
+ /* Default color format for 4EA image sensor */
+ vid_cap->fmt.code = V4L2_MBUS_FMT_VYUY8_2X8;
INIT_LIST_HEAD(&vid_cap->pending_buf_q);
INIT_LIST_HEAD(&vid_cap->active_buf_q);
@@ -865,7 +1530,7 @@ int fimc_register_capture_device(struct fimc_dev *fimc)
q->io_modes = VB2_MMAP | VB2_USERPTR;
q->drv_priv = fimc->vid_cap.ctx;
q->ops = &fimc_capture_qops;
- q->mem_ops = &vb2_dma_contig_memops;
+ q->mem_ops = ctx->fimc_dev->vb2->ops;
q->buf_struct_size = sizeof(struct fimc_vid_buffer);
vb2_queue_init(q);
@@ -879,7 +1544,7 @@ int fimc_register_capture_device(struct fimc_dev *fimc)
v4l2_info(v4l2_dev,
"FIMC capture driver registered as /dev/video%d\n",
vfd->num);
-
+ dbg("%s : code : %d\n", __func__, fimc->vid_cap.fmt.code);
return 0;
err_vd_reg: