• 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
    ");
    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
    ");
    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
    ");
    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
    ");
    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)
    ", __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
    ");
    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
    ", 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
    ", __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
    ", __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
    ", __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
    ");
    812         }
    813 
    814     return 0;
    815 }
    816 
    817 static int __devexit cmos_ov7740_remove(struct i2c_client *client)
    818 {
    819     printk("%s %s %d
    ", __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
    ", file);
    16     printf("%s w addr val
    ", 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
    ");
    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
    ", 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 }
  • 相关阅读:
    ffmpeg-3.2.4-static-win32-for-XP-bin.tar.xz
    FFmpeg Scaler Options
    MinGW GCC 6.3.0 2017年3月份出炉啦
    ffmpeg-201701[10,16,21,23,25]-bin.7z
    ffmpeg-201612[01,08,10,17,21,27,30]-bin.7z
    Firefox Portable Developer 52.0.0.6176-6178
    DIR 按文件名中数字大小进行排序
    ffmpeg-20161104[07,10,16,21,22,27,30]-bin.7z
    gnuWin32-mini-2016.10.30
    gnu coreutils-8.25 for win32 static
  • 原文地址:https://www.cnblogs.com/blogs-of-lxl/p/5272768.html
Copyright © 2020-2023  润新知