本次说一下mipi camera的驱动开发,平台用的是全志的H3芯片,项目代号:sun8iw7p1,这次使用运行在H3上面的Ubuntu进行验证的.

Linux代码:https://github.com/orangepi-xunlong/orangepi_h3_linux

Ubuntu镜像:https://pan.baidu.com/s/1kUF3Dx9

MIPI: MIPI联盟由ARM、诺基亚、意法半导体和德州仪器发起成立,作为移动行业领导者的合作组织,MIPI目的是把手机内部的接口如摄像头、显示屏接口、射频/基带接口等标准化,从而减少手机设计的复杂程度和增加设计灵活性。MIPI联盟下面有不同的WorkGroup ,分别定义了一系列的手机内部接口标准,比如摄像头接口CSI、显示接口DSI、射频接口DigRF、麦克风/喇叭接口SLIMbus等。统一接口标准的好处是手机厂商根据需要可以从市面上灵活选择不同的芯片和模组,更改设计和功能时更加快捷方便。

CSI: CMOS Sensor Interface,串行相机接口,CSI接口通常从CMOS Sensor、Video Encoder和其它视频输出设备收集数据。

CSI-1
相机最初的标准MIPI接口。它作为一种架构来定义相机和主处理器之间的接口。其继任者是MIPI CSI-2和MIPI CSI-3,两个标准仍在不断发展。
CSI-2
规范于2005年发布。它使用D-PHY或C-PHY(这两个标准均由MIPI联盟设定)作为物理层选项。该协议分为以下几个层次:
物理层(C-PHY / D-PHY)
车道合并层
低层协议层
像素到字节转换层
应用程序层
CSI-3
高速双向协议,主要用于多层对等基于UniPro的M-PHY设备网络中摄像机和主机之间的图像和视频传输。它最初于2012年发布,并于2014年在1.1版本中重新发布。

本次使用的是上海格科微的GC2035的camera,2M pixel(1616V x 1232H),框架如下:

分为两部分一部分是CSI控制器,一部分是CCI控制器,其中CCI控制器,我们这里使用其I2C部分,其它用的都是CSI部分.

