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

/* 应用程序通过读的方式读取摄像头的数据 */
static ssize_t cmos_ov7740_read(struct file *filep, char __user *buf, size_t count, loff_t *pos)
{
    size_t end;
    int i;

end = min_t(size_t, buf_size, count);

wait_event_interruptible(cam_wait_queue, ev_cam);

for(i=0; i<4; i++)
    {
        if(copy_to_user(buf, (void *)img_buff[i].virt_base, end))
            return -EFAULT;
    }

ev_cam = 0;

return end;
}

static const struct v4l2_file_operations cmos_ov7740_fops = {
    .owner            = THIS_MODULE,
    .open              = cmos_ov7740_open,
    .release            = cmos_ov7740_close,
    .unlocked_ioctl          = video_ioctl2,
    .read            = cmos_ov7740_read,
};

/*
    注意:
        该函数是必须的,否则在insmod的时候,会出错
*/
static void cmos_ov7740_release(struct video_device *vdev)
{
    unsigned int order;

order = get_order(buf_size);

free_pages(img_buff[0].virt_base, order);
    img_buff[0].phy_base = (unsigned long)NULL;
    free_pages(img_buff[1].virt_base, order);
    img_buff[1].phy_base = (unsigned long)NULL;   
    free_pages(img_buff[2].virt_base, order);
    img_buff[2].phy_base = (unsigned long)NULL;       
    free_pages(img_buff[3].virt_base, order);
    img_buff[3].phy_base = (unsigned long)NULL;   
}

/* 2.1. 分配、设置一个video_device结构体 */
static struct video_device cmos_ov7740_vdev = {
    .fops        = &cmos_ov7740_fops,
    .ioctl_ops        = &cmos_ov7740_ioctl_ops,
    .release        = cmos_ov7740_release,
    .name        = "cmos_ov7740",
};

static void cmos_ov7740_gpio_cfg(void)
{
    /* 设置相应的GPIO用于CAMIF */
    *GPJCON = 0x2aaaaaa;
    *GPJDAT = 0;

/* 使能上拉电阻 */
    *GPJUP = 0;
}

static void cmos_ov7740_camif_reset(void)
{
    /* 传输方式为BT601 */
    *CISRCFMT |= (1<<31);

/* 复位CAMIF控制器 */
    *CIGCTRL |= (1<<31);
    mdelay(10);
    *CIGCTRL &= ~(1<<31);
    mdelay(10);   
}

static void cmos_ov7740_clk_cfg(void)
{
    struct clk *camif_clk;
    struct clk *camif_upll_clk;

/* 使能CAMIF的时钟源 */
    camif_clk = clk_get(NULL, "camif");
    if(!camif_clk || IS_ERR(camif_clk))
    {
        printk(KERN_INFO "failed to get CAMIF clock source\n");
    }
    clk_enable(camif_clk);

/* 使能并设置CAMCLK = 24MHz */
    camif_upll_clk = clk_get(NULL, "camif-upll");
    clk_set_rate(camif_upll_clk, 24000000);
    mdelay(100);
}

/*
    注意:
        1.S3C2440提供的复位时序(CAMRST)为:0->1->0(0:表示正常工作的电平、1:表示复位电平)
          但是,实验证明,该复位时序与我们的OV7740需要的复位时序(1->0->1)不符合。
        2.因此,我们就应该结合OV7740的具体复位时序,来设置相应的寄存器。
*/
static void cmos_ov7740_reset(void)
{
    *CIGCTRL |= (1<<30);
    mdelay(30);
    *CIGCTRL &= ~(1<<30);
    mdelay(30);
    *CIGCTRL |= (1<<30);
    mdelay(30);   
}

static void cmos_ov7740_init(void)
{
    unsigned int mid;
    int i;

/* 读 */
    mid = i2c_smbus_read_byte_data(cmos_ov7740_client, 0x0a)<<8;
    mid |= i2c_smbus_read_byte_data(cmos_ov7740_client, 0x0b);
    printk("manufacture ID = 0x%4x\n", mid);

/* 写 */
    for(i = 0; i < OV7740_INIT_REGS_SIZE; i++)
    {
        i2c_smbus_write_byte_data(cmos_ov7740_client, ov7740_setting_30fps_VGA_640_480[i].regaddr, ov7740_setting_30fps_VGA_640_480[i].value);
        mdelay(2);
    }
}

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/124de2ba14b952f5a166e369a62106bb.html