sheldon_blogs

Linux I2C总线设备驱动模型分析(ov7740)

1. 框架
1.1 硬件协议简介
1.2 驱动框架
1.3 bus-drv-dev模型及写程序
a. 设备的4种构建方法
a.1 定义一个i2c_board_info, 里面有:名字, 设备地址
然后i2c_register_board_info(busnum, ...) (把它们放入__i2c_board_list链表)
list_add_tail(&devinfo->list, &__i2c_board_list);

链表何时使用:
i2c_register_adapter > i2c_scan_static_board_info > i2c_new_device

使用限制:必须在 i2c_register_adapter 之前 i2c_register_board_info
所以:不适合我们动态加载insmod

a.2 直接i2c_new_device, i2c_new_probed_device
a.2.1 i2c_new_device : 认为设备肯定存在
a.2.2 i2c_new_probed_device :对于"已经识别出来的设备"(probed_device),才会创建("new")
i2c_new_probed_device
probe(adap, addr_list[i]) /* 确定设备是否真实存在 */
info->addr = addr_list[i];
i2c_new_device(adap, info);

a.3 从用户空间创建设备
创建设备
echo at24c08 0x50 > /sys/class/i2c-adapter/i2c-0/new_device

导致i2c_new_device被调用

删除设备
echo 0x50 > /sys/class/i2c-adapter/i2c-0/delete_device

导致i2c_unregister_device

a.4 前面的3种方法都要事先确定适配器(I2C总线,I2C控制器)
如果我事先并不知道这个I2C设备在哪个适配器上,怎么办?去class表示的所有的适配器上查找
有上一些I2C设备的地址是一样,怎么继续分配它是哪一款?用detect函数

static struct i2c_driver at24cxx_driver = {
.class = I2C_CLASS_HWMON, /* 表示去哪些适配器上找设备 */
.driver = {
.name = "100ask",
.owner = THIS_MODULE,
},
.probe = at24cxx_probe,
.remove = __devexit_p(at24cxx_remove),
.id_table = at24cxx_id_table,
.detect = at24cxx_detect, /* 用这个函数来检测设备确实存在 */
.address_list = addr_list, /* 这些设备的地址 */
};


去"class表示的这一类"I2C适配器,用"detect函数"来确定能否找到"address_list里的设备",
如果能找到就调用i2c_new_device来注册i2c_client, 这会和i2c_driver的id_table比较,
如果匹配,调用probe

i2c_add_driver
i2c_register_driver
a. at24cxx_driver放入i2c_bus_type的drv链表
并且从dev链表里取出能匹配的i2c_client并调用probe
driver_register


b. 对于每一个适配器,调用__process_new_driver
对于每一个适配器,调用它的函数确定address_list里的设备是否存在
如果存在,再调用detect进一步确定、设置,然后i2c_new_device
/* Walk the adapters that are already present */
i2c_for_each_dev(driver, __process_new_driver);
__process_new_driver
i2c_do_add_adapter
/* Detect supported devices on that bus, and instantiate them */
i2c_detect(adap, driver);
for (i = 0; address_list[i] != I2C_CLIENT_END; i += 1) {
err = i2c_detect_address(temp_client, driver);
/* 判断这个设备是否存在:简单的发出S信号确定有ACK */
if (!i2c_default_probe(adapter, addr))
return 0;

memset(&info, 0, sizeof(struct i2c_board_info));
info.addr = addr;

// 设置info.type
err = driver->detect(temp_client, &info);


i2c_new_device.

 

 

下面示例一份cmos摄像头ov7740的i2c驱动:

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

再附一段测试程序,对i2c设备的寄存器进行读写测试:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <string.h>
 4 #include <sys/types.h>
 5 #include <sys/stat.h>
 6 #include <fcntl.h>
 7 
 8 
 9 /* i2c_test r addr
10  * i2c_test w addr val
11  */
12 
13 void print_usage(char *file)
14 {
15     printf("%s r addr\n", file);
16     printf("%s w addr val\n", file);
17 }
18 
19 int main(int argc, char **argv)
20 {
21     int fd;
22     unsigned char buf[2];
23     
24     if ((argc != 3) && (argc != 4))
25     {
26         print_usage(argv[0]);
27         return -1;
28     }
29 
30     fd = open("/dev/at24cxx", O_RDWR);
31     if (fd < 0)
32     {
33         printf("can't open /dev/at24cxx\n");
34         return -1;
35     }
36 
37     if (strcmp(argv[1], "r") == 0)
38     {
39         buf[0] = strtoul(argv[2], NULL, 0);
40         read(fd, buf, 1);
41         printf("data: %c, %d, 0x%2x\n", buf[0], buf[0], buf[0]);
42     }
43     else if (strcmp(argv[1], "w") == 0)
44     {
45         buf[0] = strtoul(argv[2], NULL, 0);
46         buf[1] = strtoul(argv[3], NULL, 0);
47         write(fd, buf, 2);
48     }
49     else
50     {
51         print_usage(argv[0]);
52         return -1;
53     }
54     
55     return 0;
56 }

 

posted on 2016-03-13 18:52  sheldon_blogs  阅读(2154)  评论(0编辑  收藏  举报

导航