* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
-
+#ifdef CONFIG_ARCH_RK29
#include <linux/init.h>
#include <linux/module.h>
#include <linux/io.h>
#include <media/v4l2-dev.h>
#include <media/videobuf-dma-contig.h>
#include <media/soc_camera.h>
+#include <media/soc_mediabus.h>
#include <mach/rk29-ipp.h>
-
+#include <asm/cacheflush.h>
static int debug;
-module_param(debug, int, S_IRUGO|S_IWUSR);
+module_param(debug, int, S_IRUGO|S_IWUSR|S_IWGRP);
#define dprintk(level, fmt, arg...) do { \
if (debug >= level) \
printk(KERN_WARNING"rk29xx_camera: " fmt , ## arg); } while (0)
#define RK29CAMERA_TR(format, ...) printk(KERN_ERR format, ## __VA_ARGS__)
-#define RK29CAMERA_DG(format, ...) dprintk(0, format, ## __VA_ARGS__)
+#define RK29CAMERA_DG(format, ...) dprintk(1, format, ## __VA_ARGS__)
// VIP Reg Offset
#define RK29_VIP_AHBR_CTRL 0x00
#define read_grf_reg(addr) __raw_readl(addr+RK29_GRF_BASE)
#define mask_grf_reg(addr, msk, val) write_vip_reg(addr, (val)|((~(msk))&read_vip_reg(addr)))
+#ifdef CONFIG_VIDEO_RK29_DIGITALZOOM_IPP_OFF
+#define CAM_WORKQUEUE_IS_EN() ((pcdev->host_width != pcdev->icd->user_width) || (pcdev->host_height != pcdev->icd->user_height)\
+ || (pcdev->icd_cb.sensor_cb))
+#define CAM_IPPWORK_IS_EN() ((pcdev->host_width != pcdev->icd->user_width) || (pcdev->host_height != pcdev->icd->user_height))
+#else
+#define CAM_WORKQUEUE_IS_EN() (true)
+#define CAM_IPPWORK_IS_EN() ((pcdev->zoominfo.a.c.width != pcdev->icd->user_width) || (pcdev->zoominfo.a.c.height != pcdev->icd->user_height))
+#endif
//Configure Macro
-#define RK29_CAM_VERSION_CODE KERNEL_VERSION(0, 0, 1)
+/*
+* Driver Version Note
+*
+*v0.0.x : this driver is 2.6.32 kernel driver;
+*v0.1.x : this driver is 3.0.8 kernel driver;
+*v0.2.x : this driver is rk30 3.0.8 kernel driver;
+*v0.3.x : this driver is camera-isp driver;
+*
+*v0.x.1 : this driver first support rk2918;
+*v0.x.2 : fix this driver support v4l2 format is V4L2_PIX_FMT_NV12 and V4L2_PIX_FMT_NV16,is not V4L2_PIX_FMT_YUV420
+* and V4L2_PIX_FMT_YUV422P;
+*v0.x.3 : this driver support VIDIOC_ENUM_FRAMEINTERVALS;
+*v0.x.4 : this driver support digital zoom;
+*v0.x.5 : this driver support test framerate and query framerate from board file configuration;
+*v0.x.6 : this driver improve test framerate method;
+*v0.x.7 : this driver product resolution by IPP crop and scale, which user request but sensor can't support;
+* note: this version is only provide yifang client, which is not official version;
+*v0.x.8 : this driver and rk29_camera.c support upto 3 back-sensors and upto 3 front-sensors;
+*v0.x.9 : camera io code is compatible for rk29xx and rk30xx
+*v0.x.a : fix error when calculate crop left-top point coordinate;
+* note: this version provided as patch camera_patch_v1.1
+*v0.x.b : fix sensor autofocus thread may in running when reinit sensor if sensor haven't stream on in first init;
+*v0.x.c : fix work queue havn't been finished after close device;
+*v0.x.d : fix error when calculate crop left-top point coordinate;
+*v0.x.f : fix struct rk29_camera_work may be reentrant.
+*v0.x.11: add support zoom by arm;
+*/
+#define RK29_CAM_VERSION_CODE KERNEL_VERSION(0, 1, 0x11)
/* limit to rk29 hardware capabilities */
#define RK29_CAM_BUS_PARAM (SOCAM_MASTER |\
#define RK29_CAM_H_MAX 2764
#define RK29_CAM_FRAME_INVAL_INIT 3
#define RK29_CAM_FRAME_INVAL_DC 3 /* ddl@rock-chips.com : */
+#define RK29_CAM_FRAME_MEASURE 5
#define RK29_CAM_AXI 0
#define RK29_CAM_AHB 1
extern void videobuf_dma_contig_free(struct videobuf_queue *q, struct videobuf_buffer *buf);
extern dma_addr_t videobuf_to_dma_contig(struct videobuf_buffer *buf);
-extern void videobuf_queue_dma_contig_init(struct videobuf_queue *q,
- struct videobuf_queue_ops *ops,
- struct device *dev,
- spinlock_t *irqlock,
- enum v4l2_buf_type type,
- enum v4l2_field field,
- unsigned int msize,
- void *priv);
/* buffer for one video frame */
struct rk29_buffer
{
/* common v4l buffer stuff -- must be first */
struct videobuf_buffer vb;
- const struct soc_camera_data_format *fmt;
+ enum v4l2_mbus_pixelcode code;
int inwork;
};
enum rk29_camera_reg_state
struct videobuf_buffer *vb;
struct rk29_camera_dev *pcdev;
struct work_struct work;
+ struct list_head queue;
+ unsigned int index;
+};
+struct rk29_camera_frmivalenum
+{
+ struct v4l2_frmivalenum fival;
+ struct rk29_camera_frmivalenum *nxt;
+};
+struct rk29_camera_frmivalinfo
+{
+ struct soc_camera_device *icd;
+ struct rk29_camera_frmivalenum *fival_list;
+};
+struct rk29_camera_zoominfo
+{
+ struct semaphore sem;
+ struct v4l2_crop a;
+ int zoom_rate;
};
+#if CAMERA_VIDEOBUF_ARM_ACCESS
+struct rk29_camera_vbinfo
+{
+ unsigned int phy_addr;
+ void __iomem *vir_addr;
+ unsigned int size;
+};
+#endif
struct rk29_camera_dev
{
struct soc_camera_host soc_host;
struct clk *hclk_cpu_display;
struct clk *vip_slave;
- struct clk *vip;
+ struct clk *vip_out;
struct clk *vip_input;
struct clk *vip_bus;
struct clk *hclk_disp_matrix;
struct clk *vip_matrix;
+ struct clk *pd_display;
+
void __iomem *base;
void __iomem *grf_base;
int frame_inval; /* ddl@rock-chips.com : The first frames is invalidate */
unsigned int irq;
unsigned int fps;
+ unsigned long frame_interval;
unsigned int pixfmt;
unsigned int vipmem_phybase;
+ void __iomem *vipmem_virbase;
unsigned int vipmem_size;
unsigned int vipmem_bsize;
+#if CAMERA_VIDEOBUF_ARM_ACCESS
+ struct rk29_camera_vbinfo *vbinfo;
+ unsigned int vbinfo_count;
+#endif
int host_width;
int host_height;
+ int icd_width;
+ int icd_height;
struct rk29camera_platform_data *pdata;
struct resource *res;
struct list_head capture;
-
+ struct rk29_camera_zoominfo zoominfo;
+
spinlock_t lock;
struct videobuf_buffer *active;
- struct videobuf_queue *vb_vidq_ptr;
struct rk29_camera_reg reginfo_suspend;
struct workqueue_struct *camera_wq;
struct rk29_camera_work *camera_work;
+ struct list_head camera_work_queue;
+ spinlock_t camera_work_lock;
unsigned int camera_work_count;
struct hrtimer fps_timer;
struct work_struct camera_reinit_work;
+ int icd_init;
+ rk29_camera_sensor_cb_s icd_cb;
+ struct rk29_camera_frmivalinfo icd_frmival[2];
+};
+
+static const struct v4l2_queryctrl rk29_camera_controls[] =
+{
+ #ifdef CONFIG_VIDEO_RK29_DIGITALZOOM_IPP_ON
+ {
+ .id = V4L2_CID_ZOOM_ABSOLUTE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "DigitalZoom Control",
+ .minimum = 100,
+ .maximum = 300,
+ .step = 5,
+ .default_value = 100,
+ },
+ #endif
};
+
static DEFINE_MUTEX(camera_lock);
static const char *rk29_cam_driver_description = "RK29_Camera";
static struct rk29_camera_dev *rk29_camdev_info_ptr;
struct soc_camera_device *icd = vq->priv_data;
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct rk29_camera_dev *pcdev = ici->priv;
- int bytes_per_pixel = (icd->current_fmt->depth + 7) >> 3;
+ int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
+ icd->current_fmt->host_fmt);
+ int bytes_per_line_host = soc_mbus_bytes_per_line(pcdev->host_width,
+ icd->current_fmt->host_fmt);
+ int i;
+ struct rk29_camera_work *wk;
dev_dbg(&icd->dev, "count=%d, size=%d\n", *count, *size);
- /* planar capture requires Y, U and V buffers to be page aligned */
- *size = PAGE_ALIGN(icd->user_width* icd->user_height * bytes_per_pixel); /* Y pages UV pages, yuv422*/
- pcdev->vipmem_bsize = PAGE_ALIGN(pcdev->host_width * pcdev->host_height * bytes_per_pixel);
-
- if ((pcdev->host_width != pcdev->icd->user_width) || (pcdev->host_height != pcdev->icd->user_height)) {
-
- if (*count > pcdev->vipmem_size/pcdev->vipmem_bsize) { /* Buffers must be limited, when this resolution is genered by IPP */
- *count = pcdev->vipmem_size/pcdev->vipmem_bsize;
- }
+ if (bytes_per_line < 0)
+ return bytes_per_line;
+ /* planar capture requires Y, U and V buffers to be page aligned */
+ *size = PAGE_ALIGN(bytes_per_line*icd->user_height); /* Y pages UV pages, yuv422*/
+ pcdev->vipmem_bsize = PAGE_ALIGN(bytes_per_line_host * pcdev->host_height);
+
+
+ if (CAM_WORKQUEUE_IS_EN()) {
+ #ifdef CONFIG_VIDEO_RK29_DIGITALZOOM_IPP_OFF
+ if (CAM_IPPWORK_IS_EN())
+ #endif
+ {
+ BUG_ON(pcdev->vipmem_size<pcdev->vipmem_bsize);
+ if (*count > pcdev->vipmem_size/pcdev->vipmem_bsize) { /* Buffers must be limited, when this resolution is genered by IPP */
+ *count = pcdev->vipmem_size/pcdev->vipmem_bsize;
+ }
+ }
if ((pcdev->camera_work_count != *count) && pcdev->camera_work) {
kfree(pcdev->camera_work);
pcdev->camera_work = NULL;
- pcdev->camera_work_count = 0;
+ pcdev->camera_work_count = 0;
}
if (pcdev->camera_work == NULL) {
- pcdev->camera_work = kmalloc(sizeof(struct rk29_camera_work)*(*count), GFP_KERNEL);
+ pcdev->camera_work = wk = kzalloc(sizeof(struct rk29_camera_work)*(*count), GFP_KERNEL);
if (pcdev->camera_work == NULL) {
RK29CAMERA_TR("\n %s kmalloc fail\n", __FUNCTION__);
BUG();
}
- pcdev->camera_work_count = *count;
+ INIT_LIST_HEAD(&pcdev->camera_work_queue);
+
+ for (i=0; i<(*count); i++) {
+ wk->index = i;
+ list_add_tail(&wk->queue, &pcdev->camera_work_queue);
+ wk++;
+ }
+ pcdev->camera_work_count = (*count);
}
+#if CAMERA_VIDEOBUF_ARM_ACCESS
+ if (pcdev->vbinfo && (pcdev->vbinfo_count != *count)) {
+ kfree(pcdev->vbinfo);
+ pcdev->vbinfo = NULL;
+ pcdev->vbinfo_count = 0x00;
+ }
+
+ if (pcdev->vbinfo == NULL) {
+ pcdev->vbinfo = kzalloc(sizeof(struct rk29_camera_vbinfo)*(*count), GFP_KERNEL);
+ if (pcdev->vbinfo == NULL) {
+ RK29CAMERA_TR("\n %s vbinfo kmalloc fail\n", __FUNCTION__);
+ BUG();
+ }
+ pcdev->vbinfo_count = *count;
+ }
+#endif
}
- RK29CAMERA_DG("%s..%d.. videobuf size:%d, vipmem_buf size:%d \n",__FUNCTION__,__LINE__, *size,pcdev->vipmem_bsize);
+ RK29CAMERA_DG("%s..%d.. videobuf size:%d, vipmem_buf size:%d, count:%d \n",__FUNCTION__,__LINE__, *size,pcdev->vipmem_size, *count);
return 0;
}
if (in_interrupt())
BUG();
-
+ /*
+ * This waits until this buffer is out of danger, i.e., until it is no
+ * longer in STATE_QUEUED or STATE_ACTIVE
+ */
+ //videobuf_waiton(vq, &buf->vb, 0, 0);
videobuf_dma_contig_free(vq, &buf->vb);
dev_dbg(&icd->dev, "%s freed\n", __func__);
buf->vb.state = VIDEOBUF_NEEDS_INIT;
struct soc_camera_device *icd = vq->priv_data;
struct rk29_buffer *buf;
int ret;
+ int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
+ icd->current_fmt->host_fmt);
+ if (bytes_per_line < 0)
+ return bytes_per_line;
buf = container_of(vb, struct rk29_buffer, vb);
BUG_ON(NULL == icd->current_fmt);
- if (buf->fmt != icd->current_fmt ||
+ if (buf->code != icd->current_fmt->code ||
vb->width != icd->user_width ||
vb->height != icd->user_height ||
vb->field != field) {
- buf->fmt = icd->current_fmt;
+ buf->code = icd->current_fmt->code;
vb->width = icd->user_width;
vb->height = icd->user_height;
vb->field = field;
vb->state = VIDEOBUF_NEEDS_INIT;
}
- vb->size = (((vb->width * vb->height *buf->fmt->depth) + 7) >> 3) ; /* ddl@rock-chips.com : fmt->depth is coorect */
+ vb->size = bytes_per_line*vb->height; /* ddl@rock-chips.com : fmt->depth is coorect */
if (0 != vb->baddr && vb->bsize < vb->size) {
ret = -EINVAL;
goto out;
struct rk29_camera_dev *pcdev = rk29_camdev_info_ptr;
if (vb) {
- if ((pcdev->host_width != pcdev->icd->user_width) || (pcdev->host_height != pcdev->icd->user_height)) {
+ if (CAM_WORKQUEUE_IS_EN()) {
y_addr = pcdev->vipmem_phybase + vb->i*pcdev->vipmem_bsize;
uv_addr = y_addr + pcdev->host_width*pcdev->host_height;
struct soc_camera_device *icd = vq->priv_data;
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct rk29_camera_dev *pcdev = ici->priv;
-
+ struct rk29_camera_vbinfo *vb_info;
+
dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %zd\n", __func__,
vb, vb->baddr, vb->bsize);
else
BUG(); /* ddl@rock-chips.com : The same videobuffer queue again */
}
+#if CAMERA_VIDEOBUF_ARM_ACCESS
+ if (pcdev->vbinfo) {
+ vb_info = pcdev->vbinfo+vb->i;
+ if ((vb_info->phy_addr != vb->boff) || (vb_info->size != vb->bsize)) {
+ if (vb_info->vir_addr) {
+ iounmap(vb_info->vir_addr);
+ release_mem_region(vb_info->phy_addr, vb_info->size);
+ vb_info->vir_addr = NULL;
+ vb_info->phy_addr = 0x00;
+ vb_info->size = 0x00;
+ }
+ if (request_mem_region(vb->boff,vb->bsize,"rk29_camera_vb")) {
+ vb_info->vir_addr = ioremap_cached(vb->boff,vb->bsize);
+ }
+
+ if (vb_info->vir_addr) {
+ vb_info->size = vb->bsize;
+ vb_info->phy_addr = vb->boff;
+ } else {
+ RK29CAMERA_TR("%s..%d:ioremap videobuf %d failed\n",__FUNCTION__,__LINE__, vb->i);
+ }
+ }
+ }
+#endif
if (!pcdev->active) {
pcdev->active = vb;
rk29_videobuf_capture(vb);
{
switch (pixfmt)
{
- case V4L2_PIX_FMT_YUV422P:
+ case V4L2_PIX_FMT_NV16:
+ case V4L2_PIX_FMT_YUV422P:
{
*ippfmt = IPP_Y_CBCR_H2V1;
break;
}
- case V4L2_PIX_FMT_YUV420:
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_YUV420:
{
*ippfmt = IPP_Y_CBCR_H2V2;
break;
rk29_pixfmt2ippfmt_err:
return -1;
}
-static void rk29_camera_capture_process(struct work_struct *work)
+#if (CONFIG_CAMERA_SCALE_CROP_MACHINE == RK_CAM_SCALE_CROP_IPP)
+static int rk29_camera_scale_crop_ipp(struct work_struct *work)
{
struct rk29_camera_work *camera_work = container_of(work, struct rk29_camera_work, work);
struct videobuf_buffer *vb = camera_work->vb;
struct rk29_camera_dev *pcdev = camera_work->pcdev;
struct rk29_ipp_req ipp_req;
unsigned long int flags;
+ int src_y_offset,src_uv_offset,dst_y_offset,dst_uv_offset,src_y_size,dst_y_size;
+ int scale_times,w,h,vipdata_base;
+ int ret = 0;
+
+ /*
+ *ddl@rock-chips.com:
+ * IPP Dest image resolution is 2047x1088, so scale operation break up some times
+ */
+ if ((pcdev->icd->user_width > 0x7f0) || (pcdev->icd->user_height > 0x430)) {
+ scale_times = MAX((pcdev->icd->user_width/0x7f0),(pcdev->icd->user_height/0x430));
+ scale_times++;
+ } else {
+ scale_times = 1;
+ }
+
+ memset(&ipp_req, 0, sizeof(struct rk29_ipp_req));
+
+ ipp_req.timeout = 100;
+ ipp_req.flag = IPP_ROT_0;
+ ipp_req.src0.w = pcdev->zoominfo.a.c.width/scale_times;
+ ipp_req.src0.h = pcdev->zoominfo.a.c.height/scale_times;
+ ipp_req.src_vir_w = pcdev->host_width;
+ rk29_pixfmt2ippfmt(pcdev->pixfmt, &ipp_req.src0.fmt);
+ ipp_req.dst0.w = pcdev->icd->user_width/scale_times;
+ ipp_req.dst0.h = pcdev->icd->user_height/scale_times;
+ ipp_req.dst_vir_w = pcdev->icd->user_width;
+ rk29_pixfmt2ippfmt(pcdev->pixfmt, &ipp_req.dst0.fmt);
+
+ vipdata_base = pcdev->vipmem_phybase + vb->i*pcdev->vipmem_bsize;
+ src_y_size = pcdev->host_width*pcdev->host_height;
+ dst_y_size = pcdev->icd->user_width*pcdev->icd->user_height;
+
+ for (h=0; h<scale_times; h++) {
+ for (w=0; w<scale_times; w++) {
+
+ src_y_offset = (pcdev->zoominfo.a.c.top + h*pcdev->zoominfo.a.c.height/scale_times)* pcdev->host_width
+ + pcdev->zoominfo.a.c.left + w*pcdev->zoominfo.a.c.width/scale_times;
+ src_uv_offset = (pcdev->zoominfo.a.c.top + h*pcdev->zoominfo.a.c.height/scale_times)* pcdev->host_width/2
+ + pcdev->zoominfo.a.c.left + w*pcdev->zoominfo.a.c.width/scale_times;
+
+ dst_y_offset = pcdev->icd->user_width*pcdev->icd->user_height*h/scale_times + pcdev->icd->user_width*w/scale_times;
+ dst_uv_offset = pcdev->icd->user_width*pcdev->icd->user_height*h/scale_times/2 + pcdev->icd->user_width*w/scale_times;
+
+ ipp_req.src0.YrgbMst = vipdata_base + src_y_offset;
+ ipp_req.src0.CbrMst = vipdata_base + src_y_size + src_uv_offset;
+ ipp_req.dst0.YrgbMst = vb->boff + dst_y_offset;
+ ipp_req.dst0.CbrMst = vb->boff + dst_y_size + dst_uv_offset;
+
+ if (ipp_blit_sync(&ipp_req)) {
+ spin_lock_irqsave(&pcdev->lock, flags);
+ vb->state = VIDEOBUF_ERROR;
+ spin_unlock_irqrestore(&pcdev->lock, flags);
+
+ RK29CAMERA_TR("Capture image(vb->i:0x%x) which IPP operated is error:\n",vb->i);
+ RK29CAMERA_TR("widx:%d hidx:%d ",w,h);
+ RK29CAMERA_TR("%dx%d@(%d,%d)->%dx%d\n",pcdev->zoominfo.a.c.width,pcdev->zoominfo.a.c.height,pcdev->zoominfo.a.c.left,pcdev->zoominfo.a.c.top,pcdev->icd->user_width,pcdev->icd->user_height);
+ RK29CAMERA_TR("ipp_req.src0.YrgbMst:0x%x ipp_req.src0.CbrMst:0x%x \n", ipp_req.src0.YrgbMst,ipp_req.src0.CbrMst);
+ RK29CAMERA_TR("ipp_req.src0.w:0x%x ipp_req.src0.h:0x%x \n",ipp_req.src0.w,ipp_req.src0.h);
+ RK29CAMERA_TR("ipp_req.src0.fmt:0x%x\n",ipp_req.src0.fmt);
+ RK29CAMERA_TR("ipp_req.dst0.YrgbMst:0x%x ipp_req.dst0.CbrMst:0x%x \n",ipp_req.dst0.YrgbMst,ipp_req.dst0.CbrMst);
+ RK29CAMERA_TR("ipp_req.dst0.w:0x%x ipp_req.dst0.h:0x%x \n",ipp_req.dst0.w ,ipp_req.dst0.h);
+ RK29CAMERA_TR("ipp_req.dst0.fmt:0x%x\n",ipp_req.dst0.fmt);
+ RK29CAMERA_TR("ipp_req.src_vir_w:0x%x ipp_req.dst_vir_w :0x%x\n",ipp_req.src_vir_w ,ipp_req.dst_vir_w);
+ RK29CAMERA_TR("ipp_req.timeout:0x%x ipp_req.flag :0x%x\n",ipp_req.timeout,ipp_req.flag);
+
+ goto rk29_camera_scale_crop_ipp_end;
+ }
+ }
+ }
+
+rk29_camera_scale_crop_ipp_end:
+ return ret;
+}
+#endif
+#if (CONFIG_CAMERA_SCALE_CROP_MACHINE == RK_CAM_SCALE_CROP_ARM)
+static int rk29_camera_scale_crop_arm(struct work_struct *work)
+{
+ struct rk29_camera_work *camera_work = container_of(work, struct rk29_camera_work, work);
+ struct videobuf_buffer *vb = camera_work->vb;
+ struct rk29_camera_dev *pcdev = camera_work->pcdev;
+ struct rk29_camera_vbinfo *vb_info;
+ unsigned char *psY,*pdY,*psUV,*pdUV;
+ unsigned char *src,*dst;
+ unsigned long src_phy,dst_phy;
+ int srcW,srcH,cropW,cropH,dstW,dstH;
+ long zoomindstxIntInv,zoomindstyIntInv;
+ long x,y;
+ long yCoeff00,yCoeff01,xCoeff00,xCoeff01;
+ long sX,sY;
+ long r0,r1,a,b,c,d;
+ int ret = 0;
+
+
+ src_phy = pcdev->vipmem_phybase + vb->i*pcdev->vipmem_bsize;
+ src = psY = (unsigned char*)(pcdev->vipmem_virbase + vb->i*pcdev->vipmem_bsize);
+ psUV = psY + pcdev->host_width*pcdev->host_height;
+ srcW = pcdev->host_width;
+ srcH = pcdev->host_height;
+ cropW = pcdev->zoominfo.a.c.width;
+ cropH = pcdev->zoominfo.a.c.height;
+ psY = psY + pcdev->host_width - pcdev->zoominfo.a.c.width;
+ psUV = psUV + pcdev->host_width - pcdev->zoominfo.a.c.width;
+
+ vb_info = pcdev->vbinfo+vb->i;
+ dst_phy = vb_info->phy_addr;
+ dst = pdY = (unsigned char*)vb_info->vir_addr;
+ pdUV = pdY + pcdev->icd->user_width*pcdev->icd->user_height;
+ dstW = pcdev->icd->user_width;
+ dstH = pcdev->icd->user_height;
+
+ zoomindstxIntInv = ((unsigned long)cropW<<16)/dstW + 1;
+ zoomindstyIntInv = ((unsigned long)cropH<<16)/dstH + 1;
+
+ //y
+ //for(y = 0; y<dstH - 1 ; y++ ) {
+ for(y = 0; y<dstH; y++ ) {
+ yCoeff00 = (y*zoomindstyIntInv)&0xffff;
+ yCoeff01 = 0xffff - yCoeff00;
+ sY = (y*zoomindstyIntInv >> 16);
+
+ for(x = 0; x<dstW; x++ ) {
+ xCoeff00 = (x*zoomindstxIntInv)&0xffff;
+ xCoeff01 = 0xffff - xCoeff00;
+ sX = (x*zoomindstxIntInv >> 16);
+
+ a = psY[sY*srcW + sX];
+ b = psY[sY*srcW + sX + 1];
+ c = psY[(sY+1)*srcW + sX];
+ d = psY[(sY+1)*srcW + sX + 1];
+
+ r0 = (a * xCoeff01 + b * xCoeff00)>>16 ;
+ r1 = (c * xCoeff01 + d * xCoeff00)>>16 ;
+ r0 = (r0 * yCoeff01 + r1 * yCoeff00)>>16;
+
+ pdY[x] = r0;
+ }
+ pdY += dstW;
+ }
- ipp_req.src0.YrgbMst = pcdev->vipmem_phybase + vb->i*pcdev->vipmem_bsize;
- ipp_req.src0.CbrMst= ipp_req.src0.YrgbMst + pcdev->host_width*pcdev->host_height;
- ipp_req.src0.w = pcdev->host_width;
- ipp_req.src0.h = pcdev->host_height;
- rk29_pixfmt2ippfmt(pcdev->pixfmt, &ipp_req.src0.fmt);
-
- ipp_req.dst0.YrgbMst = vb->boff;
- ipp_req.dst0.CbrMst= vb->boff+vb->width * vb->height;
- ipp_req.dst0.w = pcdev->icd->user_width;
- ipp_req.dst0.h = pcdev->icd->user_height;
- rk29_pixfmt2ippfmt(pcdev->pixfmt, &ipp_req.dst0.fmt);
-
- ipp_req.src_vir_w = ipp_req.src0.w;
- ipp_req.dst_vir_w = ipp_req.dst0.w;
- ipp_req.timeout = 100;
- ipp_req.flag = IPP_ROT_0;
-
- if (ipp_do_blit(&ipp_req)) {
- spin_lock_irqsave(&pcdev->lock, flags);
- vb->state = VIDEOBUF_ERROR;
- spin_unlock_irqrestore(&pcdev->lock, flags);
- RK29CAMERA_TR("Capture image(vb->i:0x%x) which IPP operated is error!\n", vb->i);
- RK29CAMERA_TR("ipp_req.src0.YrgbMst:0x%x ipp_req.src0.CbrMst:0x%x \n", ipp_req.src0.YrgbMst,ipp_req.src0.CbrMst);
- RK29CAMERA_TR("ipp_req.src0.w:0x%x ipp_req.src0.h:0x%x \n",ipp_req.src0.w,ipp_req.src0.h);
- RK29CAMERA_TR("ipp_req.src0.fmt:0x%x\n",ipp_req.src0.fmt);
- RK29CAMERA_TR("ipp_req.dst0.YrgbMst:0x%x ipp_req.dst0.CbrMst:0x%x \n",ipp_req.dst0.YrgbMst,ipp_req.dst0.CbrMst);
- RK29CAMERA_TR("ipp_req.dst0.w:0x%x ipp_req.dst0.h:0x%x \n",ipp_req.dst0.w ,ipp_req.dst0.h);
- RK29CAMERA_TR("ipp_req.dst0.fmt:0x%x\n",ipp_req.dst0.fmt);
- RK29CAMERA_TR("ipp_req.src_vir_w:0x%x ipp_req.dst_vir_w :0x%x\n",ipp_req.src_vir_w ,ipp_req.dst_vir_w);
- RK29CAMERA_TR("ipp_req.timeout:0x%x ipp_req.flag :0x%x\n",ipp_req.timeout,ipp_req.flag);
- }
+ dstW /= 2;
+ dstH /= 2;
+ srcW /= 2;
+ srcH /= 2;
+
+ //UV
+ //for(y = 0; y<dstH - 1 ; y++ ) {
+ for(y = 0; y<dstH; y++ ) {
+ yCoeff00 = (y*zoomindstyIntInv)&0xffff;
+ yCoeff01 = 0xffff - yCoeff00;
+ sY = (y*zoomindstyIntInv >> 16);
+
+ for(x = 0; x<dstW; x++ ) {
+ xCoeff00 = (x*zoomindstxIntInv)&0xffff;
+ xCoeff01 = 0xffff - xCoeff00;
+ sX = (x*zoomindstxIntInv >> 16);
+
+ //U
+ a = psUV[(sY*srcW + sX)*2];
+ b = psUV[(sY*srcW + sX + 1)*2];
+ c = psUV[((sY+1)*srcW + sX)*2];
+ d = psUV[((sY+1)*srcW + sX + 1)*2];
+
+ r0 = (a * xCoeff01 + b * xCoeff00)>>16 ;
+ r1 = (c * xCoeff01 + d * xCoeff00)>>16 ;
+ r0 = (r0 * yCoeff01 + r1 * yCoeff00)>>16;
+
+ pdUV[x*2] = r0;
+
+ //V
+ a = psUV[(sY*srcW + sX)*2 + 1];
+ b = psUV[(sY*srcW + sX + 1)*2 + 1];
+ c = psUV[((sY+1)*srcW + sX)*2 + 1];
+ d = psUV[((sY+1)*srcW + sX + 1)*2 + 1];
+
+ r0 = (a * xCoeff01 + b * xCoeff00)>>16 ;
+ r1 = (c * xCoeff01 + d * xCoeff00)>>16 ;
+ r0 = (r0 * yCoeff01 + r1 * yCoeff00)>>16;
+
+ pdUV[x*2 + 1] = r0;
+ }
+ pdUV += dstW*2;
+ }
+
+rk29_camera_scale_crop_arm_end:
+
+ dmac_flush_range((void*)src,(void*)(src+pcdev->vipmem_bsize));
+ outer_flush_range((phys_addr_t)src_phy,(phys_addr_t)(src_phy+pcdev->vipmem_bsize));
+
+ dmac_flush_range((void*)dst,(void*)(dst+vb_info->size));
+ outer_flush_range((phys_addr_t)dst_phy,(phys_addr_t)(dst_phy+vb_info->size));
+
+ return ret;
+}
+#endif
- wake_up(&(camera_work->vb->done));
+static void rk29_camera_capture_process(struct work_struct *work)
+{
+ struct rk29_camera_work *camera_work = container_of(work, struct rk29_camera_work, work);
+ struct videobuf_buffer *vb = camera_work->vb;
+ struct rk29_camera_dev *pcdev = camera_work->pcdev;
+ //enum v4l2_mbus_pixelcode icd_code = pcdev->icd->current_fmt->code;
+ unsigned long flags = 0;
+ int err = 0;
+
+ if (!CAM_WORKQUEUE_IS_EN())
+ goto rk29_camera_capture_process_end;
+
+ down(&pcdev->zoominfo.sem);
+ if (pcdev->icd_cb.scale_crop_cb)
+ err = (pcdev->icd_cb.scale_crop_cb)(work);
+ up(&pcdev->zoominfo.sem);
+
+ if (pcdev->icd_cb.sensor_cb)
+ (pcdev->icd_cb.sensor_cb)(vb);
+
+rk29_camera_capture_process_end:
+ if (err) {
+ vb->state = VIDEOBUF_ERROR;
+ } else {
+ if ((vb->state == VIDEOBUF_QUEUED) || (vb->state == VIDEOBUF_ACTIVE)) {
+ vb->state = VIDEOBUF_DONE;
+ vb->field_count++;
+ }
+ }
+ wake_up(&(camera_work->vb->done));
+ spin_lock_irqsave(&pcdev->camera_work_lock, flags);
+ list_add_tail(&camera_work->queue, &pcdev->camera_work_queue);
+ spin_unlock_irqrestore(&pcdev->camera_work_lock, flags);
+ return;
}
static irqreturn_t rk29_camera_irq(int irq, void *data)
{
struct rk29_camera_dev *pcdev = data;
struct videobuf_buffer *vb;
struct rk29_camera_work *wk;
+ static struct timeval first_tv;
+ struct timeval tv;
read_vip_reg(RK29_VIP_INT_STS); /* clear vip interrupte single */
/* ddl@rock-chps.com : Current VIP is run in One Frame Mode, Frame 1 is validate */
if (read_vip_reg(RK29_VIP_FB_SR) & 0x01) {
+ if (!pcdev->fps) {
+ do_gettimeofday(&first_tv);
+ }
pcdev->fps++;
if (!pcdev->active)
goto RK29_CAMERA_IRQ_END;
- if (pcdev->frame_inval>0) {
+ if (pcdev->frame_inval>0) {
pcdev->frame_inval--;
rk29_videobuf_capture(pcdev->active);
goto RK29_CAMERA_IRQ_END;
pcdev->frame_inval = 0;
}
+ if(pcdev->fps == RK29_CAM_FRAME_MEASURE) {
+ do_gettimeofday(&tv);
+ pcdev->frame_interval = ((tv.tv_sec*1000000 + tv.tv_usec) - (first_tv.tv_sec*1000000 + first_tv.tv_usec))
+ /(RK29_CAM_FRAME_MEASURE-1);
+ }
+
vb = pcdev->active;
/* ddl@rock-chips.com : this vb may be deleted from queue */
if ((vb->state == VIDEOBUF_QUEUED) || (vb->state == VIDEOBUF_ACTIVE)) {
if (pcdev->active == NULL) {
RK29CAMERA_DG("%s video_buf queue is empty!\n",__FUNCTION__);
}
-
- if ((vb->state == VIDEOBUF_QUEUED) || (vb->state == VIDEOBUF_ACTIVE)) {
- vb->state = VIDEOBUF_DONE;
- do_gettimeofday(&vb->ts);
- vb->field_count++;
- }
-
- if ((pcdev->host_width != pcdev->icd->user_width) || (pcdev->host_height != pcdev->icd->user_height)) {
- wk = pcdev->camera_work + vb->i;
- INIT_WORK(&(wk->work), rk29_camera_capture_process);
- wk->vb = vb;
- wk->pcdev = pcdev;
- queue_work(pcdev->camera_wq, &(wk->work));
- } else {
+
+ do_gettimeofday(&vb->ts);
+ if (CAM_WORKQUEUE_IS_EN()) {
+ if (!list_empty(&pcdev->camera_work_queue)) {
+ wk = list_entry(pcdev->camera_work_queue.next, struct rk29_camera_work, queue);
+ list_del_init(&wk->queue);
+ INIT_WORK(&(wk->work), rk29_camera_capture_process);
+ wk->vb = vb;
+ wk->pcdev = pcdev;
+ queue_work(pcdev->camera_wq, &(wk->work));
+ }
+ } else {
+ if ((vb->state == VIDEOBUF_QUEUED) || (vb->state == VIDEOBUF_ACTIVE)) {
+ vb->state = VIDEOBUF_DONE;
+ vb->field_count++;
+ }
wake_up(&vb->done);
}
}
struct soc_camera_device *icd = vq->priv_data;
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct rk29_camera_dev *pcdev = ici->priv;
-
+ struct rk29_camera_vbinfo *vb_info =NULL;
+
#ifdef DEBUG
dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
vb, vb->baddr, vb->bsize);
case VIDEOBUF_PREPARED:
dev_dbg(&icd->dev, "%s (prepared)\n", __func__);
break;
- default:
+ default:
dev_dbg(&icd->dev, "%s (unknown)\n", __func__);
break;
}
#endif
if (vb == pcdev->active) {
RK29CAMERA_DG("%s Wait for this video buf(0x%x) write finished!\n ",__FUNCTION__,(unsigned int)vb);
- interruptible_sleep_on_timeout(&vb->done, 100);
+ interruptible_sleep_on_timeout(&vb->done, msecs_to_jiffies(500));
RK29CAMERA_DG("%s This video buf(0x%x) write finished, release now!!\n",__FUNCTION__,(unsigned int)vb);
}
+
+ flush_workqueue(pcdev->camera_wq);
+#if CAMERA_VIDEOBUF_ARM_ACCESS
+ if (pcdev->vbinfo) {
+ vb_info = pcdev->vbinfo + vb->i;
+
+ if (vb_info->vir_addr) {
+ iounmap(vb_info->vir_addr);
+ release_mem_region(vb_info->phy_addr, vb_info->size);
+ memset(vb_info, 0x00, sizeof(struct rk29_camera_vbinfo));
+ }
+
+ }
+#endif
rk29_videobuf_free(vq, buf);
}
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_NONE,
sizeof(struct rk29_buffer),
- icd);
- pcdev->vb_vidq_ptr = q; /* ddl@rock-chips.com */
+ icd,&icd->video_lock);
}
static int rk29_camera_activate(struct rk29_camera_dev *pcdev, struct soc_camera_device *icd)
{
RK29CAMERA_DG("%s..%d.. \n",__FUNCTION__,__LINE__);
if (!pcdev->aclk_ddr_lcdc || !pcdev->aclk_disp_matrix || !pcdev->hclk_cpu_display ||
- !pcdev->vip_slave || !pcdev->vip || !pcdev->vip_input || !pcdev->vip_bus ||
- IS_ERR(pcdev->aclk_ddr_lcdc) || IS_ERR(pcdev->aclk_disp_matrix) || IS_ERR(pcdev->hclk_cpu_display) ||
- IS_ERR(pcdev->vip_slave) || IS_ERR(pcdev->vip) || IS_ERR(pcdev->vip_input) || IS_ERR(pcdev->vip_bus)) {
+ !pcdev->vip_slave || !pcdev->vip_out || !pcdev->vip_input || !pcdev->vip_bus || !pcdev->pd_display ||
+ IS_ERR(pcdev->aclk_ddr_lcdc) || IS_ERR(pcdev->aclk_disp_matrix) || IS_ERR(pcdev->hclk_cpu_display) || IS_ERR(pcdev->pd_display) ||
+ IS_ERR(pcdev->vip_slave) || IS_ERR(pcdev->vip_out) || IS_ERR(pcdev->vip_input) || IS_ERR(pcdev->vip_bus)) {
RK29CAMERA_TR(KERN_ERR "failed to get vip_clk(axi) source\n");
goto RK29_CAMERA_ACTIVE_ERR;
goto RK29_CAMERA_ACTIVE_ERR;
}
+ clk_enable(pcdev->pd_display);
+
clk_enable(pcdev->aclk_ddr_lcdc);
clk_enable(pcdev->aclk_disp_matrix);
goto RK29_CAMERA_ACTIVE_ERR;
}
- clk_set_parent(pcdev->vip, parent);
+ clk_set_parent(pcdev->vip_out, parent);
- clk_enable(pcdev->vip);
+ clk_enable(pcdev->vip_out);
rk29_mux_api_set(GPIO1B4_VIPCLKOUT_NAME, GPIO1L_VIP_CLKOUT);
ndelay(10);
read_vip_reg(RK29_VIP_INT_STS); //clear vip interrupte single
rk29_mux_api_set(GPIO1B4_VIPCLKOUT_NAME, GPIO1L_GPIO1B4);
- clk_disable(pcdev->vip);
+ clk_disable(pcdev->vip_out);
clk_disable(pcdev->vip_input);
clk_disable(pcdev->vip_bus);
clk_disable(pcdev->aclk_ddr_lcdc);
clk_disable(pcdev->aclk_disp_matrix);
+
+ clk_disable(pcdev->pd_display);
return;
}
struct rk29_camera_dev *pcdev = ici->priv;
struct device *control = to_soc_camera_control(icd);
struct v4l2_subdev *sd;
- int ret;
-
+ int ret,i,icd_catch;
+ struct rk29_camera_frmivalenum *fival_list,*fival_nxt;
+
mutex_lock(&camera_lock);
if (pcdev->icd) {
goto ebusy;
}
- dev_info(&icd->dev, "RK29 Camera driver attached to camera%d(%s)\n",
- icd->devnum,dev_name(icd->pdev));
-
+ RK29CAMERA_DG("RK29 Camera driver attached to %s\n",dev_name(icd->pdev));
+
pcdev->frame_inval = RK29_CAM_FRAME_INVAL_INIT;
pcdev->active = NULL;
pcdev->icd = NULL;
pcdev->reginfo_suspend.Inval = Reg_Invalidate;
+ pcdev->zoominfo.zoom_rate = 100;
+
/* ddl@rock-chips.com: capture list must be reset, because this list may be not empty,
* if app havn't dequeue all videobuf before close camera device;
*/
if (control) {
sd = dev_get_drvdata(control);
v4l2_subdev_call(sd, core, ioctl, RK29_CAM_SUBDEV_IOREQUEST,(void*)pcdev->pdata);
+ #if 0
ret = v4l2_subdev_call(sd,core, init, 0);
if (ret)
goto ebusy;
+ #endif
+ v4l2_subdev_call(sd, core, ioctl, RK29_CAM_SUBDEV_CB_REGISTER,(void*)(&pcdev->icd_cb));
}
-
+
pcdev->icd = icd;
+ pcdev->icd_init = 0;
+
+ icd_catch = 0;
+ for (i=0; i<2; i++) {
+ if (pcdev->icd_frmival[i].icd == icd)
+ icd_catch = 1;
+ if (pcdev->icd_frmival[i].icd == NULL) {
+ pcdev->icd_frmival[i].icd = icd;
+ icd_catch = 1;
+ }
+ }
+ if (icd_catch == 0) {
+ fival_list = pcdev->icd_frmival[0].fival_list;
+ fival_nxt = fival_list;
+ while(fival_nxt != NULL) {
+ fival_nxt = fival_list->nxt;
+ kfree(fival_list);
+ fival_list = fival_nxt;
+ }
+ pcdev->icd_frmival[0].icd = icd;
+ pcdev->icd_frmival[0].fival_list = kzalloc(sizeof(struct rk29_camera_frmivalenum),GFP_KERNEL);
+ }
ebusy:
mutex_unlock(&camera_lock);
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct rk29_camera_dev *pcdev = ici->priv;
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
-
+ struct rk29_camera_vbinfo *vb_info;
+ unsigned int i;
+
mutex_lock(&camera_lock);
BUG_ON(icd != pcdev->icd);
- dev_info(&icd->dev, "RK29 Camera driver detached from camera%d(%s)\n",
- icd->devnum,dev_name(icd->pdev));
+ RK29CAMERA_DG("RK29 Camera driver detached from %s\n",dev_name(icd->pdev));
/* ddl@rock-chips.com: Application will call VIDIOC_STREAMOFF before close device, but
stream may be turn on again before close device, if suspend and resume happened. */
v4l2_subdev_call(sd, core, ioctl, RK29_CAM_SUBDEV_DEACTIVATE,NULL);
rk29_camera_deactivate(pcdev);
- /* ddl@rock-chips.com: Call videobuf_mmap_free here for free the struct video_buffer which malloc in videobuf_alloc */
- #if 0
- if (pcdev->vb_vidq_ptr) {
- videobuf_mmap_free(pcdev->vb_vidq_ptr);
- pcdev->vb_vidq_ptr = NULL;
- }
- #else
- pcdev->vb_vidq_ptr = NULL;
- #endif
-
if (pcdev->camera_work) {
kfree(pcdev->camera_work);
pcdev->camera_work = NULL;
pcdev->camera_work_count = 0;
+ INIT_LIST_HEAD(&pcdev->camera_work_queue);
}
-
+#if CAMERA_VIDEOBUF_ARM_ACCESS
+ if (pcdev->vbinfo) {
+ vb_info = pcdev->vbinfo;
+ for (i=0; i<pcdev->vbinfo_count; i++) {
+ if (vb_info->vir_addr) {
+ iounmap(vb_info->vir_addr);
+ release_mem_region(vb_info->phy_addr, vb_info->size);
+ memset(vb_info, 0x00, sizeof(struct rk29_camera_vbinfo));
+ }
+ vb_info++;
+ }
+ kfree(pcdev->vbinfo);
+ pcdev->vbinfo = NULL;
+ pcdev->vbinfo_count = 0;
+ }
+#endif
pcdev->active = NULL;
pcdev->icd = NULL;
+ pcdev->icd_cb.sensor_cb = NULL;
pcdev->reginfo_suspend.Inval = Reg_Invalidate;
/* ddl@rock-chips.com: capture list must be reset, because this list may be not empty,
* if app havn't dequeue all videobuf before close camera device;
return;
}
-
static int rk29_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
{
unsigned long bus_flags, camera_flags, common_flags;
unsigned int vip_ctrl_val = 0;
- int ret = 0;
+ const struct soc_mbus_pixelfmt *fmt;
+ int ret = 0;
RK29CAMERA_DG("%s..%d..\n",__FUNCTION__,__LINE__);
+ fmt = soc_mbus_get_fmtdesc(icd->current_fmt->code);
+ if (!fmt)
+ return -EINVAL;
+
bus_flags = RK29_CAM_BUS_PARAM;
+ /* If requested data width is supported by the platform, use it */
+ switch (fmt->bits_per_sample) {
+ case 10:
+ if (!(bus_flags & SOCAM_DATAWIDTH_10))
+ return -EINVAL;
+ break;
+ case 9:
+ if (!(bus_flags & SOCAM_DATAWIDTH_9))
+ return -EINVAL;
+ break;
+ case 8:
+ if (!(bus_flags & SOCAM_DATAWIDTH_8))
+ return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
if (icd->ops->query_bus_param)
camera_flags = icd->ops->query_bus_param(icd);
else
if (ret < 0)
goto RK29_CAMERA_SET_BUS_PARAM_END;
- if (common_flags & SOCAM_DATAWIDTH_8) {
- icd->buswidth = 8;
- } else if (common_flags & SOCAM_DATAWIDTH_10) {
- icd->buswidth = 10;
- }
-
vip_ctrl_val = read_vip_reg(RK29_VIP_CTRL);
if (common_flags & SOCAM_PCLK_SAMPLE_FALLING) {
vip_ctrl_val |= NEGATIVE_EDGE;
camera_flags, bus_flags);
return ret;
}
-static const struct soc_camera_data_format rk29_camera_formats[] = {
- {
- .name = "Planar YUV420 12 bit",
- .depth = 12,
- .fourcc = V4L2_PIX_FMT_YUV420,
- .colorspace = V4L2_COLORSPACE_JPEG,
+
+static const struct soc_mbus_pixelfmt rk29_camera_formats[] = {
+ {
+ .fourcc = V4L2_PIX_FMT_NV12,
+ .name = "YUV420 NV12",
+ .bits_per_sample = 8,
+ .packing = SOC_MBUS_PACKING_1_5X8,
+ .order = SOC_MBUS_ORDER_LE,
+ },{
+ .fourcc = V4L2_PIX_FMT_NV16,
+ .name = "YUV422 NV16",
+ .bits_per_sample = 8,
+ .packing = SOC_MBUS_PACKING_2X8_PADHI,
+ .order = SOC_MBUS_ORDER_LE,
},{
- .name = "Planar YUV422 16 bit",
- .depth = 16,
- .fourcc = V4L2_PIX_FMT_YUV422P,
- .colorspace = V4L2_COLORSPACE_JPEG,
+ .fourcc = V4L2_PIX_FMT_YUV420,
+ .name = "NV12(v0.0.1)",
+ .bits_per_sample = 8,
+ .packing = SOC_MBUS_PACKING_1_5X8,
+ .order = SOC_MBUS_ORDER_LE,
},{
- .name = "Raw Bayer RGB 10 bit",
- .depth = 16,
- .fourcc = V4L2_PIX_FMT_SGRBG10,
- .colorspace = V4L2_COLORSPACE_SRGB,
+ .fourcc = V4L2_PIX_FMT_YUV422P,
+ .name = "NV16(v0.0.1)",
+ .bits_per_sample = 8,
+ .packing = SOC_MBUS_PACKING_2X8_PADHI,
+ .order = SOC_MBUS_ORDER_LE,
}
};
-static void rk29_camera_setup_format(struct soc_camera_device *icd, __u32 host_pixfmt, __u32 cam_pixfmt, struct v4l2_rect *rect)
+static void rk29_camera_setup_format(struct soc_camera_device *icd, __u32 host_pixfmt, enum v4l2_mbus_pixelcode icd_code, struct v4l2_rect *rect)
{
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct rk29_camera_dev *pcdev = ici->priv;
switch (host_pixfmt)
{
- case V4L2_PIX_FMT_YUV422P:
+ case V4L2_PIX_FMT_NV16:
+ case V4L2_PIX_FMT_YUV422P: /* ddl@rock-chips.com: V4L2_PIX_FMT_YUV422P is V4L2_PIX_FMT_NV16 actually in 0.0.1 driver */
vip_ctrl_val |= VIPREGYUV422;
pcdev->frame_inval = RK29_CAM_FRAME_INVAL_DC;
pcdev->pixfmt = host_pixfmt;
break;
- case V4L2_PIX_FMT_YUV420:
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_YUV420: /* ddl@rock-chips.com: V4L2_PIX_FMT_YUV420 is V4L2_PIX_FMT_NV12 actually in 0.0.1 driver */
vip_ctrl_val |= VIPREGYUV420;
if (pcdev->frame_inval != RK29_CAM_FRAME_INVAL_INIT)
pcdev->frame_inval = RK29_CAM_FRAME_INVAL_INIT;
pcdev->pixfmt = host_pixfmt;
break;
- case V4L2_PIX_FMT_SGRBG10:
- vip_ctrl_val |= (VIP_RAW | VIP_SENSOR | VIP_DATA_LITTLEEND);
- pcdev->frame_inval = RK29_CAM_FRAME_INVAL_DC;
- pcdev->pixfmt = host_pixfmt;
- break;
default: /* ddl@rock-chips.com : vip output format is hold when pixfmt is invalidate */
- vip_ctrl_val |= (read_vip_reg(RK29_VIP_CTRL) & VIPREGYUV422);
+ if (pcdev->frame_inval != RK29_CAM_FRAME_INVAL_INIT)
+ pcdev->frame_inval = RK29_CAM_FRAME_INVAL_INIT;
+ pcdev->pixfmt = host_pixfmt;
break;
}
- switch (cam_pixfmt)
+ switch (icd_code)
{
- case V4L2_PIX_FMT_UYVY:
- vip_ctrl_val |= SENSOR_UYVY;
+ case V4L2_MBUS_FMT_UYVY8_2X8:
+ vip_ctrl_val |= (SENSOR_UYVY|VIP_YUV);
break;
- case V4L2_PIX_FMT_YUYV:
- vip_ctrl_val |= SENSOR_YUYV;
+ case V4L2_MBUS_FMT_YUYV8_2X8:
+ vip_ctrl_val |= (SENSOR_YUYV|VIP_YUV);
break;
default :
vip_ctrl_val |= (read_vip_reg(RK29_VIP_CTRL) & SENSOR_YUYV);
return;
}
-static int rk29_camera_get_formats(struct soc_camera_device *icd, int idx,
+static int rk29_camera_get_formats(struct soc_camera_device *icd, unsigned int idx,
struct soc_camera_format_xlate *xlate)
{
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
struct device *dev = icd->dev.parent;
- int formats = 0, buswidth, ret;
-
- buswidth = 8;
+ int formats = 0, ret;
+ enum v4l2_mbus_pixelcode code;
+ const struct soc_mbus_pixelfmt *fmt;
+
+ ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code);
+ if (ret < 0)
+ /* No more formats */
+ return 0;
+
+ fmt = soc_mbus_get_fmtdesc(code);
+ if (!fmt) {
+ dev_err(dev, "Invalid format code #%u: %d\n", idx, code);
+ return 0;
+ }
- ret = rk29_camera_try_bus_param(icd, buswidth);
+ ret = rk29_camera_try_bus_param(icd, fmt->bits_per_sample);
if (ret < 0)
return 0;
- switch (icd->formats[idx].fourcc) {
- case V4L2_PIX_FMT_UYVY:
- case V4L2_PIX_FMT_YUYV:
+ switch (code) {
+ case V4L2_MBUS_FMT_UYVY8_2X8:
+ case V4L2_MBUS_FMT_YUYV8_2X8:
formats++;
if (xlate) {
xlate->host_fmt = &rk29_camera_formats[0];
- xlate->cam_fmt = icd->formats + idx;
- xlate->buswidth = buswidth;
+ xlate->code = code;
xlate++;
- dev_dbg(dev, "Providing format %s using %s\n",
- rk29_camera_formats[0].name,
- icd->formats[idx].name);
+ dev_dbg(dev, "Providing format %s using code %d\n",
+ rk29_camera_formats[0].name,code);
}
formats++;
if (xlate) {
xlate->host_fmt = &rk29_camera_formats[1];
- xlate->cam_fmt = icd->formats + idx;
- xlate->buswidth = buswidth;
+ xlate->code = code;
xlate++;
- dev_dbg(dev, "Providing format %s using %s\n",
- rk29_camera_formats[1].name,
- icd->formats[idx].name);
+ dev_dbg(dev, "Providing format %s using code %d\n",
+ rk29_camera_formats[1].name,code);
}
- break;
- case V4L2_PIX_FMT_SGRBG10:
- formats++;
+
+ formats++;
if (xlate) {
xlate->host_fmt = &rk29_camera_formats[2];
- xlate->cam_fmt = icd->formats + idx;
- xlate->buswidth = 10;
+ xlate->code = code;
+ xlate++;
+ dev_dbg(dev, "Providing format %s using code %d\n",
+ rk29_camera_formats[2].name,code);
+ }
+
+ formats++;
+ if (xlate) {
+ xlate->host_fmt = &rk29_camera_formats[3];
+ xlate->code = code;
xlate++;
- dev_dbg(dev, "Providing format %s using %s\n",
- rk29_camera_formats[2].name,
- icd->formats[idx].name);
+ dev_dbg(dev, "Providing format %s using code %d\n",
+ rk29_camera_formats[3].name,code);;
}
- break;
+ break;
default:
break;
}
struct v4l2_crop *a)
{
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
- struct v4l2_format f;
- struct v4l2_pix_format *pix = &f.fmt.pix;
+ struct v4l2_mbus_framefmt mf;
+ u32 fourcc = icd->current_fmt->host_fmt->fourcc;
int ret;
- f.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
- ret = v4l2_subdev_call(sd, video, g_fmt, &f);
+ ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf);
if (ret < 0)
return ret;
- if ((pix->width < (a->c.left + a->c.width)) || (pix->height < (a->c.top + a->c.height))) {
+ if ((mf.width < (a->c.left + a->c.width)) || (mf.height < (a->c.top + a->c.height))) {
- pix->width = a->c.left + a->c.width;
- pix->height = a->c.top + a->c.height;
+ mf.width = a->c.left + a->c.width;
+ mf.height = a->c.top + a->c.height;
- v4l_bound_align_image(&pix->width, RK29_CAM_W_MIN, RK29_CAM_W_MAX, 1,
- &pix->height, RK29_CAM_H_MIN, RK29_CAM_H_MAX, 0,
- icd->current_fmt->fourcc == V4L2_PIX_FMT_YUV422P ?4 : 0);
+ v4l_bound_align_image(&mf.width, RK29_CAM_W_MIN, RK29_CAM_W_MAX, 1,
+ &mf.height, RK29_CAM_H_MIN, RK29_CAM_H_MAX, 0,
+ fourcc == V4L2_PIX_FMT_NV16 ?4 : 0);
- ret = v4l2_subdev_call(sd, video, s_fmt, &f);
+ ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf);
if (ret < 0)
return ret;
}
- rk29_camera_setup_format(icd, icd->current_fmt->fourcc, pix->pixelformat, &a->c);
+ rk29_camera_setup_format(icd, fourcc, mf.code, &a->c);
- icd->user_width = pix->width;
- icd->user_height = pix->height;
+ icd->user_width = mf.width;
+ icd->user_height = mf.height;
return 0;
}
{
struct device *dev = icd->dev.parent;
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
- const struct soc_camera_data_format *cam_fmt = NULL;
const struct soc_camera_format_xlate *xlate = NULL;
struct soc_camera_host *ici =to_soc_camera_host(icd->dev.parent);
struct rk29_camera_dev *pcdev = ici->priv;
struct v4l2_pix_format *pix = &f->fmt.pix;
- struct v4l2_format cam_f = *f;
+ struct v4l2_mbus_framefmt mf;
struct v4l2_rect rect;
- int ret,usr_w,usr_h;
+ int ret,usr_w,usr_h,icd_width,icd_height;
+ int stream_on = 0;
usr_w = pix->width;
usr_h = pix->height;
ret = -EINVAL;
goto RK29_CAMERA_SET_FMT_END;
}
+
+ /* ddl@rock-chips.com: sensor init code transmit in here after open */
+ if (pcdev->icd_init == 0) {
+ v4l2_subdev_call(sd,core, init, 0);
+ pcdev->icd_init = 1;
+ }
- cam_fmt = xlate->cam_fmt;
-
- cam_f.fmt.pix.pixelformat = cam_fmt->fourcc;
- ret = v4l2_subdev_call(sd, video, s_fmt, &cam_f);
- cam_f.fmt.pix.pixelformat = pix->pixelformat;
- *pix = cam_f.fmt.pix;
+ stream_on = read_vip_reg(RK29_VIP_CTRL);
+ if (stream_on & ENABLE_CAPTURE)
+ write_vip_reg(RK29_VIP_CTRL, (stream_on & (~ENABLE_CAPTURE)));
+
+ mf.width = pix->width;
+ mf.height = pix->height;
+ mf.field = pix->field;
+ mf.colorspace = pix->colorspace;
+ mf.code = xlate->code;
+
+ ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf);
+
+ if (mf.code != xlate->code)
+ return -EINVAL;
+
+ icd_width = mf.width;
+ icd_height = mf.height;
#ifdef CONFIG_VIDEO_RK29_WORK_IPP
- if ((pix->width != usr_w) || (pix->height != usr_h)) {
- pix->width = usr_w;
- pix->height = usr_h;
+ if ((mf.width != usr_w) || (mf.height != usr_h)) {
+ if (unlikely((mf.width <16) || (mf.width > 8190) || (mf.height < 16) || (mf.height > 8190))) {
+ RK29CAMERA_TR("Senor and IPP both invalid source resolution(%dx%d)\n",mf.width,mf.height);
+ ret = -EINVAL;
+ goto RK29_CAMERA_SET_FMT_END;
+ }
+ if (unlikely((usr_w <16)||(usr_h < 16))) {
+ RK29CAMERA_TR("Senor and IPP both invalid destination resolution(%dx%d)\n",usr_w,usr_h);
+ ret = -EINVAL;
+ goto RK29_CAMERA_SET_FMT_END;
+ }
}
#endif
icd->sense = NULL;
if (!ret) {
- rect.left = 0;
- rect.top = 0;
- rect.width = cam_f.fmt.pix.width;
- rect.height = cam_f.fmt.pix.height;
- RK29CAMERA_DG("%s..%s..%s icd width:%d host width:%d \n",__FUNCTION__,xlate->host_fmt->name, cam_fmt->name,
- rect.width, pix->width);
- rk29_camera_setup_format(icd, pix->pixelformat, cam_fmt->fourcc, &rect);
- icd->buswidth = xlate->buswidth;
- icd->current_fmt = xlate->host_fmt;
+ if (mf.width*usr_h == mf.height*usr_w) {
+ rect.width = mf.width;
+ rect.height = mf.height;
+ } else {
+ int ratio;
+ if (usr_w > usr_h) {
+ if (mf.width > usr_w) {
+ ratio = MIN((mf.width*10/usr_w),(mf.height*10/usr_h))-1;
+ rect.width = usr_w*ratio/10;
+ rect.height = usr_h*ratio/10;
+ } else {
+ ratio = MAX((usr_w*10/mf.width),(usr_h*10/mf.height))+1;
+ rect.width = usr_w*10/ratio;
+ rect.height = usr_h*10/ratio;
+ }
+ } else {
+ if (mf.height > usr_h) {
+ ratio = MIN((mf.width*10/usr_w),(mf.height*10/usr_h))-1;
+ rect.width = usr_w*ratio/10;
+ rect.height = usr_h*ratio/10;
+ } else {
+ ratio = MAX((usr_w*10/mf.width),(usr_h*10/mf.height))+1;
+ rect.width = usr_w*10/ratio;
+ rect.height = usr_h*10/ratio;
+ }
+ }
+ }
- if (((pcdev->host_width != pcdev->icd->user_width) || (pcdev->host_height != pcdev->icd->user_height))) {
+ rect.left = (mf.width - rect.width)/2;
+ rect.top = (mf.height - rect.height)/2;
+
+ down(&pcdev->zoominfo.sem);
+ pcdev->zoominfo.a.c.width = rect.width*100/pcdev->zoominfo.zoom_rate;
+ pcdev->zoominfo.a.c.width &= ~0x03;
+ pcdev->zoominfo.a.c.height = rect.height*100/pcdev->zoominfo.zoom_rate;
+ pcdev->zoominfo.a.c.height &= ~0x03;
+ pcdev->zoominfo.a.c.left = ((rect.width - pcdev->zoominfo.a.c.width)/2 + rect.left)&(~0x01);
+ pcdev->zoominfo.a.c.top = ((rect.height - pcdev->zoominfo.a.c.height)/2 + rect.top)&(~0x01);
+ up(&pcdev->zoominfo.sem);
+
+ /* ddl@rock-chips.com: IPP work limit check */
+ if ((pcdev->zoominfo.a.c.width != usr_w) || (pcdev->zoominfo.a.c.height != usr_h)) {
+ if (usr_w > 0x7f0) {
+ if (((usr_w>>1)&0x3f) && (((usr_w>>1)&0x3f) <= 8)) {
+ RK29CAMERA_TR("IPP Destination resolution(%dx%d, ((%d div 1) mod 64)=%d is <= 8)",usr_w,usr_h, usr_w, (int)((usr_w>>1)&0x3f));
+ ret = -EINVAL;
+ goto RK29_CAMERA_SET_FMT_END;
+ }
+ } else {
+ if ((usr_w&0x3f) && ((usr_w&0x3f) <= 8)) {
+ RK29CAMERA_TR("IPP Destination resolution(%dx%d, %d mod 64=%d is <= 8)",usr_w,usr_h, usr_w, (int)(usr_w&0x3f));
+ ret = -EINVAL;
+ goto RK29_CAMERA_SET_FMT_END;
+ }
+ }
+ }
+
+ /* ddl@rock-chips.com: Crop is doing by IPP, not by VIP in rk2918 */
+ rect.left = 0;
+ rect.top = 0;
+ rect.width = mf.width;
+ rect.height = mf.height;
+
+ RK29CAMERA_DG("%s..%s Sensor output:%dx%d VIP output:%dx%d (zoom: %dx%d@(%d,%d)->%dx%d)\n",__FUNCTION__,xlate->host_fmt->name,
+ mf.width, mf.height,rect.width,rect.height, pcdev->zoominfo.a.c.width,pcdev->zoominfo.a.c.height, pcdev->zoominfo.a.c.left,pcdev->zoominfo.a.c.top,
+ pix->width, pix->height);
+
+
+ rk29_camera_setup_format(icd, pix->pixelformat, mf.code, &rect);
+
+ if (CAM_IPPWORK_IS_EN()) {
BUG_ON(pcdev->vipmem_phybase == 0);
}
+ pcdev->icd_width = icd_width;
+ pcdev->icd_height = icd_height;
+
+ pix->width = usr_w;
+ pix->height = usr_h;
+ pix->field = mf.field;
+ pix->colorspace = mf.colorspace;
+ icd->current_fmt = xlate;
}
RK29_CAMERA_SET_FMT_END:
+ if (stream_on & ENABLE_CAPTURE)
+ write_vip_reg(RK29_VIP_CTRL, (read_vip_reg(RK29_VIP_CTRL) | ENABLE_CAPTURE));
if (ret)
- RK29CAMERA_TR("\n%s..%d.. ret = %d \n",__FUNCTION__,__LINE__, ret);
+ RK29CAMERA_TR("\n%s: Driver isn't support %dx%d resolution which user request!\n",__FUNCTION__,usr_w,usr_h);
return ret;
}
+static bool rk29_camera_fmt_capturechk(struct v4l2_format *f)
+{
+ bool ret = false;
+
+ if ((f->fmt.pix.width == 1024) && (f->fmt.pix.height == 768)) {
+ ret = true;
+ } else if ((f->fmt.pix.width == 1280) && (f->fmt.pix.height == 1024)) {
+ ret = true;
+ } else if ((f->fmt.pix.width == 1600) && (f->fmt.pix.height == 1200)) {
+ ret = true;
+ } else if ((f->fmt.pix.width == 2048) && (f->fmt.pix.height == 1536)) {
+ ret = true;
+ } else if ((f->fmt.pix.width == 2592) && (f->fmt.pix.height == 1944)) {
+ ret = true;
+ }
+ if (ret == true)
+ RK29CAMERA_DG("%s %dx%d is capture format\n", __FUNCTION__, f->fmt.pix.width, f->fmt.pix.height);
+ return ret;
+}
static int rk29_camera_try_fmt(struct soc_camera_device *icd,
struct v4l2_format *f)
{
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct rk29_camera_dev *pcdev = ici->priv;
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
const struct soc_camera_format_xlate *xlate;
struct v4l2_pix_format *pix = &f->fmt.pix;
__u32 pixfmt = pix->pixelformat;
- enum v4l2_field field;
- int ret,usr_w,usr_h;
-
+ int ret,usr_w,usr_h,i;
+ bool is_capture = rk29_camera_fmt_capturechk(f);
+ bool vipmem_is_overflow = false;
+ struct v4l2_mbus_framefmt mf;
+ int bytes_per_line_host;
+
usr_w = pix->width;
usr_h = pix->height;
RK29CAMERA_DG("%s enter width:%d height:%d\n",__FUNCTION__,usr_w,usr_h);
xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
if (!xlate) {
- dev_err(ici->v4l2_dev.dev, "Format %x not found\n", pixfmt);
+ dev_err(icd->dev.parent, "Format (%c%c%c%c) not found\n", pixfmt & 0xFF, (pixfmt >> 8) & 0xFF,
+ (pixfmt >> 16) & 0xFF, (pixfmt >> 24) & 0xFF);
ret = -EINVAL;
+ RK29CAMERA_TR("%s(version:%c%c%c) support format:\n",rk29_cam_driver_description,(RK29_CAM_VERSION_CODE&0xff0000)>>16,
+ (RK29_CAM_VERSION_CODE&0xff00)>>8,(RK29_CAM_VERSION_CODE&0xff));
+ for (i = 0; i < icd->num_user_formats; i++)
+ RK29CAMERA_TR("(%c%c%c%c)-%s\n",
+ icd->user_formats[i].host_fmt->fourcc & 0xFF, (icd->user_formats[i].host_fmt->fourcc >> 8) & 0xFF,
+ (icd->user_formats[i].host_fmt->fourcc >> 16) & 0xFF, (icd->user_formats[i].host_fmt->fourcc >> 24) & 0xFF,
+ icd->user_formats[i].host_fmt->name);
goto RK29_CAMERA_TRY_FMT_END;
}
/* limit to rk29 hardware capabilities */
v4l_bound_align_image(&pix->width, RK29_CAM_W_MIN, RK29_CAM_W_MAX, 1,
&pix->height, RK29_CAM_H_MIN, RK29_CAM_H_MAX, 0,
- pixfmt == V4L2_PIX_FMT_YUV422P ? 4 : 0);
+ pixfmt == V4L2_PIX_FMT_NV16 ? 4 : 0);
- pix->bytesperline = pix->width * DIV_ROUND_UP(xlate->host_fmt->depth, 8);
- pix->sizeimage = pix->height * pix->bytesperline;
+ pix->bytesperline = soc_mbus_bytes_per_line(pix->width,
+ xlate->host_fmt);
+ if (pix->bytesperline < 0)
+ return pix->bytesperline;
- /* camera has to see its format, but the user the original one */
- pix->pixelformat = xlate->cam_fmt->fourcc;
/* limit to sensor capabilities */
- ret = v4l2_subdev_call(sd, video, try_fmt, f);
- pix->pixelformat = pixfmt;
- #ifdef CONFIG_VIDEO_RK29_WORK_IPP
- if ((pix->width > usr_w) && (pix->height > usr_h)) {
- pix->width = usr_w;
- pix->height = usr_h;
- } else if ((pix->width < usr_w) && (pix->height < usr_h)) {
- if (((usr_w>>1) < pix->width) && ((usr_h>>1) < pix->height)) {
+ mf.width = pix->width;
+ mf.height = pix->height;
+ mf.field = pix->field;
+ mf.colorspace = pix->colorspace;
+ mf.code = xlate->code;
+
+ ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf);
+ if (ret < 0)
+ goto RK29_CAMERA_TRY_FMT_END;
+ RK29CAMERA_DG("%s mf.width:%d mf.height:%d\n",__FUNCTION__,mf.width,mf.height);
+ #ifdef CONFIG_VIDEO_RK29_WORK_IPP
+ if ((mf.width != usr_w) || (mf.height != usr_h)) {
+ bytes_per_line_host = soc_mbus_bytes_per_line(mf.width,icd->current_fmt->host_fmt);
+ if (is_capture) {
+ vipmem_is_overflow = (PAGE_ALIGN(bytes_per_line_host*mf.height) > pcdev->vipmem_size);
+ } else {
+ /* Assume preview buffer minimum is 4 */
+ vipmem_is_overflow = (PAGE_ALIGN(bytes_per_line_host*mf.height)*4 > pcdev->vipmem_size);
+ }
+ if (vipmem_is_overflow == false) {
pix->width = usr_w;
pix->height = usr_h;
+ } else {
+ RK29CAMERA_TR("vipmem for IPP is overflow, This resolution(%dx%d -> %dx%d) is invalidate!\n",mf.width,mf.height,usr_w,usr_h);
+ pix->width = mf.width;
+ pix->height = mf.height;
}
+
+ if ((mf.width < usr_w) || (mf.height < usr_h)) {
+ if (((usr_w>>1) > mf.width) || ((usr_h>>1) > mf.height)) {
+ RK29CAMERA_TR("The aspect ratio(%dx%d/%dx%d) is bigger than 2 !\n",mf.width,mf.height,usr_w,usr_h);
+ pix->width = mf.width;
+ pix->height = mf.height;
+ }
+ }
+ }
+ #else
+ pix->width = mf.width;
+ pix->height = mf.height;
+ #endif
+ pix->colorspace = mf.colorspace;
+
+ switch (mf.field) {
+ case V4L2_FIELD_ANY:
+ case V4L2_FIELD_NONE:
+ pix->field = V4L2_FIELD_NONE;
+ break;
+ default:
+ /* TODO: support interlaced at least in pass-through mode */
+ dev_err(icd->dev.parent, "Field type %d unsupported.\n",
+ mf.field);
+ goto RK29_CAMERA_TRY_FMT_END;
}
- #endif
-
- field = pix->field;
-
- if (field == V4L2_FIELD_ANY) {
- pix->field = V4L2_FIELD_NONE;
- } else if (field != V4L2_FIELD_NONE) {
- dev_err(icd->dev.parent, "Field type %d unsupported.\n", field);
- ret = -EINVAL;
- goto RK29_CAMERA_TRY_FMT_END;
- }
RK29_CAMERA_TRY_FMT_END:
if (ret)
return ret;
}
-static int rk29_camera_reqbufs(struct soc_camera_file *icf,
+static int rk29_camera_reqbufs(struct soc_camera_device *icd,
struct v4l2_requestbuffers *p)
{
int i;
* a dma IRQ can occur for an in-work or unlinked buffer. Until now
* it hadn't triggered */
for (i = 0; i < p->count; i++) {
- struct rk29_buffer *buf = container_of(icf->vb_vidq.bufs[i],
+ struct rk29_buffer *buf = container_of(icd->vb_vidq.bufs[i],
struct rk29_buffer, vb);
buf->inwork = 0;
INIT_LIST_HEAD(&buf->vb.queue);
static unsigned int rk29_camera_poll(struct file *file, poll_table *pt)
{
- struct soc_camera_file *icf = file->private_data;
+ struct soc_camera_device *icd = file->private_data;
struct rk29_buffer *buf;
- buf = list_entry(icf->vb_vidq.stream.next, struct rk29_buffer,
+ buf = list_entry(icd->vb_vidq.stream.next, struct rk29_buffer,
vb.stream);
poll_wait(file, &buf->vb.done, pt);
static int rk29_camera_querycap(struct soc_camera_host *ici,
struct v4l2_capability *cap)
{
- /* cap->name is set by the firendly caller:-> */
- strlcpy(cap->card, rk29_cam_driver_description, sizeof(cap->card));
+ struct rk29_camera_dev *pcdev = ici->priv;
+ char orientation[5];
+ int i;
+
+ strlcpy(cap->card, dev_name(pcdev->icd->pdev), sizeof(cap->card));
+
+ memset(orientation,0x00,sizeof(orientation));
+ for (i=0; i<RK29_CAM_SUPPORT_NUMS;i++) {
+ if ((pcdev->pdata->info[i].dev_name!=NULL) && (strcmp(dev_name(pcdev->icd->pdev), pcdev->pdata->info[i].dev_name) == 0)) {
+ sprintf(orientation,"-%d",pcdev->pdata->info[i].orientation);
+ }
+ }
+
+ if (orientation[0] != '-') {
+ RK29CAMERA_TR("%s: %s is not registered in rk29_camera_platform_data, orientation apply default value",__FUNCTION__,dev_name(pcdev->icd->pdev));
+ if (strstr(dev_name(pcdev->icd->pdev),"front"))
+ strcat(cap->card,"-270");
+ else
+ strcat(cap->card,"-90");
+ } else {
+ strcat(cap->card,orientation);
+ }
+
cap->version = RK29_CAM_VERSION_CODE;
cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
{
struct device *control;
struct v4l2_subdev *sd;
- struct v4l2_format cam_f;
+ struct v4l2_mbus_framefmt mf;
const struct soc_camera_format_xlate *xlate;
int ret;
control = to_soc_camera_control(rk29_camdev_info_ptr->icd);
sd = dev_get_drvdata(control);
+ v4l2_subdev_call(sd, video, s_stream, 0); /* ddl@rock-chips.com: Avoid sensor autofocus thread is running */
ret = v4l2_subdev_call(sd,core, init, 1);
- cam_f.fmt.pix.width = rk29_camdev_info_ptr->icd->user_width;
- cam_f.fmt.pix.height = rk29_camdev_info_ptr->icd->user_height;
- xlate = soc_camera_xlate_by_fourcc(rk29_camdev_info_ptr->icd, rk29_camdev_info_ptr->icd->current_fmt->fourcc);
- cam_f.fmt.pix.pixelformat = xlate->cam_fmt->fourcc;
- ret |= v4l2_subdev_call(sd, video, s_fmt, &cam_f);
+ mf.width = rk29_camdev_info_ptr->icd->user_width;
+ mf.height = rk29_camdev_info_ptr->icd->user_height;
+ xlate = soc_camera_xlate_by_fourcc(rk29_camdev_info_ptr->icd, rk29_camdev_info_ptr->icd->current_fmt->host_fmt->fourcc);
+ mf.code = xlate->code;
+ ret |= v4l2_subdev_call(sd, video, s_mbus_fmt, &mf);
+ v4l2_subdev_call(sd, video, s_stream, 1);
write_vip_reg(RK29_VIP_CTRL, (read_vip_reg(RK29_VIP_CTRL)|ENABLE_CAPTURE));
RK29CAMERA_TR("Camera host haven't recevie data from sensor,Reinit sensor now! ret:0x%x\n",ret);
}
static enum hrtimer_restart rk29_camera_fps_func(struct hrtimer *timer)
{
+ struct rk29_camera_frmivalenum *fival_nxt=NULL,*fival_pre=NULL, *fival_rec=NULL;
+ int rec_flag,i;
+
RK29CAMERA_DG("rk29_camera_fps_func fps:0x%x\n",rk29_camdev_info_ptr->fps);
- if (rk29_camdev_info_ptr->fps < 3) {
+ if (rk29_camdev_info_ptr->fps < 2) {
RK29CAMERA_TR("Camera host haven't recevie data from sensor,Reinit sensor delay!\n");
INIT_WORK(&rk29_camdev_info_ptr->camera_reinit_work, rk29_camera_reinit_work);
queue_work(rk29_camdev_info_ptr->camera_wq,&(rk29_camdev_info_ptr->camera_reinit_work));
+ } else {
+ for (i=0; i<2; i++) {
+ if (rk29_camdev_info_ptr->icd == rk29_camdev_info_ptr->icd_frmival[i].icd) {
+ fival_nxt = rk29_camdev_info_ptr->icd_frmival[i].fival_list;
+ }
+ }
+
+ rec_flag = 0;
+ fival_pre = fival_nxt;
+ while (fival_nxt != NULL) {
+
+ RK29CAMERA_DG("%s %c%c%c%c %dx%d framerate : %d/%d\n", dev_name(&rk29_camdev_info_ptr->icd->dev),
+ fival_nxt->fival.pixel_format & 0xFF, (fival_nxt->fival.pixel_format >> 8) & 0xFF,
+ (fival_nxt->fival.pixel_format >> 16) & 0xFF, (fival_nxt->fival.pixel_format >> 24),
+ fival_nxt->fival.width, fival_nxt->fival.height, fival_nxt->fival.discrete.denominator,
+ fival_nxt->fival.discrete.numerator);
+
+ if (((fival_nxt->fival.pixel_format == rk29_camdev_info_ptr->pixfmt)
+ && (fival_nxt->fival.height == rk29_camdev_info_ptr->icd->user_height)
+ && (fival_nxt->fival.width == rk29_camdev_info_ptr->icd->user_width))
+ || (fival_nxt->fival.discrete.denominator == 0)) {
+
+ fival_nxt->fival.index = 0;
+ fival_nxt->fival.width = rk29_camdev_info_ptr->icd->user_width;
+ fival_nxt->fival.height= rk29_camdev_info_ptr->icd->user_height;
+ fival_nxt->fival.pixel_format = rk29_camdev_info_ptr->pixfmt;
+ fival_nxt->fival.discrete.denominator = rk29_camdev_info_ptr->frame_interval;
+ fival_nxt->fival.reserved[1] = (rk29_camdev_info_ptr->icd_width<<16)
+ |(rk29_camdev_info_ptr->icd_height);
+ fival_nxt->fival.discrete.numerator = 1000000;
+ fival_nxt->fival.type = V4L2_FRMIVAL_TYPE_DISCRETE;
+
+ rec_flag = 1;
+ fival_rec = fival_nxt;
+ }
+ fival_pre = fival_nxt;
+ fival_nxt = fival_nxt->nxt;
+ }
+
+ if ((rec_flag == 0) && fival_pre) {
+ fival_pre->nxt = kzalloc(sizeof(struct rk29_camera_frmivalenum), GFP_ATOMIC);
+ if (fival_pre->nxt != NULL) {
+ fival_pre->nxt->fival.index = fival_pre->fival.index++;
+ fival_pre->nxt->fival.width = rk29_camdev_info_ptr->icd->user_width;
+ fival_pre->nxt->fival.height= rk29_camdev_info_ptr->icd->user_height;
+ fival_pre->nxt->fival.pixel_format = rk29_camdev_info_ptr->pixfmt;
+
+ fival_pre->nxt->fival.discrete.denominator = rk29_camdev_info_ptr->frame_interval;
+
+ fival_pre->nxt->fival.reserved[1] = (rk29_camdev_info_ptr->icd_width<<16)
+ |(rk29_camdev_info_ptr->icd_height);
+
+ fival_pre->nxt->fival.discrete.numerator = 1000000;
+ fival_pre->nxt->fival.type = V4L2_FRMIVAL_TYPE_DISCRETE;
+ rec_flag = 1;
+ fival_rec = fival_pre->nxt;
+ }
+ }
}
return HRTIMER_NORESTART;
int ret;
WARN_ON(pcdev->icd != icd);
-
+ pcdev->frame_interval = 0;
vip_ctrl_val = read_vip_reg(RK29_VIP_CTRL);
if (enable) {
pcdev->fps = 0;
hrtimer_cancel(&pcdev->fps_timer);
- hrtimer_start(&pcdev->fps_timer,ktime_set(2, 0),HRTIMER_MODE_REL);
+ hrtimer_start(&pcdev->fps_timer,ktime_set(1, 0),HRTIMER_MODE_REL);
vip_ctrl_val |= ENABLE_CAPTURE;
} else {
vip_ctrl_val &= ~ENABLE_CAPTURE;
RK29CAMERA_DG("%s.. enable : 0x%x \n", __FUNCTION__, enable);
return 0;
}
+int rk29_camera_enum_frameintervals(struct soc_camera_device *icd, struct v4l2_frmivalenum *fival)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct rk29_camera_dev *pcdev = ici->priv;
+ struct rk29_camera_frmivalenum *fival_list = NULL;
+ struct v4l2_frmivalenum *fival_head=NULL;
+ int i,ret = 0,index;
+
+ index = fival->index & 0x00ffffff;
+ if ((fival->index & 0xff000000) == 0xff000000) { /* ddl@rock-chips.com: detect framerate */
+ for (i=0; i<2; i++) {
+ if (pcdev->icd_frmival[i].icd == icd) {
+ fival_list = pcdev->icd_frmival[i].fival_list;
+ }
+ }
+
+ if (fival_list != NULL) {
+ i = 0;
+ while (fival_list != NULL) {
+ if ((fival->pixel_format == fival_list->fival.pixel_format)
+ && (fival->height == fival_list->fival.height)
+ && (fival->width == fival_list->fival.width)) {
+ if (i == index)
+ break;
+ i++;
+ }
+ fival_list = fival_list->nxt;
+ }
+
+ if ((i==index) && (fival_list != NULL)) {
+ memcpy(fival, &fival_list->fival, sizeof(struct v4l2_frmivalenum));
+ } else {
+ ret = -EINVAL;
+ }
+ } else {
+ RK29CAMERA_TR("%s: fival_list is NULL\n",__FUNCTION__);
+ ret = -EINVAL;
+ }
+ } else {
+
+ for (i=0; i<RK29_CAM_SUPPORT_NUMS; i++) {
+ if (pcdev->pdata->info[i].dev_name && (strcmp(dev_name(pcdev->icd->pdev),pcdev->pdata->info[i].dev_name) == 0)) {
+ fival_head = pcdev->pdata->info[i].fival;
+ }
+ }
+
+ if (fival_head == NULL) {
+ RK29CAMERA_TR("%s: %s is not registered in rk29_camera_platform_data!!",__FUNCTION__,dev_name(pcdev->icd->pdev));
+ ret = -EINVAL;
+ goto rk29_camera_enum_frameintervals_end;
+ }
+
+ i = 0;
+ while (fival_head->width && fival_head->height) {
+ if ((fival->pixel_format == fival_head->pixel_format)
+ && (fival->height == fival_head->height)
+ && (fival->width == fival_head->width)) {
+ if (i == index) {
+ break;
+ }
+ i++;
+ }
+ fival_head++;
+ }
+
+ if ((i == index) && (fival->height == fival_head->height) && (fival->width == fival_head->width)) {
+ memcpy(fival, fival_head, sizeof(struct v4l2_frmivalenum));
+ RK29CAMERA_DG("%s %dx%d@%c%c%c%c framerate : %d/%d\n", dev_name(rk29_camdev_info_ptr->icd->pdev),
+ fival->width, fival->height,
+ fival->pixel_format & 0xFF, (fival->pixel_format >> 8) & 0xFF,
+ (fival->pixel_format >> 16) & 0xFF, (fival->pixel_format >> 24),
+ fival->discrete.denominator,fival->discrete.numerator);
+ } else {
+ if (index == 0)
+ RK29CAMERA_TR("%s have not catch %dx%d@%c%c%c%c index(%d) framerate\n",dev_name(rk29_camdev_info_ptr->icd->pdev),
+ fival->width,fival->height,
+ fival->pixel_format & 0xFF, (fival->pixel_format >> 8) & 0xFF,
+ (fival->pixel_format >> 16) & 0xFF, (fival->pixel_format >> 24),
+ index);
+ else
+ RK29CAMERA_DG("%s have not catch %dx%d@%c%c%c%c index(%d) framerate\n",dev_name(rk29_camdev_info_ptr->icd->pdev),
+ fival->width,fival->height,
+ fival->pixel_format & 0xFF, (fival->pixel_format >> 8) & 0xFF,
+ (fival->pixel_format >> 16) & 0xFF, (fival->pixel_format >> 24),
+ index);
+ ret = -EINVAL;
+ }
+ }
+rk29_camera_enum_frameintervals_end:
+ return ret;
+}
+
+#ifdef CONFIG_VIDEO_RK29_DIGITALZOOM_IPP_ON
+static int rk29_camera_set_digit_zoom(struct soc_camera_device *icd,
+ const struct v4l2_queryctrl *qctrl, int zoom_rate)
+{
+ struct v4l2_crop a;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct rk29_camera_dev *pcdev = ici->priv;
+
+/* ddl@rock-chips.com : The largest resolution is 2047x1088, so larger resolution must be operated some times
+ (Assume operate times is 4),but resolution which ipp can operate ,it is width and height must be even. */
+ a.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ a.c.width = pcdev->host_width*100/zoom_rate;
+ a.c.width &= ~0x03;
+ a.c.height = pcdev->host_height*100/zoom_rate;
+ a.c.height &= ~0x03;
+
+ a.c.left = ((pcdev->host_width - a.c.width)>>1)&(~0x01);
+ a.c.top = ((pcdev->host_height - a.c.height)>>1)&(~0x01);
+
+ down(&pcdev->zoominfo.sem);
+ pcdev->zoominfo.a.c.height = a.c.height;
+ pcdev->zoominfo.a.c.width = a.c.width;
+ pcdev->zoominfo.a.c.top = a.c.top;
+ pcdev->zoominfo.a.c.left = a.c.left;
+ up(&pcdev->zoominfo.sem);
+
+ RK29CAMERA_DG("%s..zoom_rate:%d (%dx%d at (%d,%d)-> %dx%d)\n",__FUNCTION__, zoom_rate,a.c.width, a.c.height, a.c.left, a.c.top, pcdev->host_width, pcdev->host_height );
+
+ return 0;
+}
+#endif
+static inline struct v4l2_queryctrl const *rk29_camera_soc_camera_find_qctrl(
+ struct soc_camera_host_ops *ops, int id)
+{
+ int i;
+
+ for (i = 0; i < ops->num_controls; i++)
+ if (ops->controls[i].id == id)
+ return &ops->controls[i];
+
+ return NULL;
+}
+
+
+static int rk29_camera_set_ctrl(struct soc_camera_device *icd,
+ struct v4l2_control *sctrl)
+{
+
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ const struct v4l2_queryctrl *qctrl;
+ struct rk29_camera_dev *pcdev = ici->priv;
+ int ret = 0;
+
+ qctrl = rk29_camera_soc_camera_find_qctrl(ici->ops, sctrl->id);
+ if (!qctrl) {
+ ret = -ENOIOCTLCMD;
+ goto rk29_camera_set_ctrl_end;
+ }
+
+ switch (sctrl->id)
+ {
+ #ifdef CONFIG_VIDEO_RK29_DIGITALZOOM_IPP_ON
+ case V4L2_CID_ZOOM_ABSOLUTE:
+ {
+ if ((sctrl->value < qctrl->minimum) || (sctrl->value > qctrl->maximum)){
+ ret = -EINVAL;
+ goto rk29_camera_set_ctrl_end;
+ }
+ ret = rk29_camera_set_digit_zoom(icd, qctrl, sctrl->value);
+ if (ret == 0) {
+ pcdev->zoominfo.zoom_rate = sctrl->value;
+ } else {
+ goto rk29_camera_set_ctrl_end;
+ }
+ break;
+ }
+ #endif
+ default:
+ ret = -ENOIOCTLCMD;
+ break;
+ }
+rk29_camera_set_ctrl_end:
+ return ret;
+}
static struct soc_camera_host_ops rk29_soc_camera_host_ops =
{
.remove = rk29_camera_remove_device,
.suspend = rk29_camera_suspend,
.resume = rk29_camera_resume,
+ .enum_frameinervals = rk29_camera_enum_frameintervals,
.set_crop = rk29_camera_set_crop,
- .get_formats = rk29_camera_get_formats,
+ .get_formats = rk29_camera_get_formats,
.put_formats = rk29_camera_put_formats,
.set_fmt = rk29_camera_set_fmt,
.try_fmt = rk29_camera_try_fmt,
.poll = rk29_camera_poll,
.querycap = rk29_camera_querycap,
.set_bus_param = rk29_camera_set_bus_param,
- .s_stream = rk29_camera_s_stream /* ddl@rock-chips.com : Add stream control for host */
+ .s_stream = rk29_camera_s_stream, /* ddl@rock-chips.com : Add stream control for host */
+ .set_ctrl = rk29_camera_set_ctrl,
+ .controls = rk29_camera_controls,
+ .num_controls = ARRAY_SIZE(rk29_camera_controls)
+
};
static int rk29_camera_probe(struct platform_device *pdev)
{
struct rk29_camera_dev *pcdev;
struct resource *res;
- int irq;
+ struct rk29_camera_frmivalenum *fival_list,*fival_nxt;
+ int irq,i;
int err = 0;
- RK29CAMERA_DG("%s..%s..%d \n",__FUNCTION__,__FILE__,__LINE__);
+ RK29CAMERA_TR("RK29 Camera driver version: v%d.%d.%d Zoom by %s\n",(RK29_CAM_VERSION_CODE&0xff0000)>>16,
+ (RK29_CAM_VERSION_CODE&0xff00)>>8,RK29_CAM_VERSION_CODE&0xff,CAMERA_SCALE_CROP_MACHINE);
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(pdev, 0);
if (!res || irq < 0) {
pcdev->hclk_cpu_display = clk_get(&pdev->dev, "hclk_cpu_display");
pcdev->vip_slave = clk_get(&pdev->dev, "vip_slave");
- pcdev->vip = clk_get(&pdev->dev,"vip");
+ pcdev->vip_out = clk_get(&pdev->dev,"vip_out");
pcdev->vip_input = clk_get(&pdev->dev,"vip_input");
pcdev->vip_bus = clk_get(&pdev->dev, "vip_bus");
pcdev->hclk_disp_matrix = clk_get(&pdev->dev,"hclk_disp_matrix");
pcdev->vip_matrix = clk_get(&pdev->dev,"vip_matrix");
+ pcdev->pd_display = clk_get(&pdev->dev,"pd_display");
+
+ pcdev->zoominfo.zoom_rate = 100;
+
if (!pcdev->aclk_ddr_lcdc || !pcdev->aclk_disp_matrix || !pcdev->hclk_cpu_display ||
- !pcdev->vip_slave || !pcdev->vip || !pcdev->vip_input || !pcdev->vip_bus ||
- IS_ERR(pcdev->aclk_ddr_lcdc) || IS_ERR(pcdev->aclk_disp_matrix) || IS_ERR(pcdev->hclk_cpu_display) ||
- IS_ERR(pcdev->vip_slave) || IS_ERR(pcdev->vip) || IS_ERR(pcdev->vip_input) || IS_ERR(pcdev->vip_bus)) {
+ !pcdev->vip_slave || !pcdev->vip_out || !pcdev->vip_input || !pcdev->vip_bus || !pcdev->pd_display ||
+ IS_ERR(pcdev->aclk_ddr_lcdc) || IS_ERR(pcdev->aclk_disp_matrix) || IS_ERR(pcdev->hclk_cpu_display) || IS_ERR(pcdev->pd_display) ||
+ IS_ERR(pcdev->vip_slave) || IS_ERR(pcdev->vip_out) || IS_ERR(pcdev->vip_input) || IS_ERR(pcdev->vip_bus)) {
RK29CAMERA_TR(KERN_ERR "failed to get vip_clk(axi) source\n");
err = -ENOENT;
if (pcdev->pdata && (strcmp(pcdev->pdata->meminfo.name,"camera_ipp_mem")==0)) {
pcdev->vipmem_phybase = pcdev->pdata->meminfo.start;
pcdev->vipmem_size = pcdev->pdata->meminfo.size;
+
+ if (!request_mem_region(pcdev->vipmem_phybase,pcdev->vipmem_size,"rk29_vipmem")) {
+ err = -EBUSY;
+ goto exit_ioremap_vipmem;
+ }
+ pcdev->vipmem_virbase = ioremap_cached(pcdev->vipmem_phybase,pcdev->vipmem_size);
+ if (pcdev->vipmem_virbase == NULL) {
+ dev_err(pcdev->dev, "ioremap() of vip internal memory(Ex:IPP process/raw process) failed\n");
+ err = -ENXIO;
+ goto exit_ioremap_vipmem;
+ }
+
RK29CAMERA_DG("\n%s Memory(start:0x%x size:0x%x) for IPP obtain \n",__FUNCTION__, pcdev->pdata->meminfo.start,pcdev->pdata->meminfo.size);
} else {
RK29CAMERA_TR("\n%s Memory for IPP have not obtain! IPP Function is fail\n",__FUNCTION__);
pcdev->vipmem_phybase = 0;
pcdev->vipmem_size = 0;
+ pcdev->vipmem_virbase = 0;
}
#endif
INIT_LIST_HEAD(&pcdev->capture);
+ INIT_LIST_HEAD(&pcdev->camera_work_queue);
spin_lock_init(&pcdev->lock);
+ spin_lock_init(&pcdev->camera_work_lock);
+ sema_init(&pcdev->zoominfo.sem,1);
/*
* Request the regions.
goto exit_reqirq;
}
- pcdev->camera_wq = create_workqueue("camera wq");
+ pcdev->camera_wq = create_workqueue("rk_camera_workqueue");
if (pcdev->camera_wq == NULL)
goto exit_free_irq;
INIT_WORK(&pcdev->camera_reinit_work, rk29_camera_reinit_work);
+ for (i=0; i<2; i++) {
+ pcdev->icd_frmival[i].icd = NULL;
+ pcdev->icd_frmival[i].fival_list = kzalloc(sizeof(struct rk29_camera_frmivalenum),GFP_KERNEL);
+
+ }
+
pcdev->soc_host.drv_name = RK29_CAM_DRV_NAME;
pcdev->soc_host.ops = &rk29_soc_camera_host_ops;
pcdev->soc_host.priv = pcdev;
hrtimer_init(&pcdev->fps_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
pcdev->fps_timer.function = rk29_camera_fps_func;
+ pcdev->icd_cb.sensor_cb = NULL;
+#if (CONFIG_CAMERA_SCALE_CROP_MACHINE == RK_CAM_SCALE_CROP_IPP)
+ pcdev->icd_cb.scale_crop_cb = rk29_camera_scale_crop_ipp;
+#elif (CONFIG_CAMERA_SCALE_CROP_MACHINE == RK_CAM_SCALE_CROP_ARM)
+ pcdev->icd_cb.scale_crop_cb = rk29_camera_scale_crop_arm;
+#endif
RK29CAMERA_DG("%s..%s..%d \n",__FUNCTION__,__FILE__,__LINE__);
return 0;
exit_free_irq:
+
+ for (i=0; i<2; i++) {
+ fival_list = pcdev->icd_frmival[i].fival_list;
+ fival_nxt = fival_list;
+ while(fival_nxt != NULL) {
+ fival_nxt = fival_list->nxt;
+ kfree(fival_list);
+ fival_list = fival_nxt;
+ }
+ }
+
free_irq(pcdev->irq, pcdev);
if (pcdev->camera_wq) {
destroy_workqueue(pcdev->camera_wq);
iounmap(pcdev->base);
exit_ioremap:
release_mem_region(res->start, res->end - res->start + 1);
+exit_ioremap_vipmem:
+ if (pcdev->vipmem_virbase)
+ iounmap(pcdev->vipmem_virbase);
+ release_mem_region(pcdev->vipmem_phybase,pcdev->vipmem_size);
exit_reqmem:
if (pcdev->aclk_ddr_lcdc) {
clk_put(pcdev->aclk_ddr_lcdc);
clk_put(pcdev->vip_slave);
pcdev->vip_slave = NULL;
}
- if (pcdev->vip) {
- clk_put(pcdev->vip);
- pcdev->vip = NULL;
+ if (pcdev->vip_out) {
+ clk_put(pcdev->vip_out);
+ pcdev->vip_out = NULL;
}
if (pcdev->vip_input) {
clk_put(pcdev->vip_input);
{
struct rk29_camera_dev *pcdev = platform_get_drvdata(pdev);
struct resource *res;
-
+ struct rk29_camera_frmivalenum *fival_list,*fival_nxt;
+ int i;
+
free_irq(pcdev->irq, pcdev);
if (pcdev->camera_wq) {
pcdev->camera_wq = NULL;
}
+ for (i=0; i<2; i++) {
+ fival_list = pcdev->icd_frmival[i].fival_list;
+ fival_nxt = fival_list;
+ while(fival_nxt != NULL) {
+ fival_nxt = fival_list->nxt;
+ kfree(fival_list);
+ fival_list = fival_nxt;
+ }
+ }
+
soc_camera_host_unregister(&pcdev->soc_host);
+ iounmap((void __iomem*)pcdev->vipmem_phybase);
+ release_mem_region(pcdev->vipmem_phybase, pcdev->vipmem_size);
+
res = pcdev->res;
release_mem_region(res->start, res->end - res->start + 1);
MODULE_DESCRIPTION("RK29 Soc Camera Host driver");
MODULE_AUTHOR("ddl <ddl@rock-chips>");
MODULE_LICENSE("GPL");
+#endif