我们先来了解一下camera的一些基础知识(参考:https://blog.csdn.net/radianceblau/article/details/76460907):

曝光三要素

光圈大小: 光圈就是指曝光瞬间开孔多大;
快门速度: 快门速度就是指快门开启的时间;
感光度(ISO): 感光度是指图像传感器对光线的敏感程度。

1.光圈

光圈是一个用来控制光线透过镜头,进入机身内感光面光量的装置,它通常是在镜头内。表达光圈大小我们是用f值。对于已经制造好的镜头,我们不可能随意改变镜头的直径,但是我们可以通过在镜头内部加入多边形或者圆形,并且面积可变的孔状光栅来达到控制镜头通光量,这个装置就叫做光圈。
光圈F值 = 镜头的焦距 / 镜头光圈的直径
完整的光圈值系列如下:

1/1.0,1/1.4,1/2.0,1/2.8,1/4.0,1/5.6,1/8.0,1/11,1/16,1/22,1/32,1/44,1/64

光圈的档位设计是相邻的两档的数值相差1.4倍(2的平方根1.414的近似值)相邻的两档之间,透光孔直径相差根号2倍,透光孔的面积相差一倍,底片上形成的影像的亮度相差一倍,维持相同曝光量所需要的时间相差一倍。

当光圈开得越大;背景虚化效果越明显,小光圈背景虚化效果则越不明显。在拍摄时,背景越虚化,主体突出就越明显,相对于一些人像、静物运用比较多。如果你需要烘托环境,不希望背景虚化到什么都看不清,那么采用小光圈,大景深就更适合了。

2、快门速度:

用时间表示。30s,15s,8s,4s,2s,1s,1/2  1/4  1/8   1/15   1/30  1/60    1/125    1/250   1/500   1/1000    1/2000.......
同样相邻的快门速度相差一档曝光量。很明显,数值上相差一倍。

简单的说就是:当你改变快门速度的同时也意味着改变了运动物体成像的方式(是否叠加)。快门速度越慢,运动物体越模糊;速度越快,运动物体越清晰。

3、ISO感光度:

国标表示ISO100   200    400   800  1600   3200   6400....
同样相邻的ISO相差一档曝光量。很明显,数值上成2的级数。
ISO越大噪点越明显,画质越差;但ISO提高可以使用小光圈或提高快门速度,有利于摄影师意图的实现。

摄像头构成

1,镜头:           就是凸透镜用来成像
2,对焦马达:    用来调整焦距
3,红外滤光片: 用来滤除红外光,调整光线摄入角度为直角,来达到更好的成像效果。
4,影像传感器: 核心器件,用来将光学图像转化为数字化的图片raw data。

图像传感器

图像传感器是将光信号转换为电信号的装置.

自动聚焦

自动聚焦目的是获得清晰度更高得图像。常用的聚焦方法分两类,传统的聚焦方法和基于数字图像处理方式的图像聚焦方法。传统的方式中,自动聚焦通过红外线或者超生波测距的方式来实现。数字处理方法中,自动聚焦的关键在于构造图像的清晰度评价函数。己经提出的图像清晰度评价函数苞括灰度方差、梯度能量、嫡函数和一些频域函数法。图像清晰度评价函数必须具有良好的单峰性和尖锐性,而且要计算量适度,从而可以快速的实现精准对焦。

白平衡

白平衡:字面上的理解是白色的平衡。用色彩学的知识解释,白色是指反射到人眼中的光线由于蓝、绿、红三种色光比例相同且具有一定的亮度所形成的视觉反应。摄像头并不能像人眼那样具有适应性,所以如果摄像机的色彩调整同景物照明的色温不一致就会发生偏色。白平衡就是针对不同色温条件下,通过调摄像头内部的色彩电路使拍摄出来的影像抵消偏色,更接近人眼的视觉习惯。白平衡也可以简单地理解为在任意色温条件下,摄像头所拍摄的标准白色经过电路的调整,使之成像后仍然为白色。

自动白平衡

白平衡电路自动调节红、绿、蓝增益,使得白色物体无论在任何光源下都呈白色。
手动模式:红、绿、蓝增益由手动控制。
自动模式:红、绿、蓝增益由自动白平衡电路控制。

电子快门

摄像机基本都是电子快门,概念和传统照相机中快门的概念有些出入,但基本原理都是一样的,摄像机是一秒有多少个画面,相机中的快门也是类似的.

我们来看一下板子的电路图:

结合电路图,我们看一下全志的dataset(CSI和CCI两部分):

上图是CSI的框架图,下图是CCI的框架图:

CCI这里就不说了,I2C,大家的基础,这里说说CSI,我们来看一下CSI的时序图:

从上图的figure 6-3我们可以知道,全志平台的CSI控制器支持8/10/12 bit的Sensor,我们这里是使用的8 bit,因为摄像头模组gc2035是8 bit的,下面看一下CSI寄存器的列表,具体配置列表这里就不列出来了,只列一个列表:

驱动代码我们用的是全志官方提供的linux-3.4.113,主要涉及到v4l2和具体Sensor的相关数据及提供给v4l2使用的API的实现.这部分代码在:linux-3.4.113/drivers/media/video/sunxi-vfe,这里代码编译后会生成一些.ko的文件,其中vfe_v4l2.ko和gc2035.ko就是我们要用的,vfe_v4l2.ko是v4l2的相关代码,gc2035.ko是具体Sensor的实现代码,下面我们通过Makefile文件来看这两个.ko文件的组成:

obj-$(CONFIG_CSI_VFE) += vfe_os.o
obj-$(CONFIG_CSI_VFE) += vfe_subdev.o
obj-$(CONFIG_CSI_VFE) += device/
obj-$(CONFIG_CSI_VFE) += actuator/
obj-$(CONFIG_CSI_VFE) += csi_cci/
#obj-$(CONFIG_CSI_VFE) += flash_light/
#obj-$(CONFIG_CSI_VFE) += camera_detector/obj-$(CONFIG_CSI_VFE) += vfe_v4l2.o
vfe_v4l2-y                  := csi/csi_reg.o
vfe_v4l2-y                  += csi/bsp_csi.o
vfe_v4l2-y                  += bsp_common.o
vfe_v4l2-y                  += config.o
vfe_v4l2-y                  += utility/sensor_info.o
vfe_v4l2-y                  += utility/cfg_op.o
vfe_v4l2-y                  += vfe.o
vfe_v4l2-y                  += lib/libispifneq ($(strip $(CONFIG_ARCH_SUN9I)),)
vfe_v4l2-y                  += lib/lib_mipicsi2_v2
else ifneq ($(strip $(CONFIG_ARCH_SUN8IW6)),)
obj-$(CONFIG_CSI_VFE) += vfe_v4l2.o
vfe_v4l2-y                  += mipi_csi/bsp_mipi_csi.o
else ifneq ($(strip $(CONFIG_ARCH_SUN8IW8)),)
obj-$(CONFIG_CSI_VFE) += vfe_v4l2.o
vfe_v4l2-y                  += mipi_csi/bsp_mipi_csi_v1.o \mipi_csi/protocol/protocol_reg.o \mipi_csi/dphy/dphy_reg.o
else
obj-$(CONFIG_CSI_VFE) += vfe_v4l2.o
vfe_v4l2-y                  += lib/lib_mipicsi2_v1
endif

可以看到vfe_v4l2.ko的组成文件是很多的,上面的这些个文件会编译到一起组成它,可见还是比较复杂的,其中vfe.c这个文件是入口. gc2035.ko这个文件则只有gc2035.c组成,这部分是需要我们去实现,不过格科微已经提供了,主要是实现camera寄存器的初始化,然后实现v4l2需要使用的一些API.

我们再看一下v4l2的框架:

在Android上,要稍微再复杂一点,所以这里用Linux + Ubuntu core来测试,不过这里贴一个Android上的架构,毕竟这个是目前比较流行的方式,架构如下:

下面把vfe.c的内容贴出来:

/** sunxi Camera Interface  driver* Author: raymonxiu*/
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/version.h>
#include <linux/mutex.h>
#include <linux/videodev2.h>
#include <linux/delay.h>
#include <linux/string.h>#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
#include <linux/freezer.h>
#endif#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/moduleparam.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-common.h>
#include <media/v4l2-mediabus.h>
#include <media/v4l2-subdev.h>
#include <media/videobuf-dma-contig.h>#include <linux/regulator/consumer.h>
#include <linux/ion_sunxi.h>#include "vfe.h"#include "bsp_common.h"
#include "lib/bsp_isp_algo.h"
#include "csi_cci/bsp_cci.h"
#include "csi_cci/cci_helper.h"
#include "config.h"
#include "device/camera_cfg.h"
#include "platform/vfe_resource.h"
#include "utility/sensor_info.h"
#include "utility/vfe_io.h"
#define IS_FLAG(x, y) (((x) & (y)) == y)
#define CLIP_MAX(x, max) ((x) > max ? max : x)#define VFE_MAJOR_VERSION 1
#define VFE_MINOR_VERSION 0
#define VFE_RELEASE 0
#define VFE_VERSION \KERNEL_VERSION(VFE_MAJOR_VERSION, VFE_MINOR_VERSION, VFE_RELEASE)
#define VFE_MODULE_NAME "sunxi_vfe"
//#define REG_DBG_EN#define MCLK_OUT_RATE (24 * 1000 * 1000)
#define MAX_FRAME_MEM (150 * 1024 * 1024)
#define MIN_WIDTH (32)
#define MIN_HEIGHT (32)
#define MAX_WIDTH (4800)
#define MAX_HEIGHT (4800)
#define DUMP_CSI (1 << 0)
#define DUMP_ISP (1 << 1)#define FLASH_EN_POL 1
#define FLASH_MODE_POL 1#define _FLASH_FUNC_
//#define _REGULATOR_CHANGE_static struct flash_dev_info fl_info;static char ccm[I2C_NAME_SIZE] = "";
static uint i2c_addr = 0xff;static char act_name[I2C_NAME_SIZE] = "";
static uint act_slave = 0xff;
static uint define_sensor_list = 0xff;
static uint vfe_i2c_dbg = 0;
static uint vips = 0xffff;static int touch_flash_flag = 0;
static int ev_cumul = 0;
static unsigned int isp_va_flag = 0;
static unsigned int isp_va_alloc_sel = 0;
static struct vfe_mm isp_load_mm;
static struct vfe_mm isp_saved_mm;static unsigned int vfe_opened_num = 0;
unsigned int isp_reparse_flag = 0;static unsigned int frame_cnt = 0;
static unsigned int vfe_dump = 0;
struct mutex probe_hdl_lock;module_param_string(ccm, ccm, sizeof(ccm), S_IRUGO | S_IWUSR);
module_param(i2c_addr, uint, S_IRUGO | S_IWUSR);module_param_string(act_name, act_name, sizeof(act_name), S_IRUGO | S_IWUSR);
module_param(act_slave, uint, S_IRUGO | S_IWUSR);
module_param(define_sensor_list, uint, S_IRUGO | S_IWUSR);
module_param(vfe_i2c_dbg, uint, S_IRUGO | S_IWUSR);
module_param(vips, uint, S_IRUGO | S_IWUSR);
static ssize_t vfe_dbg_en_show(struct device *dev,struct device_attribute *attr, char *buf)
{return sprintf(buf, "%d\n", vfe_dbg_en);
}static ssize_t vfe_dbg_en_store(struct device *dev,struct device_attribute *attr,const char *buf, size_t count)
{int err;unsigned long val;err = strict_strtoul(buf, 10, &val);if (err){vfe_print("Invalid size\n");return err;}if (val < 0 || val > 1){vfe_print("Invalid value, 0~1 is expected!\n");}else{vfe_dbg_en = val;vfe_print("vfe_dbg_en = %ld\n", val);}return count;
}static ssize_t vfe_dbg_lv_show(struct device *dev,struct device_attribute *attr, char *buf)
{return sprintf(buf, "%d\n", vfe_dbg_lv);
}static ssize_t vfe_dbg_lv_store(struct device *dev,struct device_attribute *attr,const char *buf, size_t count)
{int err;unsigned long val;err = strict_strtoul(buf, 10, &val);if (err){vfe_print("Invalid size\n");return err;}if (val < 0 || val > 4){vfe_print("Invalid value, 0~3 is expected!\n");}else{vfe_dbg_lv = val;vfe_print("vfe_dbg_lv = %d\n", vfe_dbg_lv);}return count;
}static ssize_t isp_reparse_flag_show(struct device *dev,struct device_attribute *attr, char *buf)
{return sprintf(buf, "%d\n", isp_reparse_flag);
}static ssize_t isp_reparse_flag_store(struct device *dev,struct device_attribute *attr,const char *buf, size_t count)
{int err;unsigned long val;err = strict_strtoul(buf, 10, &val);if (err){vfe_print("Invalid size\n");return err;}if (val < 0 || val > 4){vfe_print("Invalid value, 0~1 is expected!\n");}else{isp_reparse_flag = val;vfe_print("isp_reparse_flag = %ld\n", val);}return count;
}
static ssize_t vfe_dbg_dump_show(struct device *dev,struct device_attribute *attr, char *buf)
{return sprintf(buf, "%d\n", vfe_dump);
}static ssize_t vfe_dbg_dump_store(struct device *dev,struct device_attribute *attr,const char *buf, size_t count)
{int err;unsigned long val;err = strict_strtoul(buf, 10, &val);if (err){vfe_print("Invalid size\n");return err;}if (val < 0 || val > 3){vfe_print("Invalid value, 0~3 is expected!\n");}else{vfe_dump = val;vfe_print("vfe_dump = %ld\n", val);}return count;
}static DEVICE_ATTR(vfe_dbg_en, S_IRUGO | S_IWUSR | S_IWGRP,vfe_dbg_en_show, vfe_dbg_en_store);static DEVICE_ATTR(vfe_dbg_lv, S_IRUGO | S_IWUSR | S_IWGRP,vfe_dbg_lv_show, vfe_dbg_lv_store);
static DEVICE_ATTR(vfe_dump, S_IRUGO | S_IWUSR | S_IWGRP,vfe_dbg_dump_show, vfe_dbg_dump_store);
static DEVICE_ATTR(isp_reparse_flag, S_IRUGO | S_IWUSR | S_IWGRP,isp_reparse_flag_show, isp_reparse_flag_store);static struct attribute *vfe_attributes[] = {&dev_attr_vfe_dbg_en.attr,&dev_attr_vfe_dbg_lv.attr,&dev_attr_vfe_dump.attr,&dev_attr_isp_reparse_flag.attr,NULL};static struct attribute_group vfe_attribute_group = {.name = "vfe_attr",.attrs = vfe_attributes};static struct vfe_fmt formats[] = {{.name = "planar YUV 422",.fourcc = V4L2_PIX_FMT_YUV422P,.depth = 16,.planes_cnt = 3,},{.name = "planar YUV 420",.fourcc = V4L2_PIX_FMT_YUV420,.depth = 12,.planes_cnt = 3,},{.name = "planar YVU 420",.fourcc = V4L2_PIX_FMT_YVU420,.depth = 12,.planes_cnt = 3,},{.name = "planar YUV 422 UV combined",.fourcc = V4L2_PIX_FMT_NV16,.depth = 16,.planes_cnt = 2,},{.name = "planar YUV 420 UV combined",.fourcc = V4L2_PIX_FMT_NV12,.depth = 12,.planes_cnt = 2,},{.name = "planar YUV 422 VU combined",.fourcc = V4L2_PIX_FMT_NV61,.depth = 16,.planes_cnt = 2,},{.name = "planar YUV 420 VU combined",.fourcc = V4L2_PIX_FMT_NV21,.depth = 12,.planes_cnt = 2,},{.name = "MB YUV420",.fourcc = V4L2_PIX_FMT_HM12,.depth = 12,.planes_cnt = 2,},{.name = "YUV422 YUYV",.fourcc = V4L2_PIX_FMT_YUYV,.depth = 16,.planes_cnt = 1,},{.name = "YUV422 YVYU",.fourcc = V4L2_PIX_FMT_YVYU,.depth = 16,.planes_cnt = 1,},{.name = "YUV422 UYVY",.fourcc = V4L2_PIX_FMT_UYVY,.depth = 16,.planes_cnt = 1,},{.name = "YUV422 VYUY",.fourcc = V4L2_PIX_FMT_VYUY,.depth = 16,.planes_cnt = 1,},{.name = "RAW Bayer BGGR 8bit",.fourcc = V4L2_PIX_FMT_SBGGR8,.depth = 8,.planes_cnt = 1,},{.name = "RAW Bayer GBRG 8bit",.fourcc = V4L2_PIX_FMT_SGBRG8,.depth = 8,.planes_cnt = 1,},{.name = "RAW Bayer GRBG 8bit",.fourcc = V4L2_PIX_FMT_SGRBG8,.depth = 8,.planes_cnt = 1,},{.name = "RAW Bayer RGGB 8bit",.fourcc = V4L2_PIX_FMT_SGRBG8,.depth = 8,.planes_cnt = 1,},{.name = "RAW Bayer BGGR 10bit",.fourcc = V4L2_PIX_FMT_SBGGR10,.depth = 8,.planes_cnt = 1,},{.name = "RAW Bayer GBRG 10bit",.fourcc = V4L2_PIX_FMT_SGBRG10,.depth = 8,.planes_cnt = 1,},{.name = "RAW Bayer GRBG 10bit",.fourcc = V4L2_PIX_FMT_SGRBG10,.depth = 8,.planes_cnt = 1,},{.name = "RAW Bayer RGGB 10bit",.fourcc = V4L2_PIX_FMT_SGRBG10,.depth = 8,.planes_cnt = 1,},{.name = "RAW Bayer BGGR 12bit",.fourcc = V4L2_PIX_FMT_SBGGR12,.depth = 8,.planes_cnt = 1,},{.name = "RAW Bayer GBRG 12bit",.fourcc = V4L2_PIX_FMT_SGBRG12,.depth = 8,.planes_cnt = 1,},{.name = "RAW Bayer GRBG 12bit",.fourcc = V4L2_PIX_FMT_SGRBG12,.depth = 8,.planes_cnt = 1,},{.name = "RAW Bayer RGGB 12bit",.fourcc = V4L2_PIX_FMT_SGRBG12,.depth = 8,.planes_cnt = 1,},
};static enum v4l2_mbus_pixelcode try_yuv422_bus[] = {V4L2_MBUS_FMT_UYVY10_20X1,V4L2_MBUS_FMT_UYVY8_16X1,V4L2_MBUS_FMT_YUYV10_2X10,V4L2_MBUS_FMT_YVYU10_2X10,V4L2_MBUS_FMT_UYVY8_2X8,V4L2_MBUS_FMT_VYUY8_2X8,V4L2_MBUS_FMT_YUYV8_2X8,V4L2_MBUS_FMT_YVYU8_2X8,V4L2_MBUS_FMT_YUYV10_1X20,V4L2_MBUS_FMT_YVYU10_1X20,V4L2_MBUS_FMT_UYVY8_1X16,V4L2_MBUS_FMT_VYUY8_1X16,V4L2_MBUS_FMT_YUYV8_1X16,V4L2_MBUS_FMT_YVYU8_1X16,V4L2_MBUS_FMT_YUV8_1X24,
};#define N_TRY_YUV422 ARRAY_SIZE(try_yuv422_bus)static enum v4l2_mbus_pixelcode try_yuv420_bus[] = {V4L2_MBUS_FMT_YY10_UYVY10_15X1,V4L2_MBUS_FMT_YY8_UYVY8_12X1,
};#define N_TRY_YUV420 ARRAY_SIZE(try_yuv420_bus)static enum v4l2_mbus_pixelcode try_bayer_rgb_bus[] = {V4L2_MBUS_FMT_SBGGR12_12X1,V4L2_MBUS_FMT_SGBRG12_12X1,V4L2_MBUS_FMT_SGRBG12_12X1,V4L2_MBUS_FMT_SRGGB12_12X1,V4L2_MBUS_FMT_SBGGR12_1X12,V4L2_MBUS_FMT_SGBRG12_1X12,V4L2_MBUS_FMT_SGRBG12_1X12,V4L2_MBUS_FMT_SRGGB12_1X12,V4L2_MBUS_FMT_SBGGR10_10X1,V4L2_MBUS_FMT_SGBRG10_10X1,V4L2_MBUS_FMT_SGRBG10_10X1,V4L2_MBUS_FMT_SRGGB10_10X1,V4L2_MBUS_FMT_SBGGR10_1X10,V4L2_MBUS_FMT_SGBRG10_1X10,V4L2_MBUS_FMT_SGRBG10_1X10,V4L2_MBUS_FMT_SRGGB10_1X10,V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8,V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8,V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8,V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8,V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE,V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE,V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE,V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE,V4L2_MBUS_FMT_SBGGR8_8X1,V4L2_MBUS_FMT_SGBRG8_8X1,V4L2_MBUS_FMT_SGRBG8_8X1,V4L2_MBUS_FMT_SRGGB8_8X1,V4L2_MBUS_FMT_SBGGR8_1X8,V4L2_MBUS_FMT_SGBRG8_1X8,V4L2_MBUS_FMT_SGRBG8_1X8,V4L2_MBUS_FMT_SRGGB8_1X8,
};#define N_TRY_BAYER ARRAY_SIZE(try_bayer_rgb_bus)static enum v4l2_mbus_pixelcode try_rgb565_bus[] = {V4L2_MBUS_FMT_RGB565_16X1,V4L2_MBUS_FMT_BGR565_2X8_BE,V4L2_MBUS_FMT_BGR565_2X8_LE,V4L2_MBUS_FMT_RGB565_2X8_BE,V4L2_MBUS_FMT_RGB565_2X8_LE,
};#define N_TRY_RGB565 ARRAY_SIZE(try_rgb565_bus)static enum v4l2_mbus_pixelcode try_rgb888_bus[] = {V4L2_MBUS_FMT_RGB888_24X1,
};#define N_TRY_RGB888 ARRAY_SIZE(try_rgb888_bus)
/*
static int V4L2_AF_STATUS_TBL[] =
{V4L2_AUTO_FOCUS_STATUS_IDLE,  //AUTO_FOCUS_STATUS_IDLEV4L2_AUTO_FOCUS_STATUS_BUSY,  //AUTO_FOCUS_STATUS_BUSYV4L2_AUTO_FOCUS_STATUS_REACHED,  //AUTO_FOCUS_STATUS_REACHEDV4L2_AUTO_FOCUS_STATUS_REACHED,  //AUTO_FOCUS_STATUS_APPROCHV4L2_AUTO_FOCUS_STATUS_BUSY,  //AUTO_FOCUS_STATUS_REFOCUSV4L2_AUTO_FOCUS_STATUS_REACHED,  //AUTO_FOCUS_STATUS_FINDEDV4L2_AUTO_FOCUS_STATUS_FAILED,  //AUTO_FOCUS_STATUS_FAILED
};
*/
static int isp_resource_request(struct vfe_dev *dev)
{unsigned int isp_used_flag = 0, i;void *pa_base, *va_base, *dma_base;int ret;//requeset for isp table and statistic bufferfor (i = 0; i < dev->dev_qty; i++){if (dev->ccm_cfg[i]->is_isp_used && dev->ccm_cfg[i]->is_bayer_raw){dev->isp_lut_tbl_buf_mm[i].size = ISP_LINEAR_LUT_LENS_GAMMA_MEM_SIZE;ret = os_mem_alloc(&dev->isp_lut_tbl_buf_mm[i]);if (!ret){pa_base = dev->isp_lut_tbl_buf_mm[i].phy_addr;va_base = dev->isp_lut_tbl_buf_mm[i].vir_addr;dma_base = dev->isp_lut_tbl_buf_mm[i].dma_addr;dev->isp_tbl_addr[i].isp_def_lut_tbl_paddr = (void *)(pa_base + ISP_LUT_MEM_OFS);dev->isp_tbl_addr[i].isp_def_lut_tbl_dma_addr = (void *)(dma_base + ISP_LUT_MEM_OFS);dev->isp_tbl_addr[i].isp_def_lut_tbl_vaddr = (void *)(va_base + ISP_LUT_MEM_OFS);dev->isp_tbl_addr[i].isp_lsc_tbl_paddr = (void *)(pa_base + ISP_LENS_MEM_OFS);dev->isp_tbl_addr[i].isp_lsc_tbl_dma_addr = (void *)(dma_base + ISP_LENS_MEM_OFS);dev->isp_tbl_addr[i].isp_lsc_tbl_vaddr = (void *)(va_base + ISP_LENS_MEM_OFS);dev->isp_tbl_addr[i].isp_gamma_tbl_paddr = (void *)(pa_base + ISP_GAMMA_MEM_OFS);dev->isp_tbl_addr[i].isp_gamma_tbl_dma_addr = (void *)(dma_base + ISP_GAMMA_MEM_OFS);dev->isp_tbl_addr[i].isp_gamma_tbl_vaddr = (void *)(va_base + ISP_GAMMA_MEM_OFS);dev->isp_tbl_addr[i].isp_linear_tbl_paddr = (void *)(pa_base + ISP_LINEAR_MEM_OFS);dev->isp_tbl_addr[i].isp_linear_tbl_dma_addr = (void *)(dma_base + ISP_LINEAR_MEM_OFS);dev->isp_tbl_addr[i].isp_linear_tbl_vaddr = (void *)(va_base + ISP_LINEAR_MEM_OFS);vfe_dbg(0, "isp_def_lut_tbl_vaddr[%d] = %p\n", i, dev->isp_tbl_addr[i].isp_def_lut_tbl_vaddr);vfe_dbg(0, "isp_lsc_tbl_vaddr[%d] = %p\n", i, dev->isp_tbl_addr[i].isp_lsc_tbl_vaddr);vfe_dbg(0, "isp_gamma_tbl_vaddr[%d] = %p\n", i, dev->isp_tbl_addr[i].isp_gamma_tbl_vaddr);}else{vfe_err("isp lut_lens_gamma table request pa failed!\n");return -ENOMEM;}}if (dev->ccm_cfg[i]->is_isp_used && dev->ccm_cfg[i]->is_bayer_raw){dev->isp_drc_tbl_buf_mm[i].size = ISP_DRC_DISC_MEM_SIZE;ret = os_mem_alloc(&dev->isp_drc_tbl_buf_mm[i]);if (!ret){pa_base = dev->isp_drc_tbl_buf_mm[i].phy_addr;va_base = dev->isp_drc_tbl_buf_mm[i].vir_addr;dma_base = dev->isp_drc_tbl_buf_mm[i].dma_addr;dev->isp_tbl_addr[i].isp_drc_tbl_paddr = (void *)(pa_base + ISP_DRC_MEM_OFS);dev->isp_tbl_addr[i].isp_drc_tbl_dma_addr = (void *)(dma_base + ISP_DRC_MEM_OFS);dev->isp_tbl_addr[i].isp_drc_tbl_vaddr = (void *)(va_base + ISP_DRC_MEM_OFS);dev->isp_tbl_addr[i].isp_disc_tbl_paddr = (void *)(pa_base + ISP_DISC_MEM_OFS);dev->isp_tbl_addr[i].isp_disc_tbl_dma_addr = (void *)(dma_base + ISP_DISC_MEM_OFS);dev->isp_tbl_addr[i].isp_disc_tbl_vaddr = (void *)(va_base + ISP_DISC_MEM_OFS);vfe_dbg(0, "isp_drc_tbl_vaddr[%d] = %p\n", i, dev->isp_tbl_addr[i].isp_drc_tbl_vaddr);}else{vfe_err("isp drc table request pa failed!\n");return -ENOMEM;}}}for (i = 0; i < dev->dev_qty; i++){if (dev->ccm_cfg[i]->is_isp_used && dev->ccm_cfg[i]->is_bayer_raw){isp_used_flag = 1;break;}}if (isp_used_flag){for (i = 0; i < MAX_ISP_STAT_BUF; i++){dev->isp_stat_buf_mm[i].size = ISP_STAT_TOTAL_SIZE;ret = os_mem_alloc(&dev->isp_stat_buf_mm[i]);if (!ret){pa_base = dev->isp_stat_buf_mm[i].phy_addr;va_base = dev->isp_stat_buf_mm[i].vir_addr;dma_base = dev->isp_stat_buf_mm[i].dma_addr;INIT_LIST_HEAD(&dev->isp_stat_bq.isp_stat[i].queue);dev->isp_stat_bq.isp_stat[i].id = i;dev->isp_stat_bq.isp_stat[i].paddr = (void *)(pa_base);dev->isp_stat_bq.isp_stat[i].dma_addr = (void *)(dma_base);dev->isp_stat_bq.isp_stat[i].isp_stat_buf.stat_buf = (void *)(va_base);dev->isp_stat_bq.isp_stat[i].isp_stat_buf.buf_size = ISP_STAT_TOTAL_SIZE;dev->isp_stat_bq.isp_stat[i].isp_stat_buf.buf_status = BUF_IDLE;vfe_dbg(0, "dev->isp_stat_bq.isp_stat[i].isp_stat_buf.stat_buf[%d] = %p\n", i, dev->isp_stat_bq.isp_stat[i].isp_stat_buf.stat_buf);}else{vfe_err("isp statistic buffer request pa failed!\n");return -ENOMEM;}}}return 0;
}
static int vfe_device_regulator_get(struct ccm_config *ccm_cfg);
static int vfe_device_regulator_put(struct ccm_config *ccm_cfg);
static int vfe_set_sensor_power_on(struct vfe_dev *dev);
static int vfe_set_sensor_power_off(struct vfe_dev *dev);static void isp_resource_release(struct vfe_dev *dev)
{unsigned int isp_used_flag = 0, i;//release isp table and statistic bufferfor (i = 0; i < dev->dev_qty; i++){if (dev->ccm_cfg[i]->is_isp_used && dev->ccm_cfg[i]->is_bayer_raw){os_mem_free(&dev->isp_lut_tbl_buf_mm[i]);os_mem_free(&dev->isp_drc_tbl_buf_mm[i]);}}for (i = 0; i < dev->dev_qty; i++){if (dev->ccm_cfg[i]->is_isp_used && dev->ccm_cfg[i]->is_bayer_raw){isp_used_flag = 1;break;}}if (isp_used_flag){for (i = 0; i < MAX_ISP_STAT_BUF; i++){os_mem_free(&dev->isp_stat_buf_mm[i]);}}
}static int vfe_clk_get(struct vfe_dev *dev)
{
#ifdef VFE_CLKint ret;//Get Core clk!if (VFE_CORE_CLK){dev->clock.vfe_core_clk = os_clk_get(NULL, VFE_CORE_CLK);if (VFE_CORE_CLK_SRC){dev->clock.vfe_core_clk_src = os_clk_get(NULL, VFE_CORE_CLK_SRC);if (dev->clock.vfe_core_clk && dev->clock.vfe_core_clk_src){ret = os_clk_set_parent(dev->clock.vfe_core_clk, dev->clock.vfe_core_clk_src);if (ret != 0){vfe_err(" vfe core clock set parent failed \n");return -1;}}}os_clk_set_rate(dev->clock.vfe_core_clk, VFE_CORE_CLK_RATE);vfe_dbg(0, "vfe core clk = %ld\n", clk_get_rate(dev->clock.vfe_core_clk));}//Get Master clk!if (dev->vip_sel == 0) {if (VFE_MASTER_CLK0) {dev->clock.vfe_master_clk = os_clk_get(NULL, VFE_MASTER_CLK0);}}else if (dev->vip_sel == 1) {if (VFE_MASTER_CLK1) {dev->clock.vfe_master_clk = os_clk_get(NULL, VFE_MASTER_CLK1);}}if (VFE_MASTER_CLK_24M_SRC) {dev->clock.vfe_master_clk_24M_src = os_clk_get(NULL, VFE_MASTER_CLK_24M_SRC);}if (VFE_MASTER_CLK_PLL_SRC) {dev->clock.vfe_master_clk_pll_src = os_clk_get(NULL, VFE_MASTER_CLK_PLL_SRC);}if (!dev->clock.vfe_master_clk || !dev->clock.vfe_core_clk) {vfe_err("vfe core clk or vfe master clk is NULL!\n");ret = -1;}//Get MIPI clk!if (VFE_MIPI_DPHY_CLK) {dev->clock.vfe_dphy_clk = os_clk_get(NULL, VFE_MIPI_DPHY_CLK);if (VFE_MIPI_DPHY_CLK_SRC) {dev->clock.vfe_dphy_clk_src = os_clk_get(NULL, VFE_MIPI_DPHY_CLK_SRC);}}if (VFE_MIPI_CSI_CLK) {dev->clock.vfe_mipi_csi_clk = os_clk_get(NULL, VFE_MIPI_CSI_CLK);}
#ifdef VFE_MISC_CLKdev->clock.vfe_misc_clk = os_clk_get(NULL, VFE_MISC_CLK);
#endif#endifreturn 0;
}static int vfe_dphy_clk_set(struct vfe_dev *dev, unsigned long freq)
{
#ifdef VFE_CLKif (VFE_MIPI_DPHY_CLK_SRC) {if (dev->clock.vfe_dphy_clk && dev->clock.vfe_dphy_clk_src) {if (os_clk_set_parent(dev->clock.vfe_dphy_clk, dev->clock.vfe_dphy_clk_src)) {vfe_err("set vfe dphy clock source failed \n");return -1;}}else {vfe_err("vfe dphy clock is null\n");return -1;}}if (VFE_MIPI_DPHY_CLK) {if (dev->clock.vfe_dphy_clk) {if (os_clk_set_rate(dev->clock.vfe_dphy_clk, freq)) {vfe_err("set vip%d dphy clock error\n", dev->vip_sel);return -1;}}else {vfe_err("vfe master clock is null\n");return -1;}}
#endifreturn 0;
}static int vfe_clk_enable(struct vfe_dev *dev)
{int ret = 0;
#ifdef VFE_CLKif (dev->clock.vfe_core_clk) {if (os_clk_prepare_enable(dev->clock.vfe_core_clk)){vfe_err("vfe core clock enable error\n");ret = -1;}}else {vfe_err("vfe core clock is null\n");ret = -1;}//if (dev->clock.vfe_dphy_clk) {if (os_clk_prepare_enable(dev->clock.vfe_dphy_clk)){vfe_err("vfe dphy clock enable error\n");ret = -1;}}else {vfe_dbg(0, "vfe dphy clock is null\n");ret = -1;}if (dev->clock.vfe_mipi_csi_clk) {if (os_clk_prepare_enable(dev->clock.vfe_mipi_csi_clk)){vfe_err("vfe mipi csi clock enable error\n");ret = -1;}}else {vfe_dbg(0, "vfe mipi csi clock  is null\n");ret = -1;}if (dev->clock.vfe_misc_clk) {if (os_clk_prepare_enable(dev->clock.vfe_misc_clk)){vfe_err("vfe misc clock enable error\n");ret = -1;}}else {vfe_dbg(0, "vfe misc clock is null\n");ret = -1;}
#endifreturn ret;
}static void vfe_clk_disable(struct vfe_dev *dev)
{
#ifdef VFE_CLKif (dev->clock.vfe_core_clk)os_clk_disable_unprepare(dev->clock.vfe_core_clk);elsevfe_dbg(0, "vfe core clock is null\n");if (dev->clock.vfe_dphy_clk)os_clk_disable_unprepare(dev->clock.vfe_dphy_clk);elsevfe_dbg(0, "vfe dphy clock is null\n");if (dev->clock.vfe_misc_clk)os_clk_disable_unprepare(dev->clock.vfe_misc_clk);elsevfe_dbg(0, "vfe dphy clock is null\n");if (dev->clock.vfe_mipi_csi_clk)os_clk_disable_unprepare(dev->clock.vfe_mipi_csi_clk);elsevfe_dbg(0, "vfe mipi csi clock is null\n");
#endif
}static void vfe_clk_release(struct vfe_dev *dev)
{
#ifdef VFE_CLKif (dev->clock.vfe_core_clk)os_clk_put(dev->clock.vfe_core_clk);elsevfe_err("vfe core clock is null\n");if (dev->clock.vfe_master_clk)os_clk_put(dev->clock.vfe_master_clk);elsevfe_err("vip%d master clock is null\n", dev->vip_sel);if (dev->clock.vfe_dphy_clk)os_clk_put(dev->clock.vfe_dphy_clk);elsevfe_err("vfe dphy clock is null\n");if (dev->clock.vfe_mipi_csi_clk)os_clk_put(dev->clock.vfe_mipi_csi_clk);elsevfe_warn("vfe mipi csi clock is null\n");if (dev->clock.vfe_core_clk_src)os_clk_put(dev->clock.vfe_core_clk_src);elsevfe_warn("vfe core clock source is null\n");if (dev->clock.vfe_master_clk_24M_src)os_clk_put(dev->clock.vfe_master_clk_24M_src);elsevfe_err("vfe master clock 24M source is null\n");if (dev->clock.vfe_master_clk_pll_src)os_clk_put(dev->clock.vfe_master_clk_pll_src);elsevfe_warn("vfe master clock pll source is null\n");if (dev->clock.vfe_dphy_clk_src)os_clk_put(dev->clock.vfe_dphy_clk_src);elsevfe_warn("vfe dphy clock source is null\n");
#endif
}static void vfe_reset_enable(struct vfe_dev *dev)
{os_clk_reset_assert(dev->clock.vfe_core_clk);//  os_clk_reset_assert(dev->clock.vfe_ahb_clk);
}static void vfe_reset_disable(struct vfe_dev *dev)
{os_clk_reset_deassert(dev->clock.vfe_core_clk);//  os_clk_reset_deassert(dev->clock.vfe_ahb_clk);
}static int inline vfe_is_generating(struct vfe_dev *dev)
{return test_bit(0, &dev->generating);
}static void inline vfe_start_generating(struct vfe_dev *dev)
{set_bit(0, &dev->generating);return;
}static void inline vfe_stop_generating(struct vfe_dev *dev)
{dev->first_flag = 0;clear_bit(0, &dev->generating);return;
}static int vfe_is_opened(struct vfe_dev *dev)
{int ret;mutex_lock(&dev->opened_lock);ret = test_bit(0, &dev->opened);mutex_unlock(&dev->opened_lock);return ret;
}static void vfe_start_opened(struct vfe_dev *dev)
{mutex_lock(&dev->opened_lock);set_bit(0, &dev->opened);mutex_unlock(&dev->opened_lock);
}static void vfe_stop_opened(struct vfe_dev *dev)
{mutex_lock(&dev->opened_lock);clear_bit(0, &dev->opened);mutex_unlock(&dev->opened_lock);
}static void update_ccm_info(struct vfe_dev *dev, struct ccm_config *ccm_cfg)
{dev->sd = ccm_cfg->sd;dev->sd_act = ccm_cfg->sd_act;dev->ctrl_para.vflip = ccm_cfg->vflip;dev->ctrl_para.hflip = ccm_cfg->hflip;dev->ctrl_para.vflip_thumb = ccm_cfg->vflip_thumb;dev->ctrl_para.hflip_thumb = ccm_cfg->hflip_thumb;dev->is_isp_used = ccm_cfg->is_isp_used;dev->is_bayer_raw = ccm_cfg->is_bayer_raw;dev->power = &ccm_cfg->power;dev->gpio = &ccm_cfg->gpio;dev->flash_used = ccm_cfg->flash_used;dev->flash_type = ccm_cfg->flash_type;/* print change */vfe_dbg(0, "ccm_cfg pt = %p\n", ccm_cfg);vfe_dbg(0, "ccm_cfg->sd = %p\n", ccm_cfg->sd);vfe_dbg(0, "module vflip = %d hflip = %d\n", dev->ctrl_para.vflip, dev->ctrl_para.hflip);vfe_dbg(0, "module vflip_thumb = %d hflip_thumb = %d\n", dev->ctrl_para.vflip_thumb, dev->ctrl_para.hflip_thumb);vfe_dbg(0, "module is_isp_used = %d is_bayer_raw= %d\n", dev->is_isp_used, dev->is_bayer_raw);
}static void update_isp_setting(struct vfe_dev *dev)
{dev->isp_3a_result_pt = &dev->isp_3a_result[dev->input];dev->isp_gen_set_pt = &dev->isp_gen_set[dev->input];dev->isp_gen_set_pt->module_cfg.isp_platform_id = dev->platform_id;if (dev->is_bayer_raw){mutex_init(&dev->isp_3a_result_mutex);dev->isp_gen_set_pt->module_cfg.lut_src0_table = dev->isp_tbl_addr[dev->input].isp_def_lut_tbl_vaddr;dev->isp_gen_set_pt->module_cfg.gamma_table = dev->isp_tbl_addr[dev->input].isp_gamma_tbl_vaddr;dev->isp_gen_set_pt->module_cfg.lens_table = dev->isp_tbl_addr[dev->input].isp_lsc_tbl_vaddr;dev->isp_gen_set_pt->module_cfg.linear_table = dev->isp_tbl_addr[dev->input].isp_linear_tbl_vaddr;dev->isp_gen_set_pt->module_cfg.disc_table = dev->isp_tbl_addr[dev->input].isp_disc_tbl_vaddr;bsp_isp_update_lut_lens_gamma_table(&dev->isp_tbl_addr[dev->input]);}dev->isp_gen_set_pt->module_cfg.drc_table = dev->isp_tbl_addr[dev->input].isp_drc_tbl_vaddr;bsp_isp_update_drc_table(&dev->isp_tbl_addr[dev->input]);
}static int get_mbus_config(struct vfe_dev *dev, struct v4l2_mbus_config *mbus_config)
{int ret;ret = v4l2_subdev_call(dev->sd, video, g_mbus_config, mbus_config);if (ret < 0){vfe_err("v4l2 sub device g_mbus_config error!\n");return -EFAULT;}return 0;
};
//static int isp_addr_curr = 0;
//static int isp_addr_pst = 0;
static inline void vfe_set_addr(struct vfe_dev *dev, struct vfe_buffer *buffer)
{struct vfe_buffer *buf = buffer;dma_addr_t addr_org;struct videobuf_buffer *vb_buf = &buf->vb;if (vb_buf == NULL || vb_buf->priv == NULL){vfe_err("videobuf_buffer->priv is NULL!\n");return;}//vfe_dbg(3,"buf ptr=%p\n",buf);addr_org = videobuf_to_dma_contig(vb_buf) - CPU_DRAM_PADDR_ORG + HW_DMA_OFFSET;//isp_addr_curr = vfe_reg_readl((volatile void __iomem*)(0xf1cb8210));//if(isp_addr_pst != isp_addr_curr)//{//    vfe_warn("isp_addr_pst = %d, isp_addr_curr = %d.......\n", isp_addr_pst, isp_addr_curr);//}//isp_addr_pst = addr_org /4;if (dev->is_isp_used){bsp_isp_set_output_addr(addr_org);}else{bsp_csi_set_addr(dev->vip_sel, addr_org);}buf->image_quality = dev->isp_3a_result_pt->image_quality.dwval;vfe_dbg(3, "csi_buf_addr_orginal=%x\n", addr_org);
}static unsigned int common_af_status_to_v4l2(enum auto_focus_status af_status)
{switch (af_status){case AUTO_FOCUS_STATUS_IDLE:return V4L2_AUTO_FOCUS_STATUS_IDLE;case AUTO_FOCUS_STATUS_BUSY:return V4L2_AUTO_FOCUS_STATUS_BUSY;case AUTO_FOCUS_STATUS_APPROCH:return V4L2_AUTO_FOCUS_STATUS_BUSY;case AUTO_FOCUS_STATUS_FINDED:return V4L2_AUTO_FOCUS_STATUS_REACHED;case AUTO_FOCUS_STATUS_FAILED:return V4L2_AUTO_FOCUS_STATUS_FAILED;case AUTO_FOCUS_STATUS_REFOCUS:return V4L2_AUTO_FOCUS_STATUS_BUSY;default:return V4L2_AUTO_FOCUS_STATUS_IDLE;}
}
static void vfe_dump_csi_regs(struct vfe_dev *dev)
{int i = 0;if (vfe_dump & DUMP_CSI){if (5 == frame_cnt % 10){printk("Vfe dump CSI regs :\n");for (i = 0; i < 0xb0; i = i + 4){if (i % 0x10 == 0)printk("0x%08x:    ", i);printk("0x%08x, ", vfe_reg_readl(dev->regs.csi_regs + i));if (i % 0x10 == 0xc)printk("\n");}}}
}
static void vfe_dump_isp_regs(struct vfe_dev *dev)
{int i = 0;if (vfe_dump & DUMP_ISP){if (9 == (frame_cnt % 10)){printk("Vfe dump ISP regs :\n");for (i = 0; i < 0x40; i = i + 4){if (i % 0x10 == 0)printk("0x%08x:  ", i);printk("0x%08x, ", vfe_reg_readl(dev->regs.isp_regs + i));if (i % 0x10 == 0xc)printk("\n");}for (i = 0x40; i < 0x240; i = i + 4){if (i % 0x10 == 0)printk("0x%08x:  ", i);printk("0x%08x, ", vfe_reg_readl(dev->regs.isp_load_regs + i));if (i % 0x10 == 0xc)printk("\n");}}}
}static void isp_isr_bh_handle(struct work_struct *work)
{struct actuator_ctrl_word_t vcm_ctrl;struct vfe_dev *dev = container_of(work, struct vfe_dev, isp_isr_bh_task);FUNCTION_LOG;vfe_dump_isp_regs(dev);if (dev->is_bayer_raw){mutex_lock(&dev->isp_3a_result_mutex);if (1 == isp_reparse_flag){vfe_print("ISP reparse ini file!\n");if (read_ini_info(dev, dev->input)){vfe_warn("ISP reparse ini fail, please check isp config!\n");goto ISP_REPARSE_END;}isp_param_init(dev->isp_gen_set_pt);isp_config_init(dev->isp_gen_set_pt);isp_module_init(dev->isp_gen_set_pt, dev->isp_3a_result_pt);ISP_REPARSE_END:isp_reparse_flag = 0;}if (2 == isp_reparse_flag){vfe_reg_set(IO_ADDRESS(ISP_REGS_BASE + 0x10), (1 << 20));}if (3 == isp_reparse_flag){vfe_reg_clr_set(IO_ADDRESS(ISP_REGS_BASE + 0x10), (0xF << 16), (1 << 16));vfe_reg_set(IO_ADDRESS(ISP_REGS_BASE + 0x10), (1 << 20));}if (4 == isp_reparse_flag){//vfe_reg_clr_set(IO_ADDRESS(ISP_REGS_BASE+0x10), (0xF << 16), (1 << 16));vfe_reg_clr(IO_ADDRESS(ISP_REGS_BASE + 0x10), (1 << 20));vfe_reg_clr(IO_ADDRESS(ISP_REGS_BASE + 0x10), (0xF << 16));}isp_isr(dev->isp_gen_set_pt, dev->isp_3a_result_pt);if ((dev->ctrl_para.prev_focus_pos != dev->isp_3a_result_pt->real_vcm_pos ||dev->isp_gen_set_pt->isp_ini_cfg.isp_test_settings.isp_test_mode != 0 ||dev->isp_gen_set_pt->isp_ini_cfg.isp_test_settings.af_en == 0) &&dev->sd_act){vcm_ctrl.code = dev->isp_3a_result_pt->real_vcm_pos;vcm_ctrl.sr = 0x0;if (v4l2_subdev_call(dev->sd_act, core, ioctl, ACT_SET_CODE, &vcm_ctrl)){vfe_warn("set vcm error!\n");}else{dev->ctrl_para.prev_focus_pos = dev->isp_3a_result_pt->real_vcm_pos;}}mutex_unlock(&dev->isp_3a_result_mutex);}else{isp_isr(dev->isp_gen_set_pt, NULL);}FUNCTION_LOG;
}int set_sensor_shutter(struct vfe_dev *dev, int shutter)
{struct v4l2_control ctrl;if (shutter <= 0){return -EINVAL;}ctrl.id = V4L2_CID_EXPOSURE;ctrl.value = shutter;if (v4l2_subdev_call(dev->sd, core, s_ctrl, &ctrl) != 0){vfe_err("set sensor exposure line error!\n");return -1;}else{dev->ctrl_para.prev_exp_line = shutter;return 0;}
}int set_sensor_gain(struct vfe_dev *dev, int gain)
{struct v4l2_control ctrl;if (gain < 16){return -EINVAL;}ctrl.id = V4L2_CID_GAIN;ctrl.value = gain;if (v4l2_subdev_call(dev->sd, core, s_ctrl, &ctrl) != 0){vfe_err("set sensor gain error!\n");return -1;}else{dev->ctrl_para.prev_ana_gain = gain;return 0;}
}
int set_sensor_shutter_and_gain(struct vfe_dev *dev)
{struct sensor_exp_gain exp_gain;exp_gain.exp_val = dev->isp_3a_result_pt->exp_line_num;exp_gain.gain_val = dev->isp_3a_result_pt->exp_analog_gain;if (exp_gain.gain_val < 16 || exp_gain.exp_val <= 0){return -EINVAL;}if (v4l2_subdev_call(dev->sd, core, ioctl, ISP_SET_EXP_GAIN, &exp_gain) != 0){vfe_warn("set ISP_SET_EXP_GAIN error, set V4L2_CID_EXPOSURE!\n");return -1;}else{dev->ctrl_para.prev_exp_line = exp_gain.exp_val;dev->ctrl_para.prev_ana_gain = exp_gain.gain_val;return 0;}
}static int isp_s_ctrl_torch_open(struct vfe_dev *dev)
{if (dev->isp_gen_set_pt->exp_settings.flash_mode == FLASH_MODE_OFF){return 0;}if (((dev->isp_gen_set_pt->exp_settings.tbl_cnt > (dev->isp_gen_set_pt->exp_settings.tbl_max_ind - 25)) ||dev->isp_gen_set_pt->exp_settings.flash_mode == FLASH_MODE_ON)){vfe_dbg(0, "open flash when nigth mode\n");io_set_flash_ctrl(dev->sd, SW_CTRL_TORCH_ON, dev->fl_dev_info);touch_flash_flag = 1;}return 0;
}
static int isp_s_ctrl_torch_close(struct vfe_dev *dev)
{if (dev->isp_gen_set_pt->exp_settings.flash_mode == FLASH_MODE_OFF){return 0;}if (touch_flash_flag == 1){vfe_dbg(0, "close flash when nigth mode\n");io_set_flash_ctrl(dev->sd, SW_CTRL_FLASH_OFF, dev->fl_dev_info);touch_flash_flag = 0;}return 0;
}
static int isp_streamoff_torch_and_flash_close(struct vfe_dev *dev)
{if (dev->isp_gen_set_pt->exp_settings.flash_mode == FLASH_MODE_OFF){return 0;}if (touch_flash_flag == 1 || dev->isp_gen_set_pt->exp_settings.flash_open == 1){vfe_dbg(0, "close flash when nigth mode\n");io_set_flash_ctrl(dev->sd, SW_CTRL_FLASH_OFF, dev->fl_dev_info);touch_flash_flag = 0;}return 0;
}
static int isp_set_capture_flash(struct vfe_dev *dev)
{if (dev->isp_gen_set_pt->exp_settings.flash_mode == FLASH_MODE_OFF){return 0;}if (dev->isp_gen_set_pt->take_pic_start_cnt == 1){if (dev->isp_gen_set_pt->exp_settings.tbl_cnt > (dev->isp_gen_set_pt->exp_settings.tbl_max_ind - 40) ||dev->isp_gen_set_pt->exp_settings.flash_mode == FLASH_MODE_ON){vfe_dbg(0, "open torch when nigth mode\n");io_set_flash_ctrl(dev->sd, SW_CTRL_TORCH_ON, dev->fl_dev_info);dev->isp_gen_set_pt->exp_settings.flash_open = 1;}}if (dev->isp_gen_set_pt->exp_settings.flash_open == 1 && dev->isp_gen_set_pt->take_pic_start_cnt == dev->isp_gen_set_pt->isp_ini_cfg.isp_tunning_settings.flash_delay_frame){vfe_dbg(0, "open flash when nigth mode\n");dev->isp_gen_set_pt->exp_settings.exposure_lock = ISP_TRUE;ev_cumul = get_pre_ev_cumul(dev->isp_gen_set_pt, dev->isp_3a_result_pt);if (ev_cumul >= 100){dev->isp_gen_set_pt->exp_settings.tbl_cnt = CLIP(dev->isp_gen_set_pt->exp_settings.expect_tbl_cnt, 1,dev->isp_gen_set_pt->exp_settings.tbl_max_ind);}else if (ev_cumul >= dev->isp_gen_set_pt->isp_ini_cfg.isp_tunning_settings.flash_gain * 100 / 256 && ev_cumul < 100){dev->isp_gen_set_pt->exp_settings.tbl_cnt = CLIP(dev->isp_gen_set_pt->exp_settings.expect_tbl_cnt, 1,dev->isp_gen_set_pt->exp_settings.tbl_max_ind);}else if (ev_cumul >= -25 && ev_cumul < dev->isp_gen_set_pt->isp_ini_cfg.isp_tunning_settings.flash_gain * 100 / 256){dev->isp_gen_set_pt->exp_settings.tbl_cnt = CLIP(dev->isp_gen_set_pt->exp_settings.expect_tbl_cnt +ev_cumul * dev->isp_gen_set_pt->isp_ini_cfg.isp_tunning_settings.flash_gain / 256,1,dev->isp_gen_set_pt->exp_settings.tbl_max_ind);}else{dev->isp_gen_set_pt->exp_settings.tbl_cnt = CLIP(dev->isp_gen_set_pt->exp_settings.expect_tbl_cnt +ev_cumul * dev->isp_gen_set_pt->isp_ini_cfg.isp_tunning_settings.flash_gain / 256,1,dev->isp_gen_set_pt->exp_settings.tbl_max_ind);}config_sensor_next_exposure(dev->isp_gen_set_pt, dev->isp_3a_result_pt);io_set_flash_ctrl(dev->sd, SW_CTRL_FLASH_OFF, dev->fl_dev_info);}if (dev->isp_gen_set_pt->exp_settings.flash_open == 1 && dev->isp_gen_set_pt->take_pic_start_cnt == dev->isp_gen_set_pt->isp_ini_cfg.isp_tunning_settings.flash_delay_frame + 1){io_set_flash_ctrl(dev->sd, SW_CTRL_FLASH_ON, dev->fl_dev_info);}if (dev->isp_gen_set_pt->take_pic_start_cnt == 7 + dev->isp_gen_set_pt->isp_ini_cfg.isp_tunning_settings.flash_delay_frame){vfe_dbg(0, "close flash when nigth mode\n");io_set_flash_ctrl(dev->sd, SW_CTRL_FLASH_OFF, dev->fl_dev_info);dev->isp_gen_set_pt->exp_settings.tbl_cnt = CLIP(dev->isp_gen_set_pt->exp_settings.expect_tbl_cnt,1, dev->isp_gen_set_pt->exp_settings.tbl_max_ind);dev->isp_gen_set_pt->exp_settings.exposure_lock = ISP_FALSE;dev->isp_gen_set_pt->exp_settings.flash_open = 0;}if (dev->isp_gen_set_pt->exp_settings.flash_open == 0 && touch_flash_flag == 1 &&(dev->isp_3a_result_pt->af_status == AUTO_FOCUS_STATUS_REACHED ||dev->isp_3a_result_pt->af_status == AUTO_FOCUS_STATUS_FAILED ||dev->isp_3a_result_pt->af_status == AUTO_FOCUS_STATUS_FINDED)){vfe_dbg(0, "close flash when touch nigth mode \n");io_set_flash_ctrl(dev->sd, SW_CTRL_FLASH_OFF, dev->fl_dev_info);touch_flash_flag = 0;}return 0;
}
static void isp_isr_set_sensor_handle(struct work_struct *work)
{struct vfe_dev *dev = container_of(work, struct vfe_dev, isp_isr_set_sensor_task);if (dev->is_bayer_raw){mutex_lock(&dev->isp_3a_result_mutex);
#ifdef _FLASH_FUNC_isp_set_capture_flash(dev);
#endifif (dev->isp_gen_set_pt->isp_ini_cfg.isp_3a_settings.adaptive_frame_rate == 1 ||dev->isp_gen_set_pt->isp_ini_cfg.isp_3a_settings.force_frame_rate == 1 ||dev->isp_gen_set_pt->isp_ini_cfg.isp_3a_settings.high_quality_mode_en == 1){vfe_dbg(0, "combinate shutter = %d, gain =%d \n", dev->isp_3a_result_pt->exp_line_num,dev->isp_3a_result_pt->exp_analog_gain);if (set_sensor_shutter_and_gain(dev) != 0){set_sensor_shutter(dev, dev->isp_3a_result_pt->exp_line_num);set_sensor_gain(dev, dev->isp_3a_result_pt->exp_analog_gain);}}else{vfe_dbg(0, "separate shutter = %d, gain =%d \n", dev->isp_3a_result_pt->exp_line_num / 16,dev->isp_3a_result_pt->exp_analog_gain);set_sensor_shutter(dev, dev->isp_3a_result_pt->exp_line_num);set_sensor_gain(dev, dev->isp_3a_result_pt->exp_analog_gain);}mutex_unlock(&dev->isp_3a_result_mutex);}return;
}static void vfe_isp_stat_parse(struct isp_gen_settings *isp_gen)
{unsigned int buffer_addr = (unsigned int)isp_gen->stat.stat_buf_whole->stat_buf;isp_gen->stat.hist_buf = (void *)(buffer_addr);isp_gen->stat.ae_buf = (void *)(buffer_addr + ISP_STAT_AE_MEM_OFS);isp_gen->stat.awb_buf = (void *)(buffer_addr + ISP_STAT_AWB_MEM_OFS);isp_gen->stat.af_buf = (void *)(buffer_addr + ISP_STAT_AF_MEM_OFS);isp_gen->stat.afs_buf = (void *)(buffer_addr + ISP_STAT_AFS_MEM_OFS);isp_gen->stat.awb_win_buf = (void *)(buffer_addr + ISP_STAT_AWB_WIN_MEM_OFS);
}/**  the interrupt routine*/static irqreturn_t vfe_isr(int irq, void *priv)
{int i;unsigned long flags;struct vfe_buffer *buf;struct vfe_dev *dev = (struct vfe_dev *)priv;struct vfe_dmaqueue *dma_q = &dev->vidq;struct csi_int_status status;struct vfe_isp_stat_buf_queue *isp_stat_bq = &dev->isp_stat_bq;struct vfe_isp_stat_buf *stat_buf_pt;FUNCTION_LOG;vfe_dump_csi_regs(dev);frame_cnt++;vfe_dbg(0, "vfe interrupt!!!\n");if (vfe_is_generating(dev) == 0){bsp_csi_int_clear_status(dev->vip_sel, dev->cur_ch, CSI_INT_ALL);if (dev->is_isp_used)bsp_isp_clr_irq_status(ISP_IRQ_EN_ALL);return IRQ_HANDLED;}bsp_csi_int_get_status(dev->vip_sel, dev->cur_ch, &status);if ((status.capture_done == 0) && (status.frame_done == 0) && (status.vsync_trig == 0)){vfe_print("enter vfe int for nothing\n");bsp_csi_int_clear_status(dev->vip_sel, dev->cur_ch, CSI_INT_ALL);if (dev->is_isp_used)bsp_isp_clr_irq_status(ISP_IRQ_EN_ALL);return IRQ_HANDLED;}if (dev->is_isp_used && dev->is_bayer_raw){//update_sensor_setting:if (status.vsync_trig){if ((dev->capture_mode == V4L2_MODE_VIDEO) || (dev->capture_mode == V4L2_MODE_PREVIEW)){vfe_dbg(3, "call set sensor task schedule! \n");schedule_work(&dev->isp_isr_set_sensor_task);}bsp_csi_int_clear_status(dev->vip_sel, dev->cur_ch, CSI_INT_VSYNC_TRIG);return IRQ_HANDLED;}}FUNCTION_LOG;//spin_lock(&dev->slock);spin_lock_irqsave(&dev->slock, flags);FUNCTION_LOG;//exception handle:if ((status.buf_0_overflow) || (status.buf_1_overflow) || (status.buf_2_overflow) || (status.hblank_overflow)){if ((status.buf_0_overflow) || (status.buf_1_overflow) || (status.buf_2_overflow)){bsp_csi_int_clear_status(dev->vip_sel, dev->cur_ch, CSI_INT_BUF_0_OVERFLOW | CSI_INT_BUF_1_OVERFLOW | CSI_INT_BUF_2_OVERFLOW);vfe_err("fifo overflow\n");}if (status.hblank_overflow){bsp_csi_int_clear_status(dev->vip_sel, dev->cur_ch, CSI_INT_HBLANK_OVERFLOW);vfe_err("hblank overflow\n");}vfe_err("reset csi module\n");bsp_csi_reset(dev->vip_sel);if (dev->is_isp_used)goto isp_exp_handle;elsegoto unlock;}isp_exp_handle:if (dev->is_isp_used){if (bsp_isp_get_irq_status(SRC0_FIFO_INT_EN)){vfe_err("isp source0 fifo overflow\n");bsp_isp_clr_irq_status(SRC0_FIFO_INT_EN);goto unlock;}}vfe_dbg(3, "status vsync = %d, framedone = %d, capdone = %d\n", status.vsync_trig, status.frame_done, status.capture_done);if (dev->capture_mode == V4L2_MODE_IMAGE){if (dev->is_isp_used)bsp_isp_irq_disable(FINISH_INT_EN);elsebsp_csi_int_disable(dev->vip_sel, dev->cur_ch, CSI_INT_CAPTURE_DONE);vfe_print("capture image mode!\n");buf = list_entry(dma_q->active.next, struct vfe_buffer, vb.queue);list_del(&buf->vb.queue);buf->vb.state = VIDEOBUF_DONE;wake_up(&buf->vb.done);goto unlock;}else{if (dev->is_isp_used)bsp_isp_irq_disable(FINISH_INT_EN);elsebsp_csi_int_disable(dev->vip_sel, dev->cur_ch, CSI_INT_FRAME_DONE);if (dev->first_flag == 0){dev->first_flag++;vfe_print("capture video mode!\n");goto set_isp_stat_addr;}if (dev->first_flag == 1){dev->first_flag++;vfe_print("capture video first frame done!\n");}//video buffer handle:if ((&dma_q->active) == dma_q->active.next->next->next){vfe_warn("Only two buffer left for csi\n");dev->first_flag = 0;goto unlock;}buf = list_entry(dma_q->active.next, struct vfe_buffer, vb.queue);/* Nobody is waiting on this buffer*/if (!waitqueue_active(&buf->vb.done)){vfe_warn(" Nobody is waiting on this video buffer,buf = 0x%p\n", buf);}list_del(&buf->vb.queue);do_gettimeofday(&buf->vb.ts);buf->vb.field_count++;vfe_dbg(2, "video buffer frame interval = %ld\n", buf->vb.ts.tv_sec * 1000000 + buf->vb.ts.tv_usec - (dev->sec * 1000000 + dev->usec));dev->sec = buf->vb.ts.tv_sec;dev->usec = buf->vb.ts.tv_usec;dev->ms += jiffies_to_msecs(jiffies - dev->jiffies);dev->jiffies = jiffies;buf->vb.image_quality = dev->isp_3a_result_pt->image_quality.dwval;buf->vb.state = VIDEOBUF_DONE;buf->image_quality = dev->isp_3a_result_pt->image_quality.dwval;wake_up(&buf->vb.done);//isp_stat_handle:if (dev->is_isp_used && dev->is_bayer_raw){list_for_each_entry(stat_buf_pt, &isp_stat_bq->locked, queue){if (stat_buf_pt->isp_stat_buf.buf_status == BUF_LOCKED){vfe_dbg(3, "find isp stat buf locked!\n");goto set_next_output_addr;vfe_dbg(3, "isp_stat_bq->locked = %p\n", &isp_stat_bq->locked);vfe_dbg(3, "isp_stat_bq->locked.next = %p\n", isp_stat_bq->locked.next);vfe_dbg(3, "isp_stat_bq->isp_stat[%d].queue = %p\n", stat_buf_pt->id, &isp_stat_bq->isp_stat[stat_buf_pt->id].queue);vfe_dbg(3, "isp_stat_bq->isp_stat[%d].queue.prev = %p\n", stat_buf_pt->id, isp_stat_bq->isp_stat[stat_buf_pt->id].queue.prev);vfe_dbg(3, "isp_stat_bq->isp_stat[%d].queue.next = %p\n", stat_buf_pt->id, isp_stat_bq->isp_stat[stat_buf_pt->id].queue.next);}}for (i = 0; i < MAX_ISP_STAT_BUF; i++){stat_buf_pt = &isp_stat_bq->isp_stat[i];if (stat_buf_pt->isp_stat_buf.buf_status == BUF_IDLE){vfe_dbg(3, "find isp stat buf idle!\n");list_move_tail(&stat_buf_pt->queue, &isp_stat_bq->active);stat_buf_pt->isp_stat_buf.buf_status = BUF_ACTIVE;}}vfe_dbg(3, "before list empty isp_stat_bq->active = %p\n", &isp_stat_bq->active);vfe_dbg(3, "before list empty isp_stat_bq->active.prev = %p\n", isp_stat_bq->active.prev);vfe_dbg(3, "before list empty isp_stat_bq->active.next = %p\n", isp_stat_bq->active.next);//judge if the isp stat queue has been written to the lastif (list_empty(&isp_stat_bq->active)){vfe_err("No active isp stat queue to serve\n");goto set_next_output_addr;}vfe_dbg(3, "after list empty isp_stat_bq->active = %p\n", &isp_stat_bq->active);vfe_dbg(3, "after list empty isp_stat_bq->active.prev = %p\n", isp_stat_bq->active.prev);vfe_dbg(3, "after list empty isp_stat_bq->active.next = %p\n", isp_stat_bq->active.next);//delete the ready buffer from the actvie queue//add the ready buffer to the locked queue//stat_buf_pt = list_first_entry(&isp_stat_bq->active, struct vfe_isp_stat_buf, queue);stat_buf_pt = list_entry(isp_stat_bq->active.next, struct vfe_isp_stat_buf, queue);list_move_tail(&stat_buf_pt->queue, &isp_stat_bq->locked);stat_buf_pt->isp_stat_buf.buf_status = BUF_LOCKED;dev->isp_gen_set_pt->stat.stat_buf_whole = &isp_stat_bq->isp_stat[stat_buf_pt->id].isp_stat_buf;vfe_isp_stat_parse(dev->isp_gen_set_pt);isp_stat_bq->isp_stat[stat_buf_pt->id].isp_stat_buf.frame_number++;if ((&isp_stat_bq->active) == isp_stat_bq->active.next->next){vfe_warn("No more isp stat free frame on next time\n");goto set_next_output_addr;}}}set_isp_stat_addr:if (dev->is_isp_used && dev->is_bayer_raw){//stat_buf_pt = list_entry(isp_stat_bq->active.next->next, struct vfe_isp_stat_buf, queue);stat_buf_pt = list_entry(isp_stat_bq->active.next, struct vfe_isp_stat_buf, queue);bsp_isp_set_statistics_addr((unsigned int)(stat_buf_pt->dma_addr));}
set_next_output_addr://buf = list_entry(dma_q->active.next->next,struct vfe_buffer, vb.queue);if (list_empty(&dma_q->active) || dma_q->active.next->next == (&dma_q->active)){vfe_print("No active queue to serve\n");goto unlock;}buf = list_entry(dma_q->active.next->next, struct vfe_buffer, vb.queue);vfe_set_addr(dev, buf);unlock://spin_unlock(&dev->slock);spin_unlock_irqrestore(&dev->slock, flags);if (((dev->capture_mode == V4L2_MODE_VIDEO) || (dev->capture_mode == V4L2_MODE_PREVIEW)) && dev->is_isp_used && bsp_isp_get_irq_status(FINISH_INT_EN)){//if(bsp_isp_get_para_ready()){vfe_dbg(3, "call tasklet schedule! \n");bsp_isp_clr_para_ready();schedule_work(&dev->isp_isr_bh_task);bsp_isp_set_para_ready();}}if (dev->is_isp_used){bsp_isp_clr_irq_status(FINISH_INT_EN);bsp_isp_irq_enable(FINISH_INT_EN);}else{bsp_csi_int_clear_status(dev->vip_sel, dev->cur_ch, CSI_INT_FRAME_DONE);//bsp_csi_int_clear_status(dev->vip_sel, dev->cur_ch,CSI_INT_VSYNC_TRIG);//bsp_csi_int_clear_status(dev->vip_sel, dev->cur_ch,CSI_INT_CAPTURE_DONE);if ((dev->capture_mode == V4L2_MODE_VIDEO) || (dev->capture_mode == V4L2_MODE_PREVIEW))bsp_csi_int_enable(dev->vip_sel, dev->cur_ch, CSI_INT_FRAME_DONE);}return IRQ_HANDLED;
}/** Videobuf operations*/
static int buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
{struct vfe_dev *dev = vq->priv_data;int buf_max_flag = 0;vfe_dbg(1, "buffer_setup\n");*size = dev->buf_byte_size;while (*size * *count > MAX_FRAME_MEM){(*count)--;buf_max_flag = 1;if (*count == 0)vfe_err("one buffer size larger than max frame memory! buffer count = %d\n,", *count);}if (buf_max_flag == 0){if (dev->capture_mode == V4L2_MODE_IMAGE){if (*count != 1){*count = 1;vfe_err("buffer count is set to 1 in image capture mode\n");}}else{if (*count < 3){*count = 3;vfe_err("buffer count is invalid, set to 3 in video capture\n");}}}vfe_print("%s, buffer count=%d, size=%d\n", __func__, *count, *size);return 0;
}static void free_buffer(struct videobuf_queue *vq, struct vfe_buffer *buf)
{vfe_dbg(1, "%s, state: %i\n", __func__, buf->vb.state);videobuf_waiton(vq, &buf->vb, 0, 0);videobuf_dma_contig_free(vq, &buf->vb);vfe_dbg(1, "free_buffer: freed\n");buf->vb.state = VIDEOBUF_NEEDS_INIT;
}static int buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,enum v4l2_field field)
{struct vfe_dev *dev = vq->priv_data;struct vfe_buffer *buf = container_of(vb, struct vfe_buffer, vb);int rc;vfe_dbg(1, "buffer_prepare\n");BUG_ON(NULL == dev->fmt);if (dev->width < MIN_WIDTH || dev->width > MAX_WIDTH ||dev->height < MIN_HEIGHT || dev->height > MAX_HEIGHT){return -EINVAL;}buf->vb.size = dev->buf_byte_size;if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size){return -EINVAL;}/* These properties only change when queue is idle, see s_fmt */buf->fmt = dev->fmt;buf->vb.width = dev->width;buf->vb.height = dev->height;buf->vb.field = field;if (VIDEOBUF_NEEDS_INIT == buf->vb.state){rc = videobuf_iolock(vq, &buf->vb, NULL);if (rc < 0){goto fail;}}vb->boff = videobuf_to_dma_contig(vb);buf->vb.state = VIDEOBUF_PREPARED;return 0;fail:free_buffer(vq, buf);return rc;
}static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
{struct vfe_dev *dev = vq->priv_data;struct vfe_buffer *buf = container_of(vb, struct vfe_buffer, vb);struct vfe_dmaqueue *vidq = &dev->vidq;vfe_dbg(1, "buffer_queue\n");buf->vb.state = VIDEOBUF_QUEUED;list_add_tail(&buf->vb.queue, &vidq->active);
}static void buffer_release(struct videobuf_queue *vq,struct videobuf_buffer *vb)
{struct vfe_buffer *buf = container_of(vb, struct vfe_buffer, vb);vfe_dbg(1, "buffer_release\n");free_buffer(vq, buf);
}static struct videobuf_queue_ops vfe_video_qops = {.buf_setup = buffer_setup,.buf_prepare = buffer_prepare,.buf_queue = buffer_queue,.buf_release = buffer_release,
};/** IOCTL vidioc handling*/
static int vidioc_querycap(struct file *file, void *priv,struct v4l2_capability *cap)
{struct vfe_dev *dev = video_drvdata(file);strcpy(cap->driver, "sunxi-vfe");strcpy(cap->card, "sunxi-vfe");strlcpy(cap->bus_info, dev->v4l2_dev.name, sizeof(cap->bus_info));cap->version = VFE_VERSION;cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |V4L2_CAP_READWRITE;return 0;
}static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,struct v4l2_fmtdesc *f)
{struct vfe_fmt *fmt;vfe_dbg(0, "vidioc_enum_fmt_vid_cap\n");if (f->index > ARRAY_SIZE(formats) - 1){return -EINVAL;}fmt = &formats[f->index];strlcpy(f->description, fmt->name, sizeof(f->description));f->pixelformat = fmt->fourcc;return 0;
}static int vidioc_enum_framesizes(struct file *file, void *fh,struct v4l2_frmsizeenum *fsize)
{struct vfe_dev *dev = video_drvdata(file);vfe_dbg(0, "vidioc_enum_framesizes\n");if (dev == NULL || dev->sd->ops->video->enum_framesizes == NULL){return -EINVAL;}return v4l2_subdev_call(dev->sd, video, enum_framesizes, fsize);
}static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,struct v4l2_format *f)
{struct vfe_dev *dev = video_drvdata(file);f->fmt.pix.width = dev->width;f->fmt.pix.height = dev->height;f->fmt.pix.field = dev->vb_vidq.field;f->fmt.pix.pixelformat = dev->fmt->bus_pix_code;//  f->fmt.pix.bytesperline = (f->fmt.pix.width * dev->fmt->depth) >> 3;//  f->fmt.pix.sizeimage    = f->fmt.pix.height * f->fmt.pix.bytesperline;return 0;
}static enum bus_pixelcode bus_pix_code_v4l2_to_common(enum v4l2_mbus_pixelcode pix_code)
{return (enum bus_pixelcode)pix_code;
}static enum pixel_fmt pix_fmt_v4l2_to_common(unsigned int pix_fmt)
{switch (pix_fmt){case V4L2_PIX_FMT_RGB565:return PIX_FMT_RGB565;case V4L2_PIX_FMT_RGB24:return PIX_FMT_RGB888;case V4L2_PIX_FMT_RGB32:return PIX_FMT_PRGB888;case V4L2_PIX_FMT_YUYV:return PIX_FMT_YUYV;case V4L2_PIX_FMT_YVYU:return PIX_FMT_YVYU;case V4L2_PIX_FMT_UYVY:return PIX_FMT_UYVY;case V4L2_PIX_FMT_VYUY:return PIX_FMT_VYUY;case V4L2_PIX_FMT_YUV422P:return PIX_FMT_YUV422P_8;case V4L2_PIX_FMT_YUV420:return PIX_FMT_YUV420P_8;case V4L2_PIX_FMT_YVU420:return PIX_FMT_YVU420P_8;case V4L2_PIX_FMT_NV12:return PIX_FMT_YUV420SP_8;case V4L2_PIX_FMT_NV21:return PIX_FMT_YVU420SP_8;case V4L2_PIX_FMT_NV16:return PIX_FMT_YUV422SP_8;case V4L2_PIX_FMT_NV61:return PIX_FMT_YVU422SP_8;case V4L2_PIX_FMT_SBGGR8:return PIX_FMT_SBGGR_8;case V4L2_PIX_FMT_SGBRG8:return PIX_FMT_SGBRG_8;case V4L2_PIX_FMT_SGRBG8:return PIX_FMT_SGRBG_8;case V4L2_PIX_FMT_SRGGB8:return PIX_FMT_SRGGB_8;case V4L2_PIX_FMT_SBGGR10:return PIX_FMT_SBGGR_10;case V4L2_PIX_FMT_SGBRG10:return PIX_FMT_SGBRG_10;case V4L2_PIX_FMT_SGRBG10:return PIX_FMT_SGRBG_10;case V4L2_PIX_FMT_SRGGB10:return PIX_FMT_SRGGB_10;case V4L2_PIX_FMT_SBGGR12:return PIX_FMT_SBGGR_12;case V4L2_PIX_FMT_SGBRG12:return PIX_FMT_SGBRG_12;case V4L2_PIX_FMT_SGRBG12:return PIX_FMT_SGRBG_12;case V4L2_PIX_FMT_SRGGB12:return PIX_FMT_SRGGB_12;default:return PIX_FMT_SBGGR_8;}
}static enum field field_fmt_v4l2_to_common(enum v4l2_field field)
{return (enum field)field;
}static enum v4l2_mbus_pixelcode *try_fmt_internal(struct vfe_dev *dev, struct v4l2_format *f)
{enum pixel_fmt pix_fmt;enum pixel_fmt_type pix_fmt_type;struct v4l2_mbus_framefmt ccm_fmt;enum v4l2_mbus_pixelcode *bus_pix_code;int ret = 0;vfe_dbg(0, "try_fmt_internal\n");/*judge the resolution*/if (f->fmt.pix.width > MAX_WIDTH || f->fmt.pix.height > MAX_HEIGHT){vfe_err("size is too large,automatically set to maximum!\n");f->fmt.pix.width = MAX_WIDTH;f->fmt.pix.height = MAX_HEIGHT;}pix_fmt = pix_fmt_v4l2_to_common(f->fmt.pix.pixelformat);pix_fmt_type = find_pixel_fmt_type(pix_fmt);ccm_fmt.width = f->fmt.pix.width;ccm_fmt.height = f->fmt.pix.height;//find the expect bus format via frame format listif (pix_fmt_type == YUV422_PL || pix_fmt_type == YUV422_SPL ||pix_fmt_type == YUV420_PL || pix_fmt_type == YUV420_SPL){if (dev->is_isp_used && dev->is_bayer_raw){// vfe_print("using isp at %s!\n",__func__);for (bus_pix_code = try_bayer_rgb_bus; bus_pix_code < try_bayer_rgb_bus + N_TRY_BAYER; bus_pix_code++){ccm_fmt.code = *bus_pix_code;ccm_fmt.field = f->fmt.pix.field;ret = v4l2_subdev_call(dev->sd, video, try_mbus_fmt, &ccm_fmt);if (ret >= 0){vfe_dbg(0, "try bayer bus ok when pix fmt is yuv422/yuv420 at %s!\n", __func__);break;}}if (ret < 0){vfe_err("try bayer bus error when pix fmt is yuv422/yuv420 at %s!\n", __func__);for (bus_pix_code = try_yuv422_bus; bus_pix_code < try_yuv422_bus + N_TRY_YUV422; bus_pix_code++){ccm_fmt.code = *bus_pix_code;ccm_fmt.field = f->fmt.pix.field;ret = v4l2_subdev_call(dev->sd, video, try_mbus_fmt, &ccm_fmt);if (ret >= 0){vfe_dbg(0, "try yuv22 bus ok when pix fmt is yuv422/yuv420 at %s!\n", __func__);break;}}if (ret < 0){vfe_err("try yuv22 fmt error when pix fmt is yuv422/yuv420 at %s!\n", __func__);if (pix_fmt_type == YUV420_PL || pix_fmt_type == YUV420_SPL){for (bus_pix_code = try_yuv420_bus; bus_pix_code < try_yuv420_bus + N_TRY_YUV420; bus_pix_code++){ccm_fmt.code = *bus_pix_code;ccm_fmt.field = f->fmt.pix.field;ret = v4l2_subdev_call(dev->sd, video, try_mbus_fmt, &ccm_fmt);if (ret >= 0){vfe_dbg(0, "try yuv420 bus ok when pix fmt is yuv420 at %s!\n", __func__);break;}}if (ret < 0){vfe_err("try yuv420 bus error when pix fmt is yuv420 at %s!\n", __func__);return NULL;}}else{return NULL;}}}}else{// vfe_dbg(0,"not using isp at %s!\n",__func__);for (bus_pix_code = try_yuv422_bus; bus_pix_code < try_yuv422_bus + N_TRY_YUV422; bus_pix_code++){ccm_fmt.code = *bus_pix_code;ccm_fmt.field = f->fmt.pix.field;ret = v4l2_subdev_call(dev->sd, video, try_mbus_fmt, &ccm_fmt);vfe_dbg(0, "v4l2_subdev_call try_mbus_fmt return %x\n", ret);if (ret >= 0){vfe_dbg(0, "try yuv422 fmt ok when pix fmt is yuv422/yuv420 at %s!\n", __func__);break;}}if (ret < 0){vfe_err("try yuv422 fmt error when pix fmt is yuv422/yuv420 at %s!\n", __func__);if (pix_fmt_type == YUV420_PL || pix_fmt_type == YUV420_SPL){}else{return NULL;}}}}else if (pix_fmt_type == YUV422_INTLVD){//vfe_dbg(0,"not using isp at %s!\n",__func__);for (bus_pix_code = try_yuv422_bus; bus_pix_code < try_yuv422_bus + N_TRY_YUV422; bus_pix_code++){ccm_fmt.code = *bus_pix_code;ccm_fmt.field = f->fmt.pix.field;ret = v4l2_subdev_call(dev->sd, video, try_mbus_fmt, &ccm_fmt);if (ret >= 0){vfe_dbg(0, "try yuv422 bus ok when pix fmt is yuv422 interleaved at %s!\n", __func__);break;}}if (ret < 0){vfe_err("try yuv422 bus error when pix fmt is yuv422 interleaved at %s!\n", __func__);return NULL;}}else if (pix_fmt_type == BAYER_RGB){// vfe_dbg(0,"not using isp at %s!\n",__func__);for (bus_pix_code = try_bayer_rgb_bus; bus_pix_code < try_bayer_rgb_bus + N_TRY_BAYER; bus_pix_code++){ccm_fmt.code = *bus_pix_code;ccm_fmt.field = f->fmt.pix.field;ret = v4l2_subdev_call(dev->sd, video, try_mbus_fmt, &ccm_fmt);if (ret >= 0){vfe_dbg(0, "try bayer bus ok when pix fmt is bayer rgb at %s!\n", __func__);break;}}if (ret < 0){vfe_err("try bayer bus error when pix fmt is bayer rgb at %s!\n", __func__);return NULL;}}else if (pix_fmt_type == RGB565){//  vfe_dbg(0,"not using isp at %s!\n",__func__);for (bus_pix_code = try_rgb565_bus; bus_pix_code < try_rgb565_bus + N_TRY_BAYER; bus_pix_code++){ccm_fmt.code = *bus_pix_code;ccm_fmt.field = f->fmt.pix.field;ret = v4l2_subdev_call(dev->sd, video, try_mbus_fmt, &ccm_fmt);if (ret >= 0){vfe_dbg(0, "try rgb565 bus ok when pix fmt is rgb565 at %s!\n", __func__);break;}}if (ret < 0){vfe_err("try rgb565 bus error when pix fmt is rgb565 at %s!\n", __func__);return NULL;}}else if (pix_fmt_type == RGB888 || pix_fmt_type == PRGB888){//  vfe_dbg(0,"not using isp at %s!\n",__func__);for (bus_pix_code = try_rgb888_bus; bus_pix_code < try_rgb888_bus + N_TRY_BAYER; bus_pix_code++){ccm_fmt.code = *bus_pix_code;ccm_fmt.field = f->fmt.pix.field;ret = v4l2_subdev_call(dev->sd, video, try_mbus_fmt, &ccm_fmt);if (ret >= 0){vfe_dbg(0, "try rgb888 bus ok when pix fmt is rgb888/prgb888 at %s!\n", __func__);break;}}if (ret < 0){vfe_err("try rgb888 bus error when pix fmt is rgb888/prgb888 at %s!\n", __func__);return NULL;}}else{return NULL;}f->fmt.pix.width = ccm_fmt.width;f->fmt.pix.height = ccm_fmt.height;vfe_dbg(0, "bus pixel code = %x at %s\n", *bus_pix_code, __func__);vfe_dbg(0, "pix->width = %d at %s\n", f->fmt.pix.width, __func__);vfe_dbg(0, "pix->height = %d at %s\n", f->fmt.pix.height, __func__);return bus_pix_code;
}static enum pkt_fmt get_pkt_fmt(enum bus_pixelcode bus_pix_code)
{switch (bus_pix_code){case BUS_FMT_RGB565_16X1:return MIPI_RGB565;case BUS_FMT_UYVY8_16X1:return MIPI_YUV422;case BUS_FMT_UYVY10_20X1:return MIPI_YUV422_10;case BUS_FMT_SBGGR8_8X1:case BUS_FMT_SGBRG8_8X1:case BUS_FMT_SGRBG8_8X1:case BUS_FMT_SRGGB8_8X1:return MIPI_RAW8;case BUS_FMT_SBGGR10_10X1:case BUS_FMT_SGBRG10_10X1:case BUS_FMT_SGRBG10_10X1:case BUS_FMT_SRGGB10_10X1:return MIPI_RAW10;case BUS_FMT_SBGGR12_12X1:case BUS_FMT_SGBRG12_12X1:case BUS_FMT_SGRBG12_12X1:case BUS_FMT_SRGGB12_12X1:return MIPI_RAW12;case BUS_FMT_YY8_UYVY8_12X1:return MIPI_YUV420;case BUS_FMT_YY10_UYVY10_15X1:return MIPI_YUV420_10;default:return MIPI_RAW8;}
}static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,struct v4l2_format *f)
{struct vfe_dev *dev = video_drvdata(file);//  struct vfe_fmt *vfe_fmt;//  struct v4l2_mbus_framefmt ccm_fmt;enum v4l2_mbus_pixelcode *bus_pix_code;vfe_dbg(0, "vidioc_try_fmt_vid_cap\n");bus_pix_code = try_fmt_internal(dev, f);if (!bus_pix_code){vfe_err("pixel format (0x%08x) width %d height %d invalid at %s.\n",f->fmt.pix.pixelformat, f->fmt.pix.width, f->fmt.pix.height, __func__);return -EINVAL;}return 0;
}static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,struct v4l2_format *f)
{struct vfe_dev *dev = video_drvdata(file);struct videobuf_queue *q = &dev->vb_vidq;struct v4l2_mbus_framefmt ccm_fmt;struct v4l2_mbus_config mbus_cfg;enum v4l2_mbus_pixelcode *bus_pix_code;enum pixel_fmt isp_fmt[ISP_MAX_CH_NUM];struct isp_size isp_size[ISP_MAX_CH_NUM];struct sensor_win_size win_cfg;struct isp_size_settings size_settings;struct isp_size ob_black_size, ob_valid_size;struct coor ob_start;unsigned char ch_num;unsigned int i, scale_ratio;int ret;vfe_dbg(0, "vidioc_s_fmt_vid_cap\n");if (vfe_is_generating(dev)){vfe_err("%s device busy\n", __func__);return -EBUSY;}mutex_lock(&q->vb_lock);bus_pix_code = try_fmt_internal(dev, f);if (!bus_pix_code){vfe_err("pixel format (0x%08x) width %d height %d invalid at %s.\n",f->fmt.pix.pixelformat, f->fmt.pix.width, f->fmt.pix.height, __func__);ret = -EINVAL;goto out;}vfe_dbg(0, "bus pixel code = %x at %s\n", *bus_pix_code, __func__);vfe_dbg(0, "pix->width = %d at %s\n", f->fmt.pix.width, __func__);vfe_dbg(0, "pix->height = %d at %s\n", f->fmt.pix.height, __func__);//get current win configsmemset(&win_cfg, 0, sizeof(struct sensor_win_size));ret = v4l2_subdev_call(dev->sd, core, ioctl, GET_CURRENT_WIN_CFG, &win_cfg);ret = get_mbus_config(dev, &mbus_cfg);if (ret < 0){vfe_err("get_mbus_config failed!\n");goto out;}if (mbus_cfg.type == V4L2_MBUS_CSI2){dev->bus_info.bus_if = CSI2;if (IS_FLAG(mbus_cfg.flags, V4L2_MBUS_CSI2_4_LANE))dev->mipi_para.lane_num = 4;else if (IS_FLAG(mbus_cfg.flags, V4L2_MBUS_CSI2_3_LANE))dev->mipi_para.lane_num = 3;else if (IS_FLAG(mbus_cfg.flags, V4L2_MBUS_CSI2_2_LANE))dev->mipi_para.lane_num = 2;elsedev->mipi_para.lane_num = 1;ch_num = 0;dev->total_bus_ch = 0;if (IS_FLAG(mbus_cfg.flags, V4L2_MBUS_CSI2_CHANNEL_0)){dev->mipi_fmt.vc[ch_num] = 0;dev->mipi_fmt.field[ch_num] = dev->frame_info.ch_field[ch_num];ch_num++;dev->total_bus_ch++;}if (IS_FLAG(mbus_cfg.flags, V4L2_MBUS_CSI2_CHANNEL_1)){dev->mipi_fmt.vc[ch_num] = 1;dev->mipi_fmt.field[ch_num] = dev->frame_info.ch_field[ch_num];ch_num++;dev->total_bus_ch++;}if (IS_FLAG(mbus_cfg.flags, V4L2_MBUS_CSI2_CHANNEL_2)){dev->mipi_fmt.vc[ch_num] = 2;dev->mipi_fmt.field[ch_num] = dev->frame_info.ch_field[ch_num];ch_num++;dev->total_bus_ch++;}if (IS_FLAG(mbus_cfg.flags, V4L2_MBUS_CSI2_CHANNEL_3)){dev->mipi_fmt.vc[ch_num] = 3;dev->mipi_fmt.field[ch_num] = dev->frame_info.ch_field[ch_num];ch_num++;dev->total_bus_ch++;}dev->total_rx_ch = dev->total_bus_ch; //TODOdev->mipi_para.total_rx_ch = dev->total_rx_ch;vfe_print("V4L2_MBUS_CSI2,%d lane,bus%d channel,rx %d channel\n", dev->mipi_para.lane_num, dev->total_bus_ch, dev->total_rx_ch);}else if (mbus_cfg.type == V4L2_MBUS_PARALLEL){dev->bus_info.bus_if = PARALLEL;if (IS_FLAG(mbus_cfg.flags, V4L2_MBUS_MASTER)){if (IS_FLAG(mbus_cfg.flags, V4L2_MBUS_HSYNC_ACTIVE_HIGH)){dev->bus_info.bus_tmg.href_pol = ACTIVE_HIGH;}else{dev->bus_info.bus_tmg.href_pol = ACTIVE_LOW;}if (IS_FLAG(mbus_cfg.flags, V4L2_MBUS_VSYNC_ACTIVE_HIGH)){dev->bus_info.bus_tmg.vref_pol = ACTIVE_HIGH;}else{dev->bus_info.bus_tmg.vref_pol = ACTIVE_LOW;}if (IS_FLAG(mbus_cfg.flags, V4L2_MBUS_PCLK_SAMPLE_RISING)){dev->bus_info.bus_tmg.pclk_sample = RISING;}else{dev->bus_info.bus_tmg.pclk_sample = FALLING;}if (IS_FLAG(mbus_cfg.flags, V4L2_MBUS_FIELD_EVEN_HIGH)){dev->bus_info.bus_tmg.field_even_pol = ACTIVE_HIGH;}else{dev->bus_info.bus_tmg.field_even_pol = ACTIVE_LOW;}}else{vfe_err("Do not support MBUS SLAVE! get mbus_cfg.type = %d\n", mbus_cfg.type);goto out;}}else if (mbus_cfg.type == V4L2_MBUS_BT656){dev->bus_info.bus_if = BT656;}//get mipi bps from win configsif (mbus_cfg.type == V4L2_MBUS_CSI2){dev->mipi_para.bps = win_cfg.mipi_bps;dev->mipi_para.auto_check_bps = 0;   //TODOdev->mipi_para.dphy_freq = DPHY_CLK; //TODOfor (i = 0; i < dev->total_rx_ch; i++){ //TODOdev->bus_info.bus_ch_fmt[i] = bus_pix_code_v4l2_to_common(*bus_pix_code);//      printk("dev->bus_info.bus_ch_fmt[%d] = %x\n",i,dev->bus_info.bus_ch_fmt[i]);dev->mipi_fmt.packet_fmt[i] = get_pkt_fmt(dev->bus_info.bus_ch_fmt[i]);//      printk("dev->mipi_fmt.packet_fmt[%d] = %x\n",i,dev->mipi_fmt.packet_fmt[i]);}bsp_mipi_csi_dphy_init(dev->mipi_sel);bsp_mipi_csi_set_para(dev->mipi_sel, &dev->mipi_para);bsp_mipi_csi_set_fmt(dev->mipi_sel, dev->mipi_para.total_rx_ch, &dev->mipi_fmt);//for dphy clock asyncbsp_mipi_csi_dphy_disable(dev->mipi_sel);usleep_range(1000, 2000);if (dev->clock.vfe_dphy_clk){os_clk_disable(dev->clock.vfe_dphy_clk);}else{vfe_warn("vfe dphy clock is null\n");}bsp_mipi_csi_dphy_enable(dev->mipi_sel);if (dev->clock.vfe_dphy_clk){if (os_clk_enable(dev->clock.vfe_dphy_clk))vfe_err("vfe dphy clock enable error\n");}else{vfe_warn("vfe dphy clock is null\n");}usleep_range(10000, 12000);}//init deviceccm_fmt.code = *bus_pix_code;ccm_fmt.width = f->fmt.pix.width;ccm_fmt.height = f->fmt.pix.height;ccm_fmt.field = f->fmt.pix.field;ret = v4l2_subdev_call(dev->sd, video, s_mbus_fmt, &ccm_fmt);if (ret < 0){vfe_err("v4l2 sub device s_fmt error!\n");goto out;}//prepare the vfe bsp parameter//assuming using single channeldev->bus_info.ch_total_num = dev->total_rx_ch;//format and size infofor (i = 0; i < dev->total_bus_ch; i++)dev->bus_info.bus_ch_fmt[i] = bus_pix_code_v4l2_to_common(*bus_pix_code);for (i = 0; i < dev->total_rx_ch; i++){dev->frame_info.pix_ch_fmt[i] = pix_fmt_v4l2_to_common(f->fmt.pix.pixelformat);dev->frame_info.ch_field[i] = field_fmt_v4l2_to_common(ccm_fmt.field);dev->frame_info.ch_size[i].width = ccm_fmt.width;dev->frame_info.ch_size[i].height = ccm_fmt.height;dev->frame_info.ch_offset[i].hoff = win_cfg.hoffset;dev->frame_info.ch_offset[i].voff = win_cfg.voffset;}dev->frame_info.arrange.row = dev->arrange.row;dev->frame_info.arrange.column = dev->arrange.column;//set vfe bspret = bsp_csi_set_fmt(dev->vip_sel, &dev->bus_info, &dev->frame_info);if (ret < 0){vfe_err("bsp_csi_set_fmt error at %s!\n", __func__);goto out;}//return buffer byte size via dev->frame_info.frm_byte_sizeret = bsp_csi_set_size(dev->vip_sel, &dev->bus_info, &dev->frame_info);if (ret < 0){vfe_err("bsp_csi_set_size error at %s!\n", __func__);goto out;}//save the info to the channel infofor (i = 0; i < dev->total_bus_ch; i++){dev->ch[i].fmt.bus_pix_code = *bus_pix_code;dev->ch[i].fmt.fourcc = f->fmt.pix.pixelformat;dev->ch[i].fmt.field = ccm_fmt.field;dev->ch[i].size.width = ccm_fmt.width;dev->ch[i].size.height = ccm_fmt.height;dev->ch[i].size.hoffset = ccm_fmt.reserved[0];dev->ch[i].size.voffset = ccm_fmt.reserved[1];}if (dev->is_isp_used){isp_fmt[MAIN_CH] = pix_fmt_v4l2_to_common(f->fmt.pix.pixelformat);isp_size[MAIN_CH].width = ccm_fmt.width;isp_size[MAIN_CH].height = ccm_fmt.height;//todo for rotationif (f->fmt.pix.rot_angle != 0){isp_fmt[ROT_CH] = pix_fmt_v4l2_to_common(f->fmt.pix.pixelformat);}else{isp_fmt[ROT_CH] = PIX_FMT_NONE;}if (f->fmt.pix.subchannel){if (f->fmt.pix.subchannel->rot_angle != 0)isp_fmt[ROT_CH] = pix_fmt_v4l2_to_common(f->fmt.pix.subchannel->pixelformat);}if (f->fmt.pix.subchannel){isp_fmt[SUB_CH] = pix_fmt_v4l2_to_common(f->fmt.pix.subchannel->pixelformat);isp_size[SUB_CH].width = f->fmt.pix.subchannel->width;isp_size[SUB_CH].height = f->fmt.pix.subchannel->height;dev->thumb_width = f->fmt.pix.subchannel->width;dev->thumb_height = f->fmt.pix.subchannel->height;if (f->fmt.pix.subchannel->height > f->fmt.pix.height || f->fmt.pix.subchannel->width > f->fmt.pix.width){vfe_err("subchannel size > main channel size!!!");}}else{isp_fmt[SUB_CH] = PIX_FMT_NONE;isp_size[SUB_CH].width = 0;isp_size[SUB_CH].height = 0;scale_ratio = 0;}vfe_dbg(0, "*bus_pix_code = %d, isp_fmt = %p\n", *bus_pix_code, isp_fmt);if ((f->fmt.pix.rot_angle == 0 && f->fmt.pix.subchannel == NULL) ||(f->fmt.pix.rot_angle == 0 && f->fmt.pix.subchannel != NULL && f->fmt.pix.subchannel->rot_angle == 0)){isp_fmt[ROT_CH] = PIX_FMT_NONE;}bsp_isp_set_fmt(find_bus_type(*bus_pix_code), isp_fmt);//only has one rotation ch, priority: main ch > sub ch//from main ch firstif (f->fmt.pix.rot_angle == 0){bsp_isp_set_rot(MAIN_CH, ANGLE_0);isp_size[ROT_CH].width = ccm_fmt.width;isp_size[ROT_CH].height = ccm_fmt.height;}else if (f->fmt.pix.rot_angle == 90){bsp_isp_set_rot(MAIN_CH, ANGLE_90);isp_size[ROT_CH].height = ccm_fmt.width;isp_size[ROT_CH].width = ccm_fmt.height;}else if (f->fmt.pix.rot_angle == 180){bsp_isp_set_rot(MAIN_CH, ANGLE_180);isp_size[ROT_CH].width = ccm_fmt.width;isp_size[ROT_CH].height = ccm_fmt.height;}else if (f->fmt.pix.rot_angle == 270){bsp_isp_set_rot(MAIN_CH, ANGLE_270);isp_size[ROT_CH].height = ccm_fmt.width;isp_size[ROT_CH].width = ccm_fmt.height;}else{bsp_isp_set_rot(MAIN_CH, ANGLE_0);}//from sub ch secondif (f->fmt.pix.subchannel){if (f->fmt.pix.subchannel->rot_angle == 0){bsp_isp_set_rot(SUB_CH, ANGLE_0);isp_size[ROT_CH].width = f->fmt.pix.subchannel->width;isp_size[ROT_CH].height = f->fmt.pix.subchannel->height;}else if (f->fmt.pix.subchannel->rot_angle == 90){isp_size[ROT_CH].height = f->fmt.pix.subchannel->width;isp_size[ROT_CH].width = f->fmt.pix.subchannel->height;bsp_isp_set_rot(SUB_CH, ANGLE_90);}else if (f->fmt.pix.subchannel->rot_angle == 180){isp_size[ROT_CH].width = f->fmt.pix.subchannel->width;isp_size[ROT_CH].height = f->fmt.pix.subchannel->height;bsp_isp_set_rot(SUB_CH, ANGLE_180);}else if (f->fmt.pix.subchannel->rot_angle == 270){isp_size[ROT_CH].height = f->fmt.pix.subchannel->width;isp_size[ROT_CH].width = f->fmt.pix.subchannel->height;bsp_isp_set_rot(SUB_CH, ANGLE_270);}else{bsp_isp_set_rot(SUB_CH, ANGLE_0);}}if (0 == win_cfg.width || 0 == win_cfg.height){win_cfg.width = isp_size[MAIN_CH].width;win_cfg.height = isp_size[MAIN_CH].height;}if (0 == win_cfg.width_input || 0 == win_cfg.height_input){win_cfg.width_input = win_cfg.width;win_cfg.height_input = win_cfg.height;}vfe_print("width_input = %d, height_input = %d, width = %d, height = %d\n", win_cfg.width_input, win_cfg.height_input, win_cfg.width, win_cfg.height);ob_black_size.width = win_cfg.width_input + 2 * win_cfg.hoffset;   //OKob_black_size.height = win_cfg.height_input + 2 * win_cfg.voffset; //OKob_valid_size.width = win_cfg.width_input;ob_valid_size.height = win_cfg.height_input;ob_start.hor = win_cfg.hoffset; //OKob_start.ver = win_cfg.voffset; //OKif ((f->fmt.pix.rot_angle == 0 && f->fmt.pix.subchannel == NULL) ||(f->fmt.pix.rot_angle == 0 && f->fmt.pix.subchannel != NULL && f->fmt.pix.subchannel->rot_angle == 0)){isp_size[ROT_CH].height = 0;isp_size[ROT_CH].width = 0;isp_fmt[ROT_CH] = PIX_FMT_NONE;}if (f->fmt.pix.subchannel != NULL){dev->isp_gen_set_pt->double_ch_flag = 1;}else{dev->isp_gen_set_pt->double_ch_flag = 0;}//dev->buf_byte_size = bsp_isp_set_size(isp_fmt,&ob_black_size, &ob_valid_size, &isp_size[MAIN_CH],&isp_size[ROT_CH],&ob_start,&isp_size[SUB_CH]);size_settings.full_size = isp_size[MAIN_CH];size_settings.scale_size = isp_size[SUB_CH];size_settings.ob_black_size = ob_black_size;size_settings.ob_start = ob_start;size_settings.ob_valid_size = ob_valid_size;size_settings.ob_rot_size = isp_size[ROT_CH];dev->buf_byte_size = bsp_isp_set_size(isp_fmt, &size_settings);vfe_print("dev->buf_byte_size = %d, double_ch_flag = %d\n", dev->buf_byte_size, dev->isp_gen_set_pt->double_ch_flag);}else{dev->buf_byte_size = dev->frame_info.frm_byte_size;dev->thumb_width = 0;dev->thumb_height = 0;}dev->vb_vidq.field = ccm_fmt.field;dev->width = ccm_fmt.width;dev->height = ccm_fmt.height;dev->mbus_type = mbus_cfg.type;if (dev->is_isp_used == 1){vfe_dbg(0, "isp_module_init start!\n");if (dev->is_bayer_raw == 1){dev->isp_gen_set_pt->stat.pic_size.width = win_cfg.width_input;dev->isp_gen_set_pt->stat.pic_size.height = win_cfg.height_input;dev->isp_gen_set_pt->stat.hoffset = win_cfg.hoffset;dev->isp_gen_set_pt->stat.voffset = win_cfg.voffset;dev->isp_gen_set_pt->stat.hts = win_cfg.hts;dev->isp_gen_set_pt->stat.vts = win_cfg.vts;dev->isp_gen_set_pt->stat.pclk = win_cfg.pclk;dev->isp_gen_set_pt->stat.fps_fixed = win_cfg.fps_fixed;dev->isp_gen_set_pt->stat.bin_factor = win_cfg.bin_factor;dev->isp_gen_set_pt->stat.intg_min = win_cfg.intg_min;dev->isp_gen_set_pt->stat.intg_max = win_cfg.intg_max;dev->isp_gen_set_pt->stat.gain_min = win_cfg.gain_min;dev->isp_gen_set_pt->stat.gain_max = win_cfg.gain_max;if (V4L2_MODE_IMAGE == dev->capture_mode){dev->isp_gen_set_pt->sensor_mod = CAPTURE_MODE;}else if (V4L2_MODE_VIDEO == dev->capture_mode){dev->isp_gen_set_pt->sensor_mod = VIDEO_MODE;}else{dev->isp_gen_set_pt->sensor_mod = PREVIEW_MODE;}isp_module_init(dev->isp_gen_set_pt, dev->isp_3a_result_pt);dev->ctrl_para.prev_exp_line = 0;dev->ctrl_para.prev_ana_gain = 1;if (set_sensor_shutter_and_gain(dev) != 0){set_sensor_shutter(dev, dev->isp_3a_result_pt->exp_line_num);set_sensor_gain(dev, dev->isp_3a_result_pt->exp_analog_gain);}usleep_range(50000, 60000);}else{isp_module_init(dev->isp_gen_set_pt, NULL);}vfe_dbg(0, "isp_module_init end!\n");}ret = 0;
out:mutex_unlock(&q->vb_lock);return ret;
}static int vidioc_reqbufs(struct file *file, void *priv,struct v4l2_requestbuffers *p)
{struct vfe_dev *dev = video_drvdata(file);vfe_dbg(0, "vidioc_reqbufs\n");return videobuf_reqbufs(&dev->vb_vidq, p);
}static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
{struct vfe_dev *dev = video_drvdata(file);return videobuf_querybuf(&dev->vb_vidq, p);
}static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
{struct vfe_dev *dev = video_drvdata(file);return videobuf_qbuf(&dev->vb_vidq, p);
}static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
{int ret = 0;struct vfe_dev *dev = video_drvdata(file);vfe_dbg(2, "vidioc dqbuf\n");ret = videobuf_dqbuf(&dev->vb_vidq, p, file->f_flags & O_NONBLOCK);//if (dev->isp_3a_result_pt != NULL && dev->is_bayer_raw)//{// mutex_lock(&dev->isp_3a_result_mutex);// p->reserved = dev->isp_3a_result_pt->image_quality;// mutex_unlock(&dev->isp_3a_result_mutex);//}return ret;
}#ifdef CONFIG_VIDEO_V4L1_COMPAT
static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
{struct vfe_dev *dev = video_drvdata(file);return videobuf_cgmbuf(&dev->vb_vidq, mbuf, 8);
}
#endifstatic int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
{struct vfe_dev *dev = video_drvdata(file);struct vfe_dmaqueue *dma_q = &dev->vidq;struct vfe_isp_stat_buf_queue *isp_stat_bq = &dev->isp_stat_bq;struct vfe_buffer *buf;struct vfe_isp_stat_buf *stat_buf_pt;int ret = 0;mutex_lock(&dev->stream_lock);//  spin_lock(&dev->slock);//debugvfe_dbg(0, "video stream on\n");if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE){ret = -EINVAL;goto streamon_unlock;}if (vfe_is_generating(dev)){vfe_err("stream has been already on\n");ret = -1;goto streamon_unlock;}bsp_csi_enable(dev->vip_sel);bsp_csi_disable(dev->vip_sel);bsp_csi_enable(dev->vip_sel);if (dev->is_isp_used)bsp_isp_enable();/* Resets frame counters */dev->ms = 0;dev->jiffies = jiffies;dma_q->frame = 0;dma_q->ini_jiffies = jiffies;if (dev->is_isp_used && dev->is_bayer_raw){/* initial for isp statistic buffer queue */INIT_LIST_HEAD(&isp_stat_bq->active);INIT_LIST_HEAD(&isp_stat_bq->locked);for (i = 0; i < MAX_ISP_STAT_BUF; i++){isp_stat_bq->isp_stat[i].isp_stat_buf.buf_status = BUF_ACTIVE;list_add_tail(&isp_stat_bq->isp_stat[i].queue, &isp_stat_bq->active);}}ret = videobuf_streamon(&dev->vb_vidq);if (ret)goto streamon_unlock;buf = list_entry(dma_q->active.next, struct vfe_buffer, vb.queue);vfe_set_addr(dev, buf);if (dev->is_isp_used && dev->is_bayer_raw){stat_buf_pt = list_entry(isp_stat_bq->active.next, struct vfe_isp_stat_buf, queue);if (NULL == stat_buf_pt){vfe_err("stat_buf_pt =null");}else{bsp_isp_set_statistics_addr((unsigned int)(stat_buf_pt->dma_addr));}}if (dev->is_isp_used){bsp_isp_set_para_ready();bsp_isp_clr_irq_status(ISP_IRQ_EN_ALL);bsp_isp_irq_enable(FINISH_INT_EN | SRC0_FIFO_INT_EN);if (dev->is_isp_used && dev->is_bayer_raw)bsp_csi_int_enable(dev->vip_sel, dev->cur_ch, CSI_INT_VSYNC_TRIG);}else{bsp_csi_int_clear_status(dev->vip_sel, dev->cur_ch, CSI_INT_ALL);bsp_csi_int_enable(dev->vip_sel, dev->cur_ch, CSI_INT_CAPTURE_DONE | CSI_INT_FRAME_DONE | CSI_INT_BUF_0_OVERFLOW | CSI_INT_BUF_1_OVERFLOW | CSI_INT_BUF_2_OVERFLOW | CSI_INT_HBLANK_OVERFLOW);}if (dev->mbus_type == V4L2_MBUS_CSI2)bsp_mipi_csi_protocol_enable(dev->mipi_sel);usleep_range(10000, 11000);if (dev->capture_mode == V4L2_MODE_IMAGE){if (dev->is_isp_used)bsp_isp_image_capture_start();bsp_csi_cap_start(dev->vip_sel, dev->total_rx_ch, CSI_SCAP);}else{if (dev->is_isp_used)bsp_isp_video_capture_start();bsp_csi_cap_start(dev->vip_sel, dev->total_rx_ch, CSI_VCAP);}//  if(dev->mbus_type == V4L2_MBUS_CSI2)//    bsp_mipi_csi_protocol_enable(dev->mipi_sel);vfe_start_generating(dev);streamon_unlock://  spin_unlock(&dev->slock);//debugmutex_unlock(&dev->stream_lock);return ret;
}static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
{struct vfe_dev *dev = video_drvdata(file);struct vfe_dmaqueue *dma_q = &dev->vidq;int ret = 0;mutex_lock(&dev->stream_lock);vfe_dbg(0, "video stream off\n");if (!vfe_is_generating(dev)){vfe_err("stream has been already off\n");ret = 0;goto streamoff_unlock;}
#ifdef _FLASH_FUNC_isp_streamoff_torch_and_flash_close(dev);
#endifvfe_stop_generating(dev);/* Resets frame counters */dev->ms = 0;dev->jiffies = jiffies;dma_q->frame = 0;dma_q->ini_jiffies = jiffies;if (dev->is_isp_used){vfe_dbg(0, "disable isp int in streamoff\n");bsp_isp_irq_disable(ISP_IRQ_EN_ALL);bsp_isp_clr_irq_status(ISP_IRQ_EN_ALL);}else{vfe_dbg(0, "disable csi int in streamoff\n");bsp_csi_int_disable(dev->vip_sel, dev->cur_ch, CSI_INT_ALL);bsp_csi_int_clear_status(dev->vip_sel, dev->cur_ch, CSI_INT_ALL);}if (dev->capture_mode == V4L2_MODE_IMAGE){bsp_csi_cap_stop(dev->vip_sel, dev->total_rx_ch, CSI_SCAP);if (dev->is_isp_used)bsp_isp_image_capture_stop();vfe_dbg(0, "dev->capture_mode = %d\n", dev->capture_mode);}else{bsp_csi_cap_stop(dev->vip_sel, dev->total_rx_ch, CSI_VCAP);if (dev->is_isp_used)bsp_isp_video_capture_stop();vfe_dbg(0, "dev->capture_mode = %d\n", dev->capture_mode);}if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE){ret = -EINVAL;goto streamoff_unlock;}if (dev->mbus_type == V4L2_MBUS_CSI2)bsp_mipi_csi_protocol_disable(dev->mipi_sel);ret = videobuf_streamoff(&dev->vb_vidq);if (ret != 0){vfe_err("videobu_streamoff error!\n");goto streamoff_unlock;}/* Release all active buffers */while (!list_empty(&dma_q->active)){vfe_err("dma_q->active is not empty!\n");}//printk("%s, line: %d\n", __FUNCTION__, __LINE__);if (dev->is_isp_used)bsp_isp_disable();bsp_csi_disable(dev->vip_sel);
streamoff_unlock://spin_unlock(&dev->slock);//debugmutex_unlock(&dev->stream_lock);return ret;
}static int vidioc_enum_input(struct file *file, void *priv,struct v4l2_input *inp)
{struct vfe_dev *dev = video_drvdata(file);if (inp->index > dev->dev_qty - 1){vfe_err("input index(%d) > dev->dev_qty(%d)-1 invalid!\n", inp->index, dev->dev_qty);return -EINVAL;}if (0 == dev->device_valid_flag[inp->index]){vfe_err("input index(%d) > dev->dev_qty(%d)-1 invalid!, device_valid_flag[%d] = %d\n", inp->index, dev->dev_qty, inp->index, dev->device_valid_flag[inp->index]);return -EINVAL;}inp->type = V4L2_INPUT_TYPE_CAMERA;return 0;
}static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
{struct vfe_dev *dev = video_drvdata(file);*i = dev->input;return 0;
}
static int vfe_ctrl_para_reset(struct vfe_dev *dev)
{dev->ctrl_para.gsensor_rot = 0;dev->ctrl_para.prev_exp_line = 16;dev->ctrl_para.prev_ana_gain = 16;dev->ctrl_para.prev_focus_pos = 50;return 0;
}static int internal_s_input(struct vfe_dev *dev, unsigned int i)
{struct v4l2_control ctrl;struct sensor_item sensor_info;int ret;if (i > dev->dev_qty - 1){vfe_err("set input i(%d)>dev_qty(%d)-1 error!\n", i, dev->dev_qty);return -EINVAL;}if (i == dev->input)return 0;if (dev->input != -1){/*Power down current device*/if (dev->sd_act != NULL){v4l2_subdev_call(dev->sd_act, core, ioctl, ACT_SOFT_PWDN, 0);}if (dev->power->stby_mode == NORM_STBY){ret = v4l2_subdev_call(dev->sd, core, s_power, CSI_SUBDEV_STBY_ON);}else //POWER_OFF{ret = vfe_set_sensor_power_off(dev);}if (ret < 0)goto altend;}vfe_dbg(0, "input_num = %d\n", i);dev->input = i;/* Alternate the device info and select target device*/update_ccm_info(dev, dev->ccm_cfg[i]);//set vfe core clk rate for each sensor!if (get_sensor_info(dev->ccm_cfg[i]->ccm, &sensor_info) == 0){os_clk_set_rate(dev->clock.vfe_core_clk, sensor_info.core_clk_for_sensor);vfe_print("Set vfe core clk = %d, after Set vfe core clk = %ld \n", sensor_info.core_clk_for_sensor, clk_get_rate(dev->clock.vfe_core_clk));}else{os_clk_set_rate(dev->clock.vfe_core_clk, VFE_CORE_CLK_RATE);vfe_warn("Not find this sensor info, Set vfe core clk = %d, after Set vfe core clk = %ld \n", VFE_CORE_CLK_RATE, clk_get_rate(dev->clock.vfe_core_clk));}//alternate isp settingupdate_isp_setting(dev);if (dev->is_bayer_raw){isp_param_init(dev->isp_gen_set_pt);}#ifdef _FLASH_FUNC_if (dev->flash_used == 1){dev->fl_dev_info = &fl_info;dev->fl_dev_info->dev_if = 0;dev->fl_dev_info->en_pol = FLASH_EN_POL;dev->fl_dev_info->fl_mode_pol = FLASH_MODE_POL;dev->fl_dev_info->light_src = 0x01;dev->fl_dev_info->flash_intensity = 400;dev->fl_dev_info->flash_level = 0x01;dev->fl_dev_info->torch_intensity = 200;dev->fl_dev_info->torch_level = 0x01;dev->fl_dev_info->timeout_counter = 300 * 1000;dev->fl_dev_info->flash_driver_ic = dev->flash_type;vfe_print("init flash mode[V4L2_FLASH_LED_MODE_NONE]\n");config_flash_mode(dev->sd, V4L2_FLASH_LED_MODE_FLASH,dev->fl_dev_info);io_set_flash_ctrl(dev->sd, SW_CTRL_FLASH_OFF, dev->fl_dev_info);}
#endif//vfe_mclk_out_set(dev,dev->ccm_info->mclk);/* Initial target device */if (dev->power->stby_mode == NORM_STBY){ret = v4l2_subdev_call(dev->sd, core, s_power, CSI_SUBDEV_STBY_OFF);}else //POWER_OFF{ret = vfe_set_sensor_power_on(dev);
#ifdef USE_SPECIFIC_CCIcsi_cci_init_helper(dev->vip_sel);
#endif}if (ret != 0){vfe_err("sensor standby off error when selecting target device!\n");goto altend;}ret = v4l2_subdev_call(dev->sd, core, init, 0);if (ret != 0){vfe_err("sensor initial error when selecting target device!\n");goto altend;}if (dev->sd_act != NULL){struct actuator_para_t vcm_para;vcm_para.active_min = dev->isp_gen_set_pt->isp_ini_cfg.isp_3a_settings.vcm_min_code;vcm_para.active_max = dev->isp_gen_set_pt->isp_ini_cfg.isp_3a_settings.vcm_max_code;vfe_dbg(0, "min/max=%d/%d \n", dev->isp_gen_set_pt->isp_ini_cfg.isp_3a_settings.vcm_min_code,dev->isp_gen_set_pt->isp_ini_cfg.isp_3a_settings.vcm_max_code);v4l2_subdev_call(dev->sd_act, core, ioctl, ACT_INIT, &vcm_para);}bsp_csi_disable(dev->vip_sel);if (dev->is_isp_used){vfe_ctrl_para_reset(dev);bsp_isp_disable();bsp_isp_enable();bsp_isp_init(&dev->isp_init_para);/* Set the initial flip */if (dev->ctrl_para.vflip == 0){bsp_isp_flip_disable(MAIN_CH);bsp_isp_flip_disable(SUB_CH);}else{bsp_isp_flip_enable(MAIN_CH);bsp_isp_flip_enable(SUB_CH);}if (dev->ctrl_para.hflip == 0){bsp_isp_mirror_disable(MAIN_CH);bsp_isp_mirror_disable(SUB_CH);}else{bsp_isp_mirror_enable(MAIN_CH);bsp_isp_mirror_enable(SUB_CH);}}else{bsp_isp_exit();/* Set the initial flip */ctrl.id = V4L2_CID_VFLIP;ctrl.value = dev->ctrl_para.vflip;ret = v4l2_subdev_call(dev->sd, core, s_ctrl, &ctrl);if (ret != 0){vfe_err("sensor sensor_s_ctrl V4L2_CID_VFLIP error when vidioc_s_input!input_num = %d\n", i);}ctrl.id = V4L2_CID_HFLIP;ctrl.value = dev->ctrl_para.hflip;ret = v4l2_subdev_call(dev->sd, core, s_ctrl, &ctrl);if (ret != 0){vfe_err("sensor sensor_s_ctrl V4L2_CID_HFLIP error when vidioc_s_input!input_num = %d\n", i);}}ret = 0;
altend:dev->vfe_s_input_flag = 1;return ret;
}static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
{struct vfe_dev *dev = video_drvdata(file);int ret;vfe_dbg(0, "%s ,input_num = %d\n", __func__, i);ret = internal_s_input(dev, i);//up(&dev->standby_seq_sema);return ret;
}static enum power_line_frequency v4l2_bf_to_common(enum v4l2_power_line_frequency band_stop_mode)
{return band_stop_mode;
}static enum colorfx v4l2_colorfx_to_common(enum v4l2_colorfx colorfx)
{return colorfx;
}static enum exposure_mode v4l2_ae_mode_to_common(enum v4l2_exposure_auto_type ae_mode)
{switch (ae_mode){case V4L2_EXPOSURE_AUTO:case V4L2_EXPOSURE_SHUTTER_PRIORITY:case V4L2_EXPOSURE_APERTURE_PRIORITY:return EXP_AUTO;case V4L2_EXPOSURE_MANUAL:return EXP_MANUAL;default:return EXP_AUTO;}
}static enum white_balance_mode v4l2_wb_preset_to_common(enum v4l2_auto_n_preset_white_balance wb_preset)
{return wb_preset;
}static enum iso_mode v4l2_iso_mode_to_common(enum v4l2_iso_sensitivity_auto_type iso_mode)
{return iso_mode;
}static enum scene_mode v4l2_scene_to_common(enum v4l2_scene_mode scene_mode)
{return scene_mode;
}static enum auto_focus_range v4l2_af_range_to_common(enum v4l2_auto_focus_range af_range)
{return af_range;
}static enum flash_mode v4l2_flash_mode_to_common(enum v4l2_flash_led_mode flash_mode)
{return flash_mode;
}static int vidioc_queryctrl(struct file *file, void *priv,struct v4l2_queryctrl *qc)
{struct vfe_dev *dev = video_drvdata(file);int ret;if (dev->is_isp_used && dev->is_bayer_raw){/* Fill in min, max, step and default value for these controls. *//* see include/linux/videodev2.h for details *//* see sensor_s_parm and sensor_g_parm for the meaning of value */switch (qc->id){//V4L2_CID_BASEcase V4L2_CID_BRIGHTNESS:return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);case V4L2_CID_CONTRAST:return v4l2_ctrl_query_fill(qc, 0, 128, 1, 0);case V4L2_CID_SATURATION:return v4l2_ctrl_query_fill(qc, -4, 4, 1, 0);case V4L2_CID_HUE:return v4l2_ctrl_query_fill(qc, -180, 180, 1, 0);case V4L2_CID_AUTO_WHITE_BALANCE:return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);case V4L2_CID_EXPOSURE:return v4l2_ctrl_query_fill(qc, 0, 65536 * 16, 1, 0);case V4L2_CID_HOR_VISUAL_ANGLE:return v4l2_ctrl_query_fill(qc, 0, 360, 1, 60);case V4L2_CID_VER_VISUAL_ANGLE:return v4l2_ctrl_query_fill(qc, 0, 360, 1, 60);case V4L2_CID_FOCUS_LENGTH:return v4l2_ctrl_query_fill(qc, 0, 1000, 1, 280);case V4L2_CID_R_GAIN:return v4l2_ctrl_query_fill(qc, 32, 1024, 1, 256);case V4L2_CID_G_GAIN:return v4l2_ctrl_query_fill(qc, 32, 1024, 1, 256);case V4L2_CID_B_GAIN:return v4l2_ctrl_query_fill(qc, 32, 1024, 1, 256);case V4L2_CID_AUTOGAIN:return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);case V4L2_CID_GAIN:return v4l2_ctrl_query_fill(qc, 0, 0x7fffffff, 1, 0);case V4L2_CID_VFLIP:ret = v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);qc->default_value = dev->ctrl_para.vflip;return ret;case V4L2_CID_HFLIP:ret = v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);qc->default_value = dev->ctrl_para.hflip;return ret;case V4L2_CID_POWER_LINE_FREQUENCY:return v4l2_ctrl_query_fill(qc, 0, 3, 1, 3);case V4L2_CID_HUE_AUTO:return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);case V4L2_CID_WHITE_BALANCE_TEMPERATURE:return v4l2_ctrl_query_fill(qc, 2800, 10000, 1, 6500);case V4L2_CID_SHARPNESS:return v4l2_ctrl_query_fill(qc, -32, 32, 1, 0);case V4L2_CID_CHROMA_AGC:return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);case V4L2_CID_COLORFX:return v4l2_ctrl_query_fill(qc, 0, 15, 1, 0);case V4L2_CID_AUTOBRIGHTNESS:return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);case V4L2_CID_BAND_STOP_FILTER:return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);case V4L2_CID_ILLUMINATORS_1:case V4L2_CID_ILLUMINATORS_2:return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);//V4L2_CID_CAMERA_CLASS_BASEcase V4L2_CID_EXPOSURE_AUTO:return v4l2_ctrl_query_fill(qc, 0, 3, 1, 0);case V4L2_CID_EXPOSURE_ABSOLUTE:return v4l2_ctrl_query_fill(qc, 1, 1000000, 1, 1);case V4L2_CID_EXPOSURE_AUTO_PRIORITY:return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);case V4L2_CID_FOCUS_ABSOLUTE:return v4l2_ctrl_query_fill(qc, 0, 127, 1, 0);case V4L2_CID_FOCUS_RELATIVE:return v4l2_ctrl_query_fill(qc, -127, 127, 1, 0);case V4L2_CID_FOCUS_AUTO:return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);case V4L2_CID_AUTO_EXPOSURE_BIAS:return v4l2_ctrl_query_fill(qc, -4, 4, 1, 0);case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE:return v4l2_ctrl_query_fill(qc, 0, 10, 1, 1);case V4L2_CID_WIDE_DYNAMIC_RANGE:return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);case V4L2_CID_IMAGE_STABILIZATION:return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);case V4L2_CID_ISO_SENSITIVITY:return v4l2_ctrl_query_fill(qc, 500, 16000, 100, 1000);case V4L2_CID_ISO_SENSITIVITY_AUTO:return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);case V4L2_CID_EXPOSURE_METERING:return -EINVAL;case V4L2_CID_SCENE_MODE:return v4l2_ctrl_query_fill(qc, 0, 13, 1, 0);case V4L2_CID_3A_LOCK:return v4l2_ctrl_query_fill(qc, 0, 4, 1, 0);case V4L2_CID_AUTO_FOCUS_START:return v4l2_ctrl_query_fill(qc, 0, 0, 0, 0);case V4L2_CID_AUTO_FOCUS_STOP:return v4l2_ctrl_query_fill(qc, 0, 0, 0, 0);case V4L2_CID_AUTO_FOCUS_STATUS: //Read-Onlyreturn v4l2_ctrl_query_fill(qc, 0, 0, 0, 0);case V4L2_CID_AUTO_FOCUS_RANGE:return v4l2_ctrl_query_fill(qc, 0, 3, 1, 0);//V4L2_CID_FLASH_CLASS_BASEcase V4L2_CID_FLASH_LED_MODE:return v4l2_ctrl_query_fill(qc, 0, 4, 1, 0);//V4L2_CID_PRIVATE_BASEcase V4L2_CID_HFLIP_THUMB:ret = v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);qc->default_value = dev->ctrl_para.hflip_thumb;return ret;case V4L2_CID_VFLIP_THUMB:ret = v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);qc->default_value = dev->ctrl_para.vflip_thumb;return ret;case V4L2_CID_AUTO_FOCUS_WIN_NUM:return v4l2_ctrl_query_fill(qc, 0, 10, 1, 0);case V4L2_CID_AUTO_FOCUS_INIT:case V4L2_CID_AUTO_FOCUS_RELEASE:return v4l2_ctrl_query_fill(qc, 0, 0, 0, 0);case V4L2_CID_AUTO_EXPOSURE_WIN_NUM:return v4l2_ctrl_query_fill(qc, 0, 10, 1, 0);case V4L2_CID_GSENSOR_ROTATION:return v4l2_ctrl_query_fill(qc, -180, 180, 90, 0);case V4L2_CID_TAKE_PICTURE:return v4l2_ctrl_query_fill(qc, 0, 16, 1, 1);case V4L2_CID_HDR:return v4l2_ctrl_query_fill(qc, 0, 10, 1, 0);case V4L2_CID_SENSOR_TYPE:return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);}return -EINVAL;}else{if (qc->id == V4L2_CID_FOCUS_ABSOLUTE){ //TODO!return v4l2_ctrl_query_fill(qc, 0, 127, 1, 0);}else if (qc->id == V4L2_CID_SENSOR_TYPE){return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);}ret = v4l2_subdev_call(dev->sd, core, queryctrl, qc);if (ret < 0){if (qc->id != V4L2_CID_GAIN){vfe_warn("v4l2 sub device queryctrl unsuccess,id = %x!\n", qc->id);}}}return ret;
}static int vidioc_g_ctrl(struct file *file, void *priv,struct v4l2_control *ctrl)
{struct vfe_dev *dev = video_drvdata(file);struct v4l2_queryctrl qc;int ret;unsigned int i;qc.id = ctrl->id;ret = vidioc_queryctrl(file, priv, &qc);if (ret < 0){return ret;}if (dev->is_isp_used && dev->is_bayer_raw){switch (ctrl->id){//V4L2_CID_BASEcase V4L2_CID_BRIGHTNESS:ctrl->value = dev->isp_gen_set_pt->ae_lum / 100;break;case V4L2_CID_CONTRAST:ctrl->value = dev->ctrl_para.contrast;break;case V4L2_CID_SATURATION:ctrl->value = dev->ctrl_para.saturation;break;case V4L2_CID_HUE:ctrl->value = dev->ctrl_para.hue;break;case V4L2_CID_HOR_VISUAL_ANGLE:ctrl->value = dev->isp_gen_set_pt->isp_ini_cfg.isp_tunning_settings.hor_visual_angle;break;case V4L2_CID_VER_VISUAL_ANGLE:ctrl->value = dev->isp_gen_set_pt->isp_ini_cfg.isp_tunning_settings.ver_visual_angle;break;case V4L2_CID_FOCUS_LENGTH:ctrl->value = dev->isp_gen_set_pt->isp_ini_cfg.isp_tunning_settings.focus_length;break;case V4L2_CID_AUTO_WHITE_BALANCE:ctrl->value = dev->ctrl_para.auto_wb;break;case V4L2_CID_EXPOSURE:ctrl->value = dev->isp_3a_result_pt->exp_line_num;break;case V4L2_CID_AUTOGAIN:ctrl->value = dev->ctrl_para.auto_gain;break;case V4L2_CID_GAIN:if (dev->isp_gen_set_pt->isp_ini_cfg.isp_test_settings.isp_test_mode == ISP_TEST_ALL_ENABLE ||dev->isp_gen_set_pt->isp_ini_cfg.isp_test_settings.isp_test_mode == ISP_TEST_MANUAL){ctrl->value = CLIP(CLIP(dev->isp_3a_result_pt->exp_analog_gain, 16, 255) |(CLIP(dev->isp_gen_set_pt->sharp_cfg_to_hal[1], 0, 4095) /*level*/ << V4L2_SHARP_LEVEL_SHIFT) |(CLIP(dev->isp_gen_set_pt->sharp_cfg_to_hal[0], 0, 63) /*min*/ << V4L2_SHARP_MIN_SHIFT) |(CLIP(dev->isp_gen_set_pt->isp_ini_cfg.isp_tunning_settings.color_denoise_level, 0, 31) << V4L2_NDF_SHIFT),0, 0xffffffff);}else{ctrl->value = CLIP(dev->isp_3a_result_pt->exp_analog_gain, 16, 255);}break;case V4L2_CID_R_GAIN:ctrl->value = dev->isp_gen_set_pt->module_cfg.wb_gain_cfg.wb_gain.r_gain;break;case V4L2_CID_G_GAIN:ctrl->value = dev->isp_gen_set_pt->module_cfg.wb_gain_cfg.wb_gain.gr_gain;break;case V4L2_CID_B_GAIN:ctrl->value = dev->isp_gen_set_pt->module_cfg.wb_gain_cfg.wb_gain.b_gain;break;case V4L2_CID_HFLIP:ctrl->value = dev->ctrl_para.hflip;break;case V4L2_CID_VFLIP:ctrl->value = dev->ctrl_para.vflip;break;case V4L2_CID_POWER_LINE_FREQUENCY:ctrl->value = dev->ctrl_para.band_stop_mode;break;case V4L2_CID_HUE_AUTO:ctrl->value = dev->ctrl_para.auto_hue;break;case V4L2_CID_WHITE_BALANCE_TEMPERATURE:ctrl->value = dev->ctrl_para.wb_temperature;break;case V4L2_CID_SHARPNESS:ctrl->value = dev->ctrl_para.sharpness;break;case V4L2_CID_CHROMA_AGC:ctrl->value = dev->ctrl_para.chroma_agc;break;case V4L2_CID_COLORFX:ctrl->value = dev->ctrl_para.colorfx;break;case V4L2_CID_AUTOBRIGHTNESS:ctrl->value = dev->ctrl_para.auto_brightness;break;case V4L2_CID_BAND_STOP_FILTER:ctrl->value = dev->ctrl_para.band_stop_filter;break;case V4L2_CID_ILLUMINATORS_1:ctrl->value = dev->ctrl_para.illuminator1;break;case V4L2_CID_ILLUMINATORS_2:ctrl->value = dev->ctrl_para.illuminator2;break;//V4L2_CID_CAMERA_CLASS_BASEcase V4L2_CID_EXPOSURE_AUTO:ctrl->value = dev->ctrl_para.exp_auto_mode;break;case V4L2_CID_EXPOSURE_ABSOLUTE:ctrl->value = dev->isp_3a_result_pt->exp_time;break;case V4L2_CID_EXPOSURE_AUTO_PRIORITY:ctrl->value = dev->ctrl_para.exp_auto_pri;break;case V4L2_CID_FOCUS_ABSOLUTE:ctrl->value = dev->ctrl_para.focus_abs;break;case V4L2_CID_FOCUS_RELATIVE:ctrl->value = dev->ctrl_para.focus_rel;break;case V4L2_CID_FOCUS_AUTO:ctrl->value = dev->ctrl_para.auto_focus;break;case V4L2_CID_AUTO_EXPOSURE_BIAS:ctrl->value = dev->ctrl_para.exp_bias;break;case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE:ctrl->value = dev->ctrl_para.wb_preset;break;case V4L2_CID_WIDE_DYNAMIC_RANGE:ctrl->value = dev->ctrl_para.wdr;break;case V4L2_CID_IMAGE_STABILIZATION:ctrl->value = dev->ctrl_para.image_stabl;break;case V4L2_CID_ISO_SENSITIVITY:ctrl->value = dev->ctrl_para.iso;break;case V4L2_CID_ISO_SENSITIVITY_AUTO:ctrl->value = dev->ctrl_para.iso_mode;break;case V4L2_CID_EXPOSURE_METERING:return -EINVAL;case V4L2_CID_SCENE_MODE:ctrl->value = dev->ctrl_para.scene_mode;break;case V4L2_CID_3A_LOCK:if (dev->isp_gen_set_pt->exp_settings.exposure_lock == ISP_TRUE){dev->ctrl_para.ae_lock = 1;ctrl->value |= V4L2_LOCK_EXPOSURE;}else{dev->ctrl_para.ae_lock = 0;ctrl->value &= ~V4L2_LOCK_EXPOSURE;}if (dev->isp_gen_set_pt->wb_settings.white_balance_lock == ISP_TRUE){dev->ctrl_para.awb_lock = 1;ctrl->value |= V4L2_LOCK_WHITE_BALANCE;}else{dev->ctrl_para.awb_lock = 0;ctrl->value &= ~V4L2_LOCK_WHITE_BALANCE;}if (dev->isp_gen_set_pt->af_settings.focus_lock == ISP_TRUE){dev->ctrl_para.af_lock = 1;ctrl->value |= V4L2_LOCK_FOCUS;}else{dev->ctrl_para.af_lock = 0;ctrl->value &= ~V4L2_LOCK_FOCUS;}break;case V4L2_CID_AUTO_FOCUS_START: //write-onlyreturn -EINVAL;case V4L2_CID_AUTO_FOCUS_STOP: //write-onlyreturn -EINVAL;case V4L2_CID_AUTO_FOCUS_STATUS: //Read-Only//TODOret = common_af_status_to_v4l2(dev->isp_3a_result_pt->af_status);return ret;break;case V4L2_CID_AUTO_FOCUS_RANGE:ctrl->value = dev->ctrl_para.af_range;break;//V4L2_CID_FLASH_CLASS_BASEcase V4L2_CID_FLASH_LED_MODE:ctrl->value = dev->ctrl_para.flash_mode;break;//V4L2_CID_PRIVATE_BASEcase V4L2_CID_HFLIP_THUMB:ctrl->value = dev->ctrl_para.hflip_thumb;break;case V4L2_CID_VFLIP_THUMB:ctrl->value = dev->ctrl_para.vflip_thumb;break;case V4L2_CID_AUTO_FOCUS_WIN_NUM:if (ctrl->value > MAX_AF_WIN_NUM || ctrl->value == 0){return -EINVAL;}else{struct v4l2_win_coordinate *win_coor = (struct v4l2_win_coordinate *)(ctrl->user_pt);for (i = 0; i < ctrl->value; i++){win_coor[i].x1 = dev->ctrl_para.af_coor[i].x1;win_coor[i].y1 = dev->ctrl_para.af_coor[i].y1;win_coor[i].x2 = dev->ctrl_para.af_coor[i].x2;win_coor[i].y2 = dev->ctrl_para.af_coor[i].y2;}}ctrl->value = dev->ctrl_para.af_win_num;break;case V4L2_CID_AUTO_FOCUS_INIT:return 0;case V4L2_CID_AUTO_FOCUS_RELEASE:return 0;case V4L2_CID_AUTO_EXPOSURE_WIN_NUM:if (ctrl->value > MAX_AE_WIN_NUM || ctrl->value == 0){return -EINVAL;}else{struct v4l2_win_coordinate *win_coor = (struct v4l2_win_coordinate *)(ctrl->user_pt);for (i = 0; i < ctrl->value; i++){win_coor[i].x1 = dev->ctrl_para.ae_coor[i].x1;win_coor[i].y1 = dev->ctrl_para.ae_coor[i].y1;win_coor[i].x2 = dev->ctrl_para.ae_coor[i].x2;win_coor[i].y2 = dev->ctrl_para.ae_coor[i].y2;}}ctrl->value = dev->ctrl_para.ae_win_num;break;case V4L2_CID_GSENSOR_ROTATION:ctrl->value = dev->ctrl_para.gsensor_rot;break;case V4L2_CID_TAKE_PICTURE: //write-onlyreturn -EINVAL;case V4L2_CID_HDR:{struct isp_hdr_setting_t hdr_setting;ctrl->value = dev->isp_gen_set_pt->hdr_setting.frames_count - 1;memcpy(&hdr_setting, &dev->isp_gen_set_pt->hdr_setting, sizeof(struct isp_hdr_setting_t));ctrl->user_pt = (unsigned int)&hdr_setting;break;}case V4L2_CID_SENSOR_TYPE:ctrl->value = dev->is_bayer_raw;break;default:return -EINVAL;}return 0;}else{if (V4L2_CID_SENSOR_TYPE == ctrl->id){ctrl->value = dev->is_bayer_raw;}else{ret = v4l2_subdev_call(dev->sd, core, g_ctrl, ctrl);if (ret < 0)vfe_warn("v4l2 sub device g_ctrl error!\n");}}return ret;
}static int vidioc_s_ctrl(struct file *file, void *priv,struct v4l2_control *ctrl)
{struct vfe_dev *dev = video_drvdata(file);struct v4l2_queryctrl qc;unsigned int i;int ret;//TO DO!struct actuator_ctrl_word_t vcm_ctrl;qc.id = ctrl->id;ret = vidioc_queryctrl(file, priv, &qc);//printk("vidioc_queryctrl!\n ret = %d",ret);if (ret < 0)return ret;if (qc.type == V4L2_CTRL_TYPE_MENU || qc.type == V4L2_CTRL_TYPE_INTEGER || qc.type == V4L2_CTRL_TYPE_BOOLEAN){if (ctrl->value < qc.minimum || ctrl->value > qc.maximum){vfe_warn("value: %d, min: %d, max: %d\n ", ctrl->value, qc.minimum, qc.maximum);return -ERANGE;}}if (dev->is_isp_used && dev->is_bayer_raw){vfe_dbg(0, "s_ctrl: %s, value: 0x%x\n", v4l2_ctrl_get_name(ctrl->id), ctrl->value);switch (ctrl->id){//V4L2_CID_BASEcase V4L2_CID_BRIGHTNESS:bsp_isp_s_brightness(dev->isp_gen_set_pt, ctrl->value);dev->ctrl_para.brightness = ctrl->value;break;case V4L2_CID_CONTRAST:bsp_isp_s_contrast(dev->isp_gen_set_pt, ctrl->value);dev->ctrl_para.contrast = ctrl->value;break;case V4L2_CID_SATURATION:bsp_isp_s_saturation(dev->isp_gen_set_pt, ctrl->value * 25);dev->ctrl_para.saturation = ctrl->value;break;case V4L2_CID_HUE:bsp_isp_s_hue(dev->isp_gen_set_pt, ctrl->value);dev->ctrl_para.hue = ctrl->value;break;case V4L2_CID_AUTO_WHITE_BALANCE:if (ctrl->value == 0)bsp_isp_s_auto_white_balance(dev->isp_gen_set_pt, WB_MANUAL);elsebsp_isp_s_auto_white_balance(dev->isp_gen_set_pt, WB_AUTO);dev->ctrl_para.auto_wb = ctrl->value;break;case V4L2_CID_EXPOSURE:return v4l2_subdev_call(dev->sd, core, s_ctrl, ctrl);case V4L2_CID_AUTOGAIN:if (ctrl->value == 0)bsp_isp_s_exposure(dev->isp_gen_set_pt, ISO_MANUAL);elsebsp_isp_s_exposure(dev->isp_gen_set_pt, ISO_AUTO);dev->ctrl_para.auto_gain = ctrl->value;break;case V4L2_CID_GAIN:return v4l2_subdev_call(dev->sd, core, s_ctrl, ctrl);case V4L2_CID_HFLIP:if (ctrl->value == 0)bsp_isp_mirror_disable(MAIN_CH);elsebsp_isp_mirror_enable(MAIN_CH);dev->ctrl_para.hflip = ctrl->value;break;case V4L2_CID_VFLIP:if (ctrl->value == 0)bsp_isp_flip_disable(MAIN_CH);elsebsp_isp_flip_enable(MAIN_CH);dev->ctrl_para.vflip = ctrl->value;break;case V4L2_CID_POWER_LINE_FREQUENCY:bsp_isp_s_power_line_frequency(dev->isp_gen_set_pt, v4l2_bf_to_common(ctrl->value));dev->ctrl_para.band_stop_mode = ctrl->value;break;case V4L2_CID_HUE_AUTO:bsp_isp_s_hue_auto(dev->isp_gen_set_pt, ctrl->value);dev->ctrl_para.auto_hue = ctrl->value;break;case V4L2_CID_WHITE_BALANCE_TEMPERATURE:bsp_isp_s_white_balance_temperature(dev->isp_gen_set_pt, ctrl->value);dev->ctrl_para.wb_temperature = ctrl->value;break;case V4L2_CID_SHARPNESS:bsp_isp_s_sharpness(dev->isp_gen_set_pt, ctrl->value);dev->ctrl_para.sharpness = ctrl->value;break;case V4L2_CID_CHROMA_AGC:bsp_isp_s_chroma_agc(dev->isp_gen_set_pt, ctrl->value);dev->ctrl_para.chroma_agc = ctrl->value;break;case V4L2_CID_COLORFX:bsp_isp_s_colorfx(dev->isp_gen_set_pt, v4l2_colorfx_to_common(ctrl->value));dev->ctrl_para.colorfx = ctrl->value;break;case V4L2_CID_AUTOBRIGHTNESS:bsp_isp_s_auto_brightness(dev->isp_gen_set_pt, ctrl->value);dev->ctrl_para.auto_brightness = ctrl->value;break;case V4L2_CID_BAND_STOP_FILTER:bsp_isp_s_band_stop_filter(dev->isp_gen_set_pt, ctrl->value);dev->ctrl_para.band_stop_filter = ctrl->value;break;case V4L2_CID_ILLUMINATORS_1:bsp_isp_s_illuminators_1(dev->isp_gen_set_pt, ctrl->value);dev->ctrl_para.illuminator1 = ctrl->value;break;case V4L2_CID_ILLUMINATORS_2:bsp_isp_s_illuminators_2(dev->isp_gen_set_pt, ctrl->value);dev->ctrl_para.illuminator2 = ctrl->value;break;//V4L2_CID_CAMERA_CLASS_BASEcase V4L2_CID_EXPOSURE_AUTO:bsp_isp_s_exposure_auto(dev->isp_gen_set_pt, v4l2_ae_mode_to_common(ctrl->value));dev->ctrl_para.exp_auto_mode = ctrl->value;break;case V4L2_CID_EXPOSURE_ABSOLUTE:bsp_isp_s_exposure_absolute(dev->isp_gen_set_pt, ctrl->value);dev->ctrl_para.exp_abs = ctrl->value;break;case V4L2_CID_EXPOSURE_AUTO_PRIORITY:bsp_isp_s_exposure_auto_priority(dev->isp_gen_set_pt, ctrl->value);dev->ctrl_para.exp_auto_pri = ctrl->value;break;case V4L2_CID_FOCUS_ABSOLUTE:bsp_isp_s_focus_absolute(dev->isp_gen_set_pt, ctrl->value);dev->ctrl_para.focus_abs = ctrl->value;break;case V4L2_CID_FOCUS_RELATIVE:bsp_isp_s_focus_relative(dev->isp_gen_set_pt, ctrl->value);dev->ctrl_para.focus_rel = ctrl->value;break;case V4L2_CID_FOCUS_AUTO://printk("set V4L2_CID_FOCUS_AUTO ctrl->value = %d!\n",ctrl->value);dev->isp_3a_result_pt->af_status = AUTO_FOCUS_STATUS_REFOCUS;bsp_isp_s_focus_auto(dev->isp_gen_set_pt, ctrl->value);dev->ctrl_para.auto_focus = ctrl->value;break;case V4L2_CID_AUTO_EXPOSURE_BIAS:bsp_isp_s_auto_exposure_bias(dev->isp_gen_set_pt, ctrl->value);//printk("ctrl->value=%d\n",ctrl->value);dev->ctrl_para.exp_bias = ctrl->value;break;case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE:bsp_isp_s_auto_n_preset_white_balance(dev->isp_gen_set_pt, v4l2_wb_preset_to_common(ctrl->value));dev->ctrl_para.wb_preset = ctrl->value;break;case V4L2_CID_WIDE_DYNAMIC_RANGE:bsp_isp_s_wide_dynamic_rage(dev->isp_gen_set_pt, ctrl->value);dev->ctrl_para.wdr = ctrl->value;break;case V4L2_CID_IMAGE_STABILIZATION:bsp_isp_s_image_stabilization(dev->isp_gen_set_pt, ctrl->value);dev->ctrl_para.image_stabl = ctrl->value;break;case V4L2_CID_ISO_SENSITIVITY:bsp_isp_s_iso_sensitivity(dev->isp_gen_set_pt, ctrl->value);dev->ctrl_para.iso = ctrl->value;break;case V4L2_CID_ISO_SENSITIVITY_AUTO:bsp_isp_s_iso_sensitivity_auto(dev->isp_gen_set_pt, v4l2_iso_mode_to_common(ctrl->value));dev->ctrl_para.iso_mode = ctrl->value;break;case V4L2_CID_EXPOSURE_METERING:return -EINVAL;case V4L2_CID_SCENE_MODE:bsp_isp_s_scene_mode(dev->isp_gen_set_pt, v4l2_scene_to_common(ctrl->value));dev->ctrl_para.scene_mode = ctrl->value;break;case V4L2_CID_3A_LOCK://printk("V4L2_CID_3A_LOCK = %x!\n",ctrl->value);if (dev->ctrl_para.exp_auto_mode != V4L2_EXPOSURE_MANUAL){if (IS_FLAG(ctrl->value, V4L2_LOCK_EXPOSURE)){dev->isp_gen_set_pt->exp_settings.exposure_lock = ISP_TRUE;dev->ctrl_para.ae_lock = 1;}else{dev->isp_gen_set_pt->exp_settings.exposure_lock = ISP_FALSE;dev->ctrl_para.ae_lock = 0;}}if (dev->ctrl_para.auto_wb == 1){if (IS_FLAG(ctrl->value, V4L2_LOCK_WHITE_BALANCE)){dev->isp_gen_set_pt->wb_settings.white_balance_lock = ISP_TRUE;dev->ctrl_para.awb_lock = 1;}else{dev->isp_gen_set_pt->wb_settings.white_balance_lock = ISP_FALSE;dev->ctrl_para.awb_lock = 0;}}if (dev->ctrl_para.auto_focus == 1){//printk("V4L2_CID_3A_LOCK AF!\n");if (IS_FLAG(ctrl->value, V4L2_LOCK_FOCUS)){dev->isp_gen_set_pt->af_settings.focus_lock = ISP_TRUE;dev->ctrl_para.af_lock = 1;}else{dev->isp_gen_set_pt->af_settings.focus_lock = ISP_FALSE;dev->ctrl_para.af_lock = 0;}}break;case V4L2_CID_AUTO_FOCUS_START:dev->isp_3a_result_pt->af_status = AUTO_FOCUS_STATUS_REFOCUS;bsp_isp_s_auto_focus_start(dev->isp_gen_set_pt, ctrl->value);
#ifdef _FLASH_FUNC_isp_s_ctrl_torch_open(dev);
#endifbreak;case V4L2_CID_AUTO_FOCUS_STOP://if(dev->ctrl_para.auto_focus == 0)vfe_dbg(0, "V4L2_CID_AUTO_FOCUS_STOP\n");bsp_isp_s_auto_focus_stop(dev->isp_gen_set_pt, ctrl->value);
#ifdef _FLASH_FUNC_isp_s_ctrl_torch_close(dev);
#endifbreak;case V4L2_CID_AUTO_FOCUS_STATUS: //Read-Onlyreturn -EINVAL;case V4L2_CID_AUTO_FOCUS_RANGE:bsp_isp_s_auto_focus_range(dev->isp_gen_set_pt, v4l2_af_range_to_common(ctrl->value));dev->ctrl_para.af_range = ctrl->value;break;//V4L2_CID_FLASH_CLASS_BASEcase V4L2_CID_FLASH_LED_MODE:bsp_isp_s_flash_mode(dev->isp_gen_set_pt, v4l2_flash_mode_to_common(ctrl->value));dev->ctrl_para.flash_mode = ctrl->value;if (ctrl->value == V4L2_FLASH_LED_MODE_TORCH){io_set_flash_ctrl(dev->sd, SW_CTRL_TORCH_ON, dev->fl_dev_info);}else if (ctrl->value == V4L2_FLASH_LED_MODE_NONE){io_set_flash_ctrl(dev->sd, SW_CTRL_FLASH_OFF, dev->fl_dev_info);}break;//V4L2_CID_PRIVATE_BASEcase V4L2_CID_HFLIP_THUMB:if (ctrl->value == 0)bsp_isp_mirror_disable(SUB_CH);elsebsp_isp_mirror_enable(SUB_CH);dev->ctrl_para.hflip_thumb = ctrl->value;break;case V4L2_CID_VFLIP_THUMB:if (ctrl->value == 0)bsp_isp_flip_disable(SUB_CH);elsebsp_isp_flip_enable(SUB_CH);dev->ctrl_para.vflip_thumb = ctrl->value;break;case V4L2_CID_AUTO_FOCUS_WIN_NUM:if (ctrl->value == 0){bsp_isp_s_auto_focus_win_num(dev->isp_gen_set_pt, AF_AUTO_WIN, NULL);}else if (ctrl->value > MAX_AF_WIN_NUM){return -EINVAL;}else{struct v4l2_win_coordinate *win_coor = (struct v4l2_win_coordinate *)(ctrl->user_pt);for (i = 0; i < ctrl->value; i++){if (dev->ctrl_para.vflip == 1){dev->ctrl_para.af_coor[i].y1 = -win_coor[0].y1;dev->ctrl_para.af_coor[i].y2 = -win_coor[0].y2;}else{dev->ctrl_para.af_coor[i].y1 = win_coor[i].y1;dev->ctrl_para.af_coor[i].y2 = win_coor[i].y2;}if (dev->ctrl_para.hflip == 1){dev->ctrl_para.af_coor[i].x1 = -win_coor[0].x1;dev->ctrl_para.af_coor[i].x2 = -win_coor[0].x2;}else{dev->ctrl_para.af_coor[i].x1 = win_coor[0].x1;dev->ctrl_para.af_coor[i].x2 = win_coor[0].x2;}}bsp_isp_s_auto_focus_win_num(dev->isp_gen_set_pt, AF_NUM_WIN, &dev->ctrl_para.af_coor[0]);}dev->ctrl_para.af_win_num = ctrl->value;break;case V4L2_CID_AUTO_FOCUS_INIT:return 0;case V4L2_CID_AUTO_FOCUS_RELEASE:return 0;case V4L2_CID_AUTO_EXPOSURE_WIN_NUM:if (ctrl->value == 0){bsp_isp_s_auto_exposure_win_num(dev->isp_gen_set_pt, AE_AUTO_WIN, NULL);}else if (ctrl->value > MAX_AE_WIN_NUM){return -EINVAL;}else{struct v4l2_win_coordinate *win_coor = (struct v4l2_win_coordinate *)(ctrl->user_pt);for (i = 0; i < ctrl->value; i++){if (dev->ctrl_para.vflip == 1){dev->ctrl_para.ae_coor[i].y1 = -win_coor[0].y1;dev->ctrl_para.ae_coor[i].y2 = -win_coor[0].y2;}else{dev->ctrl_para.ae_coor[i].y1 = win_coor[i].y1;dev->ctrl_para.ae_coor[i].y2 = win_coor[i].y2;}if (dev->ctrl_para.hflip == 1){dev->ctrl_para.ae_coor[i].x1 = -win_coor[0].x1;dev->ctrl_para.ae_coor[i].x2 = -win_coor[0].x2;}else{dev->ctrl_para.ae_coor[i].x1 = win_coor[0].x1;dev->ctrl_para.ae_coor[i].x2 = win_coor[0].x2;}//printk("V4L2_CID_AUTO_EXPOSURE_WIN_NUM, [%d, %d, %d, %d]\n", win_coor[i].x1, win_coor[i].y1, win_coor[i].x2, win_coor[i].y2);}//TODOdev->isp_gen_set_pt->win.hist_coor.x1 = win_coor[0].x1;dev->isp_gen_set_pt->win.hist_coor.y1 = win_coor[0].y1;dev->isp_gen_set_pt->win.hist_coor.x2 = win_coor[0].x2;dev->isp_gen_set_pt->win.hist_coor.y2 = win_coor[0].y2;bsp_isp_s_auto_exposure_win_num(dev->isp_gen_set_pt, AE_SINGLE_WIN, &dev->ctrl_para.ae_coor[0]);}dev->ctrl_para.ae_win_num = ctrl->value;/**/break;case V4L2_CID_GSENSOR_ROTATION:bsp_isp_s_gsensor_rotation(dev->isp_gen_set_pt, ctrl->value);dev->ctrl_para.gsensor_rot = ctrl->value;break;case V4L2_CID_TAKE_PICTURE:bsp_isp_s_take_pic(dev->isp_gen_set_pt, ctrl->value);break;case V4L2_CID_HDR://struct isp_hdr_setting_t hdr;bsp_isp_s_hdr(dev->isp_gen_set_pt, (struct hdr_setting_t *)(ctrl->user_pt));dev->isp_3a_result_pt->image_quality.bits.hdr_cnt = 0;break;case V4L2_CID_R_GAIN:bsp_isp_s_r_gain(dev->isp_gen_set_pt, ctrl->value);break;case V4L2_CID_G_GAIN:bsp_isp_s_g_gain(dev->isp_gen_set_pt, ctrl->value);break;case V4L2_CID_B_GAIN:bsp_isp_s_b_gain(dev->isp_gen_set_pt, ctrl->value);break;default:return -EINVAL;}return 0;}else{if (ctrl->id == V4L2_CID_FOCUS_ABSOLUTE){//TO DO !vcm_ctrl.code = ctrl->value;vcm_ctrl.sr = 0x0;//printk("ACT_SET_CODE start code = %d!\n",vcm_ctrl.code);v4l2_subdev_call(dev->sd_act, core, ioctl, ACT_SET_CODE, &vcm_ctrl);}ret = v4l2_subdev_call(dev->sd, core, s_ctrl, ctrl);if (ret < 0){vfe_warn("v4l2 sub device s_ctrl fail!\n");}}return ret;
}static int vidioc_g_parm(struct file *file, void *priv,struct v4l2_streamparm *parms)
{struct vfe_dev *dev = video_drvdata(file);int ret;ret = v4l2_subdev_call(dev->sd, video, g_parm, parms);if (ret < 0)vfe_warn("v4l2 sub device g_parm fail!\n");return ret;
}static int vidioc_s_parm(struct file *file, void *priv,struct v4l2_streamparm *parms)
{struct vfe_dev *dev = video_drvdata(file);int ret;if (parms->parm.capture.capturemode != V4L2_MODE_VIDEO &&parms->parm.capture.capturemode != V4L2_MODE_IMAGE &&parms->parm.capture.capturemode != V4L2_MODE_PREVIEW){parms->parm.capture.capturemode = V4L2_MODE_PREVIEW;}dev->capture_mode = parms->parm.capture.capturemode;ret = v4l2_subdev_call(dev->sd, video, s_parm, parms);if (ret < 0)vfe_warn("v4l2 sub device s_parm error!\n");return ret;
}int isp_ae_stat_req(struct file *file, struct v4l2_fh *fh, struct isp_stat_buf *ae_buf)
{struct vfe_dev *dev = video_drvdata(file);int ret = 0;ae_buf->buf_size = ISP_STAT_AE_MEM_SIZE;ret = copy_to_user(ae_buf->buf,dev->isp_gen_set_pt->stat.ae_buf,ae_buf->buf_size);return ret;
}int isp_gamma_req(struct file *file, struct v4l2_fh *fh, struct isp_stat_buf *gamma_buf)
{struct vfe_dev *dev = video_drvdata(file);int ret = 0;gamma_buf->buf_size = ISP_GAMMA_MEM_SIZE;ret = copy_to_user(gamma_buf->buf,dev->isp_gen_set_pt->isp_ini_cfg.isp_tunning_settings.gamma_tbl_post,gamma_buf->buf_size);return ret;
}int isp_hist_stat_req(struct file *file, struct v4l2_fh *fh, struct isp_stat_buf *hist_buf)
{struct vfe_dev *dev = video_drvdata(file);int ret = 0;hist_buf->buf_size = ISP_STAT_HIST_MEM_SIZE;ret = copy_to_user(hist_buf->buf,dev->isp_gen_set_pt->stat.hist_buf,hist_buf->buf_size);return ret;
}int isp_af_stat_req(struct file *file, struct v4l2_fh *fh, struct isp_stat_buf *af_buf)
{struct vfe_dev *dev = video_drvdata(file);int ret = 0;af_buf->buf_size = ISP_STAT_AF_MEM_SIZE;ret = copy_to_user(af_buf->buf,dev->isp_gen_set_pt->stat.af_buf,af_buf->buf_size);return 0;
}static int isp_exif_req(struct file *file, struct v4l2_fh *fh, struct isp_exif_attribute *exif_attr)
{struct vfe_dev *dev = video_drvdata(file);struct sensor_exif_attribute exif;if (dev->isp_gen_set_pt && dev->is_bayer_raw){exif_attr->fnumber = dev->isp_gen_set_pt->isp_ini_cfg.isp_3a_settings.fno;if (exif_attr->fnumber < 40)exif_attr->fnumber = 240;exif_attr->focal_length = dev->isp_gen_set_pt->isp_ini_cfg.isp_tunning_settings.focus_length;if (dev->isp_gen_set_pt->isp_ini_cfg.isp_test_settings.isp_test_mode == ISP_TEST_ALL_ENABLE){if (exif_attr->focal_length < 40)exif_attr->focal_length = 400;}else{exif_attr->focal_length = dev->isp_3a_result_pt->real_vcm_pos; //400;}exif_attr->brightness = dev->isp_gen_set_pt->ae_lum;exif_attr->exposure_bias = dev->isp_gen_set_pt->exp_settings.exp_compensation;exif_attr->flash_fire = dev->isp_gen_set_pt->exp_settings.flash_open;exif_attr->iso_speed = (dev->isp_3a_result_pt->exp_analog_gain * dev->isp_3a_result_pt->exp_digital_gain) * 50 / 4096;exif_attr->exposure_time.numerator = 1;exif_attr->shutter_speed.numerator = 1;if (dev->isp_3a_result_pt->exp_time != 0){exif_attr->exposure_time.denominator = 1000000 / dev->isp_3a_result_pt->exp_time;exif_attr->shutter_speed.denominator = 1000000 / dev->isp_3a_result_pt->exp_time;}else{exif_attr->exposure_time.denominator = 10000;exif_attr->shutter_speed.denominator = 10000;}exif_attr->reserved[0] = dev->isp_3a_result_pt->real_vcm_pos;exif_attr->reserved[1] = dev->isp_gen_set_pt->color_temp;}else{if (v4l2_subdev_call(dev->sd, core, ioctl, GET_SENSOR_EXIF, &exif) != 0){exif_attr->fnumber = 240;exif_attr->focal_length = 180;exif_attr->brightness = 128;exif_attr->exposure_bias = dev->ctrl_para.exp_bias;exif_attr->flash_fire = 0;exif_attr->iso_speed = 200;exif_attr->exposure_time.numerator = 1;exif_attr->exposure_time.denominator = 20;exif_attr->shutter_speed.numerator = 1;exif_attr->shutter_speed.denominator = 24;}else{exif_attr->fnumber = exif.fnumber;exif_attr->focal_length = exif.focal_length;exif_attr->brightness = exif.brightness;exif_attr->exposure_bias = dev->ctrl_para.exp_bias;exif_attr->flash_fire = exif.flash_fire;exif_attr->iso_speed = exif.iso_speed;exif_attr->exposure_time.numerator = exif.exposure_time_num;exif_attr->exposure_time.denominator = exif.exposure_time_den;exif_attr->shutter_speed.numerator = exif.exposure_time_num;exif_attr->shutter_speed.denominator = exif.exposure_time_den;}}return 0;
}static ssize_t vfe_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
{struct vfe_dev *dev = video_drvdata(file);if (vfe_is_generating(dev)){return videobuf_read_stream(&dev->vb_vidq, data, count, ppos, 0,file->f_flags & O_NONBLOCK);}else{vfe_err("csi is not generating!\n");return -EINVAL;}
}static unsigned int vfe_poll(struct file *file, struct poll_table_struct *wait)
{struct vfe_dev *dev = video_drvdata(file);struct videobuf_queue *q = &dev->vb_vidq;if (vfe_is_generating(dev)){return videobuf_poll_stream(file, q, wait);}else{vfe_err("csi is not generating!\n");return -EINVAL;}
}void vfe_clk_open(struct vfe_dev *dev)
{//hardwarevfe_print("..........................vfe clk open!.......................\n");vfe_dphy_clk_set(dev, DPHY_CLK);vfe_clk_enable(dev);vfe_reset_disable(dev);
}void vfe_clk_close(struct vfe_dev *dev)
{vfe_print("..........................vfe clk close!.......................\n");vfe_clk_disable(dev);if (vfe_opened_num < 2){vfe_reset_enable(dev);}vfe_opened_num--;
}static int vfe_open(struct file *file)
{struct vfe_dev *dev = video_drvdata(file);int ret; //,input_num;vfe_print("vfe_open\n");if (vfe_is_opened(dev)){vfe_err("device open busy\n");ret = -EBUSY;goto open_end;}down(&dev->standby_seq_sema);vfe_clk_open(dev);
#ifdef USE_SPECIFIC_CCIcsi_cci_init_helper(dev->vip_sel);
#endifif (dev->ccm_cfg[0]->is_isp_used || dev->ccm_cfg[1]->is_isp_used){//must be after ahb and core clock enablebsp_isp_set_dma_load_addr((unsigned int)dev->regs.isp_load_regs_dma_addr);bsp_isp_set_dma_saved_addr((unsigned int)dev->regs.isp_saved_regs_dma_addr);//resourceret = isp_resource_request(dev);if (ret){vfe_err("isp_resource_request error at %s\n", __func__);return ret;}vfe_dbg(0, "tasklet init ! \n");INIT_WORK(&dev->isp_isr_bh_task, isp_isr_bh_handle);INIT_WORK(&dev->isp_isr_set_sensor_task, isp_isr_set_sensor_handle);}dev->input = -1; //default input nulldev->first_flag = 0;vfe_start_opened(dev);open_end:if (ret != 0){//up(&dev->standby_seq_sema);vfe_print("vfe_open busy\n");}else{vfe_print("vfe_open ok\n");vfe_opened_num++;}return ret;
}static int vfe_close(struct file *file)
{struct vfe_dev *dev = video_drvdata(file);int ret;vfe_print("vfe_close\n");//devicevfe_stop_generating(dev);if (dev->vfe_s_input_flag == 1){if (dev->sd_act != NULL){v4l2_subdev_call(dev->sd_act, core, ioctl, ACT_SOFT_PWDN, 0);}if (dev->power->stby_mode == NORM_STBY){ret = v4l2_subdev_call(dev->sd, core, s_power, CSI_SUBDEV_STBY_ON);if (ret != 0){vfe_err("sensor standby on error at device when csi close!\n");}}else{ //POWER_OFF//close the device powerret = vfe_set_sensor_power_off(dev);if (ret != 0){vfe_err("sensor power off error at device number when csi close!\n");}}dev->vfe_s_input_flag = 0;}else{vfe_print("vfe select input flag = %d, s_input have not be used .\n", dev->vfe_s_input_flag);}//hardwarebsp_csi_int_disable(dev->vip_sel, dev->cur_ch, CSI_INT_ALL);bsp_csi_cap_stop(dev->vip_sel, dev->cur_ch, CSI_VCAP);bsp_csi_disable(dev->vip_sel);if (dev->is_isp_used)bsp_isp_disable();if (dev->mbus_type == V4L2_MBUS_CSI2){bsp_mipi_csi_protocol_disable(dev->mipi_sel);bsp_mipi_csi_dphy_disable(dev->mipi_sel);bsp_mipi_csi_dphy_exit(dev->mipi_sel);}bsp_isp_exit();vfe_clk_close(dev);flush_work(&dev->resume_work);flush_delayed_work(&dev->probe_work);if (dev->ccm_cfg[0]->is_isp_used || dev->ccm_cfg[1]->is_isp_used){flush_work(&dev->isp_isr_bh_task);flush_work(&dev->isp_isr_set_sensor_task);//tasklet_kill(&dev->isp_isr_bh_task);//resourceisp_resource_release(dev);}mutex_destroy(&dev->isp_3a_result_mutex);//softwarevideobuf_stop(&dev->vb_vidq);videobuf_mmap_free(&dev->vb_vidq);vfe_stop_opened(dev);dev->ctrl_para.prev_exp_line = 0;dev->ctrl_para.prev_ana_gain = 1;vfe_print("vfe_close end\n");up(&dev->standby_seq_sema);return 0;
}static int vfe_mmap(struct file *file, struct vm_area_struct *vma)
{struct vfe_dev *dev = video_drvdata(file);int ret;vfe_dbg(0, "mmap called, vma=0x%08lx\n", (unsigned long)vma);ret = videobuf_mmap_mapper(&dev->vb_vidq, vma);vfe_dbg(0, "vma start=0x%08lx, size=%ld, ret=%d\n", (unsigned long)vma->vm_start,(unsigned long)vma->vm_end - (unsigned long)vma->vm_start, ret);return ret;
}static const struct v4l2_file_operations vfe_fops = {.owner = THIS_MODULE,.open = vfe_open,.release = vfe_close,.read = vfe_read,.poll = vfe_poll,.ioctl = video_ioctl2,//.unlocked_ioctl =.mmap = vfe_mmap,
};static const struct v4l2_ioctl_ops vfe_ioctl_ops = {.vidioc_querycap = vidioc_querycap,.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,.vidioc_enum_framesizes = vidioc_enum_framesizes,.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,.vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,.vidioc_reqbufs = vidioc_reqbufs,.vidioc_querybuf = vidioc_querybuf,.vidioc_qbuf = vidioc_qbuf,.vidioc_dqbuf = vidioc_dqbuf,.vidioc_enum_input = vidioc_enum_input,.vidioc_g_input = vidioc_g_input,.vidioc_s_input = vidioc_s_input,.vidioc_streamon = vidioc_streamon,.vidioc_streamoff = vidioc_streamoff,.vidioc_queryctrl = vidioc_queryctrl,.vidioc_g_ctrl = vidioc_g_ctrl,.vidioc_s_ctrl = vidioc_s_ctrl,.vidioc_g_parm = vidioc_g_parm,.vidioc_s_parm = vidioc_s_parm,
#ifdef CONFIG_VIDEO_V4L1_COMPAT.vidiocgmbuf = vidiocgmbuf,
#endif.vidioc_isp_ae_stat_req = isp_ae_stat_req,.vidioc_isp_hist_stat_req = isp_hist_stat_req,.vidioc_isp_af_stat_req = isp_af_stat_req,.vidioc_isp_gamma_req = isp_gamma_req,.vidioc_isp_exif_req = isp_exif_req,
};static struct video_device vfe_template[] ={[0] = {.name = "vfe_0",.fops = &vfe_fops,.ioctl_ops = &vfe_ioctl_ops,.release = video_device_release,},[1] = {.name = "vfe_1", .fops = &vfe_fops, .ioctl_ops = &vfe_ioctl_ops, .release = video_device_release,},
};static int vfe_request_pin(struct vfe_dev *dev, int enable)
{int ret = 0;
#ifdef VFE_GPIO//to cheat the pinctrldev_set_name(&dev->pdev->dev, "csi%d", dev->id);if (!IS_ERR_OR_NULL(dev->pctrl)){devm_pinctrl_put(dev->pctrl);}if (1 == enable){dev->pctrl = devm_pinctrl_get_select(&dev->pdev->dev, "default");if (IS_ERR_OR_NULL(dev->pctrl)){vfe_err("vip%d request pinctrl handle for device [%s] failed!\n", dev->id, dev_name(&dev->pdev->dev));return -EINVAL;}}else{dev->pctrl = devm_pinctrl_get_select(&dev->pdev->dev, "suspend");if (IS_ERR_OR_NULL(dev->pctrl)){vfe_err("vip%d disable pinctrl device [%s] failed!\n", dev->id, dev_name(&dev->pdev->dev));return -EINVAL;}}//to uncheat the pinctrldev_set_name(&dev->pdev->dev, "sunxi_vfe.%d", dev->id);usleep_range(5000, 6000);
#endif#ifdef FPGA_PIN//pin for FPGAvfe_print("directly write pin config @ FPGA\n");writel((volatile void *)0x33333333, (volatile void __iomem *)(GPIO_REGS_VBASE + 0x90));writel((volatile void *)0x33333333, (volatile void __iomem *)(GPIO_REGS_VBASE + 0x94));writel((volatile void *)0x03333333, (volatile void __iomem *)(GPIO_REGS_VBASE + 0x98));
//writel((volatile void*)((readl((volatile void __iomem*)(GPIO_REGS_VBASE+0x24)) & 0xff00ffff) | 0x220000), (volatile void __iomem*)(GPIO_REGS_VBASE+0x24));
//gpiob[4]:sck gpiob[5]:sda
#endifreturn ret;
}
static int vfe_pin_release(struct vfe_dev *dev)
{
#ifdef VFE_GPIOdevm_pinctrl_put(dev->pctrl);
#endifreturn 0;
}static int vfe_request_gpio(struct vfe_dev *dev)
{
#ifdef VFE_GPIOunsigned int i;for (i = 0; i < dev->dev_qty; i++){dev->ccm_cfg[i]->gpio.power_en_io = os_gpio_request(&dev->ccm_cfg[i]->gpio.power_en, 1);dev->ccm_cfg[i]->gpio.reset_io = os_gpio_request(&dev->ccm_cfg[i]->gpio.reset, 1);dev->ccm_cfg[i]->gpio.pwdn_io = os_gpio_request(&dev->ccm_cfg[i]->gpio.pwdn, 1);dev->ccm_cfg[i]->gpio.flash_en_io = os_gpio_request(&dev->ccm_cfg[i]->gpio.flash_en, 1);dev->ccm_cfg[i]->gpio.flash_mode_io = os_gpio_request(&dev->ccm_cfg[i]->gpio.flash_mode, 1);dev->ccm_cfg[i]->gpio.af_pwdn_io = os_gpio_request(&dev->ccm_cfg[i]->gpio.af_pwdn, 1);dev->ccm_cfg[i]->gpio.mclk_io = os_gpio_request(&dev->ccm_cfg[i]->gpio.mclk, 1);os_gpio_set(&dev->ccm_cfg[i]->gpio.power_en, 1);os_gpio_set(&dev->ccm_cfg[i]->gpio.reset, 1);os_gpio_set(&dev->ccm_cfg[i]->gpio.pwdn, 1);os_gpio_set(&dev->ccm_cfg[i]->gpio.flash_en, 1);os_gpio_set(&dev->ccm_cfg[i]->gpio.flash_mode, 1);os_gpio_set(&dev->ccm_cfg[i]->gpio.af_pwdn, 1);os_gpio_set(&dev->ccm_cfg[i]->gpio.mclk, 1);}
#endifreturn 0;
}static int vfe_gpio_config(struct vfe_dev *dev, int bon)
{
#ifdef VFE_GPIOstruct vfe_gpio_cfg gpio_item;if (1 == bon){os_gpio_set(&dev->gpio->power_en, 1);os_gpio_set(&dev->gpio->reset, 1);os_gpio_set(&dev->gpio->pwdn, 1);os_gpio_set(&dev->gpio->flash_en, 1);os_gpio_set(&dev->gpio->flash_mode, 1);os_gpio_set(&dev->gpio->af_pwdn, 1);os_gpio_set(&dev->gpio->mclk, 1);}else{memcpy(&gpio_item, &(dev->gpio->power_en), sizeof(struct vfe_gpio_cfg));gpio_item.mul_sel = GPIO_DISABLE;os_gpio_set(&gpio_item, 1);memcpy(&gpio_item, &(dev->gpio->reset), sizeof(struct vfe_gpio_cfg));gpio_item.mul_sel = GPIO_DISABLE;os_gpio_set(&gpio_item, 1);memcpy(&gpio_item, &(dev->gpio->pwdn), sizeof(struct vfe_gpio_cfg));gpio_item.mul_sel = GPIO_DISABLE;os_gpio_set(&gpio_item, 1);memcpy(&gpio_item, &(dev->gpio->flash_en), sizeof(struct vfe_gpio_cfg));gpio_item.mul_sel = GPIO_DISABLE;os_gpio_set(&gpio_item, 1);memcpy(&gpio_item, &(dev->gpio->flash_mode), sizeof(struct vfe_gpio_cfg));gpio_item.mul_sel = GPIO_DISABLE;os_gpio_set(&gpio_item, 1);memcpy(&gpio_item, &(dev->gpio->af_pwdn), sizeof(struct vfe_gpio_cfg));gpio_item.mul_sel = GPIO_DISABLE;os_gpio_set(&gpio_item, 1);memcpy(&gpio_item, &(dev->gpio->mclk), sizeof(struct vfe_gpio_cfg));gpio_item.mul_sel = GPIO_DISABLE;os_gpio_set(&gpio_item, 1);}
#endifreturn 0;
}static void vfe_gpio_release(struct vfe_dev *dev)
{
#ifdef VFE_GPIOunsigned int i;for (i = 0; i < dev->dev_qty; i++){os_gpio_release(dev->ccm_cfg[i]->gpio.power_en_io, 1);os_gpio_release(dev->ccm_cfg[i]->gpio.reset_io, 1);os_gpio_release(dev->ccm_cfg[i]->gpio.pwdn_io, 1);os_gpio_release(dev->ccm_cfg[i]->gpio.flash_en_io, 1);os_gpio_release(dev->ccm_cfg[i]->gpio.flash_mode_io, 1);os_gpio_release(dev->ccm_cfg[i]->gpio.af_pwdn_io, 1);os_gpio_release(dev->ccm_cfg[i]->gpio.mclk_io, 1);}
#endif
}static int vfe_resource_request(struct platform_device *pdev, struct vfe_dev *dev)
{struct resource *regs_res;void __iomem *regs;char vfe_res_csi[16] = "csi";char vfe_res_isp[16] = "isp";
#ifdef USE_SPECIFIC_CCIchar vfe_res_csi_cci[16] = "csi_cci";
#endifchar *vfe_res_name[] = {[0] = vfe_res_csi,[1] = vfe_res_isp,
#ifdef USE_SPECIFIC_CCI[2] = vfe_res_csi_cci,
#endif};struct resource *res;int ret, i, j;/* get io resource */vfe_dbg(0, "get io resource num = %d\n", pdev->num_resources);for (i = 0, j = 0; i < pdev->num_resources; i++){if (pdev->resource[i].flags != IORESOURCE_MEM)continue;vfe_dbg(0, "get resource, name = %s\n", vfe_res_name[j]);if (isp_va_flag == 1 && !strcmp(vfe_res_name[j], vfe_res_isp)){regs_res = NULL;regs = (void __iomem *)(ISP_REGS_BASE + 0xf0000000);}else{res = platform_get_resource_byname(pdev, IORESOURCE_MEM, vfe_res_name[j]);if (!res){vfe_err("failed to find the registers, name = %s\n", vfe_res_name[j]);return -ENOENT;}regs_res = request_mem_region(res->start, resource_size(res), dev_name(&pdev->dev));if (!regs_res){vfe_err("failed to obtain register region\n");return -ENOENT;}//regs = sunxi_map_kernel(res->start, resource_size(res));regs = IO_ADDRESS(res->start);if (!regs){vfe_err("failed to map registers\n");return -ENXIO;}}if (!strcmp(vfe_res_name[j], vfe_res_csi)){dev->regs.csi_regs_res = regs_res;dev->regs.csi_regs = regs;vfe_dbg(0, "dev->regs.csi_regs = %p\n", dev->regs.csi_regs);}else if (!strcmp(vfe_res_name[j], vfe_res_isp)){dev->regs.isp_regs_res = regs_res;dev->regs.isp_regs = regs;vfe_dbg(0, "dev->regs.isp_regs = %p\n", dev->regs.isp_regs);}j++;}dev->isp_load_reg_mm.size = ISP_LOAD_REG_SIZE;dev->isp_save_reg_mm.size = ISP_SAVED_REG_SIZE;if (isp_va_flag == 0){os_mem_alloc(&dev->isp_load_reg_mm);os_mem_alloc(&dev->isp_save_reg_mm);isp_load_mm = dev->isp_load_reg_mm;isp_saved_mm = dev->isp_save_reg_mm;isp_va_flag = 1;isp_va_alloc_sel = dev->vip_sel;}else{dev->isp_load_reg_mm = isp_load_mm;dev->isp_save_reg_mm = isp_saved_mm;}if (dev->isp_load_reg_mm.phy_addr != NULL){dev->regs.isp_load_regs_paddr = (void *)(dev->isp_load_reg_mm.phy_addr);dev->regs.isp_load_regs_dma_addr = (void *)(dev->isp_load_reg_mm.dma_addr);dev->regs.isp_load_regs = (void *)(dev->isp_load_reg_mm.vir_addr);vfe_dbg(0, "isp load paddr = %p\n", dev->regs.isp_load_regs_paddr);vfe_dbg(0, "isp load dma_addr = %p\n", dev->regs.isp_load_regs_dma_addr);vfe_dbg(0, "isp load addr = %p\n", dev->regs.isp_load_regs);if (!dev->regs.isp_load_regs){vfe_err("isp load regs va requset failed!\n");return -ENOMEM;}}else{vfe_err("isp load regs pa requset failed!\n");return -ENOMEM;}if (dev->isp_save_reg_mm.phy_addr != NULL){dev->regs.isp_saved_regs_paddr = (void *)(dev->isp_save_reg_mm.phy_addr);dev->regs.isp_saved_regs_dma_addr = (void *)(dev->isp_save_reg_mm.dma_addr);dev->regs.isp_saved_regs = (void *)(dev->isp_save_reg_mm.vir_addr);vfe_dbg(0, "isp saved paddr = %p\n", dev->regs.isp_saved_regs_paddr);vfe_dbg(0, "isp saved dma_addr = %p\n", dev->regs.isp_saved_regs_dma_addr);vfe_dbg(0, "isp saved addr = %p\n", dev->regs.isp_saved_regs);if (!dev->regs.isp_saved_regs){vfe_err("isp save regs va requset failed!\n");return -ENOMEM;}}else{vfe_err("isp save regs pa requset failed!\n");return -ENOMEM;}vfe_dbg(0, "get irq resource\n");/*get irq resource*/res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);if (!res){vfe_err("failed to get IRQ resource\n");return -ENXIO;}dev->irq = res->start;
//  sprintf(vfe_name,"sunxi-vfe.%d",dev->id);
#ifndef FPGA_VERret = os_request_irq(dev->irq, vfe_isr, IRQF_DISABLED, pdev->name, dev);
#elseret = os_request_irq(dev->irq, vfe_isr, IRQF_SHARED, pdev->name, dev);
#endifif (ret){vfe_err("failed to install irq (%d)\n", ret);return -ENXIO;}vfe_dbg(0, "clock resource\n");/*clock resource*/if (vfe_clk_get(dev)){vfe_err("vfe clock get failed!\n");return -ENXIO;}vfe_dbg(0, "get pin resource\n");/* pin resource *//* request gpio */vfe_request_pin(dev, 1);vfe_request_gpio(dev);return 0;
}static void vfe_resource_release(struct vfe_dev *dev)
{if (dev->regs.csi_regs_res){release_resource(dev->regs.csi_regs_res);kfree(dev->regs.csi_regs_res);}if (dev->regs.isp_regs_res){release_resource(dev->regs.isp_regs_res);kfree(dev->regs.isp_regs_res);}if (isp_va_alloc_sel == dev->vip_sel){os_mem_free(&dev->isp_load_reg_mm);os_mem_free(&dev->isp_save_reg_mm);isp_va_flag = 0;}vfe_gpio_release(dev);vfe_pin_release(dev);vfe_clk_release(dev);if (dev->irq > 0)free_irq(dev->irq, dev);
}
static int vfe_set_sensor_power_on(struct vfe_dev *dev)
{int ret = 0;
#ifdef _REGULATOR_CHANGE_vfe_device_regulator_get(dev->ccm_cfg[dev->input]);dev->power = &dev->ccm_cfg[dev->input]->power;
#endif#ifdef CONFIG_ARCH_SUN8IW6P1
#elseif (!IS_ERR_OR_NULL(dev->sd)){vfe_set_pmu_channel(dev->sd, IOVDD, ON);}usleep_range(10000, 12000);
#endifret = v4l2_subdev_call(dev->sd, core, s_power, CSI_SUBDEV_PWR_ON);dev->vfe_sensor_power_cnt++;vfe_dbg(0, "power_on______________________________\n");return ret;
}static int vfe_set_sensor_power_off(struct vfe_dev *dev)
{int ret = 0;if (dev->vfe_sensor_power_cnt > 0) {ret = v4l2_subdev_call(dev->sd, core, s_power, CSI_SUBDEV_PWR_OFF);dev->vfe_sensor_power_cnt--;}else {vfe_warn("Sensor is already power off!\n");dev->vfe_sensor_power_cnt = 0;}
#ifdef CONFIG_ARCH_SUN8IW6P1
#elseusleep_range(10000, 12000);if (!IS_ERR_OR_NULL(dev->sd)) {vfe_set_pmu_channel(dev->sd, IOVDD, OFF);}
#endif#ifdef _REGULATOR_CHANGE_vfe_device_regulator_put(dev->ccm_cfg[dev->input]);
#endifvfe_dbg(0, "power_off______________________________\n");return ret;
}static void resume_work_handle(struct work_struct *work);
static void __exit vfe_exit(void);#ifdef CONFIG_ES
static void vfe_early_suspend(struct early_suspend *h);
static void vfe_late_resume(struct early_suspend *h);
#endifstatic const char *vfe_regulator_name[] ={VFE_ISP_REGULATOR,VFE_CSI_REGULATOR,
};
static int vfe_get_regulator(struct vfe_dev *dev)
{struct regulator *regul;unsigned int i;for (i = 0; i < ARRAY_SIZE(vfe_regulator_name); ++i){if (strcmp(vfe_regulator_name[i], "") != 0){regul = regulator_get(NULL, vfe_regulator_name[i]);if (IS_ERR_OR_NULL(regul)){vfe_err("get regulator vfe system power error, i = %d!\n", i);regul = NULL;}}else{regul = NULL;}dev->vfe_system_power[i] = regul;}if (VFE_VPU_CLK){dev->clock.vfe_vpu_clk = os_clk_get(NULL, VFE_VPU_CLK);}else{dev->clock.vfe_vpu_clk = NULL;}return 0;
}
static int vfe_enable_regulator_all(struct vfe_dev *dev)
{unsigned int i;for (i = 0; i < ARRAY_SIZE(vfe_regulator_name); ++i){if (dev->vfe_system_power[i] != NULL){regulator_enable(dev->vfe_system_power[i]);}}usleep_range(5000, 6000);if (dev->clock.vfe_vpu_clk)os_clk_prepare_enable(dev->clock.vfe_vpu_clk);elsevfe_warn("vfe vpu clock is null\n");return 0;
}
static int vfe_disable_regulator_all(struct vfe_dev *dev)
{unsigned int i;for (i = 0; i < ARRAY_SIZE(vfe_regulator_name); ++i){if (dev->vfe_system_power[i] != NULL){regulator_disable(dev->vfe_system_power[i]);}}if (dev->clock.vfe_vpu_clk)os_clk_disable_unprepare(dev->clock.vfe_vpu_clk);elsevfe_warn("vfe vpu clock is null\n");return 0;
}
static int vfe_put_regulator(struct vfe_dev *dev)
{unsigned int i;for (i = 0; i < ARRAY_SIZE(vfe_regulator_name); ++i){if (dev->vfe_system_power[i] != NULL){regulator_put(dev->vfe_system_power[i]);}}if (dev->clock.vfe_vpu_clk)os_clk_put(dev->clock.vfe_vpu_clk);elsevfe_warn("vfe vpu clock is null\n");return 0;
}/*
static void vfe_enable_regulator(struct vfe_dev *dev, enum vfe_regulator regulator)
{regulator_enable(dev->vfe_system_power[regulator]);usleep_range(5000,6000);
}
static void vfe_disable_regulator(struct vfe_dev *dev, enum vfe_regulator regulator)
{regulator_disable(dev->vfe_system_power[regulator]);
}
*/
static int vfe_device_regulator_get(struct ccm_config *ccm_cfg)
{
#ifdef VFE_PMU/*power issue*/ccm_cfg->power.iovdd = NULL;ccm_cfg->power.avdd = NULL;ccm_cfg->power.dvdd = NULL;ccm_cfg->power.afvdd = NULL;if (strcmp(ccm_cfg->iovdd_str, "")){ccm_cfg->power.iovdd = regulator_get(NULL, ccm_cfg->iovdd_str);if (IS_ERR_OR_NULL(ccm_cfg->power.iovdd)){vfe_err("get regulator csi_iovdd error!\n");goto regulator_get_err;}}if (strcmp(ccm_cfg->avdd_str, "")){ccm_cfg->power.avdd = regulator_get(NULL, ccm_cfg->avdd_str);if (IS_ERR_OR_NULL(ccm_cfg->power.avdd)){vfe_err("get regulator csi_avdd error!\n");goto regulator_get_err;}}if (strcmp(ccm_cfg->dvdd_str, "")){ccm_cfg->power.dvdd = regulator_get(NULL, ccm_cfg->dvdd_str);if (IS_ERR_OR_NULL(ccm_cfg->power.dvdd)){vfe_err("get regulator csi_dvdd error!\n");goto regulator_get_err;}}if (strcmp(ccm_cfg->afvdd_str, "")){ccm_cfg->power.afvdd = regulator_get(NULL, ccm_cfg->afvdd_str);if (IS_ERR_OR_NULL(ccm_cfg->power.afvdd)){vfe_err("get regulator csi_afvdd error!\n");goto regulator_get_err;}}return 0;
regulator_get_err:return -1;
#elsereturn 0;
#endif
}static int vfe_device_regulator_put(struct ccm_config *ccm_cfg)
{/*power issue*/if (!IS_ERR_OR_NULL(ccm_cfg->power.iovdd))regulator_put(ccm_cfg->power.iovdd);if (!IS_ERR_OR_NULL(ccm_cfg->power.avdd))regulator_put(ccm_cfg->power.avdd);if (!IS_ERR_OR_NULL(ccm_cfg->power.dvdd))regulator_put(ccm_cfg->power.dvdd);if (!IS_ERR_OR_NULL(ccm_cfg->power.afvdd))regulator_put(ccm_cfg->power.afvdd);return 0;
}
static int vfe_sensor_check(struct vfe_dev *dev)
{int ret = 0;struct v4l2_subdev *sd = dev->sd;vfe_print("Check sensor!\n");vfe_set_sensor_power_on(dev);
#ifdef USE_SPECIFIC_CCIcsi_cci_init_helper(dev->vip_sel);
#endifret = v4l2_subdev_call(sd, core, init, 0);if (dev->power->stby_mode == NORM_STBY){if (ret < 0){vfe_set_sensor_power_off(dev);ret = -1;}else{v4l2_subdev_call(sd, core, s_power, CSI_SUBDEV_STBY_ON);ret = 0;}}else // if(dev->power->stby_mode == POWER_OFF){ret = (ret < 0) ? -1 : 0;vfe_set_sensor_power_off(dev);}if (vfe_i2c_dbg == 1){vfe_print("NOTE: Sensor i2c dbg, it's always power on and register success!..................\n");ret = 0;vfe_set_sensor_power_on(dev);}
#ifdef USE_SPECIFIC_CCIcsi_cci_exit_helper(dev->vip_sel);
#endifreturn ret;
}#ifdef USE_SPECIFIC_CCI
static int vfe_sensor_subdev_register_check(struct vfe_dev *dev, struct v4l2_device *v4l2_dev,struct ccm_config *ccm_cfg, struct i2c_board_info *sensor_i2c_board)
{int ret;ccm_cfg->sd = NULL;ccm_cfg->sd = cci_bus_match(ccm_cfg->ccm, dev->id, sensor_i2c_board->addr); // ccm_cfg->i2c_addr >> 1);if (ccm_cfg->sd){ret = v4l2_device_register_subdev(&dev->v4l2_dev, ccm_cfg->sd);vfe_print("v4l2_device_register_subdev return %d\n", ret);if (ret < 0){ccm_cfg->sd = NULL;}}update_ccm_info(dev, ccm_cfg);if (IS_ERR_OR_NULL(ccm_cfg->sd)){vfe_err("Error registering v4l2 subdevice No such device!\n");return -ENODEV;}else{vfe_print("registered sensor subdev is OK!\n");}//Subdev register is OK, check sensor init!return vfe_sensor_check(dev);
}
static int vfe_sensor_subdev_unregister(struct v4l2_device *v4l2_dev,struct ccm_config *ccm_cfg, struct i2c_board_info *sensor_i2c_board)
{struct cci_driver *cci_driv = v4l2_get_subdevdata(ccm_cfg->sd);if (IS_ERR_OR_NULL(cci_driv))return -ENODEV;vfe_print("vfe sensor subdev unregister!\n");v4l2_device_unregister_subdev(ccm_cfg->sd);cci_bus_match_cancel(cci_driv);return 0;
}
static int vfe_actuator_subdev_register(struct vfe_dev *dev, struct ccm_config *ccm_cfg, struct i2c_board_info *act_i2c_board)
{ccm_cfg->sd_act = NULL;ccm_cfg->sd_act = cci_bus_match(ccm_cfg->act_name, dev->id, act_i2c_board->addr); // ccm_cfg->i2c_addr >> 1);//reg_sd_act:if (!ccm_cfg->sd_act){vfe_err("Error registering v4l2 act subdevice!\n");return -EINVAL;}else{vfe_print("registered actuator device succeed! act_name is %s\n", ccm_cfg->act_name);}ccm_cfg->act_ctrl = (struct actuator_ctrl_t *)container_of(ccm_cfg->sd_act, struct actuator_ctrl_t, sdev);//printk("ccm_cfg->act_ctrl=%x\n",(unsigned int )ccm_cfg->act_ctrl);return 0;
}#else // NOT defind USE_SPECIFIC_CCIstatic int vfe_sensor_subdev_register_check(struct vfe_dev *dev, struct v4l2_device *v4l2_dev,struct ccm_config *ccm_cfg, struct i2c_board_info *sensor_i2c_board)
{struct i2c_adapter *i2c_adap = i2c_get_adapter(ccm_cfg->twi_id);if (i2c_adap == NULL){vfe_err("request i2c adapter failed!\n");return -EFAULT;}ccm_cfg->sd = v4l2_i2c_new_subdev_board(v4l2_dev, i2c_adap, sensor_i2c_board, NULL);if (IS_ERR_OR_NULL(ccm_cfg->sd)){i2c_put_adapter(i2c_adap);vfe_err("Error registering v4l2 subdevice No such device!\n");return -ENODEV;}else{vfe_print("registered sensor subdev is OK!\n");}update_ccm_info(dev, ccm_cfg);//Subdev register is OK, check sensor init!return vfe_sensor_check(dev);
}
static int vfe_sensor_subdev_unregister(struct v4l2_device *v4l2_dev,struct ccm_config *ccm_cfg, struct i2c_board_info *sensor_i2c_board)
{struct i2c_client *client = v4l2_get_subdevdata(ccm_cfg->sd);struct i2c_adapter *adapter;if (!client)return -ENODEV;vfe_print("vfe sensor subdev unregister!\n");v4l2_device_unregister_subdev(ccm_cfg->sd);adapter = client->adapter;i2c_unregister_device(client);if (adapter)i2c_put_adapter(adapter);return 0;
}
static int vfe_actuator_subdev_register(struct vfe_dev *dev, struct ccm_config *ccm_cfg, struct i2c_board_info *act_i2c_board)
{struct v4l2_device *v4l2_dev = &dev->v4l2_dev;struct i2c_adapter *i2c_adap_act = i2c_get_adapter(ccm_cfg->twi_id); //must use the same twi_channel with sensorif (i2c_adap_act == NULL){vfe_err("request act i2c adapter failed\n");return -EINVAL;}ccm_cfg->sd_act = NULL;//vfe_print("registered act sub device, slave=0x%x~~~\n",ccm_cfg->act_slave);act_i2c_board->addr = (unsigned short)(ccm_cfg->act_slave >> 1);strcpy(act_i2c_board->type, ccm_cfg->act_name);ccm_cfg->sd_act = v4l2_i2c_new_subdev_board(v4l2_dev, i2c_adap_act, act_i2c_board, NULL);//reg_sd_act:if (!ccm_cfg->sd_act){vfe_err("Error registering v4l2 act subdevice!\n");return -EINVAL;}else{vfe_print("registered actuator device succeed!\n");}ccm_cfg->act_ctrl = (struct actuator_ctrl_t *)container_of(ccm_cfg->sd_act, struct actuator_ctrl_t, sdev);//printk("ccm_cfg->act_ctrl=%x\n",(unsigned int )ccm_cfg->act_ctrl);return 0;
}
#endif
static void cpy_ccm_power_settings(struct ccm_config *ccm_cfg)
{strcpy(ccm_cfg->iovdd_str, ccm_cfg->sensor_cfg_ini->sub_power_str[ENUM_IOVDD]);ccm_cfg->power.iovdd_vol = ccm_cfg->sensor_cfg_ini->sub_power_vol[ENUM_IOVDD];strcpy(ccm_cfg->avdd_str, ccm_cfg->sensor_cfg_ini->sub_power_str[ENUM_AVDD]);ccm_cfg->power.avdd_vol = ccm_cfg->sensor_cfg_ini->sub_power_vol[ENUM_AVDD];strcpy(ccm_cfg->dvdd_str, ccm_cfg->sensor_cfg_ini->sub_power_str[ENUM_DVDD]);ccm_cfg->power.dvdd_vol = ccm_cfg->sensor_cfg_ini->sub_power_vol[ENUM_DVDD];strcpy(ccm_cfg->afvdd_str, ccm_cfg->sensor_cfg_ini->sub_power_str[ENUM_AFVDD]);ccm_cfg->power.afvdd_vol = ccm_cfg->sensor_cfg_ini->sub_power_vol[ENUM_AFVDD];
}static int cpy_ccm_sub_device_cfg(struct ccm_config *ccm_cfg, int n)
{strcpy(ccm_cfg->ccm, ccm_cfg->sensor_cfg_ini->camera_inst[n].name);if (strcmp(ccm_cfg->sensor_cfg_ini->camera_inst[n].isp_cfg_name, "")){strcpy(ccm_cfg->isp_cfg_name, ccm_cfg->sensor_cfg_ini->camera_inst[n].isp_cfg_name);}else{strcpy(ccm_cfg->isp_cfg_name, ccm_cfg->ccm);}ccm_cfg->i2c_addr = ccm_cfg->sensor_cfg_ini->camera_inst[n].i2c_addr;ccm_cfg->hflip = ccm_cfg->sensor_cfg_ini->camera_inst[n].hflip;ccm_cfg->vflip = ccm_cfg->sensor_cfg_ini->camera_inst[n].vflip;ccm_cfg->hflip_thumb = ccm_cfg->sensor_cfg_ini->camera_inst[n].hflip;ccm_cfg->vflip_thumb = ccm_cfg->sensor_cfg_ini->camera_inst[n].vflip;ccm_cfg->power.stby_mode = ccm_cfg->sensor_cfg_ini->camera_inst[n].stdby_mode;if (ccm_cfg->sensor_cfg_ini->camera_inst[n].sensor_type == SENSOR_RAW){ccm_cfg->is_bayer_raw = 1;ccm_cfg->is_isp_used = 1;}else if (ccm_cfg->sensor_cfg_ini->camera_inst[n].sensor_type == SENSOR_YUV){ccm_cfg->is_bayer_raw = 0;ccm_cfg->is_isp_used = 0;}else{ccm_cfg->is_bayer_raw = 0;ccm_cfg->is_isp_used = 1;}strcpy(ccm_cfg->act_name, ccm_cfg->sensor_cfg_ini->camera_inst[n].act_name);if (strcmp(ccm_cfg->act_name, "")){ccm_cfg->act_used = 1;vfe_print("VCM driver name is \"%s\".\n", ccm_cfg->act_name);}ccm_cfg->act_slave = ccm_cfg->sensor_cfg_ini->camera_inst[n].act_i2c_addr;return 0;
}
const char *sensor_info_type[] ={"YUV","RAW"};
static struct v4l2_subdev *vfe_sensor_register_check(struct vfe_dev *dev, struct v4l2_device *v4l2_dev, struct ccm_config *ccm_cfg,struct i2c_board_info *sensor_i2c_board, int input_num)
{int sensor_cnt, ret, sensor_num;struct sensor_item sensor_info;if (dev->vip_define_sensor_list == 1){sensor_num = ccm_cfg->sensor_cfg_ini->detect_sensor_num;if (ccm_cfg->sensor_cfg_ini->detect_sensor_num == 0){sensor_num = 1;}}else{sensor_num = 1;}for (sensor_cnt = 0; sensor_cnt < sensor_num; sensor_cnt++){if (dev->vip_define_sensor_list == 1){if (ccm_cfg->sensor_cfg_ini->detect_sensor_num > 0)cpy_ccm_sub_device_cfg(ccm_cfg, sensor_cnt);}if (get_sensor_info(ccm_cfg->ccm, &sensor_info) == 0){if (ccm_cfg->i2c_addr != sensor_info.i2c_addr){vfe_warn("Sensor info \"%s\" i2c_addr is different from sys_config!\n", sensor_info.sensor_name);//vfe_warn("Sensor info i2c_addr = %d, sys_config i2c_addr = %d!\n", sensor_info.i2c_addr, ccm_cfg->i2c_addr);//ccm_cfg->i2c_addr = sensor_info.i2c_addr;}if (ccm_cfg->is_bayer_raw != sensor_info.sensor_type){vfe_warn("Camer detect \"%s\" fmt is different from sys_config!\n", sensor_info_type[sensor_info.sensor_type]);vfe_warn("Apply detect  fmt = %d replace sys_config fmt = %d!\n", sensor_info.sensor_type, ccm_cfg->is_bayer_raw);ccm_cfg->is_bayer_raw = sensor_info.sensor_type;}if (sensor_info.sensor_type == SENSOR_RAW){ccm_cfg->is_isp_used = 1;}else{ccm_cfg->act_used = 0;}vfe_print("Find sensor name is \"%s\", i2c address is %x, type is \"%s\" !\n", sensor_info.sensor_name, sensor_info.i2c_addr,sensor_info_type[sensor_info.sensor_type]);}sensor_i2c_board->addr = (unsigned short)(ccm_cfg->i2c_addr >> 1);strcpy(sensor_i2c_board->type, ccm_cfg->ccm);vfe_print("Sub device register \"%s\" i2c_addr = 0x%x start!\n", sensor_i2c_board->type, ccm_cfg->i2c_addr);ret = vfe_sensor_subdev_register_check(dev, v4l2_dev, ccm_cfg, sensor_i2c_board);if (ret == -1){vfe_sensor_subdev_unregister(v4l2_dev, ccm_cfg, sensor_i2c_board);vfe_print("Sub device register \"%s\" failed!\n", sensor_i2c_board->type);ccm_cfg->sd = NULL;continue;}else if (ret == ENODEV || ret == EFAULT){continue;}else if (ret == 0){vfe_print("Sub device register \"%s\" is OK!\n", sensor_i2c_board->type);break;}}return ccm_cfg->sd;
}static void probe_work_handle(struct work_struct *work)
{struct vfe_dev *dev = container_of(work, struct vfe_dev, probe_work.work);int ret = 0;int input_num;struct video_device *vfd;char vfe_name[16] = {0};mutex_lock(&probe_hdl_lock);vfe_print("probe_work_handle start!\n");vfe_dbg(0, "v4l2_device_register\n");/* v4l2 device register */ret = v4l2_device_register(&dev->pdev->dev, &dev->v4l2_dev);if (ret){vfe_err("Error registering v4l2 device\n");goto probe_hdl_free_dev;}dev_set_drvdata(&dev->pdev->dev, (dev));vfe_dbg(0, "v4l2 subdev register\n");/* v4l2 subdev register */dev->is_same_module = 0;for (input_num = 0; input_num < dev->dev_qty; input_num++){vfe_print("v4l2 subdev register input_num = %d\n", input_num);if (!strcmp(dev->ccm_cfg[input_num]->ccm, "")){vfe_err("Sensor name is NULL!\n");goto snesor_register_end;}if (dev->is_same_module){dev->ccm_cfg[input_num]->sd = dev->ccm_cfg[input_num - 1]->sd;vfe_dbg(0, "num = %d , sd_0 = %p,sd_1 = %p\n", input_num, dev->ccm_cfg[input_num]->sd, dev->ccm_cfg[input_num - 1]->sd);goto snesor_register_end;}if ((dev->dev_qty > 1) && (input_num + 1 < dev->dev_qty)){if ((!strcmp(dev->ccm_cfg[input_num]->ccm, dev->ccm_cfg[input_num + 1]->ccm)))dev->is_same_module = 1;}if (dev->vip_define_sensor_list == 1){if (dev->ccm_cfg[input_num]->sensor_cfg_ini->power_settings_enable == 1){cpy_ccm_power_settings(dev->ccm_cfg[input_num]);}}
#ifdef _REGULATOR_CHANGE_
#elseif (vfe_device_regulator_get(dev->ccm_cfg[input_num])){vfe_err("vfe_device_regulator_get error at input_num = %d\n", input_num);goto snesor_register_end;}
#endif//dev->dev_sensor[input_num].addr = (unsigned short)(dev->ccm_cfg[input_num]->i2c_addr>>1);//strcpy(dev->dev_sensor[input_num].type,dev->ccm_cfg[input_num]->ccm);vfe_print("vfe sensor detect start! input_num = %d\n", input_num);dev->input = input_num;if (vfe_sensor_register_check(dev, &dev->v4l2_dev, dev->ccm_cfg[input_num], &dev->dev_sensor[input_num], input_num) == NULL){vfe_err("vfe sensor register check error at input_num = %d\n", input_num);dev->device_valid_flag[input_num] = 0;//goto snesor_register_end;}else{dev->device_valid_flag[input_num] = 1;}if (dev->ccm_cfg[input_num]->is_isp_used && dev->ccm_cfg[input_num]->is_bayer_raw){if (read_ini_info(dev, input_num)){vfe_warn("read ini info fail\n");}}if (dev->ccm_cfg[input_num]->act_used == 1){dev->dev_act[input_num].addr = (unsigned short)(dev->ccm_cfg[input_num]->act_slave >> 1);strcpy(dev->dev_act[input_num].type, dev->ccm_cfg[input_num]->act_name);if (vfe_actuator_subdev_register(dev, dev->ccm_cfg[input_num], &dev->dev_act[input_num]) != 0); //goto probe_hdl_free_dev;}snesor_register_end:vfe_dbg(0, "dev->ccm_cfg[%d] = %p\n", input_num, dev->ccm_cfg[input_num]);vfe_dbg(0, "dev->ccm_cfg[%d]->sd = %p\n", input_num, dev->ccm_cfg[input_num]->sd);//    vfe_dbg(0,"dev->ccm_cfg[%d]->ccm_info = %p\n",input_num,&dev->ccm_cfg[input_num]->ccm_info);//    vfe_dbg(0,"dev->ccm_cfg[%d]->ccm_info.mclk = %ld\n",input_num,dev->ccm_cfg[input_num]->ccm_info.mclk);vfe_dbg(0, "dev->ccm_cfg[%d]->power.iovdd = %p\n", input_num, dev->ccm_cfg[input_num]->power.iovdd);vfe_dbg(0, "dev->ccm_cfg[%d]->power.avdd = %p\n", input_num, dev->ccm_cfg[input_num]->power.avdd);vfe_dbg(0, "dev->ccm_cfg[%d]->power.dvdd = %p\n", input_num, dev->ccm_cfg[input_num]->power.dvdd);vfe_dbg(0, "dev->ccm_cfg[%d]->power.afvdd = %p\n", input_num, dev->ccm_cfg[input_num]->power.afvdd);//    dev->ccm_cfg[input_num]->ccm_info.mclk = MCLK_OUT_RATE;//    dev->ccm_cfg[input_num]->ccm_info.stby_mode = dev->ccm_cfg[input_num]->ccm_info.stby_mode;}dev->input = -1;/*video device register */ret = -ENOMEM;vfd = video_device_alloc();if (!vfd){goto probe_hdl_unreg_dev;}*vfd = vfe_template[dev->id];vfd->v4l2_dev = &dev->v4l2_dev;sprintf(vfe_name, "vfe-%d", dev->id);dev_set_name(&vfd->dev, vfe_name);ret = video_register_device(vfd, VFL_TYPE_GRABBER, dev->id);if (ret < 0){goto probe_hdl_rel_vdev;}video_set_drvdata(vfd, dev);/*add device list*//* Now that everything is fine, let's add it to device list */list_add_tail(&dev->devlist, &devlist);dev->vfd = vfd;vfe_print("V4L2 device registered as %s\n", video_device_node_name(vfd));/*initial video buffer queue*/videobuf_queue_dma_contig_init(&dev->vb_vidq, &vfe_video_qops, NULL, &dev->slock,V4L2_BUF_TYPE_VIDEO_CAPTURE,V4L2_FIELD_NONE, //default format, can be changed by s_fmtsizeof(struct vfe_buffer), dev, NULL);//vfe_print("videobuf_queue_dma_contig_init @ probe handle!\n");ret = sysfs_create_group(&dev->pdev->dev.kobj, &vfe_attribute_group);
//vfe_print("sysfs_create_group @ probe handle!\n");#ifdef CONFIG_ESdev->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB + 1;dev->early_suspend.suspend = vfe_early_suspend;dev->early_suspend.resume = vfe_late_resume;register_early_suspend(&dev->early_suspend);vfe_print("register_early_suspend @ probe handle!\n");
#endif#ifdef USE_SPECIFIC_CCIvfe_clk_close(dev);
#endifvfe_print("probe_work_handle end!\n");mutex_unlock(&probe_hdl_lock);return;probe_hdl_rel_vdev:video_device_release(vfd);vfe_print("video_device_release @ probe_hdl!\n");
probe_hdl_unreg_dev:vfe_print("v4l2_device_unregister @ probe_hdl!\n");v4l2_device_unregister(&dev->v4l2_dev);
probe_hdl_free_dev:vfe_print("vfe_resource_release @ probe_hdl!\n");
#ifdef USE_SPECIFIC_CCIcsi_cci_exit_helper(dev->vip_sel);vfe_clk_close(dev);
#endif//vfe_resource_release(dev);vfe_print("vfe_exit @ probe_hdl!\n");//vfe_exit();vfe_err("Failed to install at probe handle\n");mutex_unlock(&probe_hdl_lock);return;
}static int vfe_probe(struct platform_device *pdev)
{struct vfe_dev *dev;//  struct video_device *vfd;//  struct i2c_adapter *i2c_adap;//  struct i2c_adapter *i2c_adap_act;struct sunxi_vip_platform_data *pdata = NULL;int ret = 0;int input_num;unsigned int i;vfe_dbg(0, "vfe_probe\n");/*request mem for dev*/dev = kzalloc(sizeof(struct vfe_dev), GFP_KERNEL);if (!dev){vfe_err("request dev mem failed!\n");return -ENOMEM;}#if defined CONFIG_ARCH_SUN8IW1P1dev->platform_id = ISP_PLATFORM_SUN8IW1P1;
#elif defined CONFIG_ARCH_SUN8IW3P1dev->platform_id = ISP_PLATFORM_SUN8IW3P1;
#elif defined CONFIG_ARCH_SUN9IW1P1dev->platform_id = ISP_PLATFORM_SUN9IW1P1;
#elif defined CONFIG_ARCH_SUN8IW5P1dev->platform_id = ISP_PLATFORM_SUN8IW5P1;
#elif defined CONFIG_ARCH_SUN8IW6P1dev->platform_id = ISP_PLATFORM_SUN8IW6P1;
#elif defined CONFIG_ARCH_SUN8IW7P1dev->platform_id = ISP_PLATFORM_SUN8IW7P1;
#elif defined CONFIG_ARCH_SUN8IW8P1dev->platform_id = ISP_PLATFORM_SUN8IW8P1;
#elif defined CONFIG_ARCH_SUN8IW9P1dev->platform_id = ISP_PLATFORM_SUN8IW9P1;#endifdev->id = pdev->id;dev->pdev = pdev;pdata = pdev->dev.platform_data;dev->mipi_sel = pdata->mipi_sel;dev->vip_sel = pdata->vip_sel;dev->isp_sel = pdata->isp_sel;dev->generating = 0;dev->opened = 0;dev->vfe_sensor_power_cnt = 0;dev->vfe_s_input_flag = 0;vfe_print("pdev->id = %d\n", pdev->id);vfe_print("dev->mipi_sel = %d\n", pdata->mipi_sel);vfe_print("dev->vip_sel = %d\n", pdata->vip_sel);vfe_print("dev->isp_sel = %d\n", pdata->isp_sel);//to cheat the pinctrldev_set_name(&dev->pdev->dev, "csi%d", dev->id);spin_lock_init(&dev->slock);vfe_dbg(0, "fetch sys_config1\n");/* fetch sys_config! */for (input_num = 0; input_num < MAX_INPUT_NUM; input_num++){dev->ccm_cfg[input_num] = &dev->ccm_cfg_content[input_num];vfe_dbg(0, "dev->ccm_cfg[%d] = %p\n", input_num, dev->ccm_cfg[input_num]);dev->ccm_cfg[input_num]->i2c_addr = i2c_addr;strcpy(dev->ccm_cfg[input_num]->ccm, ccm);strcpy(dev->ccm_cfg[input_num]->isp_cfg_name, ccm);dev->ccm_cfg[input_num]->act_slave = act_slave;strcpy(dev->ccm_cfg[input_num]->act_name, act_name);dev->vip_define_sensor_list = define_sensor_list;}ret = fetch_config(dev);if (ret){vfe_err("Error at fetch_config\n");goto error;}if (vips != 0xffff){printk("vips input 0x%x\n", vips);dev->ccm_cfg[0]->is_isp_used = (vips & 0xf0) >> 4;dev->ccm_cfg[0]->is_bayer_raw = (vips & 0xf00) >> 8;if ((vips & 0xff0) == 0)dev->ccm_cfg[0]->act_used = 0;}vfe_get_regulator(dev);vfe_enable_regulator_all(dev);ret = vfe_resource_request(pdev, dev);if (ret < 0)goto free_resource;
#ifdef USE_SPECIFIC_CCIvfe_clk_open(dev);
#endif//to uncheat the pinctrldev_set_name(&dev->pdev->dev, "sunxi_vfe.%d", dev->id);ret = bsp_csi_set_base_addr(dev->vip_sel, (unsigned int)dev->regs.csi_regs);if (ret < 0)goto free_resource;
#if defined(CONFIG_ARCH_SUN8IW3P1) || defined(CONFIG_ARCH_SUN8IW5P1) || defined(CONFIG_ARCH_SUN8IW7P1)#elseif (dev->mipi_sel == 0){//todo for mipi lib.if (sunxi_get_soc_ver() > SUN9IW1P1_REV_B){bsp_mipi_csi_set_version(dev->mipi_sel, 1);}else{bsp_mipi_csi_set_version(dev->mipi_sel, 0);}
#if defined(CONFIG_ARCH_SUN8IW6P1) || defined(CONFIG_ARCH_SUN8IW8P1) //fixbsp_mipi_csi_set_base_addr(dev->mipi_sel, MIPI_CSI0_REGS_BASE + 0xf0000000);bsp_mipi_dphy_set_base_addr(dev->mipi_sel, MIPI_CSI0_REGS_BASE + 0xf0000000 + 0x1000);
#elseret = bsp_mipi_csi_set_base_addr(dev->mipi_sel, 0);if (ret < 0)goto free_resource;ret = bsp_mipi_dphy_set_base_addr(dev->mipi_sel, 0);if (ret < 0)goto free_resource;
#endif}
#endifbsp_isp_init_platform(dev->platform_id);bsp_isp_set_base_addr((unsigned int)dev->regs.isp_regs);bsp_isp_set_map_load_addr((unsigned int)dev->regs.isp_load_regs);bsp_isp_set_map_saved_addr((unsigned int)dev->regs.isp_saved_regs);memset((unsigned int *)dev->regs.isp_load_regs, 0, ISP_LOAD_REG_SIZE);memset((unsigned int *)dev->regs.isp_saved_regs, 0, ISP_SAVED_REG_SIZE);/*initial parameter */strcpy(dev->ch[0].fmt.name, "channel 0 format");strcpy(dev->ch[1].fmt.name, "channel 1 format");strcpy(dev->ch[2].fmt.name, "channel 2 format");strcpy(dev->ch[3].fmt.name, "channel 3 format");dev->fmt = &dev->ch[0].fmt;dev->total_bus_ch = 1;dev->total_rx_ch = 1;dev->cur_ch = 0;dev->arrange.row = 1;dev->arrange.column = 1;dev->isp_init_para.isp_src_ch_mode = ISP_SINGLE_CH;for (i = 0; i < MAX_ISP_SRC_CH_NUM; i++)dev->isp_init_para.isp_src_ch_en[i] = 0;dev->isp_init_para.isp_src_ch_en[dev->id] = 1;//=======================================/* init video dma queues */INIT_LIST_HEAD(&dev->vidq.active);//init_waitqueue_head(&dev->vidq.wq);INIT_WORK(&dev->resume_work, resume_work_handle);INIT_DELAYED_WORK(&dev->probe_work, probe_work_handle);mutex_init(&dev->standby_lock);mutex_init(&dev->stream_lock);mutex_init(&dev->opened_lock);sema_init(&dev->standby_seq_sema, 1);schedule_delayed_work(&dev->probe_work, msecs_to_jiffies(1));/* initial state */dev->capture_mode = V4L2_MODE_PREVIEW;//=======================================return 0;//rel_vdev:
//  video_device_release(vfd);
//unreg_dev:
//  v4l2_device_unregister(&dev->v4l2_dev);
free_resource:
//vfe_resource_release(dev);
error:vfe_err("failed to install\n");return ret;
}static int vfe_release(void)
{struct vfe_dev *dev;struct list_head *list;//  unsigned int input_num;//  int ret;vfe_dbg(0, "vfe_release\n");while (!list_empty(&devlist)){list = devlist.next;list_del(list);dev = list_entry(list, struct vfe_dev, devlist);
#ifdef CONFIG_ESunregister_early_suspend(&dev->early_suspend);
#endifkfree(dev);}vfe_print("vfe_release ok!\n");return 0;
}static int __devexit vfe_remove(struct platform_device *pdev)
{struct vfe_dev *dev;int input_num;dev = (struct vfe_dev *)dev_get_drvdata(&(pdev)->dev);mutex_destroy(&dev->stream_lock);mutex_destroy(&dev->standby_lock);mutex_destroy(&dev->opened_lock);
#ifdef USE_SPECIFIC_CCI//disable csi cci:csi_cci_bus_unmatch_helper(dev->vip_sel);
//csi_cci_exit_helper(dev->vip_sel);
#endifvfe_disable_regulator_all(dev);vfe_put_regulator(dev);for (input_num = 0; input_num < dev->dev_qty; input_num++){#ifdef _REGULATOR_CHANGE_
#elsevfe_device_regulator_put(dev->ccm_cfg[input_num]);
#endifif (!dev->ccm_cfg[input_num]->sensor_cfg_ini){kfree(dev->ccm_cfg[input_num]->sensor_cfg_ini);}}vfe_resource_release(dev);v4l2_info(&dev->v4l2_dev, "unregistering %s\n", video_device_node_name(dev->vfd));//video_device_release(dev->vfd);video_unregister_device(dev->vfd);v4l2_device_unregister(&dev->v4l2_dev);//  kfree(dev);vfe_print("vfe_remove ok!\n");return 0;
}static int vfe_suspend_helper(struct vfe_dev *dev)
{int ret = 0;unsigned int input_num;vfe_print("vfe_suspend_helper\n");if (!IS_ERR_OR_NULL(dev->power) && dev->power->stby_mode == NORM_STBY){vfe_print("Set camera to standy off and power off !\n");
#ifdef USE_SPECIFIC_CCIvfe_clk_open(dev);csi_cci_init_helper(dev->vip_sel);
#endif//close all the device powerfor (input_num = 0; input_num < dev->dev_qty; input_num++){/* update target device info and select it */update_ccm_info(dev, dev->ccm_cfg[input_num]);ret = v4l2_subdev_call(dev->sd, core, s_power, CSI_SUBDEV_STBY_OFF);if (ret != 0){vfe_err("sensor standby off error at device number %d when vfe_suspend!\n", input_num);}else{vfe_dbg(0, "sensor standby off ok at device number %d when vfe_suspend!\n", input_num);}ret = vfe_set_sensor_power_off(dev);if (ret != 0){vfe_err("sensor power off error at device number %d when vfe_suspend!\n", input_num);}else{vfe_dbg(0, "sensor power off ok at device number %d when vfe_suspend!\n", input_num);}}
#ifdef USE_SPECIFIC_CCIcsi_cci_exit_helper(dev->vip_sel);vfe_clk_close(dev);
#endif} //POWER_OFF do nothingdev->vfe_standby_poweroff_flag = 1;vfe_request_pin(dev, 0);vfe_gpio_config(dev, 0);vfe_disable_regulator_all(dev);vfe_print("vfe_suspend done!\n");return ret;
}static void resume_work_handle(struct work_struct *work)
{struct vfe_dev *dev = container_of(work, struct vfe_dev, resume_work);int ret = 0;unsigned int input_num;mutex_lock(&dev->standby_lock);vfe_print("resume_work_handle, vip_sel = %d!\n", dev->vip_sel);vfe_enable_regulator_all(dev);if (0 == dev->vfe_standby_poweroff_flag)goto resume_end;vfe_request_pin(dev, 1);vfe_gpio_config(dev, 1);if (!IS_ERR_OR_NULL(dev->power) && dev->power->stby_mode == NORM_STBY){#ifdef USE_SPECIFIC_CCIvfe_clk_open(dev);
#endif//open all the device powerfor (input_num = 0; input_num < dev->dev_qty; input_num++){/* update target device info and select it */update_ccm_info(dev, dev->ccm_cfg[input_num]);ret = vfe_set_sensor_power_on(dev);if (ret != 0){vfe_err("sensor power on error at device number %d when vfe_resume!\n", input_num);}else{vfe_dbg(0, "sensor power on ok at device number %d when vfe_resume!\n", input_num);}
#ifdef USE_SPECIFIC_CCIcsi_cci_init_helper(dev->vip_sel);
#endifret = v4l2_subdev_call(dev->sd, core, s_power, CSI_SUBDEV_STBY_ON);if (ret != 0){vfe_err("sensor standby on error at device number %d when vfe_resume!\n", input_num);}else{vfe_dbg(0, "sensor standby on ok at device number %d when vfe_resume!\n", input_num);}
#ifdef USE_SPECIFIC_CCIcsi_cci_exit_helper(dev->vip_sel);
#endif}
#ifdef USE_SPECIFIC_CCIvfe_clk_close(dev);
#endif} //POWER_OFF do nothing
resume_end:dev->vfe_standby_poweroff_flag = 0;up(&dev->standby_seq_sema);vfe_print("vfe resume work end!\n");mutex_unlock(&dev->standby_lock);
}#ifdef CONFIG_ES
static int vfe_suspend(struct platform_device *pdev, pm_message_t state)
{struct vfe_dev *dev = (struct vfe_dev *)dev_get_drvdata(&pdev->dev);mutex_lock(&dev->standby_lock);vfe_print("vfe suspend\n");if (0 == dev->early_suspend_valid_flag){if (down_timeout(&dev->standby_seq_sema, 4 * HZ)){vfe_err("Get standby sema Error!\n");}if (vfe_is_opened(dev)){vfe_err("FIXME: dev %s, err happened when calling %s.", dev_name(&dev->pdev->dev), __func__);goto suspend_end;}vfe_print("vfe power off in suspend\n");vfe_suspend_helper(dev);}
suspend_end:mutex_unlock(&dev->standby_lock);return 0;
}static int vfe_resume(struct platform_device *pdev)
{struct vfe_dev *dev = (struct vfe_dev *)dev_get_drvdata(&(pdev)->dev);vfe_print("vfe resume\n");if (0 == dev->early_suspend_valid_flag){vfe_print("vfe power on in resume\n");schedule_work(&dev->resume_work);}return 0;
}static void vfe_early_suspend(struct early_suspend *h)
{struct vfe_dev *dev = container_of(h, struct vfe_dev, early_suspend);vfe_print("vfe early suspend\n");mutex_lock(&dev->standby_lock);if (down_timeout(&dev->standby_seq_sema, 2 * HZ)){vfe_err("Enter early suspend, Get standby sema Error!\n");}if (vfe_is_opened(dev)){vfe_print("Enter early suspend, but vfe is opened, power off vfe in suspend later!");dev->early_suspend_valid_flag = 0;goto suspend_end;}vfe_print("vfe power off in early suspend\n");vfe_suspend_helper(dev);dev->early_suspend_valid_flag = 1;
suspend_end:mutex_unlock(&dev->standby_lock);
}static void vfe_late_resume(struct early_suspend *h)
{struct vfe_dev *dev = container_of(h, struct vfe_dev, early_suspend);vfe_print("vfe late resume\n");if (1 == dev->early_suspend_valid_flag){vfe_print("vfe power on in late resume\n");schedule_work(&dev->resume_work);}
}
#else
static int vfe_suspend(struct platform_device *pdev, pm_message_t state)
{struct vfe_dev *dev = (struct vfe_dev *)dev_get_drvdata(&pdev->dev);vfe_print("vfe suspend\n");mutex_lock(&dev->standby_lock);if (down_timeout(&dev->standby_seq_sema, 4 * HZ)){vfe_err("Get standby sema Error!\n");}if (vfe_is_opened(dev)){vfe_err("FIXME: dev %s, err happened when calling %s.", dev_name(&dev->pdev->dev), __func__);goto suspend_end;}vfe_print("vfe power off in suspend\n");vfe_suspend_helper(dev);
suspend_end:mutex_unlock(&dev->standby_lock);return 0;
}
static int vfe_resume(struct platform_device *pdev)
{struct vfe_dev *dev = (struct vfe_dev *)dev_get_drvdata(&(pdev)->dev);vfe_print("vfe resume\n");schedule_work(&dev->resume_work);return 0;
}
#endifstatic void vfe_shutdown(struct platform_device *pdev)
{
#if defined(CONFIG_ES) || defined(CONFIG_SUSPEND)vfe_print("Defined suspend!\n");
#elsestruct vfe_dev *dev = (struct vfe_dev *)dev_get_drvdata(&pdev->dev);unsigned int input_num;int ret = 0;//close all the device powerfor (input_num = 0; input_num < dev->dev_qty; input_num++){/* update target device info and select it */update_ccm_info(dev, dev->ccm_cfg[input_num]);ret = vfe_set_sensor_power_off(dev);if (ret != 0){vfe_err("sensor power off error at device number %d when csi close!\n", input_num);}}
#endifvfe_print("Vfe Shutdown!\n");
}static struct platform_driver vfe_driver = {.probe = vfe_probe,.remove = __devexit_p(vfe_remove),.suspend = vfe_suspend,.resume = vfe_resume,.shutdown = vfe_shutdown,//.id_table = vfe_driver_ids,.driver = {.name = VFE_MODULE_NAME,.owner = THIS_MODULE,}
};static struct sunxi_vip_platform_data sunxi_vip0_pdata[] = {{.mipi_sel = 0,.vip_sel = 0,.isp_sel = 0,},
};static struct sunxi_vip_platform_data sunxi_vip1_pdata[] = {{.mipi_sel = 1,.vip_sel = 1,.isp_sel = 0,},
};static void vfe_device_release(struct device *dev)
{//struct vfe_dev *vfe_dev = (struct vfe_dev *)dev_get_drvdata(dev);vfe_print("vfe_device_release\n");
};static struct platform_device vfe_device[] = {[0] = {.name = VFE_MODULE_NAME,.id = 0,.num_resources = ARRAY_SIZE(vfe_vip0_resource),.resource = vfe_vip0_resource,.dev = {.platform_data = sunxi_vip0_pdata,.release = vfe_device_release,},},[1] = {.name = VFE_MODULE_NAME, .id = 1, .num_resources = ARRAY_SIZE(vfe_vip1_resource), .resource = vfe_vip1_resource, .dev = {.platform_data = sunxi_vip1_pdata, .release = vfe_device_release,},},
};static int __init vfe_init(void)
{int ret, i;unsigned int vfe_used[MAX_VFE_INPUT];#ifdef VFE_SYS_CONFIGscript_item_u val;script_item_value_type_e type;char vfe_para[16] = {0};for (i = 0; i < MAX_VFE_INPUT; i++){sprintf(vfe_para, "csi%d", i);type = script_get_item(vfe_para, "vip_used", &val);if (SCIRPT_ITEM_VALUE_TYPE_INT != type){vfe_err("fetch %s vip_used from sys_config failed\n", vfe_para);return -1;}else{vfe_used[i] = val.val;}}
#else
#if defined(CONFIG_ARCH_SUN8IW3P1) || defined(CONFIG_ARCH_SUN8IW5P1) || defined(CONFIG_ARCH_SUN8IW6P1) || defined(CONFIG_ARCH_SUN8IW7P1)vfe_used[0] = 1;vfe_used[1] = 0;
#elsevfe_used[0] = 0;vfe_used[1] = 1;
#endif
#endifvfe_print("Welcome to Video Front End driver\n");mutex_init(&probe_hdl_lock);for (i = 0; i < MAX_VFE_INPUT; i++){if (vfe_used[i]){ret = platform_device_register(&vfe_device[i]);if (ret)vfe_err("platform device %d register failed\n", i);}}ret = platform_driver_register(&vfe_driver);if (ret){vfe_err("platform driver register failed\n");return ret;}vfe_print("vfe_init end\n");return 0;
}static void __exit vfe_exit(void)
{unsigned int vfe_used[MAX_VFE_INPUT];int i;
#ifdef VFE_SYS_CONFIGchar vfe_para[16] = {0};script_item_u val;script_item_value_type_e type;for (i = 0; i < MAX_VFE_INPUT; i++){sprintf(vfe_para, "csi%d", i);type = script_get_item(vfe_para, "vip_used", &val);if (SCIRPT_ITEM_VALUE_TYPE_INT != type){vfe_err("fetch %s vip_used from sys_config failed\n", vfe_para);return;}else{vfe_used[i] = val.val;}}
#else
#if defined(CONFIG_ARCH_SUN8IW3P1) || defined(CONFIG_ARCH_SUN8IW5P1) || defined(CONFIG_ARCH_SUN8IW7P1)vfe_used[0] = 1;vfe_used[1] = 0;
#elsevfe_used[0] = 0;vfe_used[1] = 1;
#endif
#endifvfe_print("vfe_exit\n");for (i = 0; i < MAX_VFE_INPUT; i++){if (vfe_used[i]){platform_device_unregister(&vfe_device[i]);vfe_print("platform_device_unregister[%d]\n", i);}}platform_driver_unregister(&vfe_driver);vfe_print("platform_driver_unregister\n");vfe_release();mutex_destroy(&probe_hdl_lock);vfe_print("vfe_exit end\n");
}module_init(vfe_init);
module_exit(vfe_exit);MODULE_AUTHOR("raymonxiu");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("Video front end driver for sunxi");

因为篇幅问题,具体Sensor需要实现的内容,这里就不贴出来了,如果需要看,可以到上前面给的连接里面看代码,位置在: linux-3.4.113/drivers/media/video/sunxi-vfe/device/gc2035.c

验证的话,如下:

1).cd /lib/modules/3.4.113/kernel/drivers/media/video/sunxi-vfe/device

sudo modprobe gc2035    // 注意,不要加.ko后缀

2).cd /lib/modules/3.4.113/kernel/drivers/media/video/sunxi-vfe/

sudo modprobe vfe_v4l2    // 注意,不要加.ko后缀

3).sudo apt-get --fix-missing install motion

4).sudo nano /etc/motion/motion.conf

找到这个选项,填off, strean_localhost off

5).mkdir ~/motion

chmod 777 motion

6).sudo nano /etc/default/motion

把选项改成: start_motion=yes

7).sudo /etc/init.d/motion start

8).在局域网浏览器中输入: $(板子IP):8081,比如192.168.1.103:8081,就可以看到实时图像了.

详细可参考如下链接:

https://www.cnx-software.com/2015/09/26/how-to-use-orange-pi-camera-in-linux-with-motion/

就先说这么多吧,下面提供一个执行的大致log:

open
===========
[  117.051917] [VFE]vfe_open
[  117.051944] [VFE]..........................vfe clk open!.......................
[  117.051972] [VFE]vfe_open ok
[  117.052040] [VFE]Set vfe core clk = 108000000, after Set vfe core clk = 99000000
[  117.052055] NOT_SUPPORT_THIS_FUNCTION:sun8iw3p1_isp_set_table_addr, line: 368
[  117.052079] [VFE]mclk on
[  117.416431] [CSI_ERR][GC0308]empty wins!
[  117.416807] [VFE]buffer_setup, buffer count=7, size=460800
[  117.449709] [VFE_WARN]v4l2 sub device queryctrl unsuccess,id = 9a091b!
[  117.580167] [VFE]capture video mode!
[  117.690126] [VFE]capture video first frame done!close
============
[  120.140076] [VFE]vfe_close
[  120.171162] [VFE]mclk off
[  120.183326] [VFE]..........................vfe clk close!.......................
[  120.183404] [VFE]vfe_close end

㉓AW-H3 Linux驱动开发之mipi camera(CSI)驱动程序相关推荐

  1. ⑨tiny4412 Linux驱动开发之1-wire子系统(DS18B20)驱动程序

    本来这次想做LCD背光灯的调节的,但是没有调通,时间很紧迫,就转向了其它东西,昨天调了一下DHT11,今天又调了一下DS18B20,还算有个安慰,本来是想用1-wire子系统做的,但是时间上有点紧,要 ...

  2. linux 串口驱动 4412,⑮tiny4412 Linux驱动开发之tty子系统(UART)驱动程序

    本次说一下tty子系统的驱动编程,因为UART相关的寄存器比较多,同时,应用比较广泛,所以本次的驱动程序量也不少,而且只是完成和特定CPU相关的一部分,通用的部分本次都没有涉及到.在写驱动之前,我们先 ...

  3. Linux驱动开发之platform设备驱动实验【完整教程】

    为了方便驱动的编写,提高软件的重用性和跨平台性能,于是就提出了Linux驱动的分离和分层   驱动的分层,分层的目的时为了在不同的层处理不同的内容,最简单的驱动分层是input子系统负责管理所有跟输入 ...

  4. ㉔AW-H3 Linux驱动开发之HDMI驱动程序

    HDMI: High Definition Multimedia Interface,高清多媒体接口,是一种全数字化视频和声音发送接口,可以发送未压缩的音频及视频信号.HDMI有4种类型的接口,分别为 ...

  5. ㉕AW-A33 Linux驱动开发之audio子系统驱动程序

    在Linux源码里,Aduio这一部分现在是一个独立文件夹叫sound,在2.x的版本时,sound这个目录是在drivers里的,后来从这个里面剥离出来了,很多人不知道其中的原因,我也不知道,我们先 ...

  6. ⑭tiny4412 Linux驱动开发之cpufreq子系统驱动程序

    本次我们来说一下CPU动态调频子系统. 首先来看一下三星Exynos 4412的datasheet,如下: 上图就是Exynos 4412的时钟分布图,可以看到CPU的频率可以在1.4GHz~200M ...

  7. linux驱动开发之spi-omap-100k.c源码分析

    代码分析 对于linux的驱动代码来说,我们要从后往前分析: /** OMAP7xx SPI 100k controller driver* Author: Fabrice Crohas <fc ...

  8. Linux驱动开发之IIC驱动实验【完整教程】

    本实验基于正点原子ALPHT开发板上的AP3216C作为实验开展对象 基础知识 1.IIC总线驱动   IIC总线驱动是对IIC硬件体系结构中适配器端的实现,适配器可由CPU控制,甚至可以直接集成在C ...

  9. Linux驱动开发之USB驱动深入学习(三)——USB2.0ECHI驱动注册

    一.前言 本篇博客仅对ECHI主机控制器驱动的注册部分进行简要叙述,后面再对一些重要的接口进行分析讲解. 二.USB 1.概述 USB(Universal Serial Bus)即"通用外部 ...

最新文章

  1. 【系列】EOS开发1 开发环境搭建
  2. python大神-6年Python大神总结10个开发技巧,80%的人都不会
  3. java 集合框架(一)
  4. 中专学计算机毕业后的去向作文,中专生的毕业感言作文
  5. 基于.net core 3 和 Orleans 3 的 开发框架:Phenix Framework 7
  6. jq 实现头像(气泡式浮动)
  7. 号外号外:Exchange2010SP2已经发布
  8. c语言课程设计实训主要目的,C语言课程设计实训指导书.doc
  9. 圆周率一千万亿位_圆周率已经达到1000万亿位了,为何还在不断计算,到底有什么用?...
  10. 24V单节锂电池充电芯片
  11. 【Android Studio】XUI框架的使用记录:源代码Demo安装+从Demo中获取捷径快速开发自己的APP
  12. 心不唤物,物不至,聊聊积极心态重要性
  13. ssh中关于antion取jsp传递的值接收不到
  14. 各种生物识别的优缺点
  15. 【每日学习】深度学习相关知识
  16. 网络硬件三剑客 - 集线器、交换机与路由器
  17. 简单的复习下箭头函式
  18. H5视频播放器--西瓜视频播放器
  19. 郝斌c语言大纲百度云,C语言学习大纲 郝斌(讲解)
  20. JAVA开发装机必备软件

热门文章

  1. Gulp老矣 尚能饭否
  2. 财务学python可以做什么-财务方面的学生如何学习python?
  3. matlab地震振幅属性分析,洛马普列塔地震分析 - MATLAB Simulink Example - MathWorks 中国...
  4. CAD图导入SU中一次成面的方法
  5. 免云挂机聚合易支付码支付V6.5修正版系统源码
  6. 应届毕业生不想应聘上班,一心想独自创业,有什么好的项目推荐?
  7. 信息收集(一)域名信息收集
  8. http://pan.baidu.com/share/link?shareid=2725301264uk=3138325909
  9. Servlet | ServletConfig接口、ServletContext接口详解
  10. 【新】CSDN文章一键打印、输出PDF(自动阅读全文、全清爽模式)