RE: [PATCH] media: fimc-lite: Add new driver for camera interface

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Sylwester,
Thanks for your comment.

> On 03/04/2012 07:17 AM, Sylwester Nawrocki wrote:
> Hi Sungchun,
> 
> On 02/15/2012 07:05 AM, Sungchun Kang wrote:
> > This patch adds support fimc-lite device which is a new device for
> > camera interface on EXYNOS5 SoCs.
> 
> It's also available in the Exynos4 SoC and I was planning adding it at
> the s5p-fimc driver eventually. It may take some time though since it
> is not described in the datasheets I have.
> 
You're right, Fimc-lite is used exynos4(4212 and 4412 except 4210) and exynos5.
But we decided to use mc in exynos5 only.
And exynos4 has fimc-lite and fimc, on the other hand, exynos5 fimc-lite and
g-scaler.
Also, fimc-lite can memory operation like as fimc and SFR is quite different.

> > This device supports the followings as key feature.
> >   1) Multiple input
> >    - ITU-R BT 601 mode
> >    - MIPI(CSI) mode
> >   2) Multiple output
> >    - DMA mode
> >    - Direct FIFO mode
> >
> > Signed-off-by: Sungchun Kang<sungchun.kang@xxxxxxxxxxx>
> >
> > NOTE : This patch is based on
> > "media: media-dev: Add media devices for EXYNOS5".
> > ---
> >   drivers/media/video/Kconfig                        |    3 +-
> >   drivers/media/video/Makefile                       |    2 +-
> >   drivers/media/video/exynos/Kconfig                 |   20 +
> >   drivers/media/video/exynos/Makefile                |    4 +
> >   drivers/media/video/exynos/fimc-lite/Kconfig       |   22 +
> >   drivers/media/video/exynos/fimc-lite/Makefile      |    6 +
> >   .../media/video/exynos/fimc-lite/fimc-lite-core.c  | 1921
> ++++++++++++++++++++
> >   .../media/video/exynos/fimc-lite/fimc-lite-core.h  |  310 ++++
> >   .../media/video/exynos/fimc-lite/fimc-lite-reg.c   |  332 ++++
> >   .../media/video/exynos/fimc-lite/fimc-lite-reg.h   |  135 ++
> >   include/media/exynos_camera.h                      |   59 +
> >   include/media/exynos_flite.h                       |   39 +
> >   12 files changed, 2851 insertions(+), 2 deletions(-)
> >   create mode 100644 drivers/media/video/exynos/Kconfig
> >   create mode 100644 drivers/media/video/exynos/Makefile
> >   create mode 100644 drivers/media/video/exynos/fimc-lite/Kconfig
> >   create mode 100644 drivers/media/video/exynos/fimc-lite/Makefile
> >   create mode 100644 drivers/media/video/exynos/fimc-lite/fimc-lite-
> core.c
> >   create mode 100644 drivers/media/video/exynos/fimc-lite/fimc-lite-
> core.h
> >   create mode 100644 drivers/media/video/exynos/fimc-lite/fimc-lite-
> reg.c
> >   create mode 100644 drivers/media/video/exynos/fimc-lite/fimc-lite-
> reg.h
> >   create mode 100644 include/media/exynos_camera.h
> >   create mode 100644 include/media/exynos_flite.h
> >
> ...
> > +if VIDEO_EXYNOS_FIMC_LITE&&  VIDEOBUF2_CMA_PHYS comment "Reserved
> > +memory configurations"
> > +config VIDEO_SAMSUNG_MEMSIZE_FLITE0
> > +	int "Memory size in kbytes for FLITE0"
> > +	default "10240"
> > +
> > +config VIDEO_SAMSUNG_MEMSIZE_FLITE1
> > +	int "Memory size in kbytes for FLITE1"
> > +	default "10240"
> > +endif
> 
> There is no VIDEOBUF2_CMA_PHYS allocator in the mainline and there
> should be no need for it. CMA should be used through the dma mapping
> framework, see https://lkml.org/lkml/2012/2/22/309.
> 
Ah...
My mistake.:-)
> > diff --git a/drivers/media/video/exynos/fimc-lite/Makefile
> > b/drivers/media/video/exynos/fimc-lite/Makefile
> > new file mode 100644
> > index 0000000..431d199
> > --- /dev/null
> > +++ b/drivers/media/video/exynos/fimc-lite/Makefile
> > @@ -0,0 +1,6 @@
> > +ifeq ($(CONFIG_ARCH_EXYNOS5),y)
> > +fimc-lite-objs := fimc-lite-core.o fimc-lite-reg.o else
> > +fimc-lite-objs := fimc-lite-core.o fimc-lite-reg.o endif
> > +obj-$(CONFIG_VIDEO_EXYNOS_FIMC_LITE)	+= fimc-lite.o
> > diff --git a/drivers/media/video/exynos/fimc-lite/fimc-lite-core.c
> > b/drivers/media/video/exynos/fimc-lite/fimc-lite-core.c
> > new file mode 100644
> > index 0000000..9bb1c88
> > --- /dev/null
> > +++ b/drivers/media/video/exynos/fimc-lite/fimc-lite-core.c
> > @@ -0,0 +1,1921 @@
> > +/*
> > + * Register interface file for Samsung Camera Interface (FIMC-Lite)
> > +driver
> > + *
> > + * Copyright (c) 2011 Samsung Electronics
> 
> 2011 - 2012 ?
OK. I will fix it.
> 
> > + *
> > + * 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/module.h>
> > +#include<linux/kernel.h>
> > +#include<linux/errno.h>
> > +#include<linux/interrupt.h>
> > +#include<linux/device.h>
> > +#include<linux/platform_device.h>
> > +#include<linux/slab.h>
> > +#include<linux/i2c.h>
> > +#include<media/exynos_mc.h>
> > +#include<media/videobuf2-dma-contig.h>
> > +
> > +#include "fimc-lite-core.h"
> > +
> > +#define MODULE_NAME			"exynos-fimc-lite"
> > +#define DEFAULT_FLITE_SINK_WIDTH	800
> > +#define DEFAULT_FLITE_SINK_HEIGHT	480
> > +
> > +static struct flite_fmt flite_formats[] = {
> > +	{
> > +		.name		= "YUV422 8-bit 1 plane(UYVY)",
> > +		.pixelformat	= V4L2_PIX_FMT_UYVY,
> > +		.depth		= { 16 },
> > +		.code		= V4L2_MBUS_FMT_UYVY8_2X8,
> > +		.fmt_reg	= FLITE_REG_CIGCTRL_YUV422_1P,
> > +		.is_yuv		= 1,
> > +	}, {
> > +		.name		= "YUV422 8-bit 1 plane(VYUY)",
> > +		.pixelformat	= V4L2_PIX_FMT_VYUY,
> > +		.depth		= { 16 },
> > +		.code		= V4L2_MBUS_FMT_VYUY8_2X8,
> > +		.fmt_reg	= FLITE_REG_CIGCTRL_YUV422_1P,
> > +		.is_yuv		= 1,
> > +	}, {
> > +		.name		= "YUV422 8-bit 1 plane(YUYV)",
> > +		.pixelformat	= V4L2_PIX_FMT_YUYV,
> > +		.depth		= { 16 },
> > +		.code		= V4L2_MBUS_FMT_YUYV8_2X8,
> > +		.fmt_reg	= FLITE_REG_CIGCTRL_YUV422_1P,
> > +		.is_yuv		= 1,
> > +	}, {
> > +		.name		= "YUV422 8-bit 1 plane(YVYU)",
> > +		.pixelformat	= V4L2_PIX_FMT_YVYU,
> > +		.depth		= { 16 },
> > +		.code		= V4L2_MBUS_FMT_YVYU8_2X8,
> > +		.fmt_reg	= FLITE_REG_CIGCTRL_YUV422_1P,
> > +		.is_yuv		= 1,
> > +	}, {
> > +		.name		= "RAW8(GRBG)",
> > +		.pixelformat	= V4L2_PIX_FMT_SGRBG8,
> > +		.depth		= { 8 },
> > +		.code		= V4L2_MBUS_FMT_SGRBG8_1X8,
> > +		.fmt_reg	= FLITE_REG_CIGCTRL_RAW8,
> > +		.is_yuv		= 0,
> > +	}, {
> > +		.name		= "RAW10(GRBG)",
> > +		.pixelformat	= V4L2_PIX_FMT_SGRBG10,
> > +		.depth		= { 10 },
> > +		.code		= V4L2_MBUS_FMT_SGRBG10_1X10,
> > +		.fmt_reg	= FLITE_REG_CIGCTRL_RAW10,
> > +		.is_yuv		= 0,
> > +	}, {
> > +		.name		= "RAW12(GRBG)",
> > +		.pixelformat	= V4L2_PIX_FMT_SGRBG12,
> > +		.depth		= { 12 },
> > +		.code		= V4L2_MBUS_FMT_SGRBG12_1X12,
> > +		.fmt_reg	= FLITE_REG_CIGCTRL_RAW12,
> > +		.is_yuv		= 0,
> > +	}, {
> > +		.name		= "User Defined(JPEG)",
> > +		.code		= V4L2_MBUS_FMT_JPEG_1X8,
> > +		.depth		= { 8 },
> > +		.fmt_reg	= FLITE_REG_CIGCTRL_USER(1),
> > +		.is_yuv		= 0,
> > +	},
> > +};
> > +
> > +static struct flite_variant variant = {
> > +	.max_w			= 8192,
> > +	.max_h			= 8192,
> > +	.align_win_offs_w	= 2,
> > +	.align_out_w		= 8,
> > +	.align_out_offs_w	= 8,
> > +};
> > +
> > +static struct flite_fmt *get_format(int index) {
> > +	return&flite_formats[index];
> > +}
> ...
> > +
> > +static int flite_s_stream(struct v4l2_subdev *sd, int enable) {
> > +	struct flite_dev *flite = v4l2_get_subdevdata(sd);
> > +	u32 index = flite->pdata->active_cam_index;
> > +	struct s3c_platform_camera *cam = NULL;
> > +	u32 int_src = 0;
> > +	unsigned long flags;
> > +	int ret = 0;
> > +
> > +	if (!(flite->output&  FLITE_OUTPUT_MEM)) {
> > +		if (enable)
> > +			flite_hw_reset(flite);
> > +		cam = flite->pdata->cam[index];
> > +	}
> > +
> > +	spin_lock_irqsave(&flite->slock, flags);
> > +
> > +	if (test_bit(FLITE_ST_SUSPEND,&flite->state))
> > +		goto s_stream_unlock;
> > +
> > +	if (enable) {
> > +		flite_hw_set_cam_channel(flite);
> > +		flite_hw_set_cam_source_size(flite);
> > +
> > +		if (!(flite->output&  FLITE_OUTPUT_MEM)) {
> > +			flite_info("@local out start@");
> > +			flite_hw_set_camera_type(flite, cam);
> > +			flite_hw_set_config_irq(flite, cam);
> > +			if (cam->use_isp)
> > +				flite_hw_set_output_dma(flite, false);
> > +			int_src = FLITE_REG_CIGCTRL_IRQ_OVFEN0_ENABLE |
> > +				FLITE_REG_CIGCTRL_IRQ_LASTEN0_ENABLE |
> > +				FLITE_REG_CIGCTRL_IRQ_ENDEN0_DISABLE |
> > +				FLITE_REG_CIGCTRL_IRQ_STARTEN0_DISABLE;
> > +		} else {
> > +			flite_info("@mem out start@");
> > +			flite_hw_set_sensor_type(flite);
> > +			flite_hw_set_inverse_polarity(flite);
> > +			set_bit(FLITE_ST_PEND,&flite->state);
> > +			flite_hw_set_output_dma(flite, true);
> > +			int_src = FLITE_REG_CIGCTRL_IRQ_OVFEN0_ENABLE |
> > +				FLITE_REG_CIGCTRL_IRQ_LASTEN0_ENABLE |
> > +				FLITE_REG_CIGCTRL_IRQ_ENDEN0_ENABLE |
> > +				FLITE_REG_CIGCTRL_IRQ_STARTEN0_DISABLE;
> > +			flite_hw_set_out_order(flite);
> > +			flite_hw_set_output_size(flite);
> > +			flite_hw_set_dma_offset(flite);
> > +		}
> > +		ret = flite_hw_set_source_format(flite);
> > +		if (unlikely(ret<  0))
> > +			goto s_stream_unlock;
> > +
> > +		flite_hw_set_interrupt_source(flite, int_src);
> > +		flite_hw_set_window_offset(flite);
> > +		flite_hw_set_capture_start(flite);
> > +
> > +		set_bit(FLITE_ST_STREAM,&flite->state);
> > +	} else {
> > +		if (test_bit(FLITE_ST_STREAM,&flite->state)) {
> > +			flite_hw_set_capture_stop(flite);
> > +			spin_unlock_irqrestore(&flite->slock, flags);
> > +			ret = wait_event_timeout(flite->irq_queue,
> > +			!test_bit(FLITE_ST_STREAM,&flite->state), HZ/20);
> > +			if (unlikely(!ret)) {
> > +				v4l2_err(sd, "wait timeout\n");
> > +				ret = -EBUSY;
> > +			}
> > +			return ret;
> > +		} else {
> > +			goto s_stream_unlock;
> > +		}
> 
> You can drop the goto statement.
> 
Ok.

> > +	}
> > +s_stream_unlock:
> > +	spin_unlock_irqrestore(&flite->slock, flags);
> > +	return ret;
> > +}
> > +
> > +static irqreturn_t flite_irq_handler(int irq, void *priv) {
> > +	struct flite_dev *flite = priv;
> > +	struct flite_buffer *buf;
> > +	u32 int_src = 0;
> > +
> > +	flite_hw_get_int_src(flite,&int_src);
> > +	flite_hw_clear_irq(flite);
> > +
> > +	spin_lock(&flite->slock);
> > +
> > +	switch (int_src&  FLITE_REG_CISTATUS_IRQ_MASK) {
> > +	case FLITE_REG_CISTATUS_IRQ_SRC_OVERFLOW:
> > +		clear_bit(FLITE_ST_RUN,&flite->state);
> > +		flite_err("overflow generated");
> > +		break;
> > +	case FLITE_REG_CISTATUS_IRQ_SRC_LASTCAPEND:
> > +		flite_hw_set_last_capture_end_clear(flite);
> > +		flite_info("last capture end");
> > +		clear_bit(FLITE_ST_STREAM,&flite->state);
> > +		wake_up(&flite->irq_queue);
> > +		break;
> > +	case FLITE_REG_CISTATUS_IRQ_SRC_FRMSTART:
> > +		flite_dbg("frame start");
> > +		break;
> > +	case FLITE_REG_CISTATUS_IRQ_SRC_FRMEND:
> > +		set_bit(FLITE_ST_RUN,&flite->state);
> > +		flite_dbg("frame end");
> > +		break;
> > +	}
> > +
> > +	if (flite->output&  FLITE_OUTPUT_MEM) {
> > +		if (!list_empty(&flite->active_buf_q)) {
> > +			buf = active_queue_pop(flite);
> > +			if (!test_bit(FLITE_ST_RUN,&flite->state)) {
> > +				vb2_buffer_done(&buf->vb,
> VB2_BUF_STATE_ERROR);
> > +				goto unlock;
> > +			}
> > +			vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
> > +			flite_dbg("done_index : %d", buf-
> >vb.v4l2_buf.index);
> > +		}
> > +		if (!list_empty(&flite->pending_buf_q)) {
> > +			buf = pending_queue_pop(flite);
> > +			flite_hw_set_output_addr(flite,&buf->paddr,
> > +					buf->vb.v4l2_buf.index);
> > +			active_queue_add(flite, buf);
> > +		}
> > +		if (flite->active_buf_cnt == 0)
> > +			clear_bit(FLITE_ST_RUN,&flite->state);
> > +	}
> > +unlock:
> > +	spin_unlock(&flite->slock);
> > +
> > +	return IRQ_HANDLED;
> > +}
> > +
> > +static int flite_s_power(struct v4l2_subdev *sd, int on) {
> > +	struct flite_dev *flite = v4l2_get_subdevdata(sd);
> > +	int ret = 0;
> > +
> > +	if (on) {
> > +		pm_runtime_get_sync(&flite->pdev->dev);
> > +		set_bit(FLITE_ST_POWER,&flite->state);
> > +	} else {
> > +		pm_runtime_put_sync(&flite->pdev->dev);
> 
> The runtime PM calls shouldn't be used from within the system sleep
> helpers AFAIK, so there may be issues when calling flite_s_power from
> within any system suspen or resume callback. And no, I don't know how
> to handle this properly yet.
> 
You're right, the runtime PM calls use schedule function. So it shouldn't
Use within atomic operation e.g) interrupt service routine.
But why s_power is system sleep function? 

> > +		clear_bit(FLITE_ST_POWER,&flite->state);
> > +	}
> > +
> > +	return ret;
> > +}
> > +
> > +static int flite_subdev_enum_mbus_code(struct v4l2_subdev *sd,
> > +				       struct v4l2_subdev_fh *fh,
> > +				       struct v4l2_subdev_mbus_code_enum *code)
> {
> > +	if (code->index>= ARRAY_SIZE(flite_formats))
> > +		return -EINVAL;
> > +
> > +	code->code = flite_formats[code->index].code;
> > +
> > +	return 0;
> > +}
> > +
> > +static struct v4l2_mbus_framefmt *__flite_get_format(
> > +		struct flite_dev *flite, struct v4l2_subdev_fh *fh,
> > +		u32 pad, enum v4l2_subdev_format_whence which) {
> > +	if (which == V4L2_SUBDEV_FORMAT_TRY)
> > +		return fh ? v4l2_subdev_get_try_format(fh, pad) : NULL;
> > +	else
> > +		return&flite->mbus_fmt;
> > +}
> > +
> > +static void flite_try_format(struct flite_dev *flite, struct
> v4l2_subdev_fh *fh,
> > +			     struct v4l2_mbus_framefmt *fmt,
> > +			     enum v4l2_subdev_format_whence which) {
> > +	struct flite_fmt *ffmt;
> > +	struct flite_frame *f =&flite->s_frame;
> 
> An empty line after variable declaration might be a good idea.
> 
> > +	ffmt = find_format(NULL,&fmt->code, 0);
> > +	if (ffmt == NULL)
> > +		ffmt =&flite_formats[1];
> > +
> > +	fmt->code = ffmt->code;
> > +	fmt->width = clamp_t(u32, fmt->width, 1, variant.max_w);
> > +	fmt->height = clamp_t(u32, fmt->height, 1, variant.max_h);
> > +
> > +	f->offs_h = f->offs_v = 0;
> > +	f->width = f->o_width = fmt->width;
> > +	f->height = f->o_height = fmt->height;
> > +
> > +	fmt->colorspace = V4L2_COLORSPACE_JPEG;
> > +	fmt->field = V4L2_FIELD_NONE;
> > +}
> > +
> > +static int flite_subdev_get_fmt(struct v4l2_subdev *sd, struct
> v4l2_subdev_fh *fh,
> > +				struct v4l2_subdev_format *fmt)
> > +{
> > +	struct flite_dev *flite = v4l2_get_subdevdata(sd);
> > +	struct v4l2_mbus_framefmt *mf;
> > +
> > +	mf = __flite_get_format(flite, fh, fmt->pad, fmt->which);
> > +	if (mf == NULL) {
> > +		flite_err("__flite_get_format is null");
> 
> How about using v4l2_err instead ? This apllies to most of other
> occurences as well.
Um.. I will consider that.
> 
> > +		return -EINVAL;
> > +	}
> > +
> > +	fmt->format = *mf;
> > +
> > +	if (fmt->pad != FLITE_PAD_SINK) {
> > +		struct flite_frame *f =&flite->s_frame;
> > +		fmt->format.width = f->width;
> > +		fmt->format.height = f->height;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +
> ...
> > +static int flite_subdev_registered(struct v4l2_subdev *sd) {
> > +	flite_dbg("");
> > +	return 0;
> > +}
> > +
> > +static void flite_subdev_unregistered(struct v4l2_subdev *sd) {
> > +	flite_dbg("");
> > +}
> 
> Just remove those empty callbacs.
Ok.
> 
> > +static const struct v4l2_subdev_internal_ops
> flite_v4l2_internal_ops = {
> > +	.open = flite_init_formats,
> > +	.close = flite_subdev_close,
> > +	.registered = flite_subdev_registered,
> > +	.unregistered = flite_subdev_unregistered, };
> > +
> ...
> > +static int flite_config_camclk(struct flite_dev *flite,
> > +		struct exynos_isp_info *isp_info, int i) {
> > +	struct clk *camclk;
> > +	struct clk *srclk;
> > +
> > +	camclk = clk_get(&flite->pdev->dev, isp_info->cam_clk_name);
> > +	if (IS_ERR_OR_NULL(camclk)) {
> > +		flite_err("failed to get cam clk");
> > +		return -ENXIO;
> > +	}
> > +	flite->sensor[i].camclk = camclk;
> > +
> > +	srclk = clk_get(&flite->pdev->dev, isp_info->cam_srclk_name);
> > +	if (IS_ERR_OR_NULL(srclk)) {
> > +		clk_put(camclk);
> > +		flite_err("failed to get cam source clk\n");
> > +		return -ENXIO;
> > +	}
> > +	clk_set_parent(camclk, srclk);
> > +	clk_set_rate(camclk, isp_info->clk_frequency);
> > +	clk_put(srclk);
> > +
> > +	flite->gsc_clk = clk_get(&flite->pdev->dev, "gscl");
> > +	if (IS_ERR_OR_NULL(flite->gsc_clk)) {
> > +		flite_err("failed to get gscl clk");
> > +		return -ENXIO;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static struct v4l2_subdev *flite_register_sensor(struct flite_dev
> *flite,
> > +		int i)
> > +{
> > +	struct exynos_platform_flite *pdata = flite->pdata;
> > +	struct exynos_isp_info *isp_info = pdata->isp_info[i];
> > +	struct exynos_md *mdev = flite->mdev;
> > +	struct i2c_adapter *adapter;
> > +	struct v4l2_subdev *sd = NULL;
> > +
> > +	adapter = i2c_get_adapter(isp_info->i2c_bus_num);
> > +	if (!adapter)
> > +		return NULL;
> > +	sd = v4l2_i2c_new_subdev_board(&mdev->v4l2_dev, adapter,
> > +				       isp_info->board_info, NULL);
> > +	if (IS_ERR_OR_NULL(sd)) {
> > +		v4l2_err(&mdev->v4l2_dev, "Failed to acquire subdev\n");
> > +		return NULL;
> > +	}
> > +	v4l2_set_subdev_hostdata(sd,&flite->sensor[i]);
> > +	sd->grp_id = SENSOR_GRP_ID;
> > +
> > +	v4l2_info(&mdev->v4l2_dev, "Registered sensor subdevice %s\n",
> > +		  isp_info->board_info->type);
> > +
> > +	return sd;
> > +}
> > +
> > +static int flite_register_sensor_entities(struct flite_dev *flite)
> {
> > +	struct exynos_platform_flite *pdata = flite->pdata;
> > +	u32 num_clients = pdata->num_clients;
> > +	int i;
> > +
> > +	for (i = 0; i<  num_clients; i++) {
> > +		flite->sensor[i].pdata = pdata->isp_info[i];
> > +		flite->sensor[i].sd = flite_register_sensor(flite, i);
> > +		if (IS_ERR_OR_NULL(flite->sensor[i].sd)) {
> > +			flite_err("failed to get register sensor");
> > +			return -EINVAL;
> > +		}
> > +		flite->mdev->sensor_sd[i] = flite->sensor[i].sd;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static int flite_create_subdev(struct flite_dev *flite, struct
> > +v4l2_subdev *sd) {
> > +	struct v4l2_device *v4l2_dev;
> > +	int ret;
> > +
> > +	sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
> > +
> > +	flite->pads[FLITE_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
> > +	flite->pads[FLITE_PAD_SOURCE_PREV].flags = MEDIA_PAD_FL_SOURCE;
> > +	flite->pads[FLITE_PAD_SOURCE_CAMCORD].flags =
> MEDIA_PAD_FL_SOURCE;
> > +	flite->pads[FLITE_PAD_SOURCE_MEM].flags = MEDIA_PAD_FL_SOURCE;
> > +
> > +	ret = media_entity_init(&sd->entity, FLITE_PADS_NUM,
> > +				flite->pads, 0);
> > +	if (ret)
> > +		goto err_ent;
> > +
> > +	sd->internal_ops =&flite_v4l2_internal_ops;
> > +	sd->entity.ops =&flite_media_ops;
> > +	sd->grp_id = FLITE_GRP_ID;
> > +	v4l2_dev =&flite->mdev->v4l2_dev;
> > +	flite->mdev->flite_sd[flite->id] = sd;
> > +
> > +	ret = v4l2_device_register_subdev(v4l2_dev, sd);
> > +	if (ret)
> > +		goto err_sub;
> > +
> > +	flite_init_formats(sd, NULL);
> > +
> > +	return 0;
> > +
> > +err_sub:
> > +	media_entity_cleanup(&sd->entity);
> > +err_ent:
> > +	return ret;
> > +}
> > +
> > +static int flite_create_link(struct flite_dev *flite) {
> > +	struct media_entity *source, *sink;
> > +	struct exynos_platform_flite *pdata = flite->pdata;
> > +	struct exynos_isp_info *isp_info;
> > +	u32 num_clients = pdata->num_clients;
> > +	int ret, i;
> > +	enum cam_port id;
> > +
> > +	/* FIMC-LITE-SUBDEV ------>  FIMC-LITE-VIDEO (Always link enable)
> */
> > +	source =&flite->sd_flite->entity;
> > +	sink =&flite->vfd->entity;
> > +	if (source&&  sink) {
> > +		ret = media_entity_create_link(source,
> FLITE_PAD_SOURCE_MEM, sink,
> > +				0, 0);
> > +		if (ret) {
> > +			flite_err("failed link flite-subdev to flite-
> video\n");
> > +			return ret;
> > +		}
> > +	}
> > +	/* link sensor to mipi-csis */
> > +	for (i = 0; i<  num_clients; i++) {
> > +		isp_info = pdata->isp_info[i];
> > +		id = isp_info->cam_port;
> > +		switch (isp_info->bus_type) {
> > +		case CAM_TYPE_ITU:
> > +			/*	SENSOR ------>  FIMC-LITE	*/
> > +			source =&flite->sensor[i].sd->entity;
> > +			sink =&flite->sd_flite->entity;
> > +			if (source&&  sink) {
> > +				ret = media_entity_create_link(source, 0,
> > +					      sink, FLITE_PAD_SINK, 0);
> > +				if (ret) {
> > +					flite_err("failed link sensor to
> flite\n");
> > +					return ret;
> > +				}
> > +			}
> > +			break;
> > +		case CAM_TYPE_MIPI:
> > +			/*	SENSOR ------>  MIPI-CSI2	*/
> > +			source =&flite->sensor[i].sd->entity;
> > +			sink =&flite->sd_csis->entity;
> > +			if (source&&  sink) {
> > +				ret = media_entity_create_link(source, 0,
> > +					      sink, CSIS_PAD_SINK, 0);
> > +				if (ret) {
> > +					flite_err("failed link sensor to
> csis\n");
> > +					return ret;
> > +				}
> > +			}
> > +			/*	MIPI-CSI2 ------>  FIMC-LITE	*/
> > +			source =&flite->sd_csis->entity;
> > +			sink =&flite->sd_flite->entity;
> > +			if (source&&  sink) {
> > +				ret = media_entity_create_link(source,
> > +						CSIS_PAD_SOURCE,
> > +						sink, FLITE_PAD_SINK, 0);
> > +				if (ret) {
> > +					flite_err("failed link csis to
> flite\n");
> > +					return ret;
> > +				}
> > +			}
> > +			break;
> > +		}
> > +	}
> > +
> > +	flite->input = FLITE_INPUT_NONE;
> > +	flite->output = FLITE_OUTPUT_NONE;
> > +
> > +	return 0;
> > +}
> > +static int flite_register_video_device(struct flite_dev *flite) {
> > +	struct video_device *vfd;
> > +	struct vb2_queue *q;
> > +	int ret = -ENOMEM;
> > +
> > +	vfd = video_device_alloc();
> > +	if (!vfd) {
> > +		flite_info("Failed to allocate video device");
> > +		return ret;
> > +	}
> > +
> > +	snprintf(vfd->name, sizeof(vfd->name), "%s",
> > +dev_name(&flite->pdev->dev));
> > +
> > +	vfd->fops	=&flite_fops;
> > +	vfd->ioctl_ops	=&flite_capture_ioctl_ops;
> > +	vfd->v4l2_dev	=&flite->mdev->v4l2_dev;
> > +	vfd->minor	= -1;
> > +	vfd->release	= video_device_release;
> > +	vfd->lock	=&flite->lock;
> > +	video_set_drvdata(vfd, flite);
> > +
> > +	flite->vfd = vfd;
> > +	flite->refcnt = 0;
> > +	flite->reqbufs_cnt  = 0;
> > +	INIT_LIST_HEAD(&flite->active_buf_q);
> > +	INIT_LIST_HEAD(&flite->pending_buf_q);
> > +
> > +	q =&flite->vbq;
> > +	memset(q, 0, sizeof(*q));
> > +	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
> > +	q->io_modes = VB2_MMAP | VB2_USERPTR;
> > +	q->drv_priv = flite;
> > +	q->ops =&flite_qops;
> > +	q->mem_ops =&vb2_dma_contig_memops;
> > +
> > +	vb2_queue_init(q);
> > +
> > +	ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
> > +	if (ret) {
> > +		flite_err("failed to register video device");
> > +		goto err_vfd_alloc;
> > +	}
> > +
> > +	flite->vd_pad.flags = MEDIA_PAD_FL_SOURCE;
> > +	ret = media_entity_init(&vfd->entity, 1,&flite->vd_pad, 0);
> > +	if (ret) {
> > +		flite_err("failed to initialize entity");
> > +		goto err_unreg_video;
> > +	}
> > +
> > +	flite_dbg("flite video-device driver registered as /dev/video%d",
> > +vfd->num);
> > +
> > +	return 0;
> > +
> > +err_unreg_video:
> > +	video_unregister_device(vfd);
> > +err_vfd_alloc:
> > +	video_device_release(vfd);
> > +
> > +	return ret;
> > +}
> > +
> > +static int flite_get_md_callback(struct device *dev, void *p) {
> > +	struct exynos_md **md_list = p;
> > +	struct exynos_md *md = NULL;
> > +
> > +	md = dev_get_drvdata(dev);
> > +
> > +	if (md)
> > +		*(md_list + md->id) = md;
> > +
> > +	return 0; /* non-zero value stops iteration */ }
> > +
> > +static struct exynos_md *flite_get_capture_md(enum mdev_node node)
> {
> > +	struct device_driver *drv;
> > +	struct exynos_md *md[MDEV_MAX_NUM] = {NULL,};
> > +	int ret;
> > +
> > +	drv = driver_find(MDEV_MODULE_NAME,&platform_bus_type);
> > +	if (!drv)
> > +		return ERR_PTR(-ENODEV);
> > +
> > +	ret = driver_for_each_device(drv, NULL,&md[0],
> > +				     flite_get_md_callback);
> > +	put_driver(drv);
> > +
> > +	return ret ? NULL : md[node];
> > +
> > +}
> > +
> > +static void flite_destroy_subdev(struct flite_dev *flite) {
> > +	struct v4l2_subdev *sd = flite->sd_flite;
> > +
> > +	if (!sd)
> > +		return;
> > +	media_entity_cleanup(&sd->entity);
> > +	v4l2_device_unregister_subdev(sd);
> > +	kfree(sd);
> > +	sd = NULL;
> 
> It doesn't make sense to clear the local variable here, instead you
> should do:
> 	flite->sd_flite = NULL;
> 
> I've fixed that bug in this commit:
> 
> http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-
> 2.6.git;a=commitdiff;h=64c570f505a0eac4914402bb7832d019c44eabd8
> 
Ok, I will fix it.
> > +}
> > +
> > +void flite_unregister_device(struct flite_dev *flite) {
> > +	struct video_device *vfd = flite->vfd;
> > +
> > +	if (vfd) {
> > +		media_entity_cleanup(&vfd->entity);
> > +		/* Can also be called if video device was
> > +		   not registered */
> > +		video_unregister_device(vfd);
> > +	}
> > +	flite_destroy_subdev(flite);
> > +}
> > +
> > +static int flite_suspend(struct device *dev) {
> > +	struct platform_device *pdev = to_platform_device(dev);
> > +	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
> 
> That's
> 	struct v4l2_subdev *sd = dev_get_drvdata(dev);
> 
Ok, I guess I am.

> > +	struct flite_dev *flite = v4l2_get_subdevdata(sd);
> > +
> > +	if (test_bit(FLITE_ST_STREAM,&flite->state))
> > +		flite_s_stream(sd, false);
> > +	if (test_bit(FLITE_ST_POWER,&flite->state))
> > +		flite_s_power(sd, false);
> > +
> > +	set_bit(FLITE_ST_SUSPEND,&flite->state);
> > +
> > +	return 0;
> > +}
> > +
> > +static int flite_resume(struct device *dev) {
> > +	struct platform_device *pdev = to_platform_device(dev);
> > +	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
> 
> Ditto.
> 
> > +	struct flite_dev *flite = v4l2_get_subdevdata(sd);
> > +
> > +	if (test_bit(FLITE_ST_POWER,&flite->state))
> > +		flite_s_power(sd, true);
> > +	if (test_bit(FLITE_ST_STREAM,&flite->state))
> > +		flite_s_stream(sd, true);
> > +
> > +	clear_bit(FLITE_ST_SUSPEND,&flite->state);
> > +
> > +	return 0;
> > +}
> > +
> > +static int flite_runtime_suspend(struct device *dev) {
> > +	struct platform_device *pdev = to_platform_device(dev);
> > +	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
> 
> Dito.
> 
> > +	struct flite_dev *flite = v4l2_get_subdevdata(sd);
> > +	unsigned long flags;
> > +
> > +	spin_lock_irqsave(&flite->slock, flags);
> > +	set_bit(FLITE_ST_SUSPEND,&flite->state);
> > +	spin_unlock_irqrestore(&flite->slock, flags);
> > +
> > +	return 0;
> > +}
> > +
> > +static int flite_runtime_resume(struct device *dev) {
> > +	struct platform_device *pdev = to_platform_device(dev);
> > +	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
> 
> Ditto.
> 
> > +	struct flite_dev *flite = v4l2_get_subdevdata(sd);
> > +	unsigned long flags;
> > +
> > +	spin_lock_irqsave(&flite->slock, flags);
> > +	clear_bit(FLITE_ST_SUSPEND,&flite->state);
> > +	spin_unlock_irqrestore(&flite->slock, flags);
> > +
> > +	return 0;
> > +}
> > +
> > +static struct v4l2_subdev_core_ops flite_core_ops = {
> > +	.s_power = flite_s_power,
> > +};
> > +
> > +static struct v4l2_subdev_video_ops flite_video_ops = {
> > +	.s_stream	= flite_s_stream,
> > +};
> > +
> > +static struct v4l2_subdev_ops flite_subdev_ops = {
> > +	.core	=&flite_core_ops,
> > +	.pad	=&flite_pad_ops,
> > +	.video	=&flite_video_ops,
> > +};
> > +
> > +static int flite_probe(struct platform_device *pdev) {
> > +	struct resource *mem_res;
> > +	struct resource *regs_res;
> > +	struct flite_dev *flite;
> > +	struct v4l2_subdev *sd;
> > +	int ret = -ENODEV;
> > +	struct exynos_isp_info *isp_info;
> > +	int i;
> > +
> > +	if (!pdev->dev.platform_data) {
> > +		dev_err(&pdev->dev, "platform data is NULL\n");
> > +		return -EINVAL;
> > +	}
> > +
> > +	flite = kzalloc(sizeof(struct flite_dev), GFP_KERNEL);
> > +	if (!flite)
> > +		return -ENOMEM;
> > +
> > +	flite->pdev = pdev;
> > +	flite->pdata = pdev->dev.platform_data;
> > +
> > +	flite->id = pdev->id;
> > +
> > +	init_waitqueue_head(&flite->irq_queue);
> > +	spin_lock_init(&flite->slock);
> > +
> > +	mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > +	if (!mem_res) {
> > +		dev_err(&pdev->dev, "Failed to get io memory region\n");
> > +		goto err_flite;
> > +	}
> > +
> > +	regs_res = request_mem_region(mem_res->start,
> resource_size(mem_res),
> > +				      pdev->name);
> > +	if (!regs_res) {
> > +		dev_err(&pdev->dev, "Failed to request io memory
> region\n");
> > +		goto err_resource;
> > +	}
> > +
> > +	flite->regs_res = regs_res;
> > +	flite->regs = ioremap(mem_res->start, resource_size(mem_res));
> > +	if (!flite->regs) {
> > +		dev_err(&pdev->dev, "Failed to remap io region\n");
> > +		goto err_reg_region;
> > +	}
> > +
> > +	flite->irq = platform_get_irq(pdev, 0);
> > +	if (flite->irq<  0) {
> > +		dev_err(&pdev->dev, "Failed to get irq\n");
> > +		goto err_reg_unmap;
> > +	}
> > +
> > +	ret = request_irq(flite->irq, flite_irq_handler, 0,
> dev_name(&pdev->dev), flite);
> > +	if (ret) {
> > +		dev_err(&pdev->dev, "request_irq failed\n");
> > +		goto err_reg_unmap;
> > +	}
> 
> Please consider using device managed resources, here is my patch
> converting the s5p-fimc driver:
> http://git.infradead.org/users/kmpark/linux-
> samsung/commitdiff/154ae8a99869da241128139e004bdec60b190b43
> 
> It saves you trouble with the error paths.
> 
Yes, I will consider that.
> > +	sd = kzalloc(sizeof(*sd), GFP_KERNEL);
> > +	if (!sd)
> > +	       goto err_irq;
> > +
> > +	v4l2_subdev_init(sd,&flite_subdev_ops);
> > +	snprintf(sd->name, sizeof(sd->name), "flite-subdev.%d", flite-
> >id);
> > +
> > +	flite->sd_flite = sd;
> > +	v4l2_set_subdevdata(flite->sd_flite, flite);
> > +
> > +	mutex_init(&flite->lock);
> > +	flite->mdev = flite_get_capture_md(MDEV_CAPTURE);
> > +	if (IS_ERR_OR_NULL(flite->mdev))
> > +		goto err_irq;
> 
> How are you making sure the media device driver is already probed at
> this point ?
Media device is probed before this point using makefile.
> 
> > +	flite_dbg("mdev = 0x%08x", (u32)flite->mdev);
> > +
> > +	ret = flite_register_video_device(flite);
> > +	if (ret)
> > +		goto err_irq;
> 
> Not all resources are initialized at this point so it's to early to
> register the video node. You need to move that after the allocator
> initialization. The driver would crash the system if the video node is
> opened right after it is registered, and it is not unusual at all.
> 
I see. I will fixed it.
> > +	/* Get mipi-csis subdev ptr using mdev */
> > +	flite->sd_csis = flite->mdev->csis_sd[flite->id];
> > +
> > +	for (i = 0; i<  flite->pdata->num_clients; i++) {
> > +		isp_info = flite->pdata->isp_info[i];
> > +		ret = flite_config_camclk(flite, isp_info, i);
> > +		if (ret) {
> > +			flite_err("failed setup cam clk");
> > +			goto err_vfd_alloc;
> > +		}
> > +	}
> > +
> > +	ret = flite_register_sensor_entities(flite);
> > +	if (ret) {
> > +		flite_err("failed register sensor entities");
> > +		goto err_clk;
> > +	}
> 
> ARGH. Please consider moving that to the media device driver probe().
> 
I don't think I can about this. As you know, separate devices use same media device.
> > +	ret = flite_create_subdev(flite, sd);
> > +	if (ret) {
> > +		flite_err("failed create subdev");
> > +		goto err_clk;
> > +	}
> > +
> > +	ret = flite_create_link(flite);
> > +	if (ret) {
> > +		flite_err("failed create link");
> > +		goto err_entity;
> > +	}
> > +
> > +	flite->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
> > +	if (IS_ERR(flite->alloc_ctx)) {
> > +		ret = PTR_ERR(flite->alloc_ctx);
> > +		goto err_entity;
> > +	}
> > +
> > +	platform_set_drvdata(flite->pdev, flite->sd_flite);
> > +	pm_runtime_enable(&pdev->dev);
> > +
> > +	flite_info("FIMC-LITE%d probe success", pdev->id);
> > +
> > +	return 0;
> > +
> > +err_entity:
> > +	media_entity_cleanup(&sd->entity);
> > +err_clk:
> > +	for (i = 0; i<  flite->pdata->num_clients; i++)
> > +		clk_put(flite->sensor[i].camclk);
> > +err_vfd_alloc:
> > +	media_entity_cleanup(&flite->vfd->entity);
> > +	video_device_release(flite->vfd);
> > +err_irq:
> > +	free_irq(flite->irq, flite);
> > +err_reg_unmap:
> > +	iounmap(flite->regs);
> > +err_reg_region:
> > +	release_mem_region(regs_res->start, resource_size(regs_res));
> > +err_resource:
> > +	release_resource(flite->regs_res);
> > +	kfree(flite->regs_res);
> > +err_flite:
> > +	kfree(flite);
> > +	return ret;
> > +}
> > +
> > +static int flite_remove(struct platform_device *pdev) {
> > +	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
> > +	struct flite_dev *flite = v4l2_get_subdevdata(sd);
> > +	struct resource *res = flite->regs_res;
> > +
> > +	flite_s_power(flite->sd_flite, 0);
> > +	flite_subdev_close(sd, NULL);
> > +	flite_unregister_device(flite);
> > +
> > +	vb2_dma_contig_cleanup_ctx(flite->alloc_ctx);
> > +
> > +	pm_runtime_disable(&pdev->dev);
> > +	free_irq(flite->irq, flite);
> > +	iounmap(flite->regs);
> > +	release_mem_region(res->start, resource_size(res));
> > +	kfree(flite);
> > +
> > +	return 0;
> > +}
> > +
> > +
> > +static const struct dev_pm_ops flite_pm_ops = {
> > +	.suspend		= flite_suspend,
> > +	.resume			= flite_resume,
> > +	.runtime_suspend	= flite_runtime_suspend,
> > +	.runtime_resume		= flite_runtime_resume,
> > +};
> > +
> > +static struct platform_driver flite_driver = {
> > +	.probe		= flite_probe,
> > +	.remove	= __devexit_p(flite_remove),
> > +	.driver = {
> > +		.name	= MODULE_NAME,
> > +		.owner	= THIS_MODULE,
> > +		.pm	=&flite_pm_ops,
> > +	}
> > +};
> > +
> > +static int __init flite_init(void)
> > +{
> > +	int ret = platform_driver_register(&flite_driver);
> > +	if (ret)
> > +		flite_err("platform_driver_register failed: %d", ret);
> > +	return ret;
> > +}
> > +
> > +static void __exit flite_exit(void)
> > +{
> > +	platform_driver_unregister(&flite_driver);
> > +}
> > +module_init(flite_init);
> > +module_exit(flite_exit);
> 
> You could also use module_platform_device().
> 
> > +
> > +MODULE_AUTHOR("Sky Kang<sungchun.kang@xxxxxxxxxxx>");
> 
> Is everything correct here ?
> 
> > +MODULE_DESCRIPTION("Exynos FIMC-Lite driver");
> MODULE_LICENSE("GPL");
> > diff --git a/drivers/media/video/exynos/fimc-lite/fimc-lite-core.h
> > b/drivers/media/video/exynos/fimc-lite/fimc-lite-core.h
> > new file mode 100644
> > index 0000000..d6da3b0
> > --- /dev/null
> > +++ b/drivers/media/video/exynos/fimc-lite/fimc-lite-core.h
> > @@ -0,0 +1,310 @@
> > +/*
> > + * Register interface file for Samsung Camera Interface (FIMC-Lite)
> > +driver
> > + *
> > + * Copyright (c) 2011 Samsung Electronics
> > + *
> > + * 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.
> > +*/
> > +#ifndef FLITE_CORE_H_
> > +#define FLITE_CORE_H_
> > +
> > +/* #define DEBUG */
> > +#include<linux/sched.h>
> > +#include<linux/spinlock.h>
> > +#include<linux/types.h>
> > +#include<linux/videodev2.h>
> > +#include<linux/io.h>
> > +#include<linux/delay.h>
> > +#include<linux/interrupt.h>
> > +#include<linux/pm_runtime.h>
> > +#include<media/videobuf2-core.h>
> > +#include<media/v4l2-ctrls.h>
> > +#include<media/v4l2-device.h>
> > +#include<media/v4l2-mediabus.h>
> > +#include<media/exynos_flite.h>
> > +#include<media/v4l2-ioctl.h>
> > +#include<media/exynos_mc.h>
> > +#include "fimc-lite-reg.h"
> > +
> > +#define flite_info(fmt, args...) \
> > +	printk(KERN_INFO "[INFO]%s:%d: "fmt "\n", __func__, __LINE__,
> > +##args) #define flite_err(fmt, args...) \
> > +	printk(KERN_ERR "[ERROR]%s:%d: "fmt "\n", __func__, __LINE__,
> > +##args) #define flite_warn(fmt, args...) \
> > +	printk(KERN_WARNING "[WARNNING]%s:%d: "fmt "\n", __func__,
> __LINE__,
> > +##args)
> > +
> > +#ifdef DEBUG
> > +#define flite_dbg(fmt, args...) \
> > +	printk(KERN_DEBUG "[DEBUG]%s:%d: " fmt "\n", __func__, __LINE__,
> > +##args) #else #define flite_dbg(fmt, args...) #endif
> > +
> > +#define FLITE_MAX_RESET_READY_TIME	20 /* 100ms */
> > +#define FLITE_MAX_CTRL_NUM		1
> > +#define FLITE_MAX_OUT_BUFS		1
> > +
> > +enum flite_input_entity {
> > +	FLITE_INPUT_NONE,
> > +	FLITE_INPUT_SENSOR,
> > +	FLITE_INPUT_CSIS,
> > +};
> > +
> > +enum flite_output_entity {
> > +	FLITE_OUTPUT_NONE = (1<<  0),
> > +	FLITE_OUTPUT_GSC = (1<<  1),
> > +	FLITE_OUTPUT_MEM = (1<<  2),
> > +};
> > +
> > +enum flite_out_path {
> > +	FLITE_ISP,
> > +	FLITE_DMA,
> > +};
> > +
> > +enum flite_state {
> > +	FLITE_ST_OPEN,
> > +	FLITE_ST_SUBDEV_OPEN,
> > +	FLITE_ST_POWER,
> > +	FLITE_ST_STREAM,
> > +	FLITE_ST_SUSPEND,
> > +	FLITE_ST_RUN,
> > +	FLITE_ST_PIPE_STREAM,
> > +	FLITE_ST_PEND,
> > +};
> > +
> > +#define flite_active(dev) test_bit(FLITE_ST_RUN,&(dev)->state)
> > +#define ctrl_to_dev(__ctrl) \
> > +	container_of((__ctrl)->handler, struct flite_dev, ctrl_handler)
> > +#define flite_get_frame(flite, pad)\
> > +	((pad == FLITE_PAD_SINK) ?&flite->s_frame :&flite->d_frame)
> > +
> > +struct flite_variant {
> > +	u16 max_w;
> > +	u16 max_h;
> > +	u16 align_win_offs_w;
> > +	u16 align_out_w;
> > +	u16 align_out_offs_w;
> > +};
> > +
> > +/**
> > +  * struct flite_fmt - driver's color format data
> > +  * @name :	format description
> > +  * @code :	Media Bus pixel code
> > +  * @fmt_reg :	H/W bit for setting format
> > +  */
> > +struct flite_fmt {
> > +	char				*name;
> > +	u32				pixelformat;
> > +	enum v4l2_mbus_pixelcode	code;
> > +	u32				fmt_reg;
> > +	u32				is_yuv;
> > +	u8				depth[VIDEO_MAX_PLANES];
> > +};
> > +
> > +struct flite_addr {
> > +	dma_addr_t	y;
> > +};
> > +
> > +/**
> > + * struct flite_frame - source/target frame properties
> > + * @o_width:	buffer width as set by S_FMT
> > + * @o_height:	buffer height as set by S_FMT
> > + * @width:	image pixel width
> > + * @height:	image pixel weight
> > + * @offs_h:	image horizontal pixel offset
> > + * @offs_v:	image vertical pixel offset
> > + */
> > +
> > +/*
> > +		o_width
> > +	---------------------
> > +	|    width(cropped) |
> > +	|	-----	    |
> > +	|offs_h |   |	    |
> > +	|	-----	    |
> > +	|		    |
> > +	---------------------
> > + */
> > +struct flite_frame {
> > +	u32 o_width;
> > +	u32 o_height;
> > +	u32 width;
> > +	u32 height;
> > +	u32 offs_h;
> > +	u32 offs_v;
> > +	unsigned long payload;
> > +	struct flite_addr addr;
> > +	struct flite_fmt *fmt;
> > +};
> > +
> > +struct flite_pipeline {
> > +	struct media_pipeline *pipe;
> > +	struct v4l2_subdev *flite;
> > +	struct v4l2_subdev *csis;
> > +	struct v4l2_subdev *sensor;
> > +};
> > +
> > +struct flite_sensor_info {
> > +	struct exynos_isp_info *pdata;
> > +	struct v4l2_subdev *sd;
> > +	struct clk *camclk;
> > +};
> > +
> > +/**
> > +  * struct flite_dev - top structure of FIMC-Lite device
> > +  * @pdev :	pointer to the FIMC-Lite platform device
> > +  * @lock :	the mutex protecting this data structure
> > +  * @sd :	subdevice pointer of FIMC-Lite
> > +  * @fmt :	Media bus format of FIMC-Lite
> > +  * @regs_res :	ioremapped regs of FIMC-Lite
> > +  * @regs :	SFR of FIMC-Lite
> > +  */
> > +struct flite_dev {
> > +	struct platform_device		*pdev;
> > +	struct exynos_platform_flite	*pdata; /* depended on isp */
> > +	spinlock_t			slock;
> > +	struct v4l2_subdev		*sd_flite;
> > +	struct exynos_md		*mdev;
> > +	struct v4l2_subdev		*sd_csis;
> > +	struct flite_sensor_info	sensor[SENSOR_MAX_ENTITIES];
> > +	struct media_pad		pads[FLITE_PADS_NUM];
> > +	struct media_pad		vd_pad;
> > +	struct flite_frame		d_frame;
> > +	struct mutex			lock;
> > +	struct video_device		*vfd;
> > +	int				refcnt;
> > +	u32				reqbufs_cnt;
> > +	struct vb2_queue		vbq;
> > +	struct vb2_alloc_ctx		*alloc_ctx;
> > +	const struct flite_vb2		*vb2;
> > +	struct flite_pipeline		pipeline;
> > +	bool				ctrls_rdy;
> > +	struct list_head		pending_buf_q;
> > +	struct list_head		active_buf_q;
> > +	int				active_buf_cnt;
> > +	int				pending_buf_cnt;
> > +	int				buf_index;
> > +	struct clk			*gsc_clk;
> > +	struct v4l2_mbus_framefmt	mbus_fmt;
> > +	struct flite_frame		s_frame;
> > +	struct resource			*regs_res;
> > +	void __iomem			*regs;
> > +	int				irq;
> > +	unsigned long			state;
> > +	u32				out_path;
> > +	wait_queue_head_t		irq_queue;
> > +	u32				id;
> > +	enum flite_input_entity		input;
> > +	enum flite_output_entity	output;
> > +};
> ...
> > diff --git a/drivers/media/video/exynos/fimc-lite/fimc-lite-reg.h
> > b/drivers/media/video/exynos/fimc-lite/fimc-lite-reg.h
> ...
> > +/* Camera General Purpose */
> > +#define FLITE_REG_CIGENERAL				0xFC
> 
> In the kernel using lower case for hex numbers is preferred.
Really?? S5p-fimc too..
> 
> > +#define FLITE_REG_CIGENERAL_CAM_A			(0<<  0)
> > +#define FLITE_REG_CIGENERAL_CAM_B			(1<<  0)
> > +
> > +#endif /* FIMC_LITE_REG_H */
> > diff --git a/include/media/exynos_camera.h
> > b/include/media/exynos_camera.h new file mode 100644 index
> > 0000000..e7fafd1
> > --- /dev/null
> > +++ b/include/media/exynos_camera.h
> > @@ -0,0 +1,59 @@
> > +/* include/media/exynos_camera.h
> > + *
> > + * Copyright (c) 2011 Samsung Electronics Co., Ltd.
> > + *		http://www.samsung.com
> > + *
> > + * The header file related to camera
> > + *
> > + * 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.
> > + */
> > +
> > +#ifndef EXYNOS_CAMERA_H_
> > +#define EXYNOS_CAMERA_H_
> > +
> > +#include<media/exynos_mc.h>
> > +
> > +enum cam_bus_type {
> > +	CAM_TYPE_ITU = 1,
> > +	CAM_TYPE_MIPI,
> > +};
> > +
> > +enum cam_port {
> > +	CAM_PORT_A,
> > +	CAM_PORT_B,
> > +};
> > +
> > +#define CAM_CLK_INV_PCLK	(1<<  0)
> > +#define CAM_CLK_INV_VSYNC	(1<<  1)
> > +#define CAM_CLK_INV_HREF	(1<<  2)
> > +#define CAM_CLK_INV_HSYNC	(1<<  3)
> 
> Please consider using the generic polarity flags from
> include/media/v4l2-mediabus.h
> 
Ok, I will fixed it.
> > +struct i2c_board_info;
> > +
> > +/**
> > + * struct exynos_isp_info - image sensor information required for
> host
> > + *			      interface configuration.
> > + *
> > + * @board_info: pointer to I2C subdevice's board info
> > + * @clk_frequency: frequency of the clock the host interface
> provides
> > +to sensor
> > + * @bus_type: determines bus type, MIPI, ITU-R BT.601 etc.
> > + * @csi_data_align: MIPI-CSI interface data alignment in bits
> > + * @i2c_bus_num: i2c control bus id the sensor is attached to
> > + * @mux_id: FIMC camera interface multiplexer index (separate for
> > +MIPI and ITU)
> > + * @flags: flags defining bus signals polarity inversion (High by
> > +default)
> > + * @use_cam: a means of used by GSCALER  */ struct exynos_isp_info {
> > +	struct i2c_board_info *board_info;
> > +	unsigned long clk_frequency;
> > +	const char *cam_srclk_name;
> > +	const char *cam_clk_name;
> > +	enum cam_bus_type bus_type;
> > +	u16 csi_data_align;
> > +	u16 i2c_bus_num;
> > +	enum cam_port cam_port;
> > +	u16 flags;
> > +};
> > +#endif /* EXYNOS_CAMERA_H_ */
> > diff --git a/include/media/exynos_flite.h
> > b/include/media/exynos_flite.h new file mode 100644 index
> > 0000000..789e040
> > --- /dev/null
> > +++ b/include/media/exynos_flite.h
> > @@ -0,0 +1,39 @@
> > +/*
> > + * Samsung S5P SoC camera interface driver header
> > + *
> > + * Copyright (c) 2011 Samsung Electronics Co., Ltd
> > + *
> > + * 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.
> > + */
> > +
> > +#ifndef EXYNOS_FLITE_H_
> > +#define EXYNOS_FLITE_H_
> > +
> > +#include<media/exynos_camera.h>
> > +
> > +struct s3c_platform_camera {
> > +	enum cam_bus_type type;
> > +	bool use_isp;
> > +	int inv_pclk;
> > +	int inv_vsync;
> > +	int inv_href;
> > +	int inv_hsync;
> 
> There are generic flags for those in include/media/v4l2-mediabus.h.
> 
Ok.
> > +};
> > +
> > +/**
> > + * struct exynos_platform_flite - camera host interface platform
> data
> > + *
> > + * @cam: properties of camera sensor required for host interface
> > +setup  */ struct exynos_platform_flite {
> > +	struct s3c_platform_camera *cam[MAX_CAMIF_CLIENTS];
> > +	struct exynos_isp_info *isp_info[MAX_CAMIF_CLIENTS];
> > +	u32 active_cam_index;
> > +	u32 num_clients;
> > +};
> 
> I don't think it is a good idea to associate the sensors with FIMC-
> LITE devices. This creates a bigger mess to deal with when you try to
> add DT support. It prevents you from re-attaching a sensor to
> different FIMC-LITE instance at runtime, doesn't it ?
> 
> Maybe you did that in order to support VIDIOC_S_INPUT, but that looks
> wrong to me. Instead the sensors should be attached to a top level
> camera media device.
> 
We have legacy fimc and v4l2 fimc driver. S3c_platform_camera structure is for legacy.
fimc-lite should support legacy, v4l2, exynos4 and exynos5.
But I will consider another method.
> > +extern struct exynos_platform_flite exynos_flite0_default_data;
> > +extern struct exynos_platform_flite exynos_flite1_default_data;
> > +#endif /* EXYNOS_FLITE_H_*/
> 
> --
> 
> Regards,
> Sylwester

--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux