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 }