coms_ov7740驱动

  1. /* 第一个参数名字用于匹配,第二个参数是摄像头地址 */  
  2. static struct i2c_board_info cmos_ov7740_info = {     
  3.     /* 由芯片手册可知,写 -- 0x42(01000010),读 -- 0x43(01000011) 
  4.      * 将读地址或者写地址,向右移动一位即可。 
  5.      */  
  6.     I2C_BOARD_INFO("cmos_ov7740", 0x21),  
  7. };  
  8.   
  9. static struct i2c_client *cmos_ov7740_client;  
  10.   
  11. static int cmos_ov7740_dev_init(void)  
  12. {  
  13.     struct i2c_adapter *i2c_adap;  
  14.     /* 获得适配器,由2440原理图可知,2440只有一个iic控制器,所以iic控制器为适配器0, 
  15.      * 也就是0号iic总线上  
  16.      */  
  17.     i2c_adap = i2c_get_adapter(0);  
  18.     cmos_ov7740_client = i2c_new_device(i2c_adap, &cmos_ov7740_info);  
  19.     /* 适配器使用完后要释放他 */  
  20.     i2c_put_adapter(i2c_adap);  
  21.   
  22.     return 0;  
  23. }  
  24.   
  25. static void cmos_ov7740_dev_exit(void)  
  26. {  
  27.     i2c_unregister_device(cmos_ov7740_client);  
  28. }  
  29.   
  30. module_init(cmos_ov7740_dev_init);  
  31. module_exit(cmos_ov7740_dev_exit);  
  32.   
  33. MODULE_LICENSE("GPL");  
  34.   
  35.   
  36.   

  1. cmos_ov7740_drv.c  

  1. #define OV7740_INIT_REGS_SIZE (sizeof(ov7740_setting_30fps_VGA_640_480)/sizeof(ov7740_setting_30fps_VGA_640_480[0]))  
  2.   
  3. #define CAM_SRC_HSIZE   (640)  
  4. #define CAM_SRC_VSIZE   (480)  
  5.   
  6. #define CAM_ORDER_YCbYCr (0)  
  7. #define CAM_ORDER_YCrYCb (1)  
  8. #define CAM_ORDER_CbYCrY (2)  
  9. #define CAM_ORDER_CrYCbY (3)  
  10.   
  11. #define WinHorOfst      (0)  
  12. #define WinVerOfst      (0)  
  13.   
  14. struct cmos_ov7740_scaler {  
  15.     unsigned int PreHorRatio;//水平变比  
  16.     unsigned int PreVerRatio;//垂直变比  
  17.     unsigned int H_Shift;//水平比  
  18.     unsigned int V_Shift;//垂直比  
  19.     unsigned int PreDstWidth;//目标宽度  
  20.     unsigned int PreDstHeight;//目标高度  
  21.     unsigned int MainHorRatio;//预览主缩放的水平比  
  22.     unsigned int MainVerRatio;//预览主缩放的垂直比  
  23.     unsigned int SHfactor;//缩放变比  
  24.     unsigned int ScaleUpDown;//放大缩小标志  
  25. };  
  26.   
  27. static struct cmos_ov7740_scaler sc;  
  28.   
  29. typedef struct cmos_ov7740_i2c_value {  
  30.     unsigned char regaddr;  
  31.     unsigned char value;  
  32. }ov7740_t;  
  33.   
  34. /* init: 640x480,30fps的,YUV422输出格式 */  
  35. ov7740_t ov7740_setting_30fps_VGA_640_480[] =  
  36. {  
  37.     {0x12, 0x80},  
  38.     {0x47, 0x02},  
  39.     {0x17, 0x27},  
  40.     {0x04, 0x40},  
  41.     {0x1B, 0x81},  
  42.     {0x29, 0x17},  
  43.     {0x5F, 0x03},  
  44.     {0x3A, 0x09},  
  45.     {0x33, 0x44},  
  46.     {0x68, 0x1A},  
  47.   
  48.     {0x14, 0x38},  
  49.     {0x5F, 0x04},  
  50.     {0x64, 0x00},  
  51.     {0x67, 0x90},  
  52.     {0x27, 0x80},  
  53.     {0x45, 0x41},  
  54.     {0x4B, 0x40},  
  55.     {0x36, 0x2f},  
  56.     {0x11, 0x01},  
  57.     {0x36, 0x3f},  
  58.     {0x0c, 0x12},  
  59.   
  60.     {0x12, 0x00},  
  61.     {0x17, 0x25},  
  62.     {0x18, 0xa0},  
  63.     {0x1a, 0xf0},  
  64.     {0x31, 0xa0},  
  65.     {0x32, 0xf0},  
  66.   
  67.     {0x85, 0x08},  
  68.     {0x86, 0x02},  
  69.     {0x87, 0x01},  
  70.     {0xd5, 0x10},  
  71.     {0x0d, 0x34},  
  72.     {0x19, 0x03},  
  73.     {0x2b, 0xf8},  
  74.     {0x2c, 0x01},  
  75.   
  76.     {0x53, 0x00},  
  77.     {0x89, 0x30},  
  78.     {0x8d, 0x30},  
  79.     {0x8f, 0x85},  
  80.     {0x93, 0x30},  
  81.     {0x95, 0x85},  
  82.     {0x99, 0x30},  
  83.     {0x9b, 0x85},  
  84.   
  85.     {0xac, 0x6E},  
  86.     {0xbe, 0xff},  
  87.     {0xbf, 0x00},  
  88.     {0x38, 0x14},  
  89.     {0xe9, 0x00},  
  90.     {0x3D, 0x08},  
  91.     {0x3E, 0x80},  
  92.     {0x3F, 0x40},  
  93.     {0x40, 0x7F},  
  94.     {0x41, 0x6A},  
  95.     {0x42, 0x29},  
  96.     {0x49, 0x64},  
  97.     {0x4A, 0xA1},  
  98.     {0x4E, 0x13},  
  99.     {0x4D, 0x50},  
  100.     {0x44, 0x58},  
  101.     {0x4C, 0x1A},  
  102.     {0x4E, 0x14},  
  103.     {0x38, 0x11},  
  104.     {0x84, 0x70}  
  105. };  
  106.   
  107. struct cmos_ov7740_fmt {  
  108.     char  *name;  
  109.     u32   fourcc;          /* v4l2 format id */  
  110.     int   depth;  
  111. };  
  112.   
  113. /* 这两个格式仅仅是预览通道支持的格式,由控制器的芯片手册可知 */  
  114. static struct cmos_ov7740_fmt formats[] = {  
  115.     {  
  116.         .name     = "RGB565",  
  117.         .fourcc   = V4L2_PIX_FMT_RGB565,  
  118.         .depth    = 16,  
  119.     },  
  120.     {  
  121.         .name     = "PACKED_RGB_888",  
  122.         .fourcc   = V4L2_PIX_FMT_RGB24,  
  123.         .depth    = 24,  
  124.     },  
  125. };  
  126.   
  127. struct camif_buffer  
  128. {  
  129.     unsigned int order;  
  130.     unsigned long virt_base;  
  131.     unsigned long phy_base;   
  132. };  
  133.   
  134. struct camif_buffer img_buff[] =  
  135. {  
  136.     {  
  137.         .order = 0,  
  138.         .virt_base = (unsigned long)NULL,  
  139.         .phy_base = (unsigned long)NULL       
  140.     },  
  141.     {  
  142.         .order = 0,  
  143.         .virt_base = (unsigned long)NULL,  
  144.         .phy_base = (unsigned long)NULL       
  145.     },  
  146.     {  
  147.         .order = 0,  
  148.         .virt_base = (unsigned long)NULL,  
  149.         .phy_base = (unsigned long)NULL       
  150.     },  
  151.     {  
  152.         .order = 0,  
  153.         .virt_base = (unsigned long)NULL,  
  154.         .phy_base = (unsigned long)NULL       
  155.     }  
  156. };  
  157.   
  158. static struct i2c_client *cmos_ov7740_client;  
  159.   
  160. // CAMIF GPIO  
  161. static unsigned long *GPJCON;  
  162. static unsigned long *GPJDAT;  
  163. static unsigned long *GPJUP;  
  164.   
  165. // CAMIF  
  166. static unsigned long *CISRCFMT;  
  167. static unsigned long *CIWDOFST;  
  168. static unsigned long *CIGCTRL;  
  169. static unsigned long *CIPRCLRSA1;  
  170. static unsigned long *CIPRCLRSA2;  
  171. static unsigned long *CIPRCLRSA3;  
  172. static unsigned long *CIPRCLRSA4;  
  173. static unsigned long *CIPRTRGFMT;  
  174. static unsigned long *CIPRCTRL;  
  175. static unsigned long *CIPRSCPRERATIO;  
  176. static unsigned long *CIPRSCPREDST;  
  177. static unsigned long *CIPRSCCTRL;  
  178. static unsigned long *CIPRTAREA;  
  179. static unsigned long *CIIMGCPT;  
  180.   
  181. // IRQ  
  182. static unsigned long *SRCPND;  
  183. static unsigned long *INTPND;  
  184. static unsigned long *SUBSRCPND;  
  185.   
  186. static unsigned int SRC_Width, SRC_Height;  
  187. static unsigned int TargetHsize_Pr, TargetVsize_Pr;  
  188. static unsigned long buf_size;  
  189. static unsigned int bytesperline;  
  190.   
  191. static DECLARE_WAIT_QUEUE_HEAD(cam_wait_queue);  
  192. /* 中断标志 */  
  193. static volatile int ev_cam = 0;  
  194.   
  195. static irqreturn_t cmos_ov7740_camif_irq_c(int irq, void *dev_id)   
  196. {  
  197.     return IRQ_HANDLED;  
  198. }  
  199.   
  200. static irqreturn_t cmos_ov7740_camif_irq_p(int irq, void *dev_id)   
  201. {  
  202.     /* 清中断,因为不是使用上升沿或者下降沿触发,所以我们要清楚中断标志位 
  203.      * 确保下次能继续产生中断。由中断控制器的手册394页可知,向相应的寄存器写入1 
  204.      * 就是清除相应的中断标识,写入0表示保持原来的标志不变。 
  205.      */  
  206.     *SRCPND = 1<<6;  
  207.     *INTPND = 1<<6;  
  208.     *SUBSRCPND = 1<<12 ev_cam="1;" wake_up_interruptible="" cam_wait_queue="" return="" irq_handled="" a2="" uvc_v4l2_do_ioctl="" static="" int="" cmos_ov7740_vidioc_querycap="" struct="" file="" file="" void="" priv="" struct="" v4l2_capability="" cap="" memset="" cap="" 0="" sizeof="" cap="" strcpy="" cap-="">driver, "cmos_ov7740");  
  209.     strcpy(cap->card, "cmos_ov7740");  
  210.     cap->version = 2;  
  211.     /* V4L2_CAP_READWRITE表示获取摄像头数据使用过读写操作,不是通过流操作 
  212.      * 所谓流操作就是通过qbuf,dqbuf,mmap,poll等函数来获得数据的 
  213.      */  
  214.     cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;  
  215.   
  216.     return 0;  
  217. }  
  218.   
  219. /* A3 列举支持哪种格式 
  220.  * 参考: uvc_fmts 数组 
  221.  */  
  222. static int cmos_ov7740_vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,  
  223.                     struct v4l2_fmtdesc *f)  
  224. {  
  225.     struct cmos_ov7740_fmt *fmt;  
  226.   
  227.     if (f->index >= ARRAY_SIZE(formats))  
  228.         return -EINVAL;  
  229.   
  230.     fmt = &formats[f->index];  
  231.   
  232.     strlcpy(f->description, fmt->name, sizeof(f->description));  
  233.     f->pixelformat = fmt->fourcc;  
  234.   
  235.     return 0;  
  236. }  
  237.   
  238. /* A4 返回当前所使用的格式 */  
  239. static int cmos_ov7740_vidioc_g_fmt_vid_cap(struct file *file, void *priv,  
  240.                     struct v4l2_format *f)  
  241. {  
  242.     return 0;  
  243. }  
  244.   
  245. /* A5 测试驱动程序是否支持某种格式, 强制设置该格式  
  246.  * 参考: uvc_v4l2_try_format 
  247.  *       myvivi_vidioc_try_fmt_vid_cap 
  248.  */  
  249. static int cmos_ov7740_vidioc_try_fmt_vid_cap(struct file *file, void *priv,  
  250.             struct v4l2_format *f)  
  251. {  
  252.     /* 判断是否为摄像头设备 */  
  253.     if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)  
  254.     {  
  255.         return -EINVAL;  
  256.     }  
  257.   
  258.     /* 在coms中的CICOSCCTRL寄存器中可知,在预览通道只支持RGB16/RGB24 */  
  259.     if ((f->fmt.pix.pixelformat != V4L2_PIX_FMT_RGB565) && (f->fmt.pix.pixelformat != V4L2_PIX_FMT_RGB24))  
  260.         return -EINVAL;  
  261.   
  262.     return 0;  
  263. }  
  264.   
  265. /* A6 参考 myvivi_vidioc_s_fmt_vid_cap  
  266.  * 设置摄像头数据格式 
  267.  */  
  268. static int cmos_ov7740_vidioc_s_fmt_vid_cap(struct file *file, void *priv,  
  269.                     struct v4l2_format *f)  
  270. {  
  271.     int ret = cmos_ov7740_vidioc_try_fmt_vid_cap(file, NULL, f);  
  272.     if (ret < 0)  
  273.         return ret;  
  274.     /* 目标图像的水平像素大小 */  
  275.     TargetHsize_Pr = f->fmt.pix.width;  
  276.     /* 目标图像的垂直像素大小 */  
  277.     TargetVsize_Pr = f->fmt.pix.height;  
  278.   
  279.     if(f->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565)  
  280.     {  
  281.         /* bit[30]: 设置图像输出格式是RGB16、RGB24 */  
  282.         *CIPRSCCTRL &= ~(1<<30 f-="">fmt.pix.bytesperline = (f->fmt.pix.width * 16) >> 3;  
  283.         f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;  
  284.         buf_size = f->fmt.pix.sizeimage;  
  285.         bytesperline = f->fmt.pix.bytesperline;  
  286.     }  
  287.     else if(f->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB24)  
  288.     {  
  289.         /* bit[30]: 设置图像输出格式是RGB16、RGB24 */  
  290.         *CIPRSCCTRL |= (1<<30 rgb24="" 32="" s3c2440="" 515="" f-="">fmt.pix.bytesperline = (f->fmt.pix.width * 32) >> 3;  
  291.         f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;  
  292.         buf_size = f->fmt.pix.sizeimage;  
  293.         bytesperline = f->fmt.pix.bytesperline;  
  294.     }  
  295.       
  296.   
  297.   
  298.     /* 
  299.     CIPRTRGFMT: 
  300.         bit[28:16] -- 表示目标图片的水平像素大小(TargetHsize_Pr) 
  301.         bit[15:14] -- 是否旋转,我们这个驱动就不选择了 
  302.         bit[12:0]    -- 表示目标图片的垂直像素大小(TargetVsize_Pr) 
  303.     */  
  304.     *CIPRTRGFMT = (TargetHsize_Pr<<16)|(0x0<<14)|(TargetVsize_Pr<<0 return="" 0="" ciprclrsa1="" static="" int="" cmos_ov7740_vidioc_reqbufs="" struct="" file="" file="" void="" priv="" struct="" v4l2_requestbuffers="" p="" unsigned="" int="" order="" __get_free_pages="" get_order="" order="get_order(buf_size);" img_buff="" 0="" order="order;" __get_free_pages="" 4m="" kmalloc="" 128k="" img_buff="" 0="" virt_base="__get_free_pages(GFP_KERNEL|__GFP_DMA," img_buff="" 0="" order="" if="" img_buff="" 0="" virt_base="=" unsigned="" long="" null="" printk="" error0="" n="" goto="" error0="" ciprclrsa1="" img_buff="" 0="" phy_base="__virt_to_phys(img_buff[0].virt_base);" img_buff="" 1="" order="order;" img_buff="" 1="" virt_base="__get_free_pages(GFP_KERNEL|__GFP_DMA," img_buff="" 1="" order="" if="" img_buff="" 1="" virt_base="=" unsigned="" long="" null="" printk="" error1="" n="" goto="" error1="" img_buff="" 1="" phy_base="__virt_to_phys(img_buff[1].virt_base);" img_buff="" 2="" order="order;" img_buff="" 2="" virt_base="__get_free_pages(GFP_KERNEL|__GFP_DMA," img_buff="" 2="" order="" if="" img_buff="" 2="" virt_base="=" unsigned="" long="" null="" printk="" error2="" n="" goto="" error2="" img_buff="" 2="" phy_base="__virt_to_phys(img_buff[2].virt_base);" img_buff="" 3="" order="order;" img_buff="" 3="" virt_base="__get_free_pages(GFP_KERNEL|__GFP_DMA," img_buff="" 3="" order="" if="" img_buff="" 3="" virt_base="=" unsigned="" long="" null="" printk="" error3="" n="" goto="" error3="" img_buff="" 3="" phy_base="__virt_to_phys(img_buff[3].virt_base);" ciprclrsa1="" ciprclrsa1="img_buff[0].phy_base;" ciprclrsa2="img_buff[1].phy_base;" ciprclrsa3="img_buff[2].phy_base;" ciprclrsa4="img_buff[3].phy_base;" return="" 0="" error3:="" free_pages="" img_buff="" 2="" virt_base="" order="" img_buff="" 2="" phy_base="(unsigned" long="" null="" error2:="" free_pages="" img_buff="" 1="" virt_base="" order="" img_buff="" 1="" phy_base="(unsigned" long="" null="" error1:="" free_pages="" img_buff="" 0="" virt_base="" order="" img_buff="" 0="" phy_base="(unsigned" long="" null="" error0:="" return="" -enomem="" 2440="" 532="" static="" void="" calculateburstsize="" unsigned="" int="" hsize="" unsigned="" int="" mainbusrtsize="" unsigned="" int="" remainedbustsize="" unsigned="" int="" tmp="" 2="" 4="" 8="" 16="" 16="" tmp="(hSize/4)%16;" switch="" tmp="" case="" 0:="" mainbusrtsize="16;" remainedbustsize="16;" break="" case="" 4:="" mainbusrtsize="16;" remainedbustsize="4;" break="" case="" 8:="" mainbusrtsize="16;" remainedbustsize="8;" break="" 16="" 8="" default:="" tmp="(hSize/4)%8;" switch="" tmp="" case="" 0:="" mainbusrtsize="8;" remainedbustsize="8;" break="" case="" 4:="" mainbusrtsize="8;" remainedbustsize="4;" break="" 8="" 4="" default:="" mainbusrtsize="4;" tmp="(hSize/4)%4;" remainedbustsize="(tmp)?tmp:4;" break="" break="" jz2440="" 527="" static="" void="" camif_get_scaler_factor="" u32="" src="" u32="" tar="" u32="" ratio="" u32="" shift="" if="" src="">= 64*tar) {return;}  
  305.     else if(src >= 32*tar) {*ratio = 32; *shift = 5;}  
  306.     else if(src >= 16*tar) {*ratio = 16; *shift = 4;}  
  307.     else if(src >= 8*tar) {*ratio = 8; *shift = 3;}  
  308.     else if(src >= 4*tar) {*ratio = 4; *shift = 2;}  
  309.     else if(src >= 2*tar) {*ratio = 2; *shift = 1;}  
  310.     else {*ratio = 1; *shift = 0;}  
  311. }  
  312.   
  313. /* 计算公式在2440用户手册的527页 */  
  314. static void cmos_ov7740_calculate_scaler_info(void)  
  315. {  
  316.     unsigned int sx, sy, tx, ty;  
  317.   
  318.     /* 这里的源宽度和源高度是经过窗口剪切的图像数据  
  319.      * 这里的目标宽度和高度是应用程序在cmos_ov7740_vidioc_s_fmt_vid_cap函数 
  320.      * 设置数据格式时传入的,表示应用程序想要获得的图像分辨率 
  321.      */  
  322.     sx = SRC_Width;  
  323.     sy = SRC_Height;  
  324.     tx = TargetHsize_Pr;  
  325.     ty = TargetVsize_Pr;  
  326.   
  327.     printk("%s: SRC_in(%d, %d), Target_out(%d, %d)\n", __func__, sx, sy, tx, ty);  
  328.   
  329.     camif_get_scaler_factor(sx, tx, &sc.PreHorRatio, &sc.H_Shift);  
  330.     camif_get_scaler_factor(sy, ty, &sc.PreVerRatio, &sc.V_Shift);  
  331.   
  332.     sc.PreDstWidth = sx / sc.PreHorRatio;  
  333.     sc.PreDstHeight = sy / sc.PreVerRatio;  
  334.       
  335.     sc.MainHorRatio = (sx << 8) / (tx << sc.H_Shift);  
  336.     sc.MainVerRatio = (sy << 8) / (ty << sc.V_Shift);  
  337.   
  338.     sc.SHfactor = 10 - (sc.H_Shift + sc.V_Shift);  
  339.   
  340.     sc.ScaleUpDown = (tx>=sx)?1:0;  
  341. }  
  342.   
  343. /* A11 启动传输  
  344.  * 参考: uvc_video_enable(video, 1): 
  345.  *           uvc_commit_video 
  346.  *           uvc_init_video 
  347.  */  
  348. static int cmos_ov7740_vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)  
  349. {  
  350.     unsigned int Main_burst, Remained_burst;  
  351.   
  352.     /* 
  353.     CISRCFMT: 
  354.         bit[31] -- 选择传输方式为BT601或者BT656 
  355.         bit[30] -- 设置偏移值(0 = +0 (正常情况下) - for YCbCr) 
  356.         bit[29] -- 保留位,必须设置为0 
  357.         bit[28:16]  -- 设置源图片的水平像素值(640) 
  358.         bit[15:14]  -- 设置源图片的颜色顺序(0x0c --> 0x2),由摄像头地址为0xc的寄存器 
  359.         可知,输出的顺序为UYVYUYVY------>CbYCrYCbYCrY, 
  360.         bit[12:0]       -- 设置源图片的垂直像素值(480) 
  361.          
  362.         水平和垂直的像素值是摄像头模块输入的,查看摄像头模块输出水平和垂直的像素值即可 
  363.     */  
  364.     *CISRCFMT |= (0<<30)|(0<<29)|(CAM_SRC_HSIZE<<16)|(CAM_ORDER_CbYCrY<<14)|(CAM_SRC_VSIZE<<0);  
  365.   
  366.     /* 
  367.     CIWDOFST: 
  368.         bit[31]     -- 1 = 使能窗口功能、0 = 不使用窗口功能 
  369.         bit[30、15:12]-- 清除溢出标志位 
  370.         bit[26:16]  -- 水平方向的裁剪的大小 
  371.         bit[10:0]       -- 垂直方向的裁剪的大小 
  372.     */  
  373.     *CIWDOFST |=(1<<30)|(0xf<<12);  
  374.     *CIWDOFST |= (1<<31)|(WinHorOfst<<16)|(WinVerOfst<<0);  
  375.     /* 裁剪后的图像宽度 = 原始图像宽度 - 2*水平窗口宽度 */  
  376.     SRC_Width = CAM_SRC_HSIZE - 2*WinHorOfst;  
  377.     /* 裁剪后的图像高度 = 原始图像高度 - 2*水平窗口高度 */  
  378.     SRC_Height = CAM_SRC_VSIZE - 2*WinVerOfst;  
  379.   
  380.     /* 
  381.     CIGCTRL: 
  382.         bit[31]     -- 软件复位CAMIF控制器 
  383.         bit[30]     -- 用于复位外部摄像头模块 
  384.         bit[29]     -- 保留位,必须设置为1 
  385.         bit[28:27]  -- 用于选择信号源(00 = 输入源来自摄像头模块) 
  386.         bit[26]     -- 设置像素时钟的极性(猜0) 
  387.         bit[25]     -- 设置VSYNC的极性(0) 
  388.         bit[24]     -- 设置HREF的极性(0),行同步信号 
  389.     */  
  390.     *CIGCTRL |= (1<<29)|(0<<27)|(0<<26)|(0<<25)|(0<<24);  
  391.   
  392.     /* 
  393.     CIPRCTRL: 
  394.         bit[23:19] -- 主突发长度(Main_burst) 
  395.         bit[18:14] -- 剩余突发长度(Remained_burst) 
  396.         bit[2]    -- 是否使能LastIRQ功能(不使能) 
  397.     */  
  398.     CalculateBurstSize(bytesperline, &Main_burst, &Remained_burst);  
  399.     *CIPRCTRL = (Main_burst<<19)|(Remained_burst<<14)|(0<<2);  
  400.   
  401.     /* 
  402.     CIPRSCPRERATIO: 
  403.         bit[31:28]: 预览缩放的变化系数(SHfactor_Pr) 
  404.         bit[22:16]: 预览缩放的水平比(PreHorRatio_Pr) 
  405.         bit[6:0]: 预览缩放的垂直比(PreVerRatio_Pr) 
  406.  
  407.     CIPRSCPREDST: 
  408.         bit[27:16]: 预览缩放的目标宽度(PreDstWidth_Pr) 
  409.         bit[11:0]: 预览缩放的目标高度(PreDstHeight_Pr) 
  410.  
  411.     CIPRSCCTRL: 
  412.         bit[29:28]: 告诉摄像头控制器(图片是缩小、放大)(ScaleUpDown_Pr) 
  413.         bit[24:16]: 预览主缩放的水平比(MainHorRatio_Pr) 
  414.         bit[8:0]: 预览主缩放的垂直比(MainVerRatio_Pr) 
  415.  
  416.         bit[31]: 必须固定设置为1 
  417.         bit[30]: 设置图像输出格式是RGB16、RGB24 
  418.         bit[15]: 预览缩放开始 
  419.  
  420.         //bit[30]在cmos_ov7740_vidioc_s_fmt_vid_cap函数中设置 
  421.          
  422.     */  
  423.     cmos_ov7740_calculate_scaler_info();  
  424.     *CIPRSCPRERATIO = (sc.SHfactor<<28)|(sc.PreHorRatio<<16)|(sc.PreVerRatio<<0);  
  425.     *CIPRSCPREDST = (sc.PreDstWidth<<16)|(sc.PreDstHeight<<0);  
  426.     *CIPRSCCTRL |= (1<<31)|(sc.ScaleUpDown<<28)|(sc.MainHorRatio<<16)|(sc.MainVerRatio<<0);  
  427.   
  428.     /* 
  429.     CIPRTAREA: 
  430.         表示预览通道的目标区域 
  431.     */  
  432.     *CIPRTAREA = TargetHsize_Pr * TargetVsize_Pr;  
  433.   
  434.     /* 
  435.     CIIMGCPT: 
  436.         bit[31]: 用来使能摄像头控制器 
  437.         bit[30]: 使能编码通道 
  438.         bit[29]: 使能预览通道 
  439.     */  
  440.     *CIIMGCPT = (1<<31)|(1<<29);  
  441.     *CIPRSCCTRL |= (1<<15);  
  442.   
  443.     return 0;  
  444. }  
  445.   
  446. /* A17 停止  
  447.  * 参考 : uvc_video_enable(video, 0) 
  448.  */  
  449. static int cmos_ov7740_vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type t)  
  450. {  
  451.     *CIPRSCCTRL &= ~(1<<15);  
  452.     *CIIMGCPT &= ~((1<<31)|(1<<29));  
  453.   
  454.     return 0;  
  455. }  
  456.   
  457. static const struct v4l2_ioctl_ops cmos_ov7740_ioctl_ops = {  
  458.         // 表示它是一个摄像头设备  
  459.         .vidioc_querycap      = cmos_ov7740_vidioc_querycap,  
  460.   
  461.         /* 用于列举、获得、测试、设置摄像头的数据的格式 */  
  462.         .vidioc_enum_fmt_vid_cap  = cmos_ov7740_vidioc_enum_fmt_vid_cap,  
  463.         .vidioc_g_fmt_vid_cap     = cmos_ov7740_vidioc_g_fmt_vid_cap,  
  464.         .vidioc_try_fmt_vid_cap   = cmos_ov7740_vidioc_try_fmt_vid_cap,  
  465.         .vidioc_s_fmt_vid_cap     = cmos_ov7740_vidioc_s_fmt_vid_cap,  
  466.           
  467.         /* 缓冲区操作: 申请/查询/放入队列/取出队列 */  
  468.         .vidioc_reqbufs       = cmos_ov7740_vidioc_reqbufs,  
  469.   
  470.     /* 说明: 因为我们是通过读的方式来获得摄像头数据,因此查询/放入队列/取出队列这些操作函数将不在需要 */  
  471. #if 0  
  472.         .vidioc_querybuf      = myuvc_vidioc_querybuf,  
  473.         .vidioc_qbuf          = myuvc_vidioc_qbuf,  
  474.         .vidioc_dqbuf         = myuvc_vidioc_dqbuf,  
  475. #endif  
  476.   
  477.         // 启动/停止  
  478.         .vidioc_streamon      = cmos_ov7740_vidioc_streamon,  
  479.         .vidioc_streamoff     = cmos_ov7740_vidioc_streamoff,     
  480. };  
  481.   
  482. /* A1 */  
  483. static int cmos_ov7740_open(struct file *file)  
  484. {  
  485.     return 0;  
  486. }  
  487.   
  488. /* A18 关闭 */  
  489. static int cmos_ov7740_close(struct file *file)  
  490. {  
  491.       
  492.     return 0;  
  493. }  
  494.   
  495. /* 应用程序通过读的方式读取摄像头的数据 */  
  496. static ssize_t cmos_ov7740_read(struct file *filep, char __user *buf, size_t count, loff_t *pos)  
  497. {  
  498.     size_t end;  
  499.     int i;  
  500.     /* 取一帧数据的大小和用户想要读取数据的大小的最小值 */  
  501.     end = min_t(size_t, buf_size, count);  
  502.     wait_event_interruptible(cam_wait_queue, ev_cam);  
  503.   
  504.     for(i=0; i<4; i++)  
  505.     {  
  506.         if(copy_to_user(buf, (void *)img_buff[i].virt_base, end))  
  507.             return -EFAULT;  
  508.     }  
  509.   
  510.     ev_cam = 0;  
  511.   
  512.     return end;  
  513. }  
  514.   
  515. /* 应用程序使用read函数来获取摄像头数据,所以不再需要mmap,poll函数。 */  
  516. static const struct v4l2_file_operations cmos_ov7740_fops = {  
  517.     .owner          = THIS_MODULE,  
  518.     .open               = cmos_ov7740_open,  
  519.     .release            = cmos_ov7740_close,  
  520.     /* video_ioctl2是内核提供的函数,只是起到中转的作用,最后会调用video_device中的ioctl_ops */  
  521.     .unlocked_ioctl         = video_ioctl2,  
  522.     .read           = cmos_ov7740_read,  
  523. };  
  524.   
  525. /* 
  526.     注意: 
  527.         该函数是必须的,否则在insmod的时候,会出错 
  528. */  
  529. static void cmos_ov7740_release(struct video_device *vdev)  
  530. {  
  531.     unsigned int order;  
  532.   
  533.     order = get_order(buf_size);  
  534.   
  535.     free_pages(img_buff[0].virt_base, order);  
  536.     img_buff[0].phy_base = (unsigned long)NULL;  
  537.     free_pages(img_buff[1].virt_base, order);  
  538.     img_buff[1].phy_base = (unsigned long)NULL;   
  539.     free_pages(img_buff[2].virt_base, order);  
  540.     img_buff[2].phy_base = (unsigned long)NULL;       
  541.     free_pages(img_buff[3].virt_base, order);  
  542.     img_buff[3].phy_base = (unsigned long)NULL;   
  543. }  
  544.   
  545. /* 2.1. 分配、设置一个video_device结构体  
  546.  * 这里采用的是静态分配结构体,使用video_device_alloc()是动态分配摄像头结构体 
  547.  */  
  548. static struct video_device cmos_ov7740_vdev = {  
  549.     .fops       = &cmos_ov7740_fops,  
  550.     .ioctl_ops      = &cmos_ov7740_ioctl_ops,  
  551.     .release        = cmos_ov7740_release,  
  552.     .name       = "cmos_ov7740",  
  553. };  
  554.   
  555. static void cmos_ov7740_gpio_cfg(void)  
  556. {  
  557.     /* 设置相应的GPIO用于CAMIF */  
  558.     *GPJCON = 0x2aaaaaa;  
  559.     /* 将数据位清0 */  
  560.     *GPJDAT = 0;  
  561.   
  562.     /* 为了让信号稳定,使能上拉电阻 */  
  563.     *GPJUP = 0;  
  564. }  
  565.   
  566. static void cmos_ov7740_camif_reset(void)  
  567. {  
  568.     /* 传输方式为BT601 */  
  569.     *CISRCFMT |= (1<<31);  
  570.   
  571.     /* 复位CAMIF控制器 */  
  572.     *CIGCTRL |= (1<<31);  
  573.     /* 稍微延迟一下 */  
  574.     mdelay(10);  
  575.     /* 使摄像头恢复正常状态 */  
  576.     *CIGCTRL &= ~(1<<31 mdelay="" 10="" static="" void="" cmos_ov7740_clk_cfg="" void="" struct="" clk="" camif_clk="" struct="" clk="" camif_upll_clk="" camif="" clk_get="" soc="" source="" insight="" camif="" s3c2440="" camif_clk="clk_get(NULL," camif="" if="" camif_clk="" is_err="" camif_clk="" printk="" kern_info="" failed="" to="" get="" camif="" clock="" source="" n="" clk_enable="" camif_clk="" camclk="24MHz,设置外部摄像头的时钟" camif-upll="" usb="" soc="" usb="" soc="" camif_upll_clk="clk_get(NULL," camif-upll="" clk_set_rate="" camif_upll_clk="" 24000000="" mdelay="" 100="" :="" 1="" s3c2440="" camrst="" :0-="">1->0(0:表示正常工作的电平、1:表示复位电平)  
  577.           但是,实验证明,该复位时序与我们的OV7740需要的复位时序(1->0->1)不符合。  
  578.         2.因此,我们就应该结合OV7740的具体复位时序,来设置相应的寄存器。  
  579. */  
  580. static void cmos_ov7740_reset(void)  
  581. {  
  582.     *CIGCTRL |= (1<<30);  
  583.     mdelay(30);  
  584.     *CIGCTRL &= ~(1<<30);  
  585.     mdelay(30);  
  586.     *CIGCTRL |= (1<<30);  
  587.     mdelay(30);   
  588. }  
  589.   
  590. static void cmos_ov7740_init(void)  
  591. {  
  592.     unsigned int mid;  
  593.     int i;  
  594.   
  595.     /* 读  
  596.      * 0xa是摄像头模块的厂家id的高8位,0xb是厂家id的低8位 
  597.      * i2c_smbus_read_byte_data函数是内核提供的函数,也可是使用i2c_transfer函数 
  598.      */  
  599.     mid = i2c_smbus_read_byte_data(cmos_ov7740_client, 0x0a)<<8;  
  600.     mid |= i2c_smbus_read_byte_data(cmos_ov7740_client, 0x0b);  
  601.     printk("manufacture ID = 0x%4x\n", mid);  
  602.   
  603.     /* 写  
  604.      * 初始化摄像头模块 
  605.      */  
  606.     for(i = 0; i < OV7740_INIT_REGS_SIZE; i++)  
  607.     {  
  608.         i2c_smbus_write_byte_data(cmos_ov7740_client, ov7740_setting_30fps_VGA_640_480[i].regaddr, ov7740_setting_30fps_VGA_640_480[i].value);  
  609.         mdelay(2);  
  610.     }  
  611. }  
  612.   
  613. static int __devinit cmos_ov7740_probe(struct i2c_client *client,  
  614.                   const struct i2c_device_id *id)  
  615. {  
  616.     printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);  
  617.   
  618.     /* 2.3 硬件相关 */  
  619.     /* 2.3.1 映射相应的寄存器 */  
  620.     GPJCON = ioremap(0x560000d0, 4);  
  621.     GPJDAT = ioremap(0x560000d4, 4);  
  622.     /* 上拉电阻相关的寄存器 */   
  623.     GPJUP = ioremap(0x560000d8, 4);  
  624.   
  625.     /* 以下是摄像头控制器的寄存器 */  
  626.   
  627.     CISRCFMT = ioremap(0x4F000000, 4);  
  628.     CIWDOFST = ioremap(0x4F000004, 4);  
  629.     CIGCTRL = ioremap(0x4F000008, 4);  
  630.     CIPRCLRSA1 = ioremap(0x4F00006C, 4);  
  631.     CIPRCLRSA2 = ioremap(0x4F000070, 4);  
  632.     CIPRCLRSA3 = ioremap(0x4F000074, 4);  
  633.     CIPRCLRSA4 = ioremap(0x4F000078, 4);  
  634.     CIPRTRGFMT = ioremap(0x4F00007C, 4);  
  635.     CIPRCTRL = ioremap(0x4F000080, 4);  
  636.     CIPRSCPRERATIO = ioremap(0x4F000084, 4);  
  637.     CIPRSCPREDST = ioremap(0x4F000088, 4);  
  638.     CIPRSCCTRL = ioremap(0x4F00008C, 4);  
  639.     CIPRTAREA = ioremap(0x4F000090, 4);  
  640.     CIIMGCPT = ioremap(0x4F0000A0, 4);  
  641.   
  642.     SRCPND = ioremap(0X4A000000, 4);  
  643.     INTPND = ioremap(0X4A000010, 4);  
  644.     SUBSRCPND = ioremap(0X4A000018, 4);  
  645.   
  646.     /* 2.3.2 设置相应的GPIO用于CAMIF */  
  647.     cmos_ov7740_gpio_cfg();  
  648.   
  649.     /* 2.3.3 复位一下CAMIF控制器 
  650.      * 接下来要操作摄像头控制器,因此要先复位一下控制器 
  651.      */  
  652.     cmos_ov7740_camif_reset();  
  653.   
  654.     /* 2.3.4 设置、使能时钟(使能HCLK用于摄像头控制器、使能并设置CAMCLK = 24MHz用于外部摄像头) */  
  655.     cmos_ov7740_clk_cfg();  
  656.   
  657.     /* 2.3.5 复位一下摄像头模块 */  
  658.     cmos_ov7740_reset();  
  659.   
  660.     /* 2.3.6 通过IIC总线,初始化摄像头模块 */  
  661.     cmos_ov7740_client = client;  
  662.     cmos_ov7740_init();  
  663.   
  664.     /* 2.3.7 注册中断  
  665.      * IRQF_DISABLED - keep irqs disabled when calling the action handler 
  666.      */  
  667.     if (request_irq(IRQ_S3C2440_CAM_C, cmos_ov7740_camif_irq_c, IRQF_DISABLED , "CAM_C", NULL))  
  668.         printk("%s:request_irq failed\n", __func__);  
  669.   
  670.     if (request_irq(IRQ_S3C2440_CAM_P, cmos_ov7740_camif_irq_p, IRQF_DISABLED , "CAM_P", NULL))  
  671.         printk("%s:request_irq failed\n", __func__);  
  672.       
  673.       
  674.     /* 3. 注册 ,以下信息是通过追踪源代码得到的结论 
  675.      * 参数-1表示分配第一个可用的号 
  676.      * which device node number (0 == /dev/video0, 1 == /dev/video1, ... 
  677.      *            -1 == first free)  
  678.      */  
  679.     if(video_register_device(&cmos_ov7740_vdev, VFL_TYPE_GRABBER, -1))  
  680.     {  
  681.         printk("unable to register video device\n");  
  682.     }  
  683.   
  684.     return 0;  
  685. }  
  686.   
  687. static int __devexit cmos_ov7740_remove(struct i2c_client *client)  
  688. {  
  689.     printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);  
  690.   
  691.     iounmap(GPJCON);  
  692.     iounmap(GPJDAT);  
  693.     iounmap(GPJUP);  
  694.   
  695.     iounmap(CISRCFMT);  
  696.     iounmap(CIWDOFST);  
  697.     iounmap(CIGCTRL);  
  698.     iounmap(CIPRCLRSA1);  
  699.     iounmap(CIPRCLRSA2);  
  700.     iounmap(CIPRCLRSA3);  
  701.     iounmap(CIPRCLRSA4);  
  702.     iounmap(CIPRTRGFMT);  
  703.     iounmap(CIPRCTRL);  
  704.     iounmap(CIPRSCPRERATIO);  
  705.     iounmap(CIPRSCPREDST);  
  706.     iounmap(CIPRSCCTRL);  
  707.     iounmap(CIPRTAREA);  
  708.     iounmap(CIIMGCPT);  
  709.       
  710.     iounmap(SRCPND);  
  711.     iounmap(INTPND);  
  712.     iounmap(SUBSRCPND);  
  713.   
  714.     free_irq(IRQ_S3C2440_CAM_C, NULL);  
  715.     free_irq(IRQ_S3C2440_CAM_P, NULL);  
  716.     video_unregister_device(&cmos_ov7740_vdev);  
  717.     return 0;  
  718. }  
  719.   
  720. static const struct i2c_device_id cmos_ov7740_id_table[] = {  
  721.     { "cmos_ov7740", 0 },  
  722.     {}  
  723. };  
  724.   
  725. /* 1.1. 分配、设置一个i2c_driver */  
  726. static struct i2c_driver cmos_ov7740_driver = {  
  727.     .driver = {  
  728.         /* 用于和iic设备进行匹配,必须和iic_dev中的名字一样,否则匹配不成功 */  
  729.         .name   = "cmos_ov7740",  
  730.         .owner  = THIS_MODULE,  
  731.     },  
  732.     .probe      = cmos_ov7740_probe,  
  733.     .remove     = __devexit_p(cmos_ov7740_remove),  
  734.     .id_table   = cmos_ov7740_id_table,  
  735. };  
  736.   
  737. static int cmos_ov7740_drv_init(void)  
  738. {  
  739.     /* 1.2.注册 */  
  740.     i2c_add_driver(&cmos_ov7740_driver);  
  741.   
  742.     return 0;  
  743. }  
  744.   
  745. static void cmos_ov7740_drv_exit(void)  
  746. {  
  747.     i2c_del_driver(&cmos_ov7740_driver);  
  748. }  
  749.   
  750. module_init(cmos_ov7740_drv_init);  
  751. module_exit(cmos_ov7740_drv_exit);  
  752.   
  753. MODULE_LICENSE("GPL");  


  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值