Linux I2C总线设备驱动模型分析(ov7740)
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了Linux I2C总线设备驱动模型分析(ov7740),小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含26497字,纯文字阅读大概需要38分钟。
内容图文
![Linux I2C总线设备驱动模型分析(ov7740)](/upload/InfoBanner/zyjiaocheng/1327/29ef10f22fb14c1d96972b06dd35e866.jpg)
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> 910staticstruct i2c_board_info cmos_ov7740_info = { 11 I2C_BOARD_INFO("cmos_ov7740", 0x21), //0x21:i2c设备地址12}; 1314staticstruct i2c_client *cmos_ov7740_client; 1516staticint cmos_ov7740_dev_init(void) 17{ 18struct i2c_adapter *i2c_adap; 1920 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之下2324return0; 25} 2627staticvoid cmos_ov7740_dev_exit(void) 28{ 29 i2c_unregister_device(cmos_ov7740_client); 30} 3132module_init(cmos_ov7740_dev_init); 33module_exit(cmos_ov7740_dev_exit); 3435 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 40struct 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 53staticstruct 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}, 101102 {0x53, 0x00}, 103 {0x89, 0x30}, 104 {0x8d, 0x30}, 105 {0x8f, 0x85}, 106 {0x93, 0x30}, 107 {0x95, 0x85}, 108 {0x99, 0x30}, 109 {0x9b, 0x85}, 110111 {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}; 132133struct cmos_ov7740_fmt { 134char *name; 135 u32 fourcc; /* v4l2 format id */136int depth; 137}; 138139staticstruct 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}; 151152struct camif_buffer 153{ 154 unsigned int order; 155 unsigned long virt_base; 156 unsigned long phy_base; 157}; 158159struct 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}; 182183staticstruct i2c_client *cmos_ov7740_client; 184185// CAMIF GPIO186static unsigned long *GPJCON; 187static unsigned long *GPJDAT; 188static unsigned long *GPJUP; 189190// CAMIF191static unsigned long *CISRCFMT; 192static unsigned long *CIWDOFST; 193static unsigned long *CIGCTRL; 194static unsigned long *CIPRCLRSA1; 195static unsigned long *CIPRCLRSA2; 196static unsigned long *CIPRCLRSA3; 197static unsigned long *CIPRCLRSA4; 198static unsigned long *CIPRTRGFMT; 199static unsigned long *CIPRCTRL; 200static unsigned long *CIPRSCPRERATIO; 201static unsigned long *CIPRSCPREDST; 202static unsigned long *CIPRSCCTRL; 203static unsigned long *CIPRTAREA; 204static unsigned long *CIIMGCPT; 205206// IRQ207static unsigned long *SRCPND; 208static unsigned long *INTPND; 209static unsigned long *SUBSRCPND; 210211static unsigned int SRC_Width, SRC_Height; 212static unsigned int TargetHsize_Pr, TargetVsize_Pr; 213static unsigned long buf_size; 214static unsigned int bytesperline; 215216static DECLARE_WAIT_QUEUE_HEAD(cam_wait_queue); 217/* 中断标志 */218staticvolatileint ev_cam = 0; 219220static irqreturn_t cmos_ov7740_camif_irq_c(int irq, void *dev_id) 221{ 222return IRQ_HANDLED; 223} 224225static 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; 231232 ev_cam = 1; 233 wake_up_interruptible(&cam_wait_queue); 234235return IRQ_HANDLED; 236} 237238/* A2 参考 uvc_v4l2_do_ioctl */239staticint cmos_ov7740_vidioc_querycap(struct file *file, void *priv, 240struct 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; 246247 cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE; 248249return0; 250} 251252/* A3 列举支持哪种格式 253 * 参考: uvc_fmts 数组 254*/255staticint cmos_ov7740_vidioc_enum_fmt_vid_cap(struct file *file, void *priv, 256struct v4l2_fmtdesc *f) 257{ 258struct cmos_ov7740_fmt *fmt; 259260if (f->index >= ARRAY_SIZE(formats)) 261return -EINVAL; 262263 fmt = &formats[f->index]; 264265 strlcpy(f->description, fmt->name, sizeof(f->description)); 266 f->pixelformat = fmt->fourcc; 267268return0; 269} 270271/* A4 返回当前所使用的格式 */272staticint cmos_ov7740_vidioc_g_fmt_vid_cap(struct file *file, void *priv, 273struct v4l2_format *f) 274{ 275return0; 276} 277278/* A5 测试驱动程序是否支持某种格式, 强制设置该格式 279 * 参考: uvc_v4l2_try_format 280 * myvivi_vidioc_try_fmt_vid_cap 281*/282staticint cmos_ov7740_vidioc_try_fmt_vid_cap(struct file *file, void *priv, 283struct v4l2_format *f) 284{ 285if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 286 { 287return -EINVAL; 288 } 289290if ((f->fmt.pix.pixelformat != V4L2_PIX_FMT_RGB565) && (f->fmt.pix.pixelformat != V4L2_PIX_FMT_RGB24)) 291return -EINVAL; 292293return0; 294} 295296/* A6 参考 myvivi_vidioc_s_fmt_vid_cap */297staticint cmos_ov7740_vidioc_s_fmt_vid_cap(struct file *file, void *priv, 298struct v4l2_format *f) 299{ 300int ret = cmos_ov7740_vidioc_try_fmt_vid_cap(file, NULL, f); 301if (ret < 0) 302return ret; 303304 TargetHsize_Pr = f->fmt.pix.width; 305 TargetVsize_Pr = f->fmt.pix.height; 306307if(f->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565) 308 { 309 *CIPRSCCTRL &= ~(1<<30); 310311 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 } 316elseif(f->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB24) 317 { 318 *CIPRSCCTRL |= (1<<30); 319320 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 } 325326327328/*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); 335336return0; 337} 338339staticint cmos_ov7740_vidioc_reqbufs(struct file *file, void *priv, 340struct v4l2_requestbuffers *p) 341{ 342 unsigned int order; 343344 order = get_order(buf_size); 345346 img_buff[0].order = order; 347 img_buff[0].virt_base = __get_free_pages(GFP_KERNEL|__GFP_DMA, img_buff[0].order); 348if(img_buff[0].virt_base == (unsigned long)NULL) 349 { 350 printk("error0\n"); 351goto error0; 352 } 353 img_buff[0].phy_base = __virt_to_phys(img_buff[0].virt_base); 354355 img_buff[1].order = order; 356 img_buff[1].virt_base = __get_free_pages(GFP_KERNEL|__GFP_DMA, img_buff[1].order); 357if(img_buff[1].virt_base == (unsigned long)NULL) 358 { 359 printk("error1\n"); 360goto error1; 361 } 362 img_buff[1].phy_base = __virt_to_phys(img_buff[1].virt_base); 363364 img_buff[2].order = order; 365 img_buff[2].virt_base = __get_free_pages(GFP_KERNEL|__GFP_DMA, img_buff[2].order); 366if(img_buff[2].virt_base == (unsigned long)NULL) 367 { 368 printk("error2\n"); 369goto error2; 370 } 371 img_buff[2].phy_base = __virt_to_phys(img_buff[2].virt_base); 372373 img_buff[3].order = order; 374 img_buff[3].virt_base = __get_free_pages(GFP_KERNEL|__GFP_DMA, img_buff[3].order); 375if(img_buff[3].virt_base == (unsigned long)NULL) 376 { 377 printk("error3\n"); 378goto error3; 379 } 380 img_buff[3].phy_base = __virt_to_phys(img_buff[3].virt_base); 381382 *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; 386387return0; 388error3: 389 free_pages(img_buff[2].virt_base, order); 390 img_buff[2].phy_base = (unsigned long)NULL; 391error2: 392 free_pages(img_buff[1].virt_base, order); 393 img_buff[1].phy_base = (unsigned long)NULL; 394error1: 395 free_pages(img_buff[0].virt_base, order); 396 img_buff[0].phy_base = (unsigned long)NULL; 397error0: 398return -ENOMEM; 399} 400401staticvoid CalculateBurstSize(unsigned int hSize, unsigned int *mainBusrtSize, unsigned int *remainedBustSize) 402{ 403 unsigned int tmp; 404405 tmp = (hSize/4)%16; 406switch(tmp) 407 { 408case0: 409 *mainBusrtSize = 16; 410 *remainedBustSize = 16; 411break; 412case4: 413 *mainBusrtSize = 16; 414 *remainedBustSize = 4; 415break; 416case8: 417 *mainBusrtSize = 16; 418 *remainedBustSize = 8; 419break; 420default: 421 tmp = (hSize/4)%8; 422switch(tmp) 423 { 424case0: 425 *mainBusrtSize = 8; 426 *remainedBustSize = 8; 427break; 428case4: 429 *mainBusrtSize = 8; 430 *remainedBustSize = 4; 431break; 432default: 433 *mainBusrtSize = 4; 434 tmp = (hSize/4)%4; 435 *remainedBustSize = (tmp)?tmp:4; 436break; 437 } 438break; 439 } 440} 441442staticvoid camif_get_scaler_factor(u32 src, u32 tar, u32 *ratio, u32 *shift) 443{ 444if(src >= 64*tar) {return;} 445elseif(src >= 32*tar) {*ratio = 32; *shift = 5;} 446elseif(src >= 16*tar) {*ratio = 16; *shift = 4;} 447elseif(src >= 8*tar) {*ratio = 8; *shift = 3;} 448elseif(src >= 4*tar) {*ratio = 4; *shift = 2;} 449elseif(src >= 2*tar) {*ratio = 2; *shift = 1;} 450else {*ratio = 1; *shift = 0;} 451} 452453staticvoid cmos_ov7740_calculate_scaler_info(void) 454{ 455 unsigned int sx, sy, tx, ty; 456457 sx = SRC_Width; 458 sy = SRC_Height; 459 tx = TargetHsize_Pr; 460 ty = TargetVsize_Pr; 461462 printk("%s: SRC_in(%d, %d), Target_out(%d, %d)\n", __func__, sx, sy, tx, ty); 463464 camif_get_scaler_factor(sx, tx, &sc.PreHorRatio, &sc.H_Shift); 465 camif_get_scaler_factor(sy, ty, &sc.PreVerRatio, &sc.V_Shift); 466467 sc.PreDstWidth = sx / sc.PreHorRatio; 468 sc.PreDstHeight = sy / sc.PreVerRatio; 469470 sc.MainHorRatio = (sx << 8) / (tx << sc.H_Shift); 471 sc.MainVerRatio = (sy << 8) / (ty << sc.V_Shift); 472473 sc.SHfactor = 10 - (sc.H_Shift + sc.V_Shift); 474475 sc.ScaleUpDown = (tx>=sx)?1:0; 476} 477478/* A11 启动传输 479 * 参考: uvc_video_enable(video, 1): 480 * uvc_commit_video 481 * uvc_init_video 482*/483staticint cmos_ov7740_vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) 484{ 485 unsigned int Main_burst, Remained_burst; 486487/*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); 497498/*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; 509510/*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); 521522/*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); 530531/*532 CIPRSCPRERATIO: 533 bit[31:28]: 预览缩放的变化系数(SHfactor_Pr) 534 bit[22:16]: 预览缩放的水平比(PreHorRatio_Pr) 535 bit[6:0]: 预览缩放的垂直比(PreVerRatio_Pr) 536537 CIPRSCPREDST: 538 bit[27:16]: 预览缩放的目标宽度(PreDstWidth_Pr) 539 bit[11:0]: 预览缩放的目标高度(PreDstHeight_Pr) 540541 CIPRSCCTRL: 542 bit[29:28]: 告诉摄像头控制器(图片是缩小、放大)(ScaleUpDown_Pr) 543 bit[24:16]: 预览主缩放的水平比(MainHorRatio_Pr) 544 bit[8:0]: 预览主缩放的垂直比(MainVerRatio_Pr) 545546 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); 554555/*556 CIPRTAREA: 557 表示预览通道的目标区域 558*/559 *CIPRTAREA = TargetHsize_Pr * TargetVsize_Pr; 560561/*562 CIIMGCPT: 563 bit[31]: 用来使能摄像头控制器 564 bit[30]: 使能编码通道 565 bit[29]: 使能预览通道 566*/567 *CIIMGCPT = (1<<31)|(1<<29); 568 *CIPRSCCTRL |= (1<<15); 569570return0; 571} 572573/* A17 停止 574 * 参考 : uvc_video_enable(video, 0) 575*/576staticint 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)); 580581return0; 582} 583584staticconststruct v4l2_ioctl_ops cmos_ov7740_ioctl_ops = { 585// 表示它是一个摄像头设备586 .vidioc_querycap = cmos_ov7740_vidioc_querycap, 587588/* 用于列举、获得、测试、设置摄像头的数据的格式 */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, 593594/* 缓冲区操作: 申请/查询/放入队列/取出队列 */595 .vidioc_reqbufs = cmos_ov7740_vidioc_reqbufs, 596597/* 说明: 因为我们是通过读的方式来获得摄像头数据,因此查询/放入队列/取出队列这些操作函数将不在需要 */598#if 0 599 .vidioc_querybuf = myuvc_vidioc_querybuf, 600 .vidioc_qbuf = myuvc_vidioc_qbuf, 601 .vidioc_dqbuf = myuvc_vidioc_dqbuf, 602#endif603604// 启动/停止605 .vidioc_streamon = cmos_ov7740_vidioc_streamon, 606 .vidioc_streamoff = cmos_ov7740_vidioc_streamoff, 607}; 608609/* A1 */610staticint cmos_ov7740_open(struct file *file) 611{ 612return0; 613} 614615/* A18 关闭 */616staticint cmos_ov7740_close(struct file *file) 617{ 618619return0; 620} 621622/* 应用程序通过读的方式读取摄像头的数据 */623static ssize_t cmos_ov7740_read(struct file *filep, char __user *buf, size_t count, loff_t *pos) 624{ 625 size_t end; 626int i; 627628 end = min_t(size_t, buf_size, count); 629630 wait_event_interruptible(cam_wait_queue, ev_cam); 631632for(i=0; i<4; i++) 633 { 634if(copy_to_user(buf, (void *)img_buff[i].virt_base, end)) 635return -EFAULT; 636 } 637638 ev_cam = 0; 639640return end; 641} 642643staticconststruct 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}; 650651/*652 注意: 653 该函数是必须的,否则在insmod的时候,会出错 654*/655staticvoid cmos_ov7740_release(struct video_device *vdev) 656{ 657 unsigned int order; 658659 order = get_order(buf_size); 660661 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} 670671/* 2.1. 分配、设置一个video_device结构体 */672staticstruct 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}; 678679staticvoid cmos_ov7740_gpio_cfg(void) 680{ 681/* 设置相应的GPIO用于CAMIF */682 *GPJCON = 0x2aaaaaa; 683 *GPJDAT = 0; 684685/* 使能上拉电阻 */686 *GPJUP = 0; 687} 688689staticvoid cmos_ov7740_camif_reset(void) 690{ 691/* 传输方式为BT601 */692 *CISRCFMT |= (1<<31); 693694/* 复位CAMIF控制器 */695 *CIGCTRL |= (1<<31); 696 mdelay(10); 697 *CIGCTRL &= ~(1<<31); 698 mdelay(10); 699} 700701staticvoid cmos_ov7740_clk_cfg(void) 702{ 703struct clk *camif_clk; 704struct clk *camif_upll_clk; 705706/* 使能CAMIF的时钟源 */707 camif_clk = clk_get(NULL, "camif"); 708if(!camif_clk || IS_ERR(camif_clk)) 709 { 710 printk(KERN_INFO "failed to get CAMIF clock source\n"); 711 } 712 clk_enable(camif_clk); 713714/* 使能并设置CAMCLK = 24MHz */715 camif_upll_clk = clk_get(NULL, "camif-upll"); 716 clk_set_rate(camif_upll_clk, 24000000); 717 mdelay(100); 718} 719720/*721 注意: 722 1.S3C2440提供的复位时序(CAMRST)为:0->1->0(0:表示正常工作的电平、1:表示复位电平) 723 但是,实验证明,该复位时序与我们的OV7740需要的复位时序(1->0->1)不符合。 724 2.因此,我们就应该结合OV7740的具体复位时序,来设置相应的寄存器。 725*/726staticvoid 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} 735736staticvoid cmos_ov7740_init(void) 737{ 738 unsigned int mid; 739int i; 740741/* 读 */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); 745746/* 写 */747for(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} 753754staticint __devinit cmos_ov7740_probe(struct i2c_client *client, 755conststruct i2c_device_id *id) 756{ 757 printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__); 758759/* 2.3 硬件相关 */760/* 2.3.1 映射相应的寄存器 */761 GPJCON = ioremap(0x560000d0, 4); 762 GPJDAT = ioremap(0x560000d4, 4); 763 GPJUP = ioremap(0x560000d8, 4); 764765 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); 779780 SRCPND = ioremap(0X4A000000, 4); 781 INTPND = ioremap(0X4A000010, 4); 782 SUBSRCPND = ioremap(0X4A000018, 4); 783784/* 2.3.2 设置相应的GPIO用于CAMIF */785 cmos_ov7740_gpio_cfg(); 786787/* 2.3.3 复位一下CAMIF控制器 */788 cmos_ov7740_camif_reset(); 789790/* 2.3.4 设置、使能时钟(使能HCLK、使能并设置CAMCLK = 24MHz) */791 cmos_ov7740_clk_cfg(); 792793/* 2.3.5 复位一下摄像头模块 */794 cmos_ov7740_reset(); 795796/* 2.3.6 通过IIC总线,初始化摄像头模块 */797 cmos_ov7740_client = client; 798 cmos_ov7740_init(); 799800/* 2.3.7 注册中断 */801if (request_irq(IRQ_S3C2440_CAM_C, cmos_ov7740_camif_irq_c, IRQF_DISABLED , "CAM_C", NULL)) 802 printk("%s:request_irq failed\n", __func__); 803804if (request_irq(IRQ_S3C2440_CAM_P, cmos_ov7740_camif_irq_p, IRQF_DISABLED , "CAM_P", NULL)) 805 printk("%s:request_irq failed\n", __func__); 806807808/* 2.2.注册 */809if(video_register_device(&cmos_ov7740_vdev, VFL_TYPE_GRABBER, -1)) 810 { 811 printk("unable to register video device\n"); 812 } 813814return0; 815} 816817staticint __devexit cmos_ov7740_remove(struct i2c_client *client) 818{ 819 printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__); 820821 iounmap(GPJCON); 822 iounmap(GPJDAT); 823 iounmap(GPJUP); 824825 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); 839840 iounmap(SRCPND); 841 iounmap(INTPND); 842 iounmap(SUBSRCPND); 843844 free_irq(IRQ_S3C2440_CAM_C, NULL); 845 free_irq(IRQ_S3C2440_CAM_P, NULL); 846 video_unregister_device(&cmos_ov7740_vdev); 847return0; 848} 849850staticconststruct i2c_device_id cmos_ov7740_id_table[] = { 851 { "cmos_ov7740", 0 }, 852 {} 853}; 854855/* 1.1. 分配、设置一个i2c_driver */856staticstruct 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}; 865866staticint cmos_ov7740_drv_init(void) 867{ 868/* 1.2.注册 */869 i2c_add_driver(&cmos_ov7740_driver); 870871return0; 872} 873874staticvoid cmos_ov7740_drv_exit(void) 875{ 876 i2c_del_driver(&cmos_ov7740_driver); 877} 878879module_init(cmos_ov7740_drv_init); 880module_exit(cmos_ov7740_drv_exit); 881882 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*/1213void print_usage(char *file) 14{ 15 printf("%s r addr\n", file); 16 printf("%s w addr val\n", file); 17} 1819int main(int argc, char **argv) 20{ 21int fd; 22 unsigned char buf[2]; 2324if ((argc != 3) && (argc != 4)) 25 { 26 print_usage(argv[0]); 27return -1; 28 } 2930 fd = open("/dev/at24cxx", O_RDWR); 31if (fd < 0) 32 { 33 printf("can‘t open /dev/at24cxx\n"); 34return -1; 35 } 3637if (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 } 43elseif (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 } 49else50 { 51 print_usage(argv[0]); 52return -1; 53 } 5455return0; 56 }
原文:http://www.cnblogs.com/blogs-of-lxl/p/5272768.html
内容总结
以上是互联网集市为您收集整理的Linux I2C总线设备驱动模型分析(ov7740)全部内容,希望文章能够帮你解决Linux I2C总线设备驱动模型分析(ov7740)所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